diff --git a/.gitignore b/.gitignore index 2f0f946..ca30bc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ +.devflag .vscode .directory __pycache__/ scripts/ .idea -cache \ No newline at end of file +cache diff --git a/.playsound.py b/.playsound.py index 09e008d..b3d8ab8 100644 --- a/.playsound.py +++ b/.playsound.py @@ -1,2 +1,5 @@ +# for Android/Termux +import os def playsound(p): + os.system(f"play-audio '{p}'") print(p) \ No newline at end of file diff --git a/auxiliary.py b/auxiliary.py index df0aa98..ed31ff3 100644 --- a/auxiliary.py +++ b/auxiliary.py @@ -4,6 +4,7 @@ import toml import typing from playsound import playsound import threading +import hashlib import edge_tts as tts class ConfigFile: @@ -60,4 +61,7 @@ def get_daystamp() -> int: if time_override != -1: return int(time_override) - return int(time.time() // (24 * 3600)) \ No newline at end of file + return int(time.time() // (24 * 3600)) + +def get_md5(text): + return hashlib.md5(text.encode('utf-8')).hexdigest() diff --git a/nucleon/作文素材.dyna.toml b/nucleon/作文素材.dyna.toml deleted file mode 100644 index e69de29..0000000 diff --git a/particles.py b/particles.py index 35d47b0..d31195d 100644 --- a/particles.py +++ b/particles.py @@ -178,6 +178,8 @@ class NucleonUnion: all = toml.load(f) lst = list() for i in all.keys(): + if "attr" in i: + continue if "data" in i: continue lst.append(Nucleon(i, all[i])) diff --git a/precache.py b/precache.py index 4a04c82..d19453c 100644 --- a/precache.py +++ b/precache.py @@ -1,18 +1,20 @@ -# 音频预缓存实用程序, 独立于主程序之外, 但依赖 particles 组件 +# 音频预缓存实用程序, 独立于主程序之外, 但依赖其他组件 import particles as pt +import auxiliary as aux import edge_tts as tts from pathlib import Path import shutil +import time def precache(text: str): """预缓存单个文本的音频""" cache_dir = Path("./cache/voice/") cache_dir.mkdir(parents=True, exist_ok=True) - cache = cache_dir / f"{text}.wav" + cache = cache_dir / f"{aux.get_md5(text)}.wav" if not cache.exists(): communicate = tts.Communicate(text, "zh-CN-XiaoxiaoNeural") - communicate.save_sync(f"./cache/voice/{text}.wav") + communicate.save_sync(f"./cache/voice/{aux.get_md5(text)}.wav") def proc_file(path: Path): @@ -29,14 +31,17 @@ def walk(path_str: str): """遍历目录处理所有文件""" path = Path(path_str) print(f"正在遍历目录: {path}") - - for item in path.iterdir(): - if item.is_file() and item.suffix == ".toml": - print(f"正预缓存文件: {item.name}") - proc_file(item) - elif item.is_dir(): - print(f"进入目录: {item.name}") - + try: + for item in path.iterdir(): + if item.is_file() and item.suffix == ".toml": + print(f"正预缓存文件: {item.name}") + proc_file(item) + elif item.is_dir(): + print(f"进入目录: {item.name}") + except: + print("发生一个异常, 于 5 秒后自动重新下载") + time.sleep(5) + walk(path_str) if __name__ == "__main__": print("音频预缓存实用程序") diff --git a/screens.py b/screens.py index 528f017..d64f7b8 100644 --- a/screens.py +++ b/screens.py @@ -111,14 +111,14 @@ class MemScreen(Screen): def play(): cache_dir = pathlib.Path(f"./cache/voice/") cache_dir.mkdir(parents=True, exist_ok=True) - cache = cache_dir / f"{self.reactor.current_atom[1].content.replace('/','')}.wav" + cache = cache_dir / f"{aux.get_md5(self.reactor.current_atom[1].content.replace('/',''))}.wav" if not cache.exists(): communicate = tts.Communicate( self.reactor.current_atom[1].content.replace("/", ""), "zh-CN-XiaoxiaoNeural", ) communicate.save_sync( - f"./cache/voice/{self.reactor.current_atom[1].content.replace('/','')}.wav" + f"./cache/voice/{aux.get_md5(self.reactor.current_atom[1].content.replace('/',''))}.wav" ) playsound(str(cache)) diff --git a/tweak.py b/tweak.py new file mode 100644 index 0000000..9bf8643 --- /dev/null +++ b/tweak.py @@ -0,0 +1,247 @@ +import os +import shutil +import subprocess +import sys + +def check_dev_flag(): + """检查是否存在开发标志文件,如果存在则退出程序""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + dev_flag_path = os.path.join(script_dir, '.devflag') + + if os.path.exists(dev_flag_path): + print("检测到开发标志文件 (.devflag),不得运行此程序") + sys.exit(0) + +def main(): + # 检查开发标志文件 + check_dev_flag() + + # 输出标题 + print("HeurAMS 更新 & 数据管理工具") + print("君欲何为?") + print("\nR: 全新安装 HeurAMS (删除 nucleon 与 electron 的用户数据, 并从上游同步软件更新)") + print("F: 翻新 HeurAMS (保留 nucleon 与 electron 的用户数据, 并从上游同步软件更新)") + print("U: 卸载 HeurAMS (删除 HeurAMS 程序文件, 保留用户数据)") + print("P: 应用 Termux 音频补丁") + + # 获取用户输入 + choice = input("\n请输入选择 (R/F/U/P): ").strip().lower() + + # 获取脚本所在目录 + script_dir = os.path.dirname(os.path.abspath(__file__)) + os.chdir(script_dir) + + if choice == 'r': + # 检查开发标志文件(再次检查,防止在运行时创建) + check_dev_flag() + + # 全新安装 - 删除所有文件和文件夹(包括.git) + print("正在执行全新安装...") + + # 遍历当前目录下的所有文件和文件夹 + for item in os.listdir('.'): + # 跳过脚本自身(如果存在)和开发标志文件 + if item == os.path.basename(__file__) or item == '.devflag': + continue + + item_path = os.path.join(script_dir, item) + + try: + if os.path.isfile(item_path) or os.path.islink(item_path): + os.remove(item_path) + elif os.path.isdir(item_path): + shutil.rmtree(item_path) + except Exception as e: + print(f"删除 {item} 时出错: {e}") + + # 执行git clone到临时目录,然后移动文件 + try: + temp_dir = os.path.join(script_dir, 'temp_clone') + subprocess.run(['git', 'clone', 'https://gitea.imwangzhiyu.xyz/ajax/HeurAMS', temp_dir], check=True) + + # 移动所有文件到当前目录(除了.git目录) + for item in os.listdir(temp_dir): + if item != '.git': + src = os.path.join(temp_dir, item) + dst = os.path.join(script_dir, item) + if os.path.exists(dst): + if os.path.isdir(dst): + shutil.rmtree(dst) + else: + os.remove(dst) + shutil.move(src, dst) + + # 删除临时目录 + shutil.rmtree(temp_dir) + print("全新安装完成!") + + except subprocess.CalledProcessError as e: + print(f"Git clone 失败: {e}") + except Exception as e: + print(f"文件操作失败: {e}") + + elif choice == 'f': + # 检查开发标志文件(再次检查,防止在运行时创建) + check_dev_flag() + + # 翻新安装 - 保留特定目录 + print("正在执行翻新安装...") + + # 需要保留的目录列表 + preserve_dirs = ['nucleon', 'electron', 'cache'] + + # 备份需要保留的目录到临时位置 + backup_dir = os.path.join(script_dir, 'temp_backup') + os.makedirs(backup_dir, exist_ok=True) + + for dir_name in preserve_dirs: + dir_path = os.path.join(script_dir, dir_name) + if os.path.exists(dir_path): + backup_path = os.path.join(backup_dir, dir_name) + if os.path.exists(backup_path): + shutil.rmtree(backup_path) + shutil.copytree(dir_path, backup_path) + + # 删除所有文件和文件夹(包括.git) + for item in os.listdir('.'): + # 跳过脚本自身、备份目录和开发标志文件 + if item == os.path.basename(__file__) or item == 'temp_backup' or item == '.devflag': + continue + + item_path = os.path.join(script_dir, item) + + try: + if os.path.isfile(item_path) or os.path.islink(item_path): + os.remove(item_path) + elif os.path.isdir(item_path): + shutil.rmtree(item_path) + except Exception as e: + print(f"删除 {item} 时出错: {e}") + + # 执行git clone到当前目录 + try: + temp_dir = os.path.join(script_dir, 'temp_clone') + subprocess.run(['git', 'clone', 'https://gitea.imwangzhiyu.xyz/ajax/HeurAMS', temp_dir], check=True) + + # 移动所有文件到当前目录(除了.git目录) + for item in os.listdir(temp_dir): + if item != '.git': + src = os.path.join(temp_dir, item) + dst = os.path.join(script_dir, item) + if os.path.exists(dst): + if os.path.isdir(dst): + shutil.rmtree(dst) + else: + os.remove(dst) + shutil.move(src, dst) + + # 删除临时克隆目录 + shutil.rmtree(temp_dir) + + # 恢复保留的目录(覆盖git仓库中的同名目录) + for dir_name in preserve_dirs: + backup_path = os.path.join(backup_dir, dir_name) + if os.path.exists(backup_path): + target_path = os.path.join(script_dir, dir_name) + if os.path.exists(target_path): + shutil.rmtree(target_path) + shutil.copytree(backup_path, target_path) + + # 删除备份目录 + shutil.rmtree(backup_dir) + print("翻新安装完成!") + + except subprocess.CalledProcessError as e: + print(f"Git clone 失败: {e}") + except Exception as e: + print(f"文件操作失败: {e}") + + elif choice == 'u': + # 检查开发标志文件(再次检查,防止在运行时创建) + check_dev_flag() + + # 卸载 HeurAMS - 删除程序文件,保留用户数据 + print("正在卸载 HeurAMS,保留用户数据...") + + # 需要保留的用户数据目录列表 + preserve_dirs = ['nucleon', 'electron', 'cache'] + + # 备份需要保留的目录到临时位置 + backup_dir = os.path.join(script_dir, 'temp_backup') + os.makedirs(backup_dir, exist_ok=True) + + for dir_name in preserve_dirs: + dir_path = os.path.join(script_dir, dir_name) + if os.path.exists(dir_path): + backup_path = os.path.join(backup_dir, dir_name) + if os.path.exists(backup_path): + shutil.rmtree(backup_path) + shutil.copytree(dir_path, backup_path) + print(f"已备份用户数据: {dir_name}") + + # 删除所有文件和文件夹(除了脚本自身、备份目录和开发标志文件) + for item in os.listdir('.'): + # 跳过脚本自身、备份目录和开发标志文件 + if item == os.path.basename(__file__) or item == 'temp_backup' or item == '.devflag': + continue + + item_path = os.path.join(script_dir, item) + + try: + if os.path.isfile(item_path) or os.path.islink(item_path): + os.remove(item_path) + print(f"已删除文件: {item}") + elif os.path.isdir(item_path): + shutil.rmtree(item_path) + print(f"已删除目录: {item}") + except Exception as e: + print(f"删除 {item} 时出错: {e}") + + # 恢复保留的用户数据目录 + for dir_name in preserve_dirs: + backup_path = os.path.join(backup_dir, dir_name) + if os.path.exists(backup_path): + target_path = os.path.join(script_dir, dir_name) + if os.path.exists(target_path): + shutil.rmtree(target_path) + shutil.copytree(backup_path, target_path) + print(f"已恢复用户数据: {dir_name}") + + # 删除备份目录 + shutil.rmtree(backup_dir) + print("卸载完成!HeurAMS 程序文件已删除,用户数据已保留。") + + elif choice == 'p': + # 应用 Termux 音频补丁 + print("应用 Termux 音频补丁") + + # 询问用户是否使用安卓Termux环境 + termux_choice = input("是否使用安卓Termux环境? (y/n): ").strip().lower() + + if termux_choice in ['y', 'yes']: + # 创建playsound.py文件 + playsound_content = '''import os +def playsound(path): + os.system(f"play-audio '{path}'") +''' + + playsound_path = os.path.join(script_dir, 'playsound.py') + + try: + with open(playsound_path, 'w', encoding='utf-8') as f: + f.write(playsound_content) + print("已创建 playsound.py 文件") + print("Termux 音频补丁应用成功!") + print("现在可以使用 play-audio 命令播放音频了。") + + except Exception as e: + print(f"创建 playsound.py 文件时出错: {e}") + else: + print("已取消应用 Termux 音频补丁。") + + else: + print("无效的选择,请输入 R、F、U 或 P。") + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file