From 94149eabead750aac85af6a49d913390861daeed Mon Sep 17 00:00:00 2001 From: 1826013250 <1826013250@qq.com> Date: Sun, 7 May 2023 01:59:03 +0800 Subject: [PATCH] COLORFUL UPDATE Make output more and more and more colorful! Change file structure and README.md --- main.py | 20 ++--- modules/functions/mainly/__init__.py | 0 modules/functions/{ => mainly}/get_song.py | 75 ++++++++++--------- .../functions/{ => mainly}/load_file_song.py | 61 +++++++-------- modules/functions/mainly/multi_download.py | 42 +++++++++++ .../functions/{ => mainly}/one_download.py | 4 +- modules/functions/multi_download.py | 38 ---------- modules/functions/settings/__init__.py | 0 .../{ => settings}/save_load_settings.py | 5 +- modules/submenus/settings.py | 22 ++---- modules/utils/bar.py | 54 +++++++++++++ modules/utils/clear_screen.py | 11 ++- requirements.txt | 3 +- 13 files changed, 198 insertions(+), 137 deletions(-) create mode 100644 modules/functions/mainly/__init__.py rename modules/functions/{ => mainly}/get_song.py (51%) rename modules/functions/{ => mainly}/load_file_song.py (87%) create mode 100644 modules/functions/mainly/multi_download.py rename modules/functions/{ => mainly}/one_download.py (83%) delete mode 100644 modules/functions/multi_download.py create mode 100644 modules/functions/settings/__init__.py rename modules/functions/{ => settings}/save_load_settings.py (94%) diff --git a/main.py b/main.py index 6dc8e6e..f336956 100644 --- a/main.py +++ b/main.py @@ -3,15 +3,18 @@ # -*- coding: utf-8 -*- # author: David-123 +from sys import exit + +from colorama import init from modules.utils.inputs import rinput from modules.utils.information import print_info -from modules.functions.multi_download import mdl -from modules.functions.one_download import download_one_lyric +from modules.functions.mainly.multi_download import mdl +from modules.functions.mainly.one_download import download_one_lyric from modules.submenus.settings import settings_menu -from modules.functions.save_load_settings import load_settings -from modules.utils.clear_screen import clear -from modules.functions.load_file_song import get_lyric_from_folder +from modules.functions.settings.save_load_settings import load_settings +from modules.utils.clear_screen import cls_stay +from modules.functions.mainly.load_file_song import get_lyric_from_folder class MainProcess(object): @@ -22,10 +25,8 @@ class MainProcess(object): def mainloop(self): """程序主循环""" while True: - clear() - print(f"[NeteaseMusicLyricDownloader] {self.version}\n" - "[程序主菜单]\n" - "[0] 退出程序\n[1] 单个歌曲的歌词下载\n[2] 多个歌曲的歌词下载\n[3] 从网易云下载的歌曲中获取歌词" + cls_stay(self, "[程序主菜单]") + print("[0] 退出程序\n[1] 单个歌曲的歌词下载\n[2] 多个歌曲的歌词下载\n[3] 从网易云下载的歌曲中获取歌词" "\n[s] 进入设置\n[i] 程序信息") r = rinput("请选择:") @@ -46,6 +47,7 @@ class MainProcess(object): if __name__ == "__main__": + init(autoreset=True) app = MainProcess() try: app.mainloop() diff --git a/modules/functions/mainly/__init__.py b/modules/functions/mainly/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/functions/get_song.py b/modules/functions/mainly/get_song.py similarity index 51% rename from modules/functions/get_song.py rename to modules/functions/mainly/get_song.py index b031b44..9b4d449 100644 --- a/modules/functions/get_song.py +++ b/modules/functions/mainly/get_song.py @@ -1,48 +1,55 @@ """集合 下载歌词 以及 获取歌曲信息 的功能""" import os -from json import loads from requests import post from requests.exceptions import ConnectionError from time import sleep +from colorama import Fore, Style + +from modules.utils.bar import CompactBar, bprint -def wait_retry(): - print("api提示操作频繁,等待恢复...") +def wait_retry(kind, identify, bar=None): + bprint("api提示操作频繁,等待恢复...", bar) + if kind == "information": + url = f"https://music.163.com/api/song/detail/?&ids=[{identify}]" + elif kind == "lyric": + url = f"https://music.163.com/api/song/media?id={identify}" + else: + return "unknown_kind" while True: try: - tmp = post(f"http://music.163.com/api/song/detail/?&ids=[1]") + tmp = post(url).json() except ConnectionError: return "dl_err_connection" else: - if loads(tmp.text)["code"] == 200: - return "continue" + if tmp["code"] == 200: + return tmp sleep(1) -def get_song_info_raw(types: list, id: str): +def get_song_info_raw(types: list, identify: str, bar: CompactBar = None): """获取歌曲信息 - types 提供一个list,将会返回内部所有符合要求的信息类型\n - id 提供一个歌曲id(str),将会把歌曲的`types`信息返回""" - print("id:%s" % id) + ``types`` 提供一个list,将会返回内部所有符合要求的信息类型\n + ``identify`` 提供一个歌曲id(str),将会把歌曲的`types`信息返回""" + bprint(Fore.CYAN + "ID:%s" % identify, bar) try: - response = post(f"http://music.163.com/api/song/detail/?&ids=[{id}]") + info = post(f"https://music.163.com/api/song/detail/?&ids=[{identify}]").json() except ConnectionError: return "dl_err_connection" else: - info = loads(response.text) if info["code"] == 406: # 判断当操作频繁时,继续获取,直到可以返回值为200为止 - result = wait_retry() - if result == "continue": - pass + result = wait_retry("information", identify, bar=bar) + if type(result) == dict: + info = result elif result == "dl_err_connection": return "dl_err_connection" else: raise Exception("Unknown exception...") if not info.get("songs"): # 判断是否存在该歌曲 - print("这首歌没有找到,跳过...") + bprint(Fore.LIGHTBLACK_EX + "\t-> 这首歌没有找到,跳过...", bar) return "song_nf" else: need = {} @@ -51,17 +58,19 @@ def get_song_info_raw(types: list, id: str): return need -def get_song_lyric(id: str | int | dict, path: str, allinfo: bool = False): +def get_song_lyric(identify: str | int | dict, path: str, allinfo: bool = False, bar: CompactBar = None): """获取歌词 - ``id`` 提供一个歌曲id + ``identify`` 提供一个歌曲id ``path`` 提供歌曲下载的路径 - ``allinfo`` 若此项为 True ,则提供的id格式必须为 {"id": int | str, "name": str, "artists": [[str, ...], ...]} (dict)""" + ``allinfo`` 若此项为 True ,则提供的identify格式必须为存储在网易云下载文件中meta_data的格式 + ``bar`` 若获取歌词时下方有进度条, 则应当传入此参数""" if allinfo: - sinfo = id - id = id["id"] + sinfo = identify + identify = identify["id"] + bprint(Fore.CYAN + f"ID: {identify}", bar) else: - sinfo = get_song_info_raw(["name", "artists"], id) + sinfo = get_song_info_raw(["name", "artists"], identify, bar) if sinfo == "dl_err_connection": # 处理各式各样的事件 return "dl_err_connection" elif sinfo == "song_nf": @@ -79,7 +88,7 @@ def get_song_lyric(id: str | int | dict, path: str, allinfo: bool = False): name = sinfo["name"] if not name: - print("歌曲错误!这是网易云的问题,请不要找作者") + bprint(Fore.RED + "歌曲错误!这是网易云的问题,请不要找作者", bar) return "song_err" replaces = { # 处理非法字符所用的替换字典(根据网易云下载的文件分析得到) "|": "|", @@ -96,30 +105,28 @@ def get_song_lyric(id: str | int | dict, path: str, allinfo: bool = False): name = name.replace(k, v) artists = artists.replace(k, v) - print(f"歌曲:{name} - {artists}") + bprint(Fore.YELLOW + "\t-> 歌曲:" + Style.RESET_ALL + f"{name} - {artists}", bar) filename = f"{name} - {artists}.lrc" try: - response = post(f"http://music.163.com/api/song/media?id={id}") + info = post(f"https://music.163.com/api/song/media?id={identify}").json() except ConnectionError: return "dl_err_connection" else: - info = loads(response.text) if info["code"] == 406: # 此处与上方一样,防止因为请求限制而跳过下载 - result = wait_retry() - if result == "continue": - pass + result = wait_retry("lyric", identify, bar=bar) + if type(result) == dict: + info = result elif result == "dl_err_connection": return "dl_err_connection" else: raise Exception("Unknown exception...") - tmp = loads(response.text) - if tmp.get("nolyric") or not tmp.get('lyric'): - print("这首歌没有歌词,跳过...") + if info.get("nolyric") or not info.get('lyric'): + bprint(Fore.LIGHTBLACK_EX + "\t--> 这首歌没有歌词,跳过...\n", bar) return else: with open(os.path.join(path, filename), "w", encoding="utf-8") as f: - f.write(tmp["lyric"]) - print(f"歌词下载完成!被保存在{os.path.join(path, filename)}") + f.write(info["lyric"]) + bprint(Fore.GREEN + "\t--> 歌词下载完成!被保存在" + Style.RESET_ALL + f"{os.path.join(path, filename)}\n", bar) return diff --git a/modules/functions/load_file_song.py b/modules/functions/mainly/load_file_song.py similarity index 87% rename from modules/functions/load_file_song.py rename to modules/functions/mainly/load_file_song.py index ec40c21..7b0ef71 100644 --- a/modules/functions/load_file_song.py +++ b/modules/functions/mainly/load_file_song.py @@ -9,13 +9,15 @@ from time import sleep import mutagen.mp3 from Cryptodome.Cipher import AES +from Cryptodome.Util.Padding import unpad from mutagen import File, flac from mutagen.id3 import ID3, TPE1, APIC, COMM, TIT2, TALB +from colorama import Fore, Style -from modules.utils.clear_screen import clear -from modules.functions.get_song import get_song_lyric +from modules.utils.clear_screen import cls_stay +from modules.functions.mainly.get_song import get_song_lyric from modules.utils.inputs import cinput, rinput -from modules.utils.bar import CompactBar +from modules.utils.bar import CompactBar, CompactArrowBar def load_information_from_song(path) -> str | dict: @@ -43,20 +45,12 @@ def load_information_from_song(path) -> str | dict: else: return "not_support" - def unpad(s): # 创建清理针对于网易云的 AES-128-ECB 解密后末尾占位符的函数 - if type(s[-1]) == int: - end = s[-1] - else: - end = ord(s[-1]) - return s[0:-end] - # return s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] 更加清晰的理解 ↑ - cryptor = AES.new(b"#14ljk_!\\]&0U<'(", AES.MODE_ECB) # 使用密钥创建解密器 # 下方这一行将密文 ciphertext 转换为 bytes 后进行 base64 解码, 得到加密过的 AES 密文 # 再通过上方创建的 AES 128-ECB 的解密器进行解密, 然后使用 unpad 清除末尾无用的占位符后得到结果 try: - r = unpad((cryptor.decrypt(b64decode(bytes(ciphertext, "utf-8"))).decode("utf-8"))) + r = unpad(cryptor.decrypt(b64decode(bytes(ciphertext, "utf-8"))), 16).decode("utf-8") except ValueError: return "decrypt_failed" @@ -72,9 +66,6 @@ def load_information_from_song(path) -> str | dict: def load_and_decrypt_from_ncm(file_path, target_dir) -> dict: # nondanee的源代码, 根据需求更改了某些东西 core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857") meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728") - - def unpad(s): - return s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(file_path, 'rb') header = f.read(8) assert binascii.b2a_hex(header) == b'4354454e4644414d' @@ -87,7 +78,7 @@ def load_and_decrypt_from_ncm(file_path, target_dir) -> dict: # nondanee的源 key_data_array[i] ^= 0x64 key_data = bytes(key_data_array) cryptor = AES.new(core_key, AES.MODE_ECB) - key_data = unpad(cryptor.decrypt(key_data))[17:] + key_data = unpad(cryptor.decrypt(key_data), 16)[17:] key_length = len(key_data) key_data = bytearray(key_data) key_box = bytearray(range(256)) @@ -112,7 +103,7 @@ def load_and_decrypt_from_ncm(file_path, target_dir) -> dict: # nondanee的源 comment = meta_data meta_data = b64decode(meta_data[22:]) cryptor = AES.new(meta_key, AES.MODE_ECB) - meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] + meta_data = unpad(cryptor.decrypt(meta_data), 16).decode('utf-8')[6:] meta_data = json.loads(meta_data) crc32 = f.read(4) crc32 = struct.unpack('检测队列->检测任务完成 的循环 @@ -252,7 +240,7 @@ def get_lyric_from_folder(self): target_path, q_err, q_info)).start() - bar.print_onto_bar("已分配: %s" % ncm_files[allocated]) + bar.print_onto_bar(Fore.CYAN + "已分配: " + Style.RESET_ALL + "%s" % ncm_files[allocated]) allocated += 1 current_process += 1 while True: # 错误队列检测 @@ -270,16 +258,17 @@ def get_lyric_from_folder(self): musics.append({"id": r['musicId'], "name": r["musicName"], "artists": r["artist"]}) passed += 1 current_process -= 1 - bar.print_onto_bar(f"\"{r['musicName']} - " + bar.print_onto_bar(Fore.YELLOW + + f"\"{r['musicName']} - " f"{''.join([x + ', ' for x in [x[0] for x in r['artist']]])[:-2]}" - "\" 已完成!") + "\"" + Fore.GREEN + " 已完成!") bar.next() except Empty: break if passed >= len(ncm_files): break if errors: - print("解密过程中发现了以下错误:") + print(Fore.LIGHTRED_EX+"解锁过程中发现了以下错误:") for i in errors: print(i) @@ -304,18 +293,20 @@ def get_lyric_from_folder(self): else: try: input("无效选择, 若取消请按 ^C ,继续请按回车") - clear() except KeyboardInterrupt: return - clear() - for i in range(0, len(musics)): # 根据索引结果获取歌词 - print("\n进度: %d/%d" % (i + 1, len(musics))) - if get_song_lyric(musics[i], lyric_path, allinfo=True) == "dl_err_connection": - input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") + cls_stay(self, "[自动获取 - 下载歌词]") + with CompactArrowBar(f"进度: %(index){len(str(len(musics)))}d/%(max)d", + suffix="", max=len(musics), color="yellow", width=9999) as bar: + for i in range(0, len(musics)): # 根据索引结果获取歌词 + if get_song_lyric(musics[i], lyric_path, allinfo=True, bar=bar) == "dl_err_connection": + bar.print_onto_bar(Fore.RED + "下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") + input() + bar.next() if ncm_files: if target_path != "NOT_DECRYPT": - agree = rinput("是否删除原ncm文件? (y/n)") + agree = rinput(Fore.RED + "是否删除原ncm文件? (y/n)") if agree == "y": for i in range(0, len(ncm_files)): print("删除进度: %d/%d\n -> %s\033[F" % (i + 1, len(ncm_files), ncm_files[i]), end="") diff --git a/modules/functions/mainly/multi_download.py b/modules/functions/mainly/multi_download.py new file mode 100644 index 0000000..27c36a2 --- /dev/null +++ b/modules/functions/mainly/multi_download.py @@ -0,0 +1,42 @@ +import re +from colorama import Fore + +from modules.utils.clear_screen import cls_stay +from modules.utils.inputs import rinput +from modules.functions.mainly.get_song import get_song_lyric +from modules.utils.bar import CompactArrowBar + + +def mdl(self): + """多个歌词文件的下载 + + ``path: str`` 传入歌词文件保存的路径""" + cls_stay(self, "[手动-多个下载]") + ids = [] + print("输入歌曲id,用回车分开,输入s停止") + while True: + r = rinput() + if r == 's': + break + else: + try: + int(r) + except ValueError: + tmp = re.search(r"song\?id=[0-9]*", r) + if tmp: + r = tmp.group()[8:] + else: + print("不合法的形式.\n") + continue + ids.append(int(r)) + print("\t#%d id:%s - 已添加!" % (len(ids), r)) + cls_stay(self, "[手动-多个下载]") + with CompactArrowBar(f"进度: %(index){len(str(len(ids)))}d/%(max)d", + suffix="", max=len(ids), color="yellow", width=9999) as bar: + for i in range(0, len(ids)): + r = get_song_lyric(ids[i], self.settings.lyric_path, bar=bar) + if r == "dl_err_connection": + bar.print_onto_bar(Fore.RED + "下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") + input() + bar.next() + input("按回车键返回...") diff --git a/modules/functions/one_download.py b/modules/functions/mainly/one_download.py similarity index 83% rename from modules/functions/one_download.py rename to modules/functions/mainly/one_download.py index 3122c86..d88e987 100644 --- a/modules/functions/one_download.py +++ b/modules/functions/mainly/one_download.py @@ -1,6 +1,6 @@ import re from modules.utils.inputs import rinput -from modules.functions.get_song import get_song_lyric +from modules.functions.mainly.get_song import get_song_lyric from modules.utils.clear_screen import clear @@ -23,6 +23,6 @@ def download_one_lyric(self): input("不合法的形式.\n按回车键返回...") return - if get_song_lyric(song_id, self.settings.lyric_path) == "dl_err_connection": + if get_song_lyric(int(song_id), self.settings.lyric_path) == "dl_err_connection": input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键返回...") input("按回车键返回...") diff --git a/modules/functions/multi_download.py b/modules/functions/multi_download.py deleted file mode 100644 index 5cb0a23..0000000 --- a/modules/functions/multi_download.py +++ /dev/null @@ -1,38 +0,0 @@ -import re -from modules.utils.clear_screen import clear -from modules.utils.inputs import rinput -from modules.functions.get_song import get_song_lyric - - -def mdl(self): - """多个歌词文件的下载 - - ``path: str`` 传入歌词文件保存的路径""" - clear() - ids = [] - print(f"[NeteaseMusicLyricDownloader] {self.version}\n" - "[手动-多个下载]\n" - "输入歌曲id,用回车分开,输入s停止") - while True: - r = rinput() - if r == 's': - break - else: - try: - int(r) - except ValueError: - tmp = re.search(r"song\?id=[0-9]*", r) - if tmp: - r = tmp.group()[8:] - else: - print("不合法的形式.\n") - continue - ids.append(r) - print("\t#%d id:%s - 已添加!" % (len(ids), r)) - clear() - for i in range(0, len(ids)): - print("进度: %d/%d" % (i+1, len(ids))) - r = get_song_lyric(ids[i], self.settings.lyric_path) - if r == "dl_err_connection": - input("下载发生错误!可能是连接被拒绝!请检查网络后再试\n按回车键继续任务(该任务会被跳过)...") - input("按回车键返回...") diff --git a/modules/functions/settings/__init__.py b/modules/functions/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/functions/save_load_settings.py b/modules/functions/settings/save_load_settings.py similarity index 94% rename from modules/functions/save_load_settings.py rename to modules/functions/settings/save_load_settings.py index 71ac4f6..b02c5dc 100644 --- a/modules/functions/save_load_settings.py +++ b/modules/functions/settings/save_load_settings.py @@ -5,8 +5,9 @@ import os class Settings(object): # 设定一个基础的存储设置信息的 class ,并设置形参用于 json 导入设置 - def __init__(self, l_p="./out/", lang="en"): + def __init__(self, l_p="./out/", l_f="", lang="en"): self.lyric_path = l_p + self.lyric_format = l_f self.language = lang @@ -24,7 +25,7 @@ def dict2class(adict): # 让 json.load 将读取到的 dict 转化为我们所 return Settings(adict["lyric_path"], adict["language"]) -def load_settings(): # 加载 的函数 +def load_settings() -> Settings: # 加载 的函数 """加载设置 调用即可,无需参数 返回: 设置 class""" diff --git a/modules/submenus/settings.py b/modules/submenus/settings.py index b1c0ba4..7b279ed 100644 --- a/modules/submenus/settings.py +++ b/modules/submenus/settings.py @@ -1,18 +1,16 @@ """集合设置参数""" import os -from modules.utils.clear_screen import clear +from modules.utils.clear_screen import cls_stay from modules.utils.inputs import rinput, cinput -from modules.functions.save_load_settings import save_settings +from modules.functions.settings.save_load_settings import save_settings def settings_menu(self): """设置菜单主循环""" while True: - clear() - print(f"[NeteaseMusicLyricDownloader] {self.version}\n" - "[设置菜单]\n" - "[0] 返回上级\n[1] 歌曲保存路径\n[2] 清空输出文件夹内的内容\n[3] 歌词文件保存格式\n[4] 部分动态效果\n" + cls_stay(self, "[设置菜单]") + print("[0] 返回上级\n[1] 歌曲保存路径\n[2] 清空输出文件夹内的内容\n[3] 歌词文件保存格式\n[4] 部分动态效果\n" "[s] 将设置保存到文件") r = rinput("请选择:") if r == "0": @@ -33,10 +31,8 @@ def settings_menu(self): def __remove_output_files(self): while True: - clear() - print(f"[NeteaseMusicLyricDownloader] {self.version}\n" - "[设置菜单 - 删除文件]\n" - "[0] 返回上级\n[1] 清除歌词文件\n[2] 清除歌曲文件\n[a] 清除所有文件") + cls_stay(self, "[设置菜单 - 删除文件]") + print("[0] 返回上级\n[1] 清除歌词文件\n[2] 清除歌曲文件\n[a] 清除所有文件") r = rinput("请选择:") # 选择清除的文件格式 if r == "0": return @@ -74,7 +70,7 @@ def __remove_output_files(self): def __set_lyric_path(self): - clear() + cls_stay(self, "[设置菜单 - 保存路径]") print("允许使用相对路径和绝对路径,默认为\"./out/\"\n请*不要*使用反斜杠来确保通用性\n" "当前值:%s\n请输入新的歌词保存路径:" % self.settings.lyric_path) r = cinput() @@ -93,6 +89,7 @@ def __set_lyric_path(self): if not os.path.exists(path): os.mkdir(path) self.settings.lyric_path = r + save_settings(self.settings) input("设置成功!\n按回车继续...") return @@ -100,6 +97,3 @@ def __set_lyric_path(self): def __set_lyric_format(self): pass - -def __save_settings(self): - return save_settings(self.settings) diff --git a/modules/utils/bar.py b/modules/utils/bar.py index d22d86c..82d9fa9 100644 --- a/modules/utils/bar.py +++ b/modules/utils/bar.py @@ -67,3 +67,57 @@ class CompactBar(Bar): line = ''.join([message, suffix])[:display_length]+"..." shorten = len_abs(line) self.writeln(line, shorten=shorten) + + +class CompactArrowBar(CompactBar): + def update(self): + """ + 覆写原有的update方法,自适应终端宽度 + 支持中文 + """ + filled_length = int(self.width * self.progress) + empty_length = self.width - filled_length + + message = self.message % self + s = "=" * filled_length + if s: + s = s[:-1] + ">" + bar = color(s, fg=self.color) + empty = self.empty_fill * empty_length + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, empty, self.bar_suffix, + suffix]) + # 以上为原本update代码 + term_size = get_terminal_size().columns + shorten = False + if len_abs(line) > term_size: # 检测完整长度是否小于终端长度 + if len_abs(line) - len_abs(''.join([bar, empty])) <= term_size: # 检测无进度条时是否小于终端长度 + width = term_size - (len_abs(line) - len_abs("".join([bar, empty]))) - 1 + filled_length = int(width * self.progress) + empty_length = width - filled_length + s = "=" * filled_length + if s: + s = s[:-1] + ">" + bar = color(s, fg=self.color) + empty = self.empty_fill * empty_length + line = ''.join([message, self.bar_prefix, bar, empty, self.bar_suffix, + suffix]) + shorten = len_abs(line) + elif len_abs(''.join([message, suffix])) <= term_size: # 检测仅有前缀后缀时是否小于终端长度 + line = ''.join([message, suffix]) + shorten = len_abs(line) + else: # 全部不符合时,以仅有前缀后缀的模式,直接截断 + display_length = term_size - get_more_length(''.join([message, suffix])[:term_size]) - 3 + if display_length < 0: + display_length = 0 + line = ''.join([message, suffix])[:display_length] + "..." + shorten = len_abs(line) + self.writeln(line, shorten=shorten) + + +def bprint(content, bar: CompactBar = None): + """添加对进度条的支持的print, 若传入bar参数, 则使用print_onto_bar参数来打印内容""" + if bar: + bar.print_onto_bar(content) + else: + print(content) diff --git a/modules/utils/clear_screen.py b/modules/utils/clear_screen.py index 7a9b7f5..62f290b 100644 --- a/modules/utils/clear_screen.py +++ b/modules/utils/clear_screen.py @@ -1,4 +1,4 @@ -"""包含一个函数,用来清空命令行的信息,自动判别系统""" +"""用来清空命令行的信息,自动判别系统""" import os @@ -9,4 +9,11 @@ def clear(): elif name == "posix": os.system("clear") else: - os.system("clear") \ No newline at end of file + os.system("clear") + + +def cls_stay(self, custom=""): + """保留版本号清除屏幕""" + clear() + print(f"[NeteaseMusicLyricDownloader] {self.version}") + print(custom) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 1a8d1c2..ac1a456 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ requests mutagen pycryptodomex -progress \ No newline at end of file +progress +colorama \ No newline at end of file