From dded74a4a9f794cec4bf312541cd336d467bc79e Mon Sep 17 00:00:00 2001 From: 1826013250 <1826013250@qq.com> Date: Sun, 30 Apr 2023 22:14:52 +0800 Subject: [PATCH] Optimize Progress Bar, again... Fix "Changing Destination Path" bug, provided by YXRain05 --- .gitignore | 1 + modules/functions/load_file_song.py | 16 ++++--- modules/submenus/settings.py | 4 ++ modules/utils/bar.py | 67 +++++++++++++++++++++++++---- modules/utils/length.py | 11 +++-- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index cbe31f2..42b8692 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ settings.json venv/ venv_win/ test/ +modules/test/ \ No newline at end of file diff --git a/modules/functions/load_file_song.py b/modules/functions/load_file_song.py index 0d36d83..ec40c21 100644 --- a/modules/functions/load_file_song.py +++ b/modules/functions/load_file_song.py @@ -212,7 +212,10 @@ def get_lyric_from_folder(self): while True: print(f"\n发现{len(ncm_files)}个ncm加密文件!") print("请问解密后的文件保存在哪里?\n" - "[1] 保存在相同文件夹内\n[2] 保存在程序设定的下载文件夹中\n[3] 保存在自定义文件夹内\n[q] 取消解密,下载歌词时将忽略这些文件") + "[1] 保存在相同文件夹内\n" + "[2] 保存在程序设定的下载文件夹中\n" + "[3] 保存在自定义文件夹内\n" + "[q] 取消解密,下载歌词时将忽略这些文件") select = rinput("请选择: ") if select == 'q': target_path = "NOT_DECRYPT" @@ -237,11 +240,11 @@ def get_lyric_from_folder(self): current_process = 0 # 当前正在活动的进程数 passed = 0 # 总共结束的进程数 with CompactBar(f"正在破解 %(index){len(str(len(ncm_files)))}d/%(max)d", - suffix="", max=len(ncm_files), color="blue") as bar: + suffix="", max=len(ncm_files), color="blue", width=9999) as bar: total = len(ncm_files) allocated = 0 # 已经分配的任务数量 while True: # 进入循环,执行 新建进程->检测队列->检测任务完成 的循环 - sleep(0) + sleep(0.05) if current_process <= max_process and allocated < total: # 分配进程 Process(target=process_work, args=(os.path.join(path, ncm_files[allocated]), @@ -249,9 +252,9 @@ def get_lyric_from_folder(self): target_path, q_err, q_info)).start() + bar.print_onto_bar("已分配: %s" % ncm_files[allocated]) allocated += 1 current_process += 1 - bar.update() while True: # 错误队列检测 try: errors.append(q_err.get_nowait()) @@ -267,8 +270,9 @@ 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']} - " - f"{''.join([x + ', ' for x in [x[0] for x in r['artist']]])[:-2]}") + bar.print_onto_bar(f"\"{r['musicName']} - " + f"{''.join([x + ', ' for x in [x[0] for x in r['artist']]])[:-2]}" + "\" 已完成!") bar.next() except Empty: break diff --git a/modules/submenus/settings.py b/modules/submenus/settings.py index 6d1edc0..b1c0ba4 100644 --- a/modules/submenus/settings.py +++ b/modules/submenus/settings.py @@ -84,6 +84,10 @@ def __set_lyric_path(self): if r[-1] != "/": r += "/" path = "" + for i in r.split("/"): + if len(i) >= 30: + input("抱歉, 目标或子目录名过长!至多30字符\n问题的目录: %s" % i) + return for i in r.split("/"): path += i+"/" if not os.path.exists(path): diff --git a/modules/utils/bar.py b/modules/utils/bar.py index 9debb33..d22d86c 100644 --- a/modules/utils/bar.py +++ b/modules/utils/bar.py @@ -2,17 +2,68 @@ from os import get_terminal_size from progress.bar import Bar +from progress.colors import color -from modules.utils.length import get_more_length +from modules.utils.length import get_more_length, len_abs class CompactBar(Bar): def print_onto_bar(self, message: str): - print() - self.update() - print(f"\x1b[1A\x1b[{get_terminal_size().columns}D{(get_terminal_size().columns-1) * ' '}" - f"\x1b[{get_terminal_size().columns}D"+message[:(get_terminal_size().columns - get_more_length(message))]) - self.update() + """在进度条的上方打印消息,进度条保持在下方""" + # 光标移动到行首,并通过打印空格清空残留的进度条 ↓ + print(f"\x1b[{get_terminal_size().columns}D{(get_terminal_size().columns - 1) * ' '}" + # 光标移动到该行的首部(\x1b[nD, n为前移个数),将需要的信息打印出来,再将光标移动到下一行 ↓ + f"\x1b[{get_terminal_size().columns}D" + message) + self.update() # 更新进度条 - def next_without_newline(self): - self.next() + def writeln(self, line, shorten=False): + """覆写writeln配合修改过后的update""" + if self.file and self.is_tty(): + width = len_abs(line) + if shorten: + self._max_width = shorten + elif width < self._max_width: + # Add padding to cover previous contents + line += ' ' * (self._max_width - width) + else: + self._max_width = width + print('\r' + line, end='', file=self.file) + self.file.flush() + + def update(self): + """ + 覆写原有的update方法,自适应终端宽度 + 支持中文 + """ + filled_length = int(self.width * self.progress) + empty_length = self.width - filled_length + + message = self.message % self + bar = color(self.fill * filled_length, 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 + bar = color(self.fill * filled_length, 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) diff --git a/modules/utils/length.py b/modules/utils/length.py index 97c9310..10917dc 100644 --- a/modules/utils/length.py +++ b/modules/utils/length.py @@ -1,12 +1,11 @@ """一些有关计算长度的工具""" -def len_abs(content): - """针对中文:将一个汉字识别为2个长度,而不是1个""" - - return len(content) + (len(content.encode("utf-8")) - len(content)) // 2 - - def get_more_length(content): """将相对于正常长度的超出值返回""" return (len(content.encode("utf-8")) - len(content)) // 2 + + +def len_abs(content): + """针对中文:将一个汉字识别为2个长度,而不是1个""" + return len(content) + get_more_length(content)