websocket播放支持

This commit is contained in:
EillesWan 2024-05-01 01:16:05 +08:00
parent c17ff0e53a
commit 382b0e1601
10 changed files with 197 additions and 73 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@ RES.txt
/Packer/*.MPK
/Packer/checksum.txt
/bgArrayLib
/fcwslib
# Byte-compiled / optimized
__pycache__/

View File

@ -7,9 +7,9 @@
5. Apache2.0 协议的英文原文副本可见下文
> The English Translation of the TERMS AND CONDITIONS above is listed below
>
>
> This translated version is for reference only and has no legal effect.
>
>
> The version with legal effect is the Chinese version above.
**Note, The TERMS AND CONDITIONS below should and must be above all others in this project**
@ -23,7 +23,6 @@
3. Apache 2.0 License.
5. A copy of the original Apache Lisence 2.0 can be found below.
```text
Apache License
Version 2.0, January 2004

View File

@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__version__ = "2.0.0"
__vername__ = "全新组织架构"
__version__ = "2.1.0"
__vername__ = "Websocket支持"
__author__ = (
("金羿", "Eilles Wan"),
("诸葛亮与八卦阵", "bgArray"),

View File

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
"""
存放有关WebSocket服务器操作的内容
"""
"""
版权所有 © 2024 · 开发者
Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿乐组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import fcwslib
# 这个库有问题,正在检修
class Plugin(fcwslib.Plugin):
async def on_connect(self) -> None:
print("对象已被连接")
await self.send_command("list", callback=self.list)
await self.subscribe("PlayerMessage", callback=self.player_message)
async def on_disconnect(self) -> None:
print("对象停止连接")
async def on_receive(self, response) -> None:
print("已接收非常规回复 {}".format(response))
async def list(self, response) -> None:
print("已收取指令执行回复 {}".format(response))
async def player_message(self, response) -> None:
print("已收取玩家事件回复 {}".format(response))

View File

@ -11,19 +11,120 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import fcwslib
import asyncio
import uuid
import time
# from ...main import MidiConvert
from ...main import MidiConvert
from ...subclass import ProgressBarStyle
from ...types import Optional, Literal, Tuple, List
# from ..main import ConvertConfig
# from ...subclass import MineCommand
from ...subclass import MineCommand
# def open_websocket_server(
# midi_cvt: MidiConvert,
# data_cfg: ConvertConfig,
# player: str = "@a",
# server_dist: str = "localhost",
# server_port: int = 8000,
# ):
# wssever = fcwslib.Server(server=server_dist,port=server_port,debug_mode=False)
def to_websocket_server(
midi_cvt_lst: List[MidiConvert],
server_dist: str,
server_port: int,
progressbar_style: Optional[ProgressBarStyle],
) -> None:
"""
将midi以延迟播放器形式转换为mcstructure结构文件后打包成附加包并在附加包中生成相应地导入函数
Parameters
----------
midi_cvt: List[MidiConvert]
一组用于转换的MidiConvert对象
server_dist: str
WebSocket播放服务器开启地址
server_port: str
WebSocket播放服务器开启端口
progressbar_style: ProgressBarStyle 对象
进度条对象
Returns
-------
None
"""
replacement = str(uuid.uuid4())
musics = dict(
[
(k.music_name, k.to_command_list_in_delay(replacement)[:2])
for k in midi_cvt_lst
]
)
class Plugin(fcwslib.Plugin):
async def on_connect(self) -> None:
print("已成功获连接")
await self.send_command("list", callback=self.cmd_feedback)
await self.subscribe("PlayerMessage", callback=self.player_message)
async def on_disconnect(self) -> None:
print("连接已然终止")
await self.disconnect()
async def on_receive(self, response) -> None:
print("已收取非已知列回复 {}".format(response))
async def cmd_feedback(self, response) -> None:
print("已收取指令执行回复 {}".format(response))
async def player_message(self, response) -> None:
print("已收取玩家事件回复 {}".format(response))
if response["body"]["message"].startswith(("。播放", ".play")):
whom_to_play: str = response["body"]["sender"]
music_to_play: str = (
response["body"]["message"]
.replace("。播放", "")
.replace(".play", "")
.strip()
)
if music_to_play in musics.keys():
self.check_play = True
delay_of_now = 0
for cmd in musics[music_to_play][0]:
if not self.check_play:
break
_time = time.time()
if progressbar_style:
await self.send_command(
"title {} actionbar {}".format(
whom_to_play,
progressbar_style.play_output(
played_delays=delay_of_now,
total_delays=musics[music_to_play][1],
music_name=music_to_play,
),
),
callback=self.cmd_feedback,
)
await self.send_command(
cmd.command_text.replace(replacement, whom_to_play),
callback=self.cmd_feedback,
)
delay_of_now += cmd.delay
await asyncio.sleep((time.time() - _time) + cmd.delay / 20)
else:
await self.send_command(
"tellraw {} {}{}{}".format(
whom_to_play,
r'{"rawtext":[{"text":"§c§l所选歌曲',
music_to_play,
'无法播放:播放列表不存在之"}]}',
),
callback=self.cmd_feedback,
)
elif response["body"]["message"].startswith(
("。停止播放", ".stopplay", ".stoplay")
):
self.check_play = False
server = fcwslib.Server(server=server_dist, port=server_port, debug_mode=True)
server.add_plugin(Plugin)
asyncio.run(server.run_forever())

View File

@ -155,7 +155,7 @@ class MineNote:
def encode(self, is_displacement_included: bool = True) -> bytes:
"""
将数据打包为字节码
:param is_displacement_included:`bool` 是否包含声像偏移数据默认为****
:return bytes 打包好的字节码
@ -662,9 +662,21 @@ class ProgressBarStyle:
def __init__(self, base_s: str, to_play_s: str, played_s: str):
"""用于存储进度条样式的类
| 标识符 | 指定的可变量 |
|---------|----------------|
| `%%N` | 乐曲名(即传入的文件名)|
| `%%s` | 当前计分板值 |
| `%^s` | 计分板最大值 |
| `%%t` | 当前播放时间 |
| `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位|
:param base_s 基础样式用以定义进度条整体
:param to_play_s 进度条样式尚未播放的样子
:param played_s 已经播放的样子"""
:param played_s 已经播放的样子
"""
self.base_style = base_s
self.to_play_style = to_play_s
self.played_style = played_s
@ -704,11 +716,47 @@ class ProgressBarStyle:
dst = ProgressBarStyle(self.base_style, self.to_play_style, self.played_style)
return dst
def play_output(
self,
played_delays: int,
total_delays: int,
music_name: str = "无题",
) -> str:
"""
直接依照此格式输出一个进度条
:param played_delays: int 当前播放进度积分值
:param total_delays: int 乐器总延迟数积分数
:param music_name: str 曲名
"""
return (
self.base_style.replace(r"%%N", music_name)
.replace(r"%%s", str(played_delays))
.replace(r"%^s", str(total_delays))
.replace(r"%%t", mctick2timestr(played_delays))
.replace(r"%^t", mctick2timestr(total_delays))
.replace(r"%%%", str(int(10000 * played_delays / total_delays) / 100) + "%")
.replace(
"_",
self.played_style,
(played_delays * self.base_style.count("_") // total_delays) + 1,
)
.replace("_", self.to_play_style)
)
def mctick2timestr(mc_tick: int) -> str:
"""
我的世界的游戏刻计转为表示时间的字符串
"""
return "{:0>2d}:{:0>2d}".format(mc_tick // 1200, (mc_tick // 20) % 60)
DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle(
r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
r"§e=§r",
r"§7=§r",
r"%%N [ %%s/%^s %%% §e__________§r %%t|%^t ]",
r"§7=",
r"=",
)
"""
默认的进度条样式

View File

@ -24,7 +24,7 @@ from .constants import (
MC_PITCHED_INSTRUMENT_LIST,
MM_INSTRUMENT_RANGE_TABLE,
)
from .subclass import SingleNote, MineNote
from .subclass import SingleNote, MineNote, mctick2timestr
from .types import (
Any,
@ -38,12 +38,6 @@ from .types import (
)
def mctick2timestr(mc_tick: int) -> str:
"""
我的世界的游戏刻计转为表示时间的字符串
"""
return str(int(int(mc_tick / 20) / 60)) + ":" + str(int(int(mc_tick / 20) % 60))
def empty_midi_channels(channel_count: int = 17, staff: Any = {}) -> Dict[int, Any]:
"""

View File

@ -40,18 +40,19 @@
## 安装 🔳
- 使用 pypi
```bash
pip install --upgrade Musicreater
```
- 如果无法更新最新可以尝试
```bash
pip install --upgrade -i https://pypi.python.org/simple Musicreater
```
- 克隆仓库并安装最新版本但**不推荐**
```bash
git clone https://gitee.com/TriM-Organization/Musicreater.git
cd Musicreater
@ -91,7 +92,7 @@
- <table><tr><td>感谢 **油炸**\<QQ2836146704\> 激励我们不断开发新的内容</td><td><img height="50" src="https://foruda.gitee.com/images/1695478907647543027/08ea9909_9911226.jpeg"></td></tr></table>
> 感谢广大群友为此库提供的测试和建议等
>
>
> 若您对我们有所贡献但您的名字没有出现在此列表中请联系我们
## 联系 📞

View File

@ -7,14 +7,14 @@ console = Console()
def main():
with console.status("Find the full path of .egg-info folder"):
with console.status("寻众迹于 .egg-info 内"):
egg_info: list = []
for file in os.listdir():
if file.endswith(".egg-info"):
egg_info.append(file)
console.print(file)
for file in track(
["build", "dist", "logs", *egg_info], description="Deleting files"
["build", "dist", "logs", *egg_info], description="正删档"
):
if os.path.isdir(file) and os.access(file, os.W_OK):
shutil.rmtree(file)

20
example_websocket.py Normal file
View File

@ -0,0 +1,20 @@
import Musicreater
import Musicreater.plugin
import Musicreater.plugin.websocket
import os
dire = input("midi目录")
print(
Musicreater.plugin.websocket.to_websocket_server(
[
Musicreater.MidiConvert.from_midi_file(
os.path.join(dire,names), old_exe_format=False
) for names in os.listdir(dire,) if names.endswith((".mid",".midi"))
],
input("服务器地址:"),
int(input("服务器端口:")),
Musicreater.DEFAULT_PROGRESSBAR_STYLE,
)
)