mirror of
https://github.com/TriM-Organization/Linglun-Converter.git
synced 2025-09-07 05:06:27 +00:00
支持自动更新音·创库,支持更优美的错误提示,支持选择输出目录
This commit is contained in:
103
utils/io.py
103
utils/io.py
@ -4,7 +4,7 @@
|
||||
伶伦转换器 命令行组件
|
||||
Linglun Converter Command Line IO Component
|
||||
|
||||
版权所有 © 2024 金羿 & 睿穆开发组
|
||||
版权所有 © 2024 金羿 & 睿乐开发组
|
||||
Copyright © 2024 EillesWan & TriM Org.
|
||||
|
||||
开源相关声明请见 ./License.md
|
||||
@ -12,8 +12,7 @@ Terms & Conditions: ./Lisense.md
|
||||
"""
|
||||
|
||||
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import requests
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
@ -26,31 +25,28 @@ from typing import (
|
||||
Tuple,
|
||||
Iterable,
|
||||
Sequence,
|
||||
Union,
|
||||
)
|
||||
|
||||
import TrimLog
|
||||
from TrimLog import object_constants, logger
|
||||
from TrimLog import object_constants, logger, log__init__
|
||||
|
||||
is_logging: bool = True
|
||||
|
||||
MainConsole = logger.console
|
||||
|
||||
logger.is_logging = True
|
||||
logger.suffix = ".llc"
|
||||
logger.is_tips = True
|
||||
|
||||
logger.info("读取 言·论 信息……")
|
||||
|
||||
try:
|
||||
myWords = (
|
||||
urllib.request.urlopen(
|
||||
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt"
|
||||
)
|
||||
.read()
|
||||
.decode("utf-8")
|
||||
requests.get(
|
||||
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt",
|
||||
).text
|
||||
.strip("\n")
|
||||
.split("\n")
|
||||
)
|
||||
except (ConnectionError, urllib.error.HTTPError) as E:
|
||||
except (ConnectionError, requests.HTTPError, requests.RequestException) as E:
|
||||
logger.warning(f"读取言·论信息发生 互联网连接 错误:\n{E}")
|
||||
myWords = ["以梦想为驱使 创造属于自己的未来"]
|
||||
# noinspection PyBroadException
|
||||
@ -59,6 +55,9 @@ except BaseException as E:
|
||||
myWords = ["灵光焕发 深艺献心"]
|
||||
|
||||
|
||||
|
||||
logger.info("注册出入方法……")
|
||||
|
||||
JustifyMethod = Literal["default", "left", "center", "right", "full"]
|
||||
OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"]
|
||||
|
||||
@ -98,7 +97,7 @@ def prt(
|
||||
soft_wrap (bool, 可选): 启用软包装模式,禁止文字包装和裁剪,或`None``用于 控制台默认值。默认为`None`。
|
||||
new_line_start (bool, False): 如果输出包含多行,在开始时插入一个新行。默认值为`False`。
|
||||
"""
|
||||
MainConsole.print(
|
||||
logger.console.print(
|
||||
*objects,
|
||||
sep=sep,
|
||||
end=end,
|
||||
@ -159,7 +158,7 @@ def ipt(
|
||||
Returns:
|
||||
str: 从stdin读取的字符串
|
||||
"""
|
||||
MainConsole.print(
|
||||
logger.console.print(
|
||||
*objects,
|
||||
sep=sep,
|
||||
end="",
|
||||
@ -177,7 +176,7 @@ def ipt(
|
||||
new_line_start=new_line_start,
|
||||
)
|
||||
|
||||
return MainConsole.input(password=password, stream=stream)
|
||||
return logger.console.input(password=password, stream=stream)
|
||||
|
||||
|
||||
def format_ipt(
|
||||
@ -213,61 +212,57 @@ def isin(sth: str, range_list: dict):
|
||||
for bool_value, res_list in range_list.items():
|
||||
if sth in res_list:
|
||||
return bool_value
|
||||
raise ValueError
|
||||
raise ValueError(
|
||||
"不在可选范围内:{}".format([j for i in range_list.values() for j in i])
|
||||
)
|
||||
|
||||
|
||||
# 真假字符串判断
|
||||
def bool_str(sth: str):
|
||||
try:
|
||||
return bool(float(sth))
|
||||
except:
|
||||
except ValueError:
|
||||
if str(sth).lower() in ("true", "真", "是", "y", "t"):
|
||||
return True
|
||||
elif str(sth).lower() in ("false", "假", "否", "f", "n"):
|
||||
return False
|
||||
else:
|
||||
raise ValueError
|
||||
raise ValueError("非法逻辑字串")
|
||||
|
||||
|
||||
def float_str(sth: str):
|
||||
try:
|
||||
return float(sth)
|
||||
except ValueError:
|
||||
try:
|
||||
return float(
|
||||
sth.replace("壹", "1")
|
||||
.replace("贰", "2")
|
||||
.replace("叁", "3")
|
||||
.replace("肆", "4")
|
||||
.replace("伍", "5")
|
||||
.replace("陆", "6")
|
||||
.replace("柒", "7")
|
||||
.replace("捌", "8")
|
||||
.replace("玖", "9")
|
||||
.replace("零", "0")
|
||||
.replace("一", "1")
|
||||
.replace("二", "2")
|
||||
.replace("三", "3")
|
||||
.replace("四", "4")
|
||||
.replace("五", "5")
|
||||
.replace("六", "6")
|
||||
.replace("七", "7")
|
||||
.replace("八", "8")
|
||||
.replace("九", "9")
|
||||
.replace("〇", "0")
|
||||
.replace("洞", "0")
|
||||
.replace("幺", "1")
|
||||
.replace("俩", "2")
|
||||
.replace("两", "2")
|
||||
.replace("拐", "7")
|
||||
.replace("点", ".")
|
||||
)
|
||||
except:
|
||||
raise ValueError
|
||||
return float(
|
||||
sth.replace("壹", "1")
|
||||
.replace("贰", "2")
|
||||
.replace("叁", "3")
|
||||
.replace("肆", "4")
|
||||
.replace("伍", "5")
|
||||
.replace("陆", "6")
|
||||
.replace("柒", "7")
|
||||
.replace("捌", "8")
|
||||
.replace("玖", "9")
|
||||
.replace("零", "0")
|
||||
.replace("一", "1")
|
||||
.replace("二", "2")
|
||||
.replace("三", "3")
|
||||
.replace("四", "4")
|
||||
.replace("五", "5")
|
||||
.replace("六", "6")
|
||||
.replace("七", "7")
|
||||
.replace("八", "8")
|
||||
.replace("九", "9")
|
||||
.replace("〇", "0")
|
||||
.replace("洞", "0")
|
||||
.replace("幺", "1")
|
||||
.replace("俩", "2")
|
||||
.replace("两", "2")
|
||||
.replace("拐", "7")
|
||||
.replace("点", ".")
|
||||
)
|
||||
|
||||
|
||||
def int_str(sth: str):
|
||||
try:
|
||||
return int(float_str(sth))
|
||||
except ValueError:
|
||||
raise ValueError
|
||||
return int(float_str(sth))
|
||||
|
@ -4,7 +4,7 @@
|
||||
伶伦转换器 本地化组件
|
||||
Linglun Converter Language Localization Component
|
||||
|
||||
版权所有 © 2024 金羿 & 睿穆开发组
|
||||
版权所有 © 2024 金羿 & 睿乐开发组
|
||||
Copyright © 2024 EillesWan & TriM Org.
|
||||
|
||||
开源相关声明请见 ./License.md
|
||||
|
@ -4,7 +4,7 @@
|
||||
伶伦转换器 打包存档组件
|
||||
Linglun Converter Language Localization Component
|
||||
|
||||
版权所有 © 2024 金羿 & 睿穆开发组
|
||||
版权所有 © 2024 金羿 & 睿乐开发组
|
||||
Copyright © 2024 EillesWan & TriM Org.
|
||||
|
||||
开源相关声明请见 ./License.md
|
||||
@ -12,7 +12,6 @@ Terms & Conditions: ./Lisense.md
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import hashlib
|
||||
|
||||
import dill
|
||||
@ -62,3 +61,60 @@ def enpack_llc_pack(sth: Any, to_dist: str):
|
||||
f.write(md5_value)
|
||||
f.write(b" | \n")
|
||||
f.write(packing_bytes)
|
||||
|
||||
|
||||
def enpack_msct_pack(sth, to_dist: str):
|
||||
packing_bytes = brotli.compress(
|
||||
dill.dumps(
|
||||
sth,
|
||||
)
|
||||
)
|
||||
with open(
|
||||
to_dist,
|
||||
"wb",
|
||||
) as f:
|
||||
f.write(packing_bytes)
|
||||
|
||||
return hashlib.sha256(packing_bytes)
|
||||
|
||||
|
||||
def unpack_msct_pack(from_dist: str, hash_value: str, raise_error: bool = True):
|
||||
with open(from_dist, "rb") as f:
|
||||
packed_data = f.read()
|
||||
now_hash = hashlib.sha256(packed_data).hexdigest()
|
||||
if now_hash == hash_value:
|
||||
return dill.loads(brotli.decompress(packed_data))
|
||||
else:
|
||||
if raise_error:
|
||||
raise ValueError(
|
||||
"文件读取失败:\n传入:{}\n需求:{}\n签名不一致,可能存在注入风险。".format(
|
||||
now_hash, hash_value
|
||||
)
|
||||
)
|
||||
else:
|
||||
return ValueError(
|
||||
"文件读取失败:\n传入:{}\n需求:{}\n签名不一致,可能存在注入风险。".format(
|
||||
now_hash, hash_value
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def load_msct_packed_data(
|
||||
packed_data: bytes, hash_value: str, raise_error: bool = True
|
||||
):
|
||||
now_hash = hashlib.sha256(packed_data).hexdigest()
|
||||
if now_hash == hash_value:
|
||||
return dill.loads(brotli.decompress(packed_data))
|
||||
else:
|
||||
if raise_error:
|
||||
raise ValueError(
|
||||
"文件读取失败:\n传入:{}\n需求:{}\n签名不一致,可能存在注入风险。".format(
|
||||
now_hash, hash_value
|
||||
)
|
||||
)
|
||||
else:
|
||||
return ValueError(
|
||||
"文件读取失败:\n传入:{}\n需求:{}\n签名不一致,可能存在注入风险。".format(
|
||||
now_hash, hash_value
|
||||
)
|
||||
)
|
||||
|
@ -4,14 +4,14 @@
|
||||
伶伦转换器 版本检查组件
|
||||
Linglun Converter Version Checking Component
|
||||
|
||||
版权所有 © 2024 金羿 & 睿穆开发组
|
||||
版权所有 © 2024 金羿 & 睿乐开发组
|
||||
Copyright © 2024 EillesWan & TriM Org.
|
||||
|
||||
开源相关声明请见 ./License.md
|
||||
Terms & Conditions: ./Lisense.md
|
||||
"""
|
||||
|
||||
from .io import TrimLog, urllib, Sequence, Iterable, Callable, Optional
|
||||
from .io import TrimLog, requests, Sequence, Iterable, Callable, Optional, Dict, Union
|
||||
|
||||
|
||||
def is_ver_char(text: str) -> bool:
|
||||
@ -64,20 +64,21 @@ def is_ver_bigger(ver_1: Sequence[int], ver_2: Sequence[int]) -> bool:
|
||||
return len_v1 > len_v2
|
||||
|
||||
|
||||
def check_update(
|
||||
def check_update_repo(
|
||||
appname: str,
|
||||
get_text_url: str,
|
||||
version_now: str,
|
||||
message_show_fun: Callable,
|
||||
logger: TrimLog.Logger,
|
||||
version_disp: Optional[str] = None,
|
||||
version_renew_tip: str = "!有新版本!\n最新的 {app} 已经是 {latest} 版本,当前您正在使用的仍是 {current} 版本,您可以前往下载地址更新。",
|
||||
):
|
||||
if not version_disp:
|
||||
version_disp = version_now
|
||||
|
||||
logger.info("当前版本信息:{}".format(version_now))
|
||||
logger.info("当前 {} 版本:{}".format(appname,version_now))
|
||||
try:
|
||||
code_content: str = urllib.request.urlopen(get_text_url).read().decode("utf-8")
|
||||
code_content: str = requests.get(get_text_url).text
|
||||
except Exception as E: # noinspection PyBroadException
|
||||
logger.warning("无法获取更新版本信息:{}".format(E))
|
||||
return
|
||||
@ -86,7 +87,7 @@ def check_update(
|
||||
code_content = code_content[code_content.find('"') + 1 :]
|
||||
version_content = code_content[: code_content.find('"')]
|
||||
|
||||
logger.info("已获取更新版本信息:{}".format(version_content))
|
||||
logger.info("已获取 {} 新版本信息:{}".format(appname,version_content))
|
||||
|
||||
if is_ver_bigger(
|
||||
[int(v) for v in cut_ver_str(version_content).split(".")],
|
||||
@ -98,7 +99,7 @@ def check_update(
|
||||
version_content = code_content[: code_content.find('"')]
|
||||
|
||||
message_show_fun(
|
||||
"!有新版本!\n最新的 {app} 已经是 {latest} 版本,当前您正在使用的仍是 {current} 版本,您可以前往下载地址更新。".format(
|
||||
version_renew_tip.format(
|
||||
app=appname, latest=version_content, current=version_disp
|
||||
)
|
||||
)
|
||||
@ -116,3 +117,42 @@ def check_update(
|
||||
# return version_content[i:j]
|
||||
|
||||
# "".join([version_content[i] for i in range(version_content.__len__()) if is_ver_char(version_content[i]) and ((version_content[i-1] if i > 0 else False) or (version_content[i+1] if i < version_content.__len__() else False))]).split('.')
|
||||
|
||||
|
||||
def check_update_release(
|
||||
appname: str,
|
||||
get_release_url: str,
|
||||
version_now: str,
|
||||
notice_fun: Callable[[str, str], bool],
|
||||
logger: TrimLog.Logger,
|
||||
version_renew_tip: str = "!有新版本!\n最新的 {app} 已经是 {latest} 版本,当前您正在使用的仍是 {current} 版本,是否更新?",
|
||||
) -> Union[None, Dict[str, str]]:
|
||||
|
||||
logger.info("当前 {} 版本:{}".format(appname,version_now))
|
||||
try:
|
||||
code_content: Dict = requests.get(get_release_url).json()
|
||||
except Exception as E: # noinspection PyBroadException
|
||||
logger.warning("无法获取更新版本信息:{}".format(E))
|
||||
return
|
||||
|
||||
version_content = code_content["release"]["tag"]["name"]
|
||||
|
||||
logger.info("已获取 {} 新版本信息:{}".format(appname,version_content))
|
||||
|
||||
if is_ver_bigger(
|
||||
[int(v) for v in cut_ver_str(version_content).split(".")],
|
||||
[int(v) for v in cut_ver_str(version_now).split(".")],
|
||||
):
|
||||
|
||||
if notice_fun(
|
||||
version_renew_tip.format(
|
||||
app=appname, latest=version_content, current=version_now
|
||||
),
|
||||
code_content["release"]["release"]["description"],
|
||||
):
|
||||
return dict(
|
||||
[
|
||||
(d["name"], d["download_url"])
|
||||
for d in code_content["release"]["release"]["attach_files"]
|
||||
]
|
||||
)
|
||||
|
147
utils/webview.py
Normal file
147
utils/webview.py
Normal file
@ -0,0 +1,147 @@
|
||||
import wx
|
||||
import wx.html
|
||||
|
||||
|
||||
class HTMLFrame(wx.Frame):
|
||||
"""桌面程序主窗口类"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
tip_text,
|
||||
web_text,
|
||||
window_title: str = "新版本已发布",
|
||||
bg_colour: tuple = (0, 0, 0),
|
||||
window_size: tuple = (800, 480),
|
||||
):
|
||||
"""构造函数"""
|
||||
|
||||
wx.Frame.__init__(
|
||||
self,
|
||||
parent,
|
||||
id=wx.ID_ANY,
|
||||
title=window_title,
|
||||
pos=wx.DefaultPosition,
|
||||
size=window_size,
|
||||
style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL,
|
||||
)
|
||||
|
||||
# self.SetIcon(wx.Icon('', wx.BITMAP_TYPE_ICO))
|
||||
self.SetBackgroundColour(bg_colour)
|
||||
self.Center()
|
||||
|
||||
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
|
||||
|
||||
bSizer1 = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.m_staticText1 = wx.StaticText(
|
||||
self,
|
||||
wx.ID_ANY,
|
||||
tip_text,
|
||||
wx.DefaultPosition,
|
||||
wx.DefaultSize,
|
||||
wx.ALIGN_CENTER_HORIZONTAL,
|
||||
)
|
||||
self.m_staticText1.Wrap(-1)
|
||||
|
||||
self.m_staticText1.SetFont(
|
||||
wx.Font(
|
||||
wx.NORMAL_FONT.GetPointSize() * 2,
|
||||
wx.FONTFAMILY_DEFAULT,
|
||||
wx.FONTSTYLE_NORMAL,
|
||||
wx.FONTWEIGHT_NORMAL,
|
||||
False,
|
||||
"OPPOSans M",
|
||||
)
|
||||
)
|
||||
|
||||
bSizer1.Add(self.m_staticText1, 3, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 5)
|
||||
|
||||
self.m_htmlWin1 = wx.html.HtmlWindow(
|
||||
self,
|
||||
wx.ID_ANY,
|
||||
wx.DefaultPosition,
|
||||
wx.DefaultSize,
|
||||
wx.html.HW_SCROLLBAR_AUTO,
|
||||
)
|
||||
self.m_htmlWin1.SetFont(
|
||||
wx.Font(
|
||||
wx.NORMAL_FONT.GetPointSize(),
|
||||
wx.FONTFAMILY_DEFAULT,
|
||||
wx.FONTSTYLE_NORMAL,
|
||||
wx.FONTWEIGHT_NORMAL,
|
||||
False,
|
||||
"OPPOSans R",
|
||||
)
|
||||
)
|
||||
self.m_htmlWin1.SetStandardFonts(normal_face="OPPOSans R")
|
||||
|
||||
bSizer1.Add(self.m_htmlWin1, 5, wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 5)
|
||||
|
||||
bSizer2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.m_button1 = wx.Button(
|
||||
self, wx.ID_ANY, "取消", wx.DefaultPosition, wx.DefaultSize, 0
|
||||
)
|
||||
bSizer2.Add(self.m_button1, 0, wx.ALL, 5)
|
||||
|
||||
self.m_button2 = wx.Button(
|
||||
self, wx.ID_ANY, "更新", wx.DefaultPosition, wx.DefaultSize, 0
|
||||
)
|
||||
bSizer2.Add(self.m_button2, 0, wx.ALL, 5)
|
||||
|
||||
bSizer1.Add(bSizer2, 0, wx.ALIGN_RIGHT, 5)
|
||||
|
||||
self.SetSizer(bSizer1)
|
||||
self.Layout()
|
||||
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
self.m_htmlWin1.SetPage(web_text)
|
||||
|
||||
# Connect Events
|
||||
self.m_button1.Bind(wx.EVT_BUTTON, self.on_Cancel_Click)
|
||||
self.m_button2.Bind(wx.EVT_BUTTON, self.on_Update_Click)
|
||||
|
||||
self.ok = False
|
||||
|
||||
def __del__(self):
|
||||
# return self.ok
|
||||
pass
|
||||
|
||||
def getok(self) -> bool:
|
||||
return self.ok
|
||||
|
||||
# Virtual event handlers, override them in your derived class
|
||||
def on_Cancel_Click(self, event):
|
||||
self.ok = False
|
||||
self.Destroy()
|
||||
|
||||
def on_Update_Click(self, event):
|
||||
self.ok = True
|
||||
self.Destroy()
|
||||
|
||||
|
||||
def go_update_tip(tip_text: str, html_context: str) -> bool:
|
||||
app = wx.App()
|
||||
frame = HTMLFrame(
|
||||
None,
|
||||
tip_text,
|
||||
html_context,
|
||||
bg_colour=wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENU),
|
||||
)
|
||||
frame.Show()
|
||||
app.MainLoop()
|
||||
return frame.getok()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
go_update_tip(
|
||||
"!有新版本!\n最新的 {app} 已经是 {latest} 版本,当前您正在使用的仍是 {current} 版本,是否更新?",
|
||||
'<ol>\n<li>\n<strong>[修复]</strong> 完成<ahref="https://gitee.com/TriM-Organization/Linglun-Converter/issues/I8YN22" rel="nofollow noreferrer noopener"target="_blank">#I8YN22</a>问题的修复,解决转换错误的问题</li>\n<li>\n<strong>[新增]</strong>支持选择自定的乐器对照表</li>\n<li>\n<strong>[新增]</strong>支持自选距离音量算法</li>\n<li>\n<strong>[新增]</strong>使用Packer以打包发行版(详情如下方说明)</li>\n<li>\n<strong>[优化]</strong>提高调用效率,优化代码结构</li>\n<li>\n<strong>[优化]</strong>提升部分注释可读性</li>\n</ol>\n',
|
||||
)
|
||||
|
||||
go_update_tip(
|
||||
"!有新版本!\n最新的 音·创 已经是 1.7.3 版本,当前您正在使用的仍是 1.7.0 版本,是否更新?",
|
||||
'<ol>\n<li>\n<strong>[修复]</strong> 完成<a href="https://gitee.com/TriM-Organization/Linglun-Converter/issues/I8YN22" rel="nofollow noreferrer noopener" target="_blank">#I8YN22</a>问题的修复,解决转换错误的问题</li>\n<li>\n<strong>[新增]</strong> 支持选择自定的乐器对照表</li>\n<li>\n<strong>[新增]</strong> 支持自选距离音量算法</li>\n<li>\n<strong>[新增]</strong> 使用Packer以打包发行版(详情如下方说明)</li>\n<li>\n<strong>[优化]</strong> 提高调用效率,优 化代码结构</li>\n<li>\n<strong>[优化]</strong> 提升部分注释可读性</li>\n</ol>\n<h2>打包文件结构</h2>\n<p>我们使用Python库 <code>dill</code> 和 <code>Brotli</code> 对整个库的包体进行打包,方式如下:</p>\n<div class="markdown-code-block">\n<pre lang="python" class="python"><code>packing_bytes = brotli.compress(dill.dumps(sth,))\n</code></pre>\n<div class="markdown-code-block-copy-btn"></div>\n</div>\n<p>每个包中的内容为:</p>\n<div class="markdown-code-block">\n<pre lang="python" class="python"><code>MSCT_MAIN = (\n Musicreater,\n Musicreater.experiment,\n Musicreater.previous,\n)\n\nMSCT_PLUGIN = (Musicreater.plugin,)\n\nMSCT_PLUGIN_FUNCTION = (\n to_addon_pack_in_delay,\n to_addon_pack_in_repeater,\n to_addon_pack_in_score,\n to_mcstructure_file_in_delay,\n to_mcstructure_file_in_repeater,\n to_mcstructure_file_in_score,\n to_BDX_file_in_delay,\n to_BDX_file_in_score,\n)\n</code></pre>\n<div class="markdown-code-block-copy-btn"></div>\n</div>',
|
||||
)
|
Reference in New Issue
Block a user