mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2026-01-26 21:51:47 +00:00
基本的设计已经完成,今天休息一下
This commit is contained in:
@@ -85,7 +85,7 @@ __all__ = [
|
|||||||
"midi_inst_to_mc_sound",
|
"midi_inst_to_mc_sound",
|
||||||
]
|
]
|
||||||
|
|
||||||
from .main import MusicSequence, MidiConvert
|
from .old_main import MusicSequence, MidiConvert
|
||||||
|
|
||||||
from .subclass import (
|
from .subclass import (
|
||||||
MineNote,
|
MineNote,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
存储音·创新数据存储类
|
存储 音·创 v3 的内部数据类
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
版权所有 © 2025 金羿
|
版权所有 © 2026 金羿
|
||||||
Copyright © 2025 Eilles
|
Copyright © 2026 Eilles
|
||||||
|
|
||||||
开源相关声明请见 仓库根目录下的 License.md
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
Terms & Conditions: License.md in the root directory
|
Terms & Conditions: License.md in the root directory
|
||||||
@@ -16,7 +16,6 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# Email TriM-Organization@hotmail.com
|
# Email TriM-Organization@hotmail.com
|
||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
# WARNING 本文件中使用之功能尚未启用
|
|
||||||
|
|
||||||
from math import sin, cos, asin, radians, degrees, sqrt, atan, inf, ceil
|
from math import sin, cos, asin, radians, degrees, sqrt, atan, inf, ceil
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@@ -37,9 +36,7 @@ from typing import (
|
|||||||
)
|
)
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from .types import FittingFunctionType
|
from .exceptions import SingleNoteDecodeError, ParameterTypeError
|
||||||
from .constants import MC_PITCHED_INSTRUMENT_LIST
|
|
||||||
|
|
||||||
from .paramcurve import ParamCurve
|
from .paramcurve import ParamCurve
|
||||||
|
|
||||||
|
|
||||||
@@ -205,13 +202,21 @@ class SingleNote:
|
|||||||
last_time=duration_,
|
last_time=duration_,
|
||||||
mass_precision_time=code_buffer[6] if is_high_time_precision else 0,
|
mass_precision_time=code_buffer[6] if is_high_time_precision else 0,
|
||||||
)
|
)
|
||||||
except:
|
except Exception as e:
|
||||||
|
# 我也不知道为什么这里要放一个异常处理
|
||||||
|
# 之前用到过吗?
|
||||||
|
# —— 2026.01.25 金羿
|
||||||
print(
|
print(
|
||||||
"[Error] 单音符解析错误,字节码`{}`,{}启用高精度时间偏移\n".format(
|
"[Exception] 单音符解析错误,字节码`{}`,{}启用高精度时间偏移\n".format(
|
||||||
code_buffer, "已" if is_high_time_precision else "未"
|
code_buffer, "已" if is_high_time_precision else "未"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
raise
|
raise SingleNoteDecodeError(
|
||||||
|
e,
|
||||||
|
"技术信息:\nGROUP1\t`{}`\nCODE_BUFFER\t`{}`".format(
|
||||||
|
group_1, code_buffer
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def encode(self, is_high_time_precision: bool = True) -> bytes:
|
def encode(self, is_high_time_precision: bool = True) -> bytes:
|
||||||
"""
|
"""
|
||||||
@@ -267,7 +272,9 @@ class SingleNote:
|
|||||||
self.extra_info[key[i]] = value[i]
|
self.extra_info[key[i]] = value[i]
|
||||||
else:
|
else:
|
||||||
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
||||||
raise TypeError("参数类型错误;键:`{}` 值:`{}`".format(key, value))
|
raise ParameterTypeError(
|
||||||
|
"参数类型错误;键:`{}` 值:`{}`".format(key, value)
|
||||||
|
)
|
||||||
|
|
||||||
def get_info(self, key: str, default: Any = None) -> Any:
|
def get_info(self, key: str, default: Any = None) -> Any:
|
||||||
"""获取附加信息"""
|
"""获取附加信息"""
|
||||||
@@ -369,6 +376,7 @@ class MineNote:
|
|||||||
note: SingleNote,
|
note: SingleNote,
|
||||||
note_instrument: str,
|
note_instrument: str,
|
||||||
sound_volume: float,
|
sound_volume: float,
|
||||||
|
is_persiced_time: bool,
|
||||||
is_percussive_note: bool,
|
is_percussive_note: bool,
|
||||||
sound_position: SoundAtmos,
|
sound_position: SoundAtmos,
|
||||||
adjust_note_pitch: float = 0.0,
|
adjust_note_pitch: float = 0.0,
|
||||||
@@ -391,7 +399,7 @@ class MineNote:
|
|||||||
volume=sound_volume + adjust_note_volume,
|
volume=sound_volume + adjust_note_volume,
|
||||||
start_tick=note.start_time,
|
start_tick=note.start_time,
|
||||||
duration_tick=note.duration,
|
duration_tick=note.duration,
|
||||||
persiced_time=note.high_precision_start_time,
|
persiced_time=note.high_precision_start_time if is_persiced_time else 0,
|
||||||
percussive=is_percussive_note,
|
percussive=is_percussive_note,
|
||||||
position=sound_position,
|
position=sound_position,
|
||||||
)
|
)
|
||||||
@@ -480,8 +488,8 @@ class SingleTrack(List[SingleNote]):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not isinstance(item, SingleNote):
|
if not isinstance(item, SingleNote):
|
||||||
raise TypeError(
|
raise ParameterTypeError(
|
||||||
"单音轨类的元素类型须为单音符(SingleNote),不可为:{}".format(
|
"单音轨类的元素类型须为单音符(`SingleNote`),不可为:`{}`".format(
|
||||||
type(item).__name__
|
type(item).__name__
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -514,15 +522,16 @@ class SingleTrack(List[SingleNote]):
|
|||||||
) -> Generator[MineNote, Any, None]:
|
) -> Generator[MineNote, Any, None]:
|
||||||
"""获取能够用以在我的世界播放的音符数据类"""
|
"""获取能够用以在我的世界播放的音符数据类"""
|
||||||
|
|
||||||
for note in self.get_range(range_start_time, range_end_time):
|
for _note in self.get_range(range_start_time, range_end_time):
|
||||||
yield MineNote.from_single_note(
|
yield MineNote.from_single_note(
|
||||||
note,
|
note=_note,
|
||||||
self.track_instrument,
|
note_instrument=self.track_instrument,
|
||||||
self.track_volume,
|
sound_volume=self.track_volume,
|
||||||
self.is_percussive,
|
is_persiced_time=self.is_high_time_precision,
|
||||||
self.sound_position,
|
is_percussive_note=self.is_percussive,
|
||||||
|
sound_position=self.sound_position,
|
||||||
**{
|
**{
|
||||||
item.value: self.argument_curves[item].value_at(note.start_time) # type: ignore
|
item.value: self.argument_curves[item].value_at(_note.start_time) # type: ignore
|
||||||
for item in CurvableParam
|
for item in CurvableParam
|
||||||
if self.argument_curves[item]
|
if self.argument_curves[item]
|
||||||
},
|
},
|
||||||
@@ -551,7 +560,9 @@ class SingleTrack(List[SingleNote]):
|
|||||||
self.extra_info[key[i]] = value[i]
|
self.extra_info[key[i]] = value[i]
|
||||||
else:
|
else:
|
||||||
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
||||||
raise TypeError("参数类型错误;键:`{}` 值:`{}`".format(key, value))
|
raise ParameterTypeError(
|
||||||
|
"参数类型错误;键:`{}` 值:`{}`".format(key, value)
|
||||||
|
)
|
||||||
|
|
||||||
def get_info(self, key: str, default: Any = None) -> Any:
|
def get_info(self, key: str, default: Any = None) -> Any:
|
||||||
"""获取附加信息"""
|
"""获取附加信息"""
|
||||||
@@ -632,7 +643,9 @@ class SingleMusic(List[SingleTrack]):
|
|||||||
self.extra_info[key[i]] = value[i]
|
self.extra_info[key[i]] = value[i]
|
||||||
else:
|
else:
|
||||||
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
# 提供简单报错就行了,如果放一堆 if 语句,降低处理速度
|
||||||
raise TypeError("参数类型错误;键:`{}` 值:`{}`".format(key, value))
|
raise ParameterTypeError(
|
||||||
|
"参数类型错误;键:`{}` 值:`{}`".format(key, value)
|
||||||
|
)
|
||||||
|
|
||||||
def get_info(self, key: str, default: Any = None) -> Any:
|
def get_info(self, key: str, default: Any = None) -> Any:
|
||||||
"""获取附加信息"""
|
"""获取附加信息"""
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
存放一些报错类型
|
存储 音·创 v3 用到的一些报错类型
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
版权所有 © 2025 金羿 & 诸葛亮与八卦阵
|
版权所有 © 2025 金羿 & 玉衡
|
||||||
Copyright © 2025 Eilles & bgArray
|
Copyright © 2025 Eilles & Alioth
|
||||||
|
|
||||||
开源相关声明请见 仓库根目录下的 License.md
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
Terms & Conditions: License.md in the root directory
|
Terms & Conditions: License.md in the root directory
|
||||||
@@ -17,146 +17,211 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
class MSCTBaseException(Exception):
|
|
||||||
"""音·创 的所有错误均继承于此"""
|
class MusicreaterBaseException(Exception):
|
||||||
|
"""音·创 v3 的所有错误均继承于此"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""音·创 的所有错误均继承于此"""
|
"""音·创 的所有错误均继承于此"""
|
||||||
super().__init__("音·创", *args)
|
super().__init__("[音·创] - ", *args)
|
||||||
|
|
||||||
def meow(
|
def meow(self):
|
||||||
self,
|
|
||||||
):
|
|
||||||
for i in self.args:
|
for i in self.args:
|
||||||
print(i + "喵!")
|
print(i + "喵~", end=":")
|
||||||
|
|
||||||
def crash_it(self):
|
def crash_it(self):
|
||||||
raise self
|
raise self
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "".join(self.args)
|
||||||
|
|
||||||
class MidiFormatException(MSCTBaseException):
|
|
||||||
"""音·创 的所有MIDI格式错误均继承于此"""
|
# =====================================
|
||||||
|
# NOTE
|
||||||
|
# 面对用户时候爆出去的我们认为这就是“外部错误”
|
||||||
|
# 如果是在程序内部数据传输等情况下出现的就是“内部错误”
|
||||||
|
# 例如,无法读取文件,这就是一个外部错误
|
||||||
|
# 某个参数的数据类型错误,这就是内部错误
|
||||||
|
# =====================================
|
||||||
|
|
||||||
|
|
||||||
|
class MusicreaterInnerlyError(MusicreaterBaseException):
|
||||||
|
"""内部错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""音·创 的所有MIDI格式错误均继承于此"""
|
"""内部错误(面向开发者的报错信息)"""
|
||||||
super().__init__("MIDI 格式错误", *args)
|
super().__init__("内部错误 - ", *args)
|
||||||
|
|
||||||
|
class MusicreaterOuterlyError(MusicreaterBaseException):
|
||||||
class MidiDestroyedError(MSCTBaseException):
|
"""外部错误"""
|
||||||
"""Midi文件损坏"""
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""Midi文件损坏"""
|
"""外部错误(面向用户的报错信息)"""
|
||||||
super().__init__("MIDI文件损坏:无法读取 MIDI 文件", *args)
|
super().__init__("外部错误 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
# class MidiUnboundError(MSCTBaseException):
|
|
||||||
# """未定义Midi对象(无用)"""
|
|
||||||
|
|
||||||
# def __init__(self, *args):
|
|
||||||
# """未绑定Midi对象"""
|
|
||||||
# super().__init__("未定义MidiFile对象:你甚至没有对象就想要生孩子?", *args)
|
|
||||||
# 此错误在本版本内已经不再使用
|
|
||||||
|
|
||||||
|
|
||||||
class CommandFormatError(MSCTBaseException, RuntimeError):
|
class InnerlyParameterError(MusicreaterInnerlyError):
|
||||||
"""指令格式与目标格式不匹配而引起的错误"""
|
"""内部传参错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""指令格式与目标格式不匹配而引起的错误"""
|
"""参数错误"""
|
||||||
super().__init__("指令格式不匹配", *args)
|
super().__init__("传参错误 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
# class CrossNoteError(MidiFormatException):
|
class ParameterTypeError(InnerlyParameterError, TypeError):
|
||||||
# """同通道下同音符交叉出现所产生的错误"""
|
"""参数类型错误"""
|
||||||
|
|
||||||
# def __init__(self, *args):
|
|
||||||
# """同通道下同音符交叉出现所产生的错误"""
|
|
||||||
# super().__init__("同通道下同音符交叉", *args)
|
|
||||||
# 这TM是什么错误?
|
|
||||||
# 我什么时候写的这玩意?
|
|
||||||
# 我哪知道这说的是啥?
|
|
||||||
# !!!
|
|
||||||
# 我知道这是什么了 —— 金羿 2025 0401
|
|
||||||
# 两个其他属性相同的音符在同一个通道,出现连续两个开音信息和连续两个停止信息
|
|
||||||
# 那么这两个音符的音长无法判断。这是个好问题,但是不是我现在能解决的,也不是我们现在想解决的问题
|
|
||||||
|
|
||||||
|
|
||||||
class NotDefineTempoError(MidiFormatException):
|
|
||||||
"""没有Tempo设定导致时间无法计算的错误"""
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""没有Tempo设定导致时间无法计算的错误"""
|
"""参数类型错误"""
|
||||||
super().__init__("在曲目开始时没有声明 Tempo(未指定拍长)", *args)
|
super().__init__("参数类型错误:", *args)
|
||||||
|
|
||||||
|
|
||||||
class ChannelOverFlowError(MidiFormatException):
|
class ParameterValueError(InnerlyParameterError, ValueError):
|
||||||
"""一个midi中含有过多的通道"""
|
"""参数值存在错误"""
|
||||||
|
|
||||||
def __init__(self, max_channel=16, *args):
|
|
||||||
"""一个midi中含有过多的通道"""
|
|
||||||
super().__init__("含有过多的通道(数量应≤{})".format(max_channel), *args)
|
|
||||||
|
|
||||||
|
|
||||||
class NotDefineProgramError(MidiFormatException):
|
|
||||||
"""没有Program设定导致没有乐器可以选择的错误"""
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""没有Program设定导致没有乐器可以选择的错误"""
|
"""参数其值存在错误"""
|
||||||
super().__init__("未指定演奏乐器", *args)
|
super().__init__("参数数值错误:", *args)
|
||||||
|
|
||||||
|
|
||||||
class NoteOnOffMismatchError(MidiFormatException):
|
|
||||||
"""音符开音和停止不匹配的错误"""
|
class OuterlyParameterError(MusicreaterOuterlyError):
|
||||||
|
"""外部参数错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""音符开音和停止不匹配的错误"""
|
"""参数错误"""
|
||||||
super().__init__("音符不匹配", *args)
|
super().__init__("参数错误 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
class LyricMismatchError(MSCTBaseException):
|
class ZeroSpeedError(OuterlyParameterError, ZeroDivisionError):
|
||||||
"""歌词匹配解析错误"""
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""有可能产生了错误的歌词解析"""
|
|
||||||
super().__init__("歌词解析错误", *args)
|
|
||||||
|
|
||||||
|
|
||||||
class ZeroSpeedError(MSCTBaseException, ZeroDivisionError):
|
|
||||||
"""以0作为播放速度的错误"""
|
"""以0作为播放速度的错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""以0作为播放速度的错误"""
|
"""以0作为播放速度的错误"""
|
||||||
super().__init__("播放速度为零", *args)
|
super().__init__("播放速度为零:", *args)
|
||||||
|
|
||||||
|
|
||||||
class IllegalMinimumVolumeError(MSCTBaseException, ValueError):
|
class IllegalMinimumVolumeError(OuterlyParameterError, ValueError):
|
||||||
"""最小播放音量有误的错误"""
|
"""最小播放音量有误的错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""最小播放音量错误"""
|
"""最小播放音量错误"""
|
||||||
super().__init__("最小播放音量超出范围", *args)
|
super().__init__("最小播放音量超出范围:", *args)
|
||||||
|
|
||||||
|
|
||||||
class MusicSequenceDecodeError(MSCTBaseException):
|
|
||||||
"""音乐序列解码错误"""
|
|
||||||
|
class NoteBinaryDecodeError(MusicreaterOuterlyError):
|
||||||
|
"""音乐存储二进制数据解码错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""音乐序列无法正确解码的错误"""
|
"""音乐存储二进制数据无法正确解码"""
|
||||||
super().__init__("解码音符序列文件时出现问题", *args)
|
super().__init__("解码音乐存储二进制数据时出现问题 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
class MusicSequenceTypeError(MSCTBaseException):
|
class SingleNoteDecodeError(NoteBinaryDecodeError):
|
||||||
"""音乐序列类型错误"""
|
"""单个音符的二进制数据解码错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""无法识别音符序列字节码的类型"""
|
"""单个音符的二进制数据无法正确解码"""
|
||||||
super().__init__("错误的音符序列字节类型", *args)
|
super().__init__("音符解码出错:", *args)
|
||||||
|
|
||||||
|
|
||||||
class MusicSequenceVerificationFailed(MusicSequenceDecodeError):
|
class NoteBinaryFileTypeError(NoteBinaryDecodeError):
|
||||||
"""音乐序列校验失败"""
|
"""音乐存储二进制数据的文件类型错误"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""音符序列文件与其校验值不一致"""
|
"""无法识别音乐存储文件的类型"""
|
||||||
super().__init__("音符序列文件校验失败", *args)
|
super().__init__("无法识别音乐存储文件对应的类型:", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class NoteBinaryFileVerificationFailed(NoteBinaryDecodeError):
|
||||||
|
"""音乐存储二进制数据校验失败"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音乐存储文件与其校验值不一致"""
|
||||||
|
super().__init__("音乐存储文件校验失败:", *args)
|
||||||
|
|
||||||
|
class PluginDefineError(MusicreaterInnerlyError):
|
||||||
|
"""插件定义错误(内部相关)"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件本身存在错误"""
|
||||||
|
super().__init__("插件内部错误 - ", *args)
|
||||||
|
|
||||||
|
class PluginInstanceNotFoundError(PluginDefineError, LookupError):
|
||||||
|
"""插件实例未找到"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件实例未找到"""
|
||||||
|
super().__init__("插件实例未找到:", *args)
|
||||||
|
|
||||||
|
class PluginAttributeNotFoundError(PluginDefineError, AttributeError):
|
||||||
|
"""插件属性定义错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件属性定义错误"""
|
||||||
|
super().__init__("插件类的必要属性不存在:", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginMetainfoError(PluginDefineError):
|
||||||
|
"""插件元信息定义错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件元信息定义错误"""
|
||||||
|
super().__init__("插件元信息定义错误 - ", *args)
|
||||||
|
|
||||||
|
class PluginMetainfoTypeError(PluginMetainfoError, TypeError):
|
||||||
|
"""插件元信息定义类型错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件元信息定义类型错误"""
|
||||||
|
super().__init__("插件元信息类型错误:", *args)
|
||||||
|
|
||||||
|
class PluginMetainfoValueError(PluginMetainfoError, ValueError):
|
||||||
|
"""插件元信息定义值错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件元信息定义值错误"""
|
||||||
|
super().__init__("插件元信息数值错误:", *args)
|
||||||
|
|
||||||
|
class PluginMetainfoNotFoundError(PluginMetainfoError, PluginAttributeNotFoundError):
|
||||||
|
"""插件元信息定义缺少错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件元信息定义缺少错误"""
|
||||||
|
super().__init__("插件元信息未定义:", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginLoadError(MusicreaterOuterlyError):
|
||||||
|
"""插件加载错误(外部相关)"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件加载错误"""
|
||||||
|
super().__init__("插件加载错误 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginConfigRelatedError(MusicreaterOuterlyError):
|
||||||
|
"""插件配置相关错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""插件配置相关错误"""
|
||||||
|
super().__init__("插件配置相关错误 - ", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginConfigLoadError(PluginLoadError, PluginConfigRelatedError):
|
||||||
|
"""插件配置加载错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""配置文件无法加载"""
|
||||||
|
super().__init__("插件配置文件加载错误:", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginConfigDumpError(PluginConfigRelatedError):
|
||||||
|
"""插件配置保存错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""配置文件无法保存"""
|
||||||
|
super().__init__("插件配置文件保存错误:", *args)
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ Terms & Conditions: License.md in the root directory
|
|||||||
|
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
from .exceptions import *
|
from .old_exceptions import *
|
||||||
from .main import (
|
from .old_main import (
|
||||||
MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE,
|
MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE,
|
||||||
MM_CLASSIC_PITCHED_INSTRUMENT_TABLE,
|
MM_CLASSIC_PITCHED_INSTRUMENT_TABLE,
|
||||||
MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||||
@@ -30,7 +30,7 @@ from .main import (
|
|||||||
|
|
||||||
from .constants import MIDI_PAN, MIDI_PROGRAM, MIDI_VOLUME
|
from .constants import MIDI_PAN, MIDI_PROGRAM, MIDI_VOLUME
|
||||||
from .subclass import *
|
from .subclass import *
|
||||||
from .types import ChannelType, FittingFunctionType
|
from .old_types import ChannelType, FittingFunctionType
|
||||||
from .utils import *
|
from .utils import *
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
165
Musicreater/old_exceptions.py
Normal file
165
Musicreater/old_exceptions.py
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
存放一些报错类型
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
版权所有 © 2025 金羿 & 诸葛亮与八卦阵
|
||||||
|
Copyright © 2025 Eilles & bgArray
|
||||||
|
|
||||||
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
|
Terms & Conditions: License.md in the root directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 睿乐组织 开发交流群 861684859
|
||||||
|
# Email TriM-Organization@hotmail.com
|
||||||
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
|
class MSCTBaseException(Exception):
|
||||||
|
"""音·创 的所有错误均继承于此"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音·创 的所有错误均继承于此"""
|
||||||
|
super().__init__("音·创", *args)
|
||||||
|
|
||||||
|
def meow(
|
||||||
|
self,
|
||||||
|
):
|
||||||
|
for i in self.args:
|
||||||
|
print(i + "喵!")
|
||||||
|
|
||||||
|
def crash_it(self):
|
||||||
|
raise self
|
||||||
|
|
||||||
|
|
||||||
|
class MidiFormatException(MSCTBaseException):
|
||||||
|
"""音·创 的所有MIDI格式错误均继承于此"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音·创 的所有MIDI格式错误均继承于此"""
|
||||||
|
super().__init__("MIDI 格式错误", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class MidiDestroyedError(MSCTBaseException):
|
||||||
|
"""Midi文件损坏"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""Midi文件损坏"""
|
||||||
|
super().__init__("MIDI文件损坏:无法读取 MIDI 文件", *args)
|
||||||
|
|
||||||
|
|
||||||
|
# class MidiUnboundError(MSCTBaseException):
|
||||||
|
# """未定义Midi对象(无用)"""
|
||||||
|
|
||||||
|
# def __init__(self, *args):
|
||||||
|
# """未绑定Midi对象"""
|
||||||
|
# super().__init__("未定义MidiFile对象:你甚至没有对象就想要生孩子?", *args)
|
||||||
|
# 此错误在本版本内已经不再使用
|
||||||
|
|
||||||
|
|
||||||
|
class CommandFormatError(MSCTBaseException, RuntimeError):
|
||||||
|
"""指令格式与目标格式不匹配而引起的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""指令格式与目标格式不匹配而引起的错误"""
|
||||||
|
super().__init__("指令格式不匹配", *args)
|
||||||
|
|
||||||
|
|
||||||
|
# class CrossNoteError(MidiFormatException):
|
||||||
|
# """同通道下同音符交叉出现所产生的错误"""
|
||||||
|
|
||||||
|
# def __init__(self, *args):
|
||||||
|
# """同通道下同音符交叉出现所产生的错误"""
|
||||||
|
# super().__init__("同通道下同音符交叉", *args)
|
||||||
|
# 这TM是什么错误?
|
||||||
|
# 我什么时候写的这玩意?
|
||||||
|
# 我哪知道这说的是啥?
|
||||||
|
# !!!
|
||||||
|
# 我知道这是什么了 —— 金羿 2025 0401
|
||||||
|
# 两个其他属性相同的音符在同一个通道,出现连续两个开音信息和连续两个停止信息
|
||||||
|
# 那么这两个音符的音长无法判断。这是个好问题,但是不是我现在能解决的,也不是我们现在想解决的问题
|
||||||
|
|
||||||
|
|
||||||
|
class NotDefineTempoError(MidiFormatException):
|
||||||
|
"""没有Tempo设定导致时间无法计算的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""没有Tempo设定导致时间无法计算的错误"""
|
||||||
|
super().__init__("在曲目开始时没有声明 Tempo(未指定拍长)", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelOverFlowError(MidiFormatException):
|
||||||
|
"""一个midi中含有过多的通道"""
|
||||||
|
|
||||||
|
def __init__(self, max_channel=16, *args):
|
||||||
|
"""一个midi中含有过多的通道"""
|
||||||
|
super().__init__("含有过多的通道(数量应≤{})".format(max_channel), *args)
|
||||||
|
|
||||||
|
|
||||||
|
class NotDefineProgramError(MidiFormatException):
|
||||||
|
"""没有Program设定导致没有乐器可以选择的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""没有Program设定导致没有乐器可以选择的错误"""
|
||||||
|
super().__init__("未指定演奏乐器", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class NoteOnOffMismatchError(MidiFormatException):
|
||||||
|
"""音符开音和停止不匹配的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音符开音和停止不匹配的错误"""
|
||||||
|
super().__init__("音符不匹配", *args)
|
||||||
|
|
||||||
|
|
||||||
|
class LyricMismatchError(MSCTBaseException):
|
||||||
|
"""歌词匹配解析错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""有可能产生了错误的歌词解析"""
|
||||||
|
super().__init__("歌词解析错误", *args)
|
||||||
|
|
||||||
|
# 已重构
|
||||||
|
class ZeroSpeedError(MSCTBaseException, ZeroDivisionError):
|
||||||
|
"""以0作为播放速度的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""以0作为播放速度的错误"""
|
||||||
|
super().__init__("播放速度为零", *args)
|
||||||
|
|
||||||
|
# 已重构
|
||||||
|
class IllegalMinimumVolumeError(MSCTBaseException, ValueError):
|
||||||
|
"""最小播放音量有误的错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""最小播放音量错误"""
|
||||||
|
super().__init__("最小播放音量超出范围", *args)
|
||||||
|
|
||||||
|
|
||||||
|
# 已重构
|
||||||
|
class MusicSequenceDecodeError(MSCTBaseException):
|
||||||
|
"""音乐序列解码错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音乐序列无法正确解码的错误"""
|
||||||
|
super().__init__("解码音符序列文件时出现问题", *args)
|
||||||
|
|
||||||
|
|
||||||
|
# 已重构
|
||||||
|
class MusicSequenceTypeError(MSCTBaseException):
|
||||||
|
"""音乐序列类型错误"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""无法识别音符序列字节码的类型"""
|
||||||
|
super().__init__("错误的音符序列字节类型", *args)
|
||||||
|
|
||||||
|
|
||||||
|
# 已重构
|
||||||
|
class MusicSequenceVerificationFailed(MusicSequenceDecodeError):
|
||||||
|
"""音乐序列校验失败"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""音符序列文件与其校验值不一致"""
|
||||||
|
super().__init__("音符序列文件校验失败", *args)
|
||||||
@@ -37,9 +37,9 @@ from itertools import chain
|
|||||||
import mido
|
import mido
|
||||||
|
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .exceptions import *
|
from .old_exceptions import *
|
||||||
from .subclass import *
|
from .subclass import *
|
||||||
from .types import *
|
from .old_types import *
|
||||||
from .utils import *
|
from .utils import *
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -16,7 +16,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
from typing import Literal, Optional, Tuple
|
from typing import Literal, Optional, Tuple
|
||||||
|
|
||||||
from ...main import MidiConvert
|
from ...old_main import MidiConvert
|
||||||
from ...subclass import ProgressBarStyle
|
from ...subclass import ProgressBarStyle
|
||||||
from ..archive import behavior_mcpack_manifest, compress_zipfile
|
from ..archive import behavior_mcpack_manifest, compress_zipfile
|
||||||
from ..mcstructure import (
|
from ..mcstructure import (
|
||||||
@@ -17,7 +17,7 @@ from typing import Optional
|
|||||||
|
|
||||||
import brotli
|
import brotli
|
||||||
|
|
||||||
from ...main import MidiConvert
|
from ...old_main import MidiConvert
|
||||||
from ...subclass import MineCommand, ProgressBarStyle
|
from ...subclass import MineCommand, ProgressBarStyle
|
||||||
from ..bdx import (
|
from ..bdx import (
|
||||||
bdx_move,
|
bdx_move,
|
||||||
@@ -14,7 +14,7 @@ Terms & Conditions: License.md in the root directory
|
|||||||
import os
|
import os
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from ...main import MidiConvert
|
from ...old_main import MidiConvert
|
||||||
from ...subclass import MineCommand
|
from ...subclass import MineCommand
|
||||||
from ..mcstructure import (
|
from ..mcstructure import (
|
||||||
COMPABILITY_VERSION_117,
|
COMPABILITY_VERSION_117,
|
||||||
@@ -16,8 +16,8 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
from ..exceptions import NotDefineProgramError, ZeroSpeedError
|
from ..old_exceptions import NotDefineProgramError, ZeroSpeedError
|
||||||
from ..main import MidiConvert
|
from ..old_main import MidiConvert
|
||||||
from ..subclass import MineCommand
|
from ..subclass import MineCommand
|
||||||
from ..utils import inst_to_sould_with_deviation, perc_inst_to_soundID_withX
|
from ..utils import inst_to_sould_with_deviation, perc_inst_to_soundID_withX
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ from typing import List, Literal, Optional, Tuple
|
|||||||
|
|
||||||
import fcwslib
|
import fcwslib
|
||||||
|
|
||||||
from ...main import MidiConvert
|
from ...old_main import MidiConvert
|
||||||
from ...subclass import MineCommand, ProgressBarStyle
|
from ...subclass import MineCommand, ProgressBarStyle
|
||||||
|
|
||||||
|
|
||||||
73
Musicreater/old_types.py
Normal file
73
Musicreater/old_types.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
存放数据类型的定义
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
版权所有 © 2025 金羿 & 诸葛亮与八卦阵
|
||||||
|
Copyright © 2025 Eilles & bgArray
|
||||||
|
|
||||||
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
|
Terms & Conditions: License.md in the root directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 睿乐组织 开发交流群 861684859
|
||||||
|
# Email TriM-Organization@hotmail.com
|
||||||
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
from typing import Callable, Dict, List, Literal, Mapping, Tuple, Union
|
||||||
|
|
||||||
|
from .subclass import MineNote
|
||||||
|
|
||||||
|
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
|
||||||
|
"""
|
||||||
|
Midi音符名称对照表类型
|
||||||
|
"""
|
||||||
|
|
||||||
|
MidiInstrumentTableType = Mapping[int, str]
|
||||||
|
"""
|
||||||
|
Midi乐器对照表类型
|
||||||
|
"""
|
||||||
|
|
||||||
|
FittingFunctionType = Callable[[float], float]
|
||||||
|
"""
|
||||||
|
拟合函数类型
|
||||||
|
"""
|
||||||
|
|
||||||
|
ChannelType = Dict[
|
||||||
|
int,
|
||||||
|
Dict[
|
||||||
|
int,
|
||||||
|
List[
|
||||||
|
Union[
|
||||||
|
Tuple[Literal["PgmC"], int, int],
|
||||||
|
Tuple[Literal["NoteS"], int, int, int],
|
||||||
|
Tuple[Literal["NoteE"], int, int],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
以字典所标记的通道信息类型(已弃用)
|
||||||
|
|
||||||
|
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
MineNoteChannelType = Mapping[
|
||||||
|
int,
|
||||||
|
List[MineNote,],
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
我的世界通道信息类型
|
||||||
|
|
||||||
|
Dict[int,Dict[int,List[MineNote,],],]
|
||||||
|
"""
|
||||||
|
|
||||||
|
MineNoteTrackType = Mapping[
|
||||||
|
int,
|
||||||
|
List[MineNote,],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
存储音·创音轨所需的参数曲线
|
存储 音·创 v3 内部数据使用的参数曲线
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
版权所有 © 2025 金羿
|
版权所有 © 2026 金羿
|
||||||
Copyright © 2025 Eilles
|
Copyright © 2026 Eilles
|
||||||
|
|
||||||
开源相关声明请见 仓库根目录下的 License.md
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
Terms & Conditions: License.md in the root directory
|
Terms & Conditions: License.md in the root directory
|
||||||
@@ -17,7 +17,7 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
# WARNING 本文件中使用之功能尚未启用
|
# WARNING 本文件所含之功能未经完整测试
|
||||||
# 鉴于白谭若佬给出的建议:本功能应是处于低优先级开发的
|
# 鉴于白谭若佬给出的建议:本功能应是处于低优先级开发的
|
||||||
# 因此暂时用处不大,可以稍微放一会再进行开发
|
# 因此暂时用处不大,可以稍微放一会再进行开发
|
||||||
# 目前用人工智能生成了部分代码,只经过简单的测试
|
# 目前用人工智能生成了部分代码,只经过简单的测试
|
||||||
|
|||||||
783
Musicreater/plugin.py
Normal file
783
Musicreater/plugin.py
Normal file
@@ -0,0 +1,783 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
存储 音·创 v3 的插件接口与管理相关,提供抽象基类以供其他插件使用
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
版权所有 © 2025 金羿
|
||||||
|
Copyright © 2025 Eilles
|
||||||
|
|
||||||
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
|
Terms & Conditions: License.md in the root directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 睿乐组织 开发交流群 861684859
|
||||||
|
# Email TriM-Organization@hotmail.com
|
||||||
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# NOTE: [WARNING]
|
||||||
|
# 这个文件是一坨屎山代码
|
||||||
|
# 请勿模仿,请多包容
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod, ABCMeta
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import (
|
||||||
|
Dict,
|
||||||
|
Any,
|
||||||
|
Optional,
|
||||||
|
List,
|
||||||
|
Tuple,
|
||||||
|
Union,
|
||||||
|
Sequence,
|
||||||
|
BinaryIO,
|
||||||
|
Generator,
|
||||||
|
Iterator,
|
||||||
|
Set,
|
||||||
|
)
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
import tomllib
|
||||||
|
import tomli_w
|
||||||
|
else:
|
||||||
|
import tomli as tomllib # 第三方包
|
||||||
|
import tomli_w
|
||||||
|
|
||||||
|
from .exceptions import (
|
||||||
|
PluginConfigDumpError,
|
||||||
|
PluginConfigLoadError,
|
||||||
|
PluginMetainfoNotFoundError,
|
||||||
|
PluginMetainfoTypeError,
|
||||||
|
PluginMetainfoValueError,
|
||||||
|
PluginAttributeNotFoundError,
|
||||||
|
ParameterTypeError,
|
||||||
|
PluginInstanceNotFoundError,
|
||||||
|
)
|
||||||
|
from .data import SingleMusic, SingleTrack
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
# 枚举类
|
||||||
|
"PluginType",
|
||||||
|
# 抽象基类/数据类(插件参数定义)
|
||||||
|
"PluginConfig",
|
||||||
|
"PluginMetaInformation",
|
||||||
|
# 抽象基类(插件定义)
|
||||||
|
"MusicInputPlugin",
|
||||||
|
"TrackInputPlugin",
|
||||||
|
"MusicOperatePlugin",
|
||||||
|
"TrackOperatePlugin",
|
||||||
|
"MusicOutputPlugin",
|
||||||
|
"TrackOutputPlugin",
|
||||||
|
"ServicePlugin",
|
||||||
|
"LibraryPlugin",
|
||||||
|
# 插件注册用装饰函数
|
||||||
|
"music_input_plugin",
|
||||||
|
"track_input_plugin",
|
||||||
|
"music_operate_plugin",
|
||||||
|
"track_operate_plugin",
|
||||||
|
"music_output_plugin",
|
||||||
|
"track_output_plugin",
|
||||||
|
"service_plugin",
|
||||||
|
"library_plugin",
|
||||||
|
# 全局插件注册表
|
||||||
|
"plugin_registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PluginConfig(ABC):
|
||||||
|
"""插件配置基类"""
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
"""字典化配置文件"""
|
||||||
|
return {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "PluginConfig":
|
||||||
|
"""从字典创建配置实例"""
|
||||||
|
# 只保留类中定义的字段
|
||||||
|
field_names = {f.name for f in cls.__dataclass_fields__.values()}
|
||||||
|
filtered_data = {k: v for k, v in data.items() if k in field_names}
|
||||||
|
return cls(**filtered_data)
|
||||||
|
|
||||||
|
def save_to_file(self, file_path: Path) -> None:
|
||||||
|
"""保存配置到文件"""
|
||||||
|
if file_path.suffix.upper() == ".TOML":
|
||||||
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
else:
|
||||||
|
raise PluginConfigDumpError(
|
||||||
|
"插件配置文件类型不应为`{}`,须为`TOML`格式。".format(file_path.suffix)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with file_path.open("wb") as f:
|
||||||
|
tomli_w.dump(self.to_dict(), f, multiline_strings=False, indent=4)
|
||||||
|
except Exception as e:
|
||||||
|
raise PluginConfigDumpError(e)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_from_file(cls, file_path: Path) -> "PluginConfig":
|
||||||
|
"""从文件加载配置"""
|
||||||
|
try:
|
||||||
|
with file_path.open("rb") as f:
|
||||||
|
return cls.from_dict(tomllib.load(f))
|
||||||
|
except Exception as e:
|
||||||
|
raise PluginConfigLoadError(e)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginType(str, Enum):
|
||||||
|
"""插件类型枚举"""
|
||||||
|
|
||||||
|
FUNCTION_IMPORT = "import_data"
|
||||||
|
FUNCTION_EXPORT = "export_data"
|
||||||
|
FUNCTION_OPERATE = "data_operate"
|
||||||
|
SERVICE = "service"
|
||||||
|
LIBRARY = "library"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PluginMetaInformation(ABC):
|
||||||
|
"""插件元信息"""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
"""插件名称,应为惟一之名"""
|
||||||
|
author: str
|
||||||
|
"""插件作者"""
|
||||||
|
description: str
|
||||||
|
"""插件简介"""
|
||||||
|
version: Tuple[int, ...]
|
||||||
|
"""插件版本号"""
|
||||||
|
type: PluginType
|
||||||
|
"""插件类型"""
|
||||||
|
license: str = "MIT License"
|
||||||
|
"""插件发布时采用的许可协议"""
|
||||||
|
dependencies: Sequence[str] = []
|
||||||
|
"""插件是否对其他插件存在依赖"""
|
||||||
|
|
||||||
|
|
||||||
|
class TopBasePlugin(ABC):
|
||||||
|
"""所有插件的抽象基类"""
|
||||||
|
|
||||||
|
metainfo: PluginMetaInformation
|
||||||
|
"""插件元信息"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
if hasattr(cls, "metainfo"):
|
||||||
|
if not isinstance(cls.metainfo, PluginMetaInformation):
|
||||||
|
raise PluginMetainfoTypeError(
|
||||||
|
"类`{cls_name}`之属性`metainfo`的类型,必须为`PluginMetaInformation`".format(
|
||||||
|
cls_name=cls.__name__
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise PluginMetainfoNotFoundError(
|
||||||
|
"类`{cls_name}`必须定义一个`metainfo`属性。".format(
|
||||||
|
cls_name=cls.__name__
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TopInOutBasePlugin(TopBasePlugin, ABC):
|
||||||
|
"""导入导出用抽象基类"""
|
||||||
|
|
||||||
|
supported_formats: Tuple[str, ...] = tuple()
|
||||||
|
"""支持的格式"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if hasattr(cls, "supported_formats"):
|
||||||
|
if cls.supported_formats:
|
||||||
|
# 强制转换为大写,并使用元组
|
||||||
|
cls.supported_formats = tuple(map(str.upper, cls.supported_formats))
|
||||||
|
else:
|
||||||
|
cls.supported_formats = tuple()
|
||||||
|
else:
|
||||||
|
raise PluginAttributeNotFoundError(
|
||||||
|
"用于导入导出数据的类`{cls_name}`必须定义一个`supported_formats`属性。".format(
|
||||||
|
cls_name=cls.__name__
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def can_handle_file(self, file_path: Path) -> bool:
|
||||||
|
"""判断是否可处理某个文件"""
|
||||||
|
return file_path.suffix.upper().endswith(self.supported_formats)
|
||||||
|
|
||||||
|
def can_handle_format(self, format_name: str) -> bool:
|
||||||
|
"""判断是否可处理某个格式"""
|
||||||
|
return format_name.upper().endswith(self.supported_formats)
|
||||||
|
|
||||||
|
|
||||||
|
class MusicInputPlugin(TopInOutBasePlugin, ABC):
|
||||||
|
"""导入用插件抽象基类-完整曲目"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_IMPORT:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`MusicInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def loadbytes(
|
||||||
|
self, bytes_buffer_in: BinaryIO, config: Optional[PluginConfig]
|
||||||
|
) -> "SingleMusic":
|
||||||
|
"""从字节流加载数据到完整曲目"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load(self, file_path: Path, config: Optional[PluginConfig]) -> "SingleMusic":
|
||||||
|
"""从文件加载数据到完整曲目"""
|
||||||
|
with file_path.open("rb") as f:
|
||||||
|
return self.loadbytes(f, config)
|
||||||
|
|
||||||
|
|
||||||
|
class TrackInputPlugin(TopInOutBasePlugin, ABC):
|
||||||
|
"""导入用插件抽象基类-单个音轨"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_IMPORT:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`TrackInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def loadbytes(
|
||||||
|
self, bytes_buffer_in: BinaryIO, config: Optional[PluginConfig]
|
||||||
|
) -> "SingleTrack":
|
||||||
|
"""从字节流加载音符数据到单个音轨"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load(self, file_path: Path, config: Optional[PluginConfig]) -> "SingleTrack":
|
||||||
|
"""从文件加载音符数据到单个音轨"""
|
||||||
|
with file_path.open("rb") as f:
|
||||||
|
return self.loadbytes(f, config)
|
||||||
|
|
||||||
|
|
||||||
|
class MusicOperatePlugin(TopBasePlugin, ABC):
|
||||||
|
"""音乐处理用插件抽象基类-完整曲目"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_OPERATE:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`MusicOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def process(
|
||||||
|
self, data: "SingleMusic", config: Optional[PluginConfig]
|
||||||
|
) -> "SingleMusic":
|
||||||
|
"""处理完整曲目的数据"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TrackOperatePlugin(TopBasePlugin, ABC):
|
||||||
|
"""音乐处理用插件抽象基类-单个音轨"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_OPERATE:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`TrackOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def process(
|
||||||
|
self, data: "SingleTrack", config: Optional[PluginConfig]
|
||||||
|
) -> "SingleTrack":
|
||||||
|
"""处理单个音轨的音符数据"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MusicOutputPlugin(TopInOutBasePlugin, ABC):
|
||||||
|
"""导出用插件的抽象基类-完整曲目"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_EXPORT:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`MusicOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def dumpbytes(
|
||||||
|
self, data: "SingleMusic", config: Optional[PluginConfig]
|
||||||
|
) -> BinaryIO:
|
||||||
|
"""将完整曲目导出为对应格式的字节流"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def dump(
|
||||||
|
self, data: "SingleMusic", file_path: Path, config: Optional[PluginConfig]
|
||||||
|
):
|
||||||
|
"""将完整曲目导出为对应格式的文件"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TrackOutputPlugin(TopInOutBasePlugin, ABC):
|
||||||
|
"""导出用插件的抽象基类-单个音轨"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.FUNCTION_EXPORT:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`TrackOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def dumpbytes(
|
||||||
|
self, data: "SingleTrack", config: Optional[PluginConfig]
|
||||||
|
) -> BinaryIO:
|
||||||
|
"""将单个音轨导出为对应格式的字节流"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def dump(
|
||||||
|
self, data: "SingleTrack", file_path: Path, config: Optional[PluginConfig]
|
||||||
|
):
|
||||||
|
"""将单个音轨导出为对应格式的文件"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ServicePlugin(TopBasePlugin, ABC):
|
||||||
|
"""服务插件抽象基类"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.SERVICE:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`ServicePlugin`继承的,该类的子类应当为一个`PluginType.SERVICE`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def serve(self, config: Optional[PluginConfig], *args) -> None:
|
||||||
|
"""服务插件的运行逻辑"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryPlugin(TopBasePlugin, ABC):
|
||||||
|
"""插件依赖库的抽象基类"""
|
||||||
|
|
||||||
|
def __init_subclass__(cls) -> None:
|
||||||
|
super().__init_subclass__()
|
||||||
|
|
||||||
|
if cls.metainfo.type != PluginType.LIBRARY:
|
||||||
|
raise PluginMetainfoValueError(
|
||||||
|
"插件类`{cls_name}`是从`LibraryPlugin`继承的,该类的子类应当为一个`PluginType.LIBRARY`类型的插件,而不是`PluginType.{cls_type}`".format(
|
||||||
|
cls_name=cls.__name__,
|
||||||
|
cls_type=cls.metainfo.type.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 怎么?
|
||||||
|
# 插件的彼此依赖就不需要什么调用了吧
|
||||||
|
|
||||||
|
|
||||||
|
class PluginRegistry:
|
||||||
|
"""插件注册管理器"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._music_input_plugins: List[MusicInputPlugin] = []
|
||||||
|
self._track_input_plugins: List[TrackInputPlugin] = []
|
||||||
|
self._music_operate_plugins: List[MusicOperatePlugin] = []
|
||||||
|
self._track_operate_plugins: List[TrackOperatePlugin] = []
|
||||||
|
self._music_output_plugins: List[MusicOutputPlugin] = []
|
||||||
|
self._track_output_plugins: List[TrackOutputPlugin] = []
|
||||||
|
self._service_plugins: List[ServicePlugin] = []
|
||||||
|
self._library_plugins: List[LibraryPlugin] = []
|
||||||
|
|
||||||
|
def register_music_input_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册输入插件-整首曲目"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._music_input_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_track_input_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册输入插件-单个音轨"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._track_input_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_music_operate_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册曲目处理插件"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._music_operate_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_track_operate_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册音轨处理插件"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._track_operate_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_music_output_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册输出插件-整首曲目"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._music_output_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_track_output_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册输出插件-单个音轨"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._track_output_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_service_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册服务插件"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._service_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def register_library_plugin(self, plugin_class: type) -> None:
|
||||||
|
"""注册支持库插件"""
|
||||||
|
plugin_instance = plugin_class()
|
||||||
|
self._library_plugins.append(plugin_instance)
|
||||||
|
|
||||||
|
def get_music_input_plugin_by_format(
|
||||||
|
self, filepath_or_format: Union[Path, str]
|
||||||
|
) -> Generator[MusicInputPlugin, None, None]:
|
||||||
|
"""通过指定输入的文件或格式,以获取对应的全曲导入用插件"""
|
||||||
|
if isinstance(filepath_or_format, str):
|
||||||
|
for plugin in self._music_input_plugins:
|
||||||
|
if plugin.can_handle_format(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
elif isinstance(filepath_or_format, Path):
|
||||||
|
for plugin in self._music_input_plugins:
|
||||||
|
if plugin.can_handle_file(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
else:
|
||||||
|
raise ParameterTypeError(
|
||||||
|
"用于指定“导入全曲的数据之类型”的参数,其类型须为`Path`路径或字符串,而非`{}`类型的`{}`值".format(
|
||||||
|
type(filepath_or_format), filepath_or_format
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_track_input_plugin_by_format(
|
||||||
|
self, filepath_or_format: Union[Path, str]
|
||||||
|
) -> Generator[TrackInputPlugin, None, None]:
|
||||||
|
"""通过指定输入的文件或格式,以获取对应的单音轨导入用插件"""
|
||||||
|
if isinstance(filepath_or_format, str):
|
||||||
|
for plugin in self._track_input_plugins:
|
||||||
|
if plugin.can_handle_format(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
elif isinstance(filepath_or_format, Path):
|
||||||
|
for plugin in self._track_input_plugins:
|
||||||
|
if plugin.can_handle_file(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
else:
|
||||||
|
raise ParameterTypeError(
|
||||||
|
"用于指定“导入单个音轨的数据之类型”的参数,其类型须为`Path`路径或字符串,而非`{}`类型的`{}`值".format(
|
||||||
|
type(filepath_or_format), filepath_or_format
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_music_output_plugin_by_format(
|
||||||
|
self, filepath_or_format: Union[Path, str]
|
||||||
|
) -> Generator[MusicOutputPlugin, None, None]:
|
||||||
|
"""通过指定输出的文件或格式,以获取对应的导出全曲用插件"""
|
||||||
|
if isinstance(filepath_or_format, str):
|
||||||
|
for plugin in self._music_output_plugins:
|
||||||
|
if plugin.can_handle_format(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
elif isinstance(filepath_or_format, Path):
|
||||||
|
for plugin in self._music_output_plugins:
|
||||||
|
if plugin.can_handle_file(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
else:
|
||||||
|
raise ParameterTypeError(
|
||||||
|
"用于指定“全曲数据导出的类型”的参数,其类型须为`Path`路径或字符串,而非`{}`类型的`{}`值".format(
|
||||||
|
type(filepath_or_format), filepath_or_format
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_track_output_plugin_by_format(
|
||||||
|
self, filepath_or_format: Union[Path, str]
|
||||||
|
) -> Generator[TrackOutputPlugin, None, None]:
|
||||||
|
"""通过指定输出的文件或格式,以获取对应的导出单个音轨用插件"""
|
||||||
|
if isinstance(filepath_or_format, str):
|
||||||
|
for plugin in self._track_output_plugins:
|
||||||
|
if plugin.can_handle_format(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
elif isinstance(filepath_or_format, Path):
|
||||||
|
for plugin in self._track_output_plugins:
|
||||||
|
if plugin.can_handle_file(filepath_or_format):
|
||||||
|
yield plugin
|
||||||
|
else:
|
||||||
|
raise ParameterTypeError(
|
||||||
|
"用于指定“单音轨数据导出的类型”的参数,其类型须为`Path`路径或字符串,而非`{}`类型的`{}`值".format(
|
||||||
|
type(filepath_or_format), filepath_or_format
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_music_input_plugin(self, plugin_name: str) -> MusicInputPlugin:
|
||||||
|
"""获取指定名称的全曲导入用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._music_input_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到“用于导入曲目、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_track_input_plugin(self, plugin_name: str) -> TrackInputPlugin:
|
||||||
|
"""获取指定名称的单音轨导入用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._track_input_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到“用于导入单个音轨、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_music_operate_plugin(self, plugin_name: str) -> MusicOperatePlugin:
|
||||||
|
"""获取指定名称的全曲处理用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._music_operate_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到“用于处理整个曲目、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_track_operate_plugin(self, plugin_name: str) -> TrackOperatePlugin:
|
||||||
|
"""获取指定名称的单音轨处理用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._track_operate_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到“用于处理单个音轨、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_music_output_plugin(self, plugin_name: str) -> MusicOutputPlugin:
|
||||||
|
"""获取指定名称的导出全曲用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._music_output_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginMetainfoNotFoundError(
|
||||||
|
"未找到“用于导出完整曲目、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_track_output_plugin(self, plugin_name: str) -> TrackOutputPlugin:
|
||||||
|
"""获取指定名称的导出单音轨用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._track_output_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginMetainfoNotFoundError(
|
||||||
|
"未找到“用于导出单个音轨、名为`{}`”的插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_service_plugin(self, plugin_name: str) -> ServicePlugin:
|
||||||
|
"""获取服务用插件,当名称重叠时,取版本号最大的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._service_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到名为`{}`的服务用插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_library_plugin(self, plugin_name: str) -> LibraryPlugin:
|
||||||
|
"""获取依赖库类插件,当名称重叠时,取版本号最高的"""
|
||||||
|
try:
|
||||||
|
return max(
|
||||||
|
filter(
|
||||||
|
lambda plugin: plugin.metainfo.name == plugin_name,
|
||||||
|
self._library_plugins,
|
||||||
|
),
|
||||||
|
key=lambda plugin: plugin.metainfo.version,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
raise PluginInstanceNotFoundError(
|
||||||
|
"未找到名为`{}`的依赖库插件".format(plugin_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def supported_input_formats(self) -> Set[str]:
|
||||||
|
"""所有支持的导入格式"""
|
||||||
|
return set(
|
||||||
|
chain.from_iterable(
|
||||||
|
plugin.supported_formats
|
||||||
|
for plugin in chain(
|
||||||
|
self._music_input_plugins, self._track_input_plugins
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def supported_output_formats(self) -> Set[str]:
|
||||||
|
"""所有支持的导出格式"""
|
||||||
|
return set(
|
||||||
|
chain.from_iterable(
|
||||||
|
plugin.supported_formats
|
||||||
|
for plugin in chain(
|
||||||
|
self._music_output_plugins, self._track_output_plugins
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
plugin_registry = PluginRegistry()
|
||||||
|
"""全局插件注册表实例"""
|
||||||
|
|
||||||
|
|
||||||
|
def music_input_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""全曲输入用插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_music_input_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def track_input_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""单轨输入用插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_track_input_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def music_operate_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""全曲处理用插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_music_operate_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def track_operate_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""音轨处理插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_track_operate_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def music_output_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""乐曲输出用插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_music_output_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def track_output_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""音轨输出用插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_track_output_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def service_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""服务插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_service_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def library_plugin(metainfo: PluginMetaInformation):
|
||||||
|
"""支持库插件装饰器"""
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
global plugin_registry
|
||||||
|
cls.metainfo = metainfo
|
||||||
|
plugin_registry.register_library_plugin(cls)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
22
Musicreater/plugins.py
Normal file
22
Musicreater/plugins.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
存储 音·创 v3 的插件管理和上层设计内容
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
版权所有 © 2025 金羿
|
||||||
|
Copyright © 2025 Eilles
|
||||||
|
|
||||||
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
|
Terms & Conditions: License.md in the root directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 睿乐组织 开发交流群 861684859
|
||||||
|
# Email TriM-Organization@hotmail.com
|
||||||
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
from typing import List, Optional, Dict, Generator, Any
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .plugin import MusicInputPlugin, MusicOperatePlugin, MusicOutputPlugin, TrackInputPlugin, TrackOperatePlugin, TrackOutputPlugin, ServicePlugin, LibraryPlugin
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
存放数据类型的定义
|
存储 音·创 v3 定义的一些数据类型,可以用于类型检查器
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
版权所有 © 2025 金羿 & 诸葛亮与八卦阵
|
版权所有 © 2025 金羿 & 玉衡
|
||||||
Copyright © 2025 Eilles & bgArray
|
Copyright © 2025 Eilles & Alioth
|
||||||
|
|
||||||
开源相关声明请见 仓库根目录下的 License.md
|
开源相关声明请见 仓库根目录下的 License.md
|
||||||
Terms & Conditions: License.md in the root directory
|
Terms & Conditions: License.md in the root directory
|
||||||
@@ -16,58 +16,10 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# Email TriM-Organization@hotmail.com
|
# Email TriM-Organization@hotmail.com
|
||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
from typing import Callable, Dict, List, Literal, Mapping, Tuple, Union
|
from typing import Callable, Dict, List, Literal, Mapping, Tuple, Union
|
||||||
|
|
||||||
from .subclass import MineNote
|
|
||||||
|
|
||||||
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
|
|
||||||
"""
|
|
||||||
Midi音符名称对照表类型
|
|
||||||
"""
|
|
||||||
|
|
||||||
MidiInstrumentTableType = Mapping[int, str]
|
|
||||||
"""
|
|
||||||
Midi乐器对照表类型
|
|
||||||
"""
|
|
||||||
|
|
||||||
FittingFunctionType = Callable[[float], float]
|
FittingFunctionType = Callable[[float], float]
|
||||||
"""
|
"""
|
||||||
拟合函数类型
|
拟合函数类型
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ChannelType = Dict[
|
|
||||||
int,
|
|
||||||
Dict[
|
|
||||||
int,
|
|
||||||
List[
|
|
||||||
Union[
|
|
||||||
Tuple[Literal["PgmC"], int, int],
|
|
||||||
Tuple[Literal["NoteS"], int, int, int],
|
|
||||||
Tuple[Literal["NoteE"], int, int],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
以字典所标记的通道信息类型(已弃用)
|
|
||||||
|
|
||||||
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
MineNoteChannelType = Mapping[
|
|
||||||
int,
|
|
||||||
List[MineNote,],
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
我的世界通道信息类型
|
|
||||||
|
|
||||||
Dict[int,Dict[int,List[MineNote,],],]
|
|
||||||
"""
|
|
||||||
|
|
||||||
MineNoteTrackType = Mapping[
|
|
||||||
int,
|
|
||||||
List[MineNote,],
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ from .constants import (
|
|||||||
MM_INSTRUMENT_DEVIATION_TABLE,
|
MM_INSTRUMENT_DEVIATION_TABLE,
|
||||||
MM_INSTRUMENT_RANGE_TABLE,
|
MM_INSTRUMENT_RANGE_TABLE,
|
||||||
)
|
)
|
||||||
from .exceptions import MusicSequenceDecodeError
|
from .old_exceptions import MusicSequenceDecodeError
|
||||||
from .subclass import MineNote, mctick2timestr, SingleNoteBox
|
from .subclass import MineNote, mctick2timestr, SingleNoteBox
|
||||||
from .types import MidiInstrumentTableType, MineNoteChannelType, FittingFunctionType
|
from .old_types import MidiInstrumentTableType, MineNoteChannelType, FittingFunctionType
|
||||||
|
|
||||||
|
|
||||||
def empty_midi_channels(
|
def empty_midi_channels(
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import Musicreater
|
import Musicreater
|
||||||
import Musicreater.experiment
|
import Musicreater.experiment
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
|
|
||||||
# import Musicreater.previous
|
# import Musicreater.previous
|
||||||
from Musicreater.plugin.addonpack import (
|
from Musicreater.old_plugin.addonpack import (
|
||||||
to_addon_pack_in_delay,
|
to_addon_pack_in_delay,
|
||||||
to_addon_pack_in_repeater,
|
to_addon_pack_in_repeater,
|
||||||
to_addon_pack_in_score,
|
to_addon_pack_in_score,
|
||||||
)
|
)
|
||||||
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
|
from Musicreater.old_plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
|
||||||
from Musicreater.plugin.mcstructfile import (
|
from Musicreater.old_plugin.mcstructfile import (
|
||||||
to_mcstructure_file_in_delay,
|
to_mcstructure_file_in_delay,
|
||||||
to_mcstructure_file_in_repeater,
|
to_mcstructure_file_in_repeater,
|
||||||
to_mcstructure_file_in_score,
|
to_mcstructure_file_in_score,
|
||||||
@@ -21,7 +21,7 @@ MSCT_MAIN = (
|
|||||||
# Musicreater.previous,
|
# Musicreater.previous,
|
||||||
)
|
)
|
||||||
|
|
||||||
MSCT_PLUGIN = (Musicreater.plugin,)
|
MSCT_PLUGIN = (Musicreater.old_plugin,)
|
||||||
|
|
||||||
MSCT_PLUGIN_FUNCTION = (
|
MSCT_PLUGIN_FUNCTION = (
|
||||||
to_addon_pack_in_delay,
|
to_addon_pack_in_delay,
|
||||||
|
|||||||
@@ -19,18 +19,18 @@ Terms & Conditions: ./License.md
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import Musicreater
|
import Musicreater
|
||||||
from Musicreater.plugin.addonpack import (
|
from Musicreater.old_plugin.addonpack import (
|
||||||
to_addon_pack_in_delay,
|
to_addon_pack_in_delay,
|
||||||
to_addon_pack_in_repeater,
|
to_addon_pack_in_repeater,
|
||||||
to_addon_pack_in_score,
|
to_addon_pack_in_score,
|
||||||
)
|
)
|
||||||
from Musicreater.plugin.mcstructfile import (
|
from Musicreater.old_plugin.mcstructfile import (
|
||||||
to_mcstructure_file_in_delay,
|
to_mcstructure_file_in_delay,
|
||||||
to_mcstructure_file_in_repeater,
|
to_mcstructure_file_in_repeater,
|
||||||
to_mcstructure_file_in_score,
|
to_mcstructure_file_in_score,
|
||||||
)
|
)
|
||||||
|
|
||||||
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
|
from Musicreater.old_plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
|
||||||
|
|
||||||
# 获取midi列表
|
# 获取midi列表
|
||||||
midi_path = input(f"请输入MIDI路径:")
|
midi_path = input(f"请输入MIDI路径:")
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import Musicreater.experiment
|
import Musicreater.experiment
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
import Musicreater.plugin.mcstructfile
|
import Musicreater.old_plugin.mcstructfile
|
||||||
|
|
||||||
print(
|
print(
|
||||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
Musicreater.old_plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||||
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
|
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
|
||||||
input("midi路径:"), old_exe_format=False
|
input("midi路径:"), old_exe_format=False
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import Musicreater
|
import Musicreater
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
import Musicreater.plugin.mcstructfile
|
import Musicreater.old_plugin.mcstructfile
|
||||||
|
|
||||||
print(
|
print(
|
||||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
Musicreater.old_plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||||
Musicreater.MidiConvert.from_midi_file(
|
Musicreater.MidiConvert.from_midi_file(
|
||||||
input("midi路径:"),
|
input("midi路径:"),
|
||||||
old_exe_format=False,
|
old_exe_format=False,
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import Musicreater
|
import Musicreater
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
import Musicreater.plugin.websocket
|
import Musicreater.old_plugin.websocket
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
dire = input("midi目录:")
|
dire = input("midi目录:")
|
||||||
|
|
||||||
print(
|
print(
|
||||||
Musicreater.plugin.websocket.to_websocket_server(
|
Musicreater.old_plugin.websocket.to_websocket_server(
|
||||||
[
|
[
|
||||||
Musicreater.MidiConvert.from_midi_file(
|
Musicreater.MidiConvert.from_midi_file(
|
||||||
os.path.join(dire, names), old_exe_format=False
|
os.path.join(dire, names), old_exe_format=False
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import shutil
|
|||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import Musicreater.experiment
|
import Musicreater.experiment
|
||||||
from Musicreater.plugin.archive import compress_zipfile
|
from Musicreater.old_plugin.archive import compress_zipfile
|
||||||
from Musicreater.utils import guess_deviation, is_in_diapason
|
from Musicreater.utils import guess_deviation, is_in_diapason
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
requires-python = ">= 3.8, < 4.0"
|
requires-python = ">= 3.8, < 4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mido >= 1.3",
|
"mido >= 1.3",
|
||||||
|
"tomli>=2.4.0; python_version < '3.11'",
|
||||||
|
"tomli-w>=1.0.0",
|
||||||
"xxhash >= 3",
|
"xxhash >= 3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@
|
|||||||
full = [
|
full = [
|
||||||
"TrimMCStruct <= 0.0.5.9",
|
"TrimMCStruct <= 0.0.5.9",
|
||||||
"brotli >= 1.0.0",
|
"brotli >= 1.0.0",
|
||||||
"numpy"
|
"numpy",
|
||||||
]
|
]
|
||||||
dev = [
|
dev = [
|
||||||
"TrimMCStruct <= 0.0.5.9",
|
"TrimMCStruct <= 0.0.5.9",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Musicreater.experiment
|
import Musicreater.experiment
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
import Musicreater.plugin.mcstructfile
|
import Musicreater.old_plugin.mcstructfile
|
||||||
|
|
||||||
msct = Musicreater.experiment.FutureMidiConvertKamiRES.from_midi_file(
|
msct = Musicreater.experiment.FutureMidiConvertKamiRES.from_midi_file(
|
||||||
input("midi路径:"), old_exe_format=False
|
input("midi路径:"), old_exe_format=False
|
||||||
@@ -24,7 +24,7 @@ for name in sorted(
|
|||||||
|
|
||||||
print(
|
print(
|
||||||
"\n输出:",
|
"\n输出:",
|
||||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
Musicreater.old_plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||||
msct,
|
msct,
|
||||||
opt,
|
opt,
|
||||||
# Musicreater.plugin.ConvertConfig(input("输出路径:"),),
|
# Musicreater.plugin.ConvertConfig(input("输出路径:"),),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Musicreater.experiment
|
import Musicreater.experiment
|
||||||
import Musicreater.plugin
|
import Musicreater.old_plugin
|
||||||
import Musicreater.plugin.mcstructfile
|
import Musicreater.old_plugin.mcstructfile
|
||||||
|
|
||||||
msct = Musicreater.experiment.FutureMidiConvertLyricSupport.from_midi_file(
|
msct = Musicreater.experiment.FutureMidiConvertLyricSupport.from_midi_file(
|
||||||
input("midi路径:"), old_exe_format=False
|
input("midi路径:"), old_exe_format=False
|
||||||
@@ -24,7 +24,7 @@ opt = input("输出路径:")
|
|||||||
|
|
||||||
print(
|
print(
|
||||||
"\n输出:",
|
"\n输出:",
|
||||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
Musicreater.old_plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||||
msct,
|
msct,
|
||||||
opt,
|
opt,
|
||||||
# Musicreater.plugin.ConvertConfig(input("输出路径:"),),
|
# Musicreater.plugin.ConvertConfig(input("输出路径:"),),
|
||||||
|
|||||||
90
uv.lock
generated
90
uv.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 1
|
revision = 3
|
||||||
requires-python = ">=3.8, <4.0"
|
requires-python = ">=3.8, <4.0"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"python_full_version >= '3.10'",
|
"python_full_version >= '3.10'",
|
||||||
@@ -578,6 +578,9 @@ name = "musicreater"
|
|||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "mido" },
|
{ name = "mido" },
|
||||||
|
{ name = "tomli" },
|
||||||
|
{ name = "tomli-w", version = "1.0.0", source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }, marker = "python_full_version < '3.9'" },
|
||||||
|
{ name = "tomli-w", version = "1.2.0", source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }, marker = "python_full_version >= '3.9'" },
|
||||||
{ name = "xxhash" },
|
{ name = "xxhash" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -592,6 +595,9 @@ dev = [
|
|||||||
]
|
]
|
||||||
full = [
|
full = [
|
||||||
{ name = "brotli" },
|
{ name = "brotli" },
|
||||||
|
{ name = "numpy", version = "1.24.4", source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }, marker = "python_full_version < '3.9'" },
|
||||||
|
{ name = "numpy", version = "2.0.2", source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }, marker = "python_full_version == '3.9.*'" },
|
||||||
|
{ name = "numpy", version = "2.2.6", source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }, marker = "python_full_version >= '3.10'" },
|
||||||
{ name = "trimmcstruct" },
|
{ name = "trimmcstruct" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -601,8 +607,11 @@ requires-dist = [
|
|||||||
{ name = "brotli", marker = "extra == 'full'", specifier = ">=1.0.0" },
|
{ name = "brotli", marker = "extra == 'full'", specifier = ">=1.0.0" },
|
||||||
{ name = "dill", marker = "extra == 'dev'" },
|
{ name = "dill", marker = "extra == 'dev'" },
|
||||||
{ name = "mido", specifier = ">=1.3" },
|
{ name = "mido", specifier = ">=1.3" },
|
||||||
|
{ name = "numpy", marker = "extra == 'full'" },
|
||||||
{ name = "pyinstaller", marker = "extra == 'dev'" },
|
{ name = "pyinstaller", marker = "extra == 'dev'" },
|
||||||
{ name = "rich", marker = "extra == 'dev'" },
|
{ name = "rich", marker = "extra == 'dev'" },
|
||||||
|
{ name = "tomli" },
|
||||||
|
{ name = "tomli-w" },
|
||||||
{ name = "trimmcstruct", marker = "extra == 'dev'", specifier = "<=0.0.5.9" },
|
{ name = "trimmcstruct", marker = "extra == 'dev'", specifier = "<=0.0.5.9" },
|
||||||
{ name = "trimmcstruct", marker = "extra == 'full'", specifier = "<=0.0.5.9" },
|
{ name = "trimmcstruct", marker = "extra == 'full'", specifier = "<=0.0.5.9" },
|
||||||
{ name = "twine", marker = "extra == 'dev'" },
|
{ name = "twine", marker = "extra == 'dev'" },
|
||||||
@@ -1041,6 +1050,85 @@ wheels = [
|
|||||||
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/58/29/93c53c098d301132196c3238c312825324740851d77a8500a2462c0fd888/setuptools-80.8.0-py3-none-any.whl", hash = "sha256:95a60484590d24103af13b686121328cc2736bee85de8936383111e421b9edc0" },
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/58/29/93c53c098d301132196c3238c312825324740851d77a8500a2462c0fd888/setuptools-80.8.0-py3-none-any.whl", hash = "sha256:95a60484590d24103af13b686121328cc2736bee85de8936383111e421b9edc0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }
|
||||||
|
sdist = { url = "https://mirror.nju.edu.cn/pypi/web/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4" },
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli-w"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version < '3.9'",
|
||||||
|
]
|
||||||
|
sdist = { url = "https://mirror.nju.edu.cn/pypi/web/packages/49/05/6bf21838623186b91aedbda06248ad18f03487dc56fbc20e4db384abde6c/tomli_w-1.0.0.tar.gz", hash = "sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/bb/01/1da9c66ecb20f31ed5aa5316a957e0b1a5e786a0d9689616ece4ceaf1321/tomli_w-1.0.0-py3-none-any.whl", hash = "sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli-w"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://mirror.nju.edu.cn/pypi/web/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version >= '3.10'",
|
||||||
|
"python_full_version == '3.9.*'",
|
||||||
|
]
|
||||||
|
sdist = { url = "https://mirror.nju.edu.cn/pypi/web/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://mirror.nju.edu.cn/pypi/web/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trimmcstruct"
|
name = "trimmcstruct"
|
||||||
version = "0.0.5.9"
|
version = "0.0.5.9"
|
||||||
|
|||||||
Reference in New Issue
Block a user