add small tools

This commit is contained in:
David-123 2024-10-04 10:55:48 +08:00
parent c10bd094da
commit 620f030d5f
8 changed files with 138 additions and 37 deletions

20
main.py
View File

@ -15,6 +15,7 @@ from modules.submenus.settings import settings_menu
from modules.functions.settings.save_load_settings import load_settings from modules.functions.settings.save_load_settings import load_settings
from modules.utils.clear_screen import cls_stay from modules.utils.clear_screen import cls_stay
from modules.functions.mainly.load_file_song import get_lyric_from_folder from modules.functions.mainly.load_file_song import get_lyric_from_folder
from modules.submenus.tools import tools_menu
class MainProcess(object): class MainProcess(object):
@ -31,24 +32,27 @@ class MainProcess(object):
"1": "单个歌曲的歌词下载", "1": "单个歌曲的歌词下载",
"2": "多个歌曲的歌词下载", "2": "多个歌曲的歌词下载",
"3": "从网易云下载的歌曲中获取歌词", "3": "从网易云下载的歌曲中获取歌词",
"t": "小工具",
"s": "进入设置", "s": "进入设置",
"i": "程序信息", "i": "程序信息",
}) })
r = rinput("请选择:") r = rinput("请选择:")
match r:
if r == "1": case "1":
download_one_lyric(self) download_one_lyric(self)
elif r == "2": case "2":
mdl(self) mdl(self)
elif r == "3": case "3":
get_lyric_from_folder(self) get_lyric_from_folder(self)
elif r == "0": case "0":
exit(0) exit(0)
elif r == "i": case "t":
tools_menu(self)
case "i":
print_info(self) print_info(self)
elif r == "s": case "s":
settings_menu(self) settings_menu(self)
else: case _:
input("请输入正确的选项\n按回车键继续...") input("请输入正确的选项\n按回车键继续...")

View File

@ -147,7 +147,7 @@ def get_lyric_from_folder(self):
suffix="", max=len(ncm_files), color="green", width=9999) as bar: suffix="", max=len(ncm_files), color="green", width=9999) as bar:
total = len(ncm_files) total = len(ncm_files)
allocated = 0 # 已经分配的任务数量 allocated = 0 # 已经分配的任务数量
while True: # 进入循环,执行 新建进程->检测队列->检测任务完成 的循环 while True: # 进入循环,执行 "新建进程->检测队列->检测任务完成" 的循环
sleep(0.05) sleep(0.05)
if current_process <= max_process and allocated < total: # 分配进程 if current_process <= max_process and allocated < total: # 分配进程
Process(target=process_work, Process(target=process_work,
@ -176,7 +176,7 @@ def get_lyric_from_folder(self):
passed += 1 passed += 1
current_process -= 1 current_process -= 1
bar.print_onto_bar(Fore.YELLOW + bar.print_onto_bar(Fore.YELLOW +
f"\"{r['musicName']} - " f"\"{r['musicName']} by "
f"{''.join([x + ', ' for x in [x[0] for x in r['artist']]])[:-2]}" f"{''.join([x + ', ' for x in [x[0] for x in r['artist']]])[:-2]}"
"\"" + Fore.GREEN + " 已完成!") "\"" + Fore.GREEN + " 已完成!")
bar.next() bar.next()

View File

@ -6,7 +6,6 @@ from modules.utils.inputs import rinput
from modules.functions.mainly.get_song import get_song_lyric from modules.functions.mainly.get_song import get_song_lyric
from modules.utils.bar import CompactArrowBar from modules.utils.bar import CompactArrowBar
def mdl(self): def mdl(self):
"""多个歌词文件的下载 """多个歌词文件的下载
@ -34,7 +33,7 @@ def mdl(self):
with CompactArrowBar(f"进度: %(index){len(str(len(ids)))}d/%(max)d", with CompactArrowBar(f"进度: %(index){len(str(len(ids)))}d/%(max)d",
suffix="", max=len(ids), color="yellow", width=9999) as bar: suffix="", max=len(ids), color="yellow", width=9999) as bar:
for i in range(0, len(ids)): for i in range(0, len(ids)):
r = get_song_lyric(ids[i], self.settings.lyric_path, self.settings.lyric_path, bar=bar) r = get_song_lyric(ids[i], self.settings.lyric_path, self.settings.lyric_format, bar=bar)
if r == "dl_err_connection": if r == "dl_err_connection":
bar.print_onto_bar(Fore.RED + "下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") bar.print_onto_bar(Fore.RED + "下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...")
input() input()

View File

@ -0,0 +1,3 @@
def mult_unlock(...)

View File

@ -24,19 +24,20 @@ def settings_menu(self):
"4": "部分动态效果", "4": "部分动态效果",
"s": "切换设置自动保存" "s": "切换设置自动保存"
}) })
if r == "0": match r:
case "0":
return return
elif r == "1": case "1":
__set_lyric_path(self) __set_lyric_path(self)
elif r == "2": case "2":
__remove_output_files(self) __remove_output_files(self)
elif r == "3": case "3":
__set_lyric_format(self) __set_lyric_format(self)
elif r == "4": case "4":
pass pass
elif r == "s": case "s":
self.settings.auto_save = not self.settings.auto_save self.settings.auto_save = not self.settings.auto_save
else: case _:
input("输入无效!按回车键继续...") input("输入无效!按回车键继续...")

50
modules/submenus/tools.py Normal file
View File

@ -0,0 +1,50 @@
"""小工具以及菜单"""
import os
from colorama import Fore
from modules.utils.prints import print_menu
from modules.utils.clear_screen import cls_stay
from modules.utils.inputs import cinput
from modules.functions.mainly.load_file_song import load_and_decrypt_from_ncm, process_work
def tools_menu(self):
while True:
cls_stay(self, "[小工具菜单]")
print_menu({
"0": "返回上级菜单",
"d": "解锁指定ncm文件/指定文件夹"
})
r = cinput("请选择:")
match r:
case "0":
return
case "d":
ncm_unlock(self)
input("按回车继续...")
case _:
input("请输入正确的选项\n按回车键继续...")
def ncm_unlock(self):
cls_stay(self, "[小工具 - 文件解锁]")
path = cinput("请输入绝对路径:").replace("\\","")
if not os.path.exists(path): # 判断目标存在与否
print("目标不存在!")
return
if os.path.isfile(path): # 目标为文件则执行单文件解密
r = load_and_decrypt_from_ncm(path, os.path.split(path)[-1], "original", True)
match r:
case "file_not_found":
print("文件未找到")
case "perm_error":
print("权限错误。请检查是否拥有对应权限或者文件是否被占用。")
case _:
print(f"解锁完毕!文件保存在:\n{Fore.GREEN}{r[-1]}")
return
elif os.path.isdir(path): # 目标为文件夹则执行文件夹遍历
...
else:
print("无法识别目标文件。请确认目标文件是否正确以及是否拥有对应权限。")

View File

@ -8,6 +8,7 @@ from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad from Cryptodome.Util.Padding import unpad
from Cryptodome.Util.strxor import strxor as xor from Cryptodome.Util.strxor import strxor as xor
from mutagen import mp3, flac, id3 from mutagen import mp3, flac, id3
from modules.utils.wrappers import escape_file_not_found, escape_permission_error
def regular_filename(filename): def regular_filename(filename):
@ -28,7 +29,14 @@ def regular_filename(filename):
return filename return filename
def load_and_decrypt_from_ncm(file_path, target_dir, out_format) -> dict | str: # author: Nzix Repo: nondanee @escape_file_not_found
@escape_permission_error
def load_and_decrypt_from_ncm(file_path, target_dir, out_format, return_output_path=False) -> dict | str | tuple:
# Original author: Nzix Repo: nondanee
"""解锁指定文件并按照规则保存在指定位置
``file_path`` 源文件路径
``target_dir`` 解锁后文件保存路径
``out_format`` 输出文件格式使用字典格式字符串若使用源文件名仅替换后缀则传入\"original\""""
core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857')
meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728')
@ -89,7 +97,9 @@ def load_and_decrypt_from_ncm(file_path, target_dir, out_format) -> dict | str:
f.seek(image_space - image_size, 1) f.seek(image_space - image_size, 1)
# media data # media data
if meta_length: if out_format == "original":
output_path = f"{os.path.splitext(file_path)[0]}.{meta_data['format']}"
elif meta_length:
output_path = os.path.join(target_dir, regular_filename(out_format % {"name": meta_data["musicName"], output_path = os.path.join(target_dir, regular_filename(out_format % {"name": meta_data["musicName"],
"artists": "".join( "artists": "".join(
[x[0]+"," for x in meta_data["artist"]] [x[0]+"," for x in meta_data["artist"]]
@ -145,6 +155,12 @@ def load_and_decrypt_from_ncm(file_path, target_dir, out_format) -> dict | str:
audio['album'] = meta_data['album'] audio['album'] = meta_data['album']
audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']])
audio.save() audio.save()
if return_output_path:
return meta_data, output_path
else:
return meta_data return meta_data
else:
if return_output_path:
return "no_meta_data", output_path
else: else:
return "no_meta_data" return "no_meta_data"

28
modules/utils/wrappers.py Normal file
View File

@ -0,0 +1,28 @@
"""一些有的没有的装饰器"""
def escape_file_not_found(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except FileNotFoundError:
return "file_not_found"
return wrapper
def escape_decrypt_unsatisfied_file(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except (AssertionError, IsADirectoryError):
return "file_not_satisfied"
return wrapper
def escape_permission_error(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except PermissionError:
return "perm_error"
return wrapper