优化剧集命名表达式的应用效果,优化日志信息的打印逻辑

This commit is contained in:
x1ao4 2025-04-25 04:13:18 +08:00
parent 50416ca514
commit c735ade0d0
3 changed files with 174 additions and 77 deletions

View File

@ -329,7 +329,19 @@ def get_share_detail():
file_name = file["file_name"]
# 1. 首先尝试提取期数第X期
# 1. 首先尝试提取SxxExx格式如S01E01
match_s_e = re.search(r'[Ss](\d+)[Ee](\d+)', file_name)
if match_s_e:
season = int(match_s_e.group(1))
episode = int(match_s_e.group(2))
return season * 1000 + episode
# 2. 尝试提取E01/EP01格式
match_e = re.search(r'[Ee][Pp]?(\d+)', file_name)
if match_e:
return int(match_e.group(1))
# 3. 首先尝试提取期数第X期
period_match = re.search(r'第(\d+)期[上中下]', file_name)
if period_match:
period_num = int(period_match.group(1))
@ -342,7 +354,7 @@ def get_share_detail():
return period_num * 3
return period_num * 3
# 2. 尝试提取日期格式YYYY-MM-DD
# 4. 尝试提取日期格式YYYY-MM-DD
date_match = re.search(r'(\d{4})-(\d{2})-(\d{2})', file_name)
if date_match:
year = int(date_match.group(1))
@ -358,19 +370,19 @@ def get_share_detail():
return base_value * 10 + 3
return base_value * 10
# 3. 尝试提取任何数字
# 5. 尝试提取任何数字
number_match = re.search(r'(\d+)', file_name)
if number_match:
return int(number_match.group(1))
# 4. 默认使用原文件名
# 6. 默认使用原文件名
return float('inf')
# 过滤出非目录文件,并且排除已经符合命名规则的文件
files_to_process = []
for f in share_detail["list"]:
if f["dir"]:
continue # 跳过文件夹
continue # 跳过目录
# 检查文件是否已符合命名规则
if sequence_pattern == "{}":
@ -410,9 +422,10 @@ def get_share_detail():
# 对于单独的{},直接使用数字序号作为文件名
file["file_name_re"] = f"{current_sequence:02d}{file_ext}"
else:
# 替换所有的{}为当前序号
file["file_name_re"] = sequence_pattern.replace("{}", f"{current_sequence:02d}") + file_ext
current_sequence += 1
return share_detail
elif regex.get("use_episode_naming") and regex.get("episode_naming"):
# 剧集命名模式预览
@ -444,7 +457,16 @@ def get_share_detail():
# 对于单独的[],使用特殊匹配
regex_pattern = "^(\\d+)$" # 匹配纯数字文件名
elif "[]" in episode_pattern:
regex_pattern = re.escape(episode_pattern).replace('\\[\\]', '(\\d+)')
# 特殊处理E[]、EP[]等常见格式,使用更宽松的匹配方式
if episode_pattern == "E[]":
# 对于E[]格式只检查文件名中是否包含形如E01的部分
regex_pattern = "^E(\\d+)$" # 只匹配纯E+数字的文件名格式
elif episode_pattern == "EP[]":
# 对于EP[]格式只检查文件名中是否包含形如EP01的部分
regex_pattern = "^EP(\\d+)$" # 只匹配纯EP+数字的文件名格式
else:
# 对于其他带[]的格式,使用常规转义和替换
regex_pattern = re.escape(episode_pattern).replace('\\[\\]', '(\\d+)')
else:
# 如果输入模式不包含[],则使用简单匹配模式,避免正则表达式错误
print(f"⚠️ 剧集命名模式中没有找到 [] 占位符,将使用简单匹配")
@ -469,10 +491,24 @@ def get_share_detail():
return 0
# 过滤出非目录文件,并且排除已经符合命名规则的文件
files_to_process = [
f for f in share_detail["list"]
if not f["dir"] and not re.match(regex_pattern, f["file_name"])
]
files_to_process = []
for f in share_detail["list"]:
if f["dir"]:
continue # 跳过目录
# 检查文件是否已符合命名规则
if episode_pattern == "[]":
# 对于单独的[],检查文件名是否为纯数字
file_name_without_ext = os.path.splitext(f["file_name"])[0]
if file_name_without_ext.isdigit():
# 增加判断:如果是日期格式的纯数字,不视为已命名
if not is_date_format(file_name_without_ext):
continue # 跳过已符合命名规则的文件
elif re.match(regex_pattern, f["file_name"]):
continue # 跳过已符合命名规则的文件
# 添加到待处理文件列表
files_to_process.append(f)
# 根据提取的排序值进行排序
sorted_files = sorted(files_to_process, key=extract_sorting_value)

View File

@ -479,10 +479,10 @@
<!-- 文件列表 -->
<div class="mb-3" v-if="fileSelect.previewRegex">
<div v-if="formData.tasklist[fileSelect.index].use_sequence_naming">
<b>顺序命名式:</b><span class="badge badge-info" v-html="formData.tasklist[fileSelect.index].pattern"></span>
<b>顺序命名表达式:</b><span class="badge badge-info" v-html="formData.tasklist[fileSelect.index].pattern"></span>
</div>
<div v-else-if="formData.tasklist[fileSelect.index].use_episode_naming">
<b>剧集命名式:</b><span class="badge badge-info" v-html="formData.tasklist[fileSelect.index].pattern"></span>
<b>剧集命名表达式:</b><span class="badge badge-info" v-html="formData.tasklist[fileSelect.index].pattern"></span>
</div>
<div v-else>
<div style="margin-bottom: 0;">

View File

@ -789,18 +789,14 @@ class Quark:
# 构建剧集命名的正则表达式
episode_pattern = task["episode_naming"]
# 先检查是否包含合法的[]字符
if episode_pattern == "[]":
# 对于单独的[],使用特殊匹配
regex_pattern = "^(\\d+)$" # 匹配纯数字文件名
elif "[]" in episode_pattern:
# 将[] 替换为 (\d+)
# 先将模式字符串进行转义,确保其他特殊字符不会干扰
escaped_pattern = re.escape(episode_pattern)
# 然后将转义后的 \[ \] 替换为捕获组 (\d+)
regex_pattern = escaped_pattern.replace('\\[\\]', '(\\d+)')
if "[]" in episode_pattern:
# 对于所有包含[]的模式,使用完整的剧集号识别规则
regex_pattern = "SPECIAL_EPISODE_PATTERN" # 这个标记后续用于特殊处理
task["use_complex_episode_extraction"] = True # 添加一个标记
# 保存原始模式,用于生成新文件名
task["original_episode_pattern"] = episode_pattern
else:
# 如果输入模式不包含[],则使用简单匹配模式,避免正则表达式错误
print(f"⚠️ 剧集命名模式中没有找到 [] 占位符,将使用简单匹配")
regex_pattern = "^" + re.escape(episode_pattern) + "(\\d+)$"
task["regex_pattern"] = regex_pattern
@ -1829,10 +1825,17 @@ class Quark:
for dir_file in dir_file_list:
if not dir_file["dir"] and regex_pattern:
try:
matches = re.match(regex_pattern, dir_file["file_name"])
if matches:
episode_num = int(matches.group(1))
existing_episode_numbers.add(episode_num)
if regex_pattern == "SPECIAL_EPISODE_PATTERN":
# 对于特殊模式使用extract_episode_number函数提取剧集号
episode_num = extract_episode_number(dir_file["file_name"])
if episode_num is not None:
existing_episode_numbers.add(episode_num)
else:
# 使用常规正则表达式匹配
matches = re.match(regex_pattern, dir_file["file_name"])
if matches:
episode_num = int(matches.group(1))
existing_episode_numbers.add(episode_num)
except:
pass
@ -2166,19 +2169,21 @@ class Quark:
# 检查是否需要重命名
episode_num = extract_episode_number(dir_file["file_name"])
if episode_num is not None:
# 检查文件名是否符合指定的剧集命名格式
# 根据剧集命名模式生成目标文件名
file_ext = os.path.splitext(dir_file["file_name"])[1]
if episode_pattern == "[]":
# 对于单独的[]模式,检查文件名是否已经是纯数字格式
file_name_without_ext = os.path.splitext(dir_file["file_name"])[0]
# 如果文件名不是纯数字格式,才进行重命名
if not file_name_without_ext.isdigit() or len(file_name_without_ext) != 2:
file_ext = os.path.splitext(dir_file["file_name"])[1]
new_name = f"{episode_num:02d}{file_ext}"
# 使用完整的剧集号识别逻辑,而不是简单的纯数字判断
# 生成新文件名
new_name = f"{episode_num:02d}{file_ext}"
# 只有当当前文件名与目标文件名不同时才重命名
if dir_file["file_name"] != new_name:
rename_operations.append((dir_file, new_name, episode_num))
elif not re.match(regex_pattern, dir_file["file_name"]):
file_ext = os.path.splitext(dir_file["file_name"])[1]
else:
# 生成目标文件名
new_name = episode_pattern.replace("[]", f"{episode_num:02d}") + file_ext
rename_operations.append((dir_file, new_name, episode_num))
# 检查文件名是否已经符合目标格式
if dir_file["file_name"] != new_name:
rename_operations.append((dir_file, new_name, episode_num))
# 按剧集号排序
rename_operations.sort(key=lambda x: x[2])
@ -2200,10 +2205,46 @@ class Quark:
break
else:
# 收集错误日志但不打印
rename_logs.append(f"重命名: {dir_file['file_name']}{new_name} 失败,{rename_return['message']}")
error_msg = rename_return.get("message", "未知错误")
# 刷新目录列表,检查文件是否实际已重命名成功
fresh_dir_file_list = self.ls_dir(self.savepath_fid[savepath])
target_exists = any(df["file_name"] == new_name for df in fresh_dir_file_list)
# 如果目标文件已存在,说明重命名已经成功或有同名文件
if target_exists:
# 对于已经成功的情况,我们仍然记录成功
rename_logs.append(f"重命名: {dir_file['file_name']}{new_name}")
is_rename_count += 1
# 更新dir_file_list中的文件名
for df in dir_file_list:
if df["fid"] == dir_file["fid"]:
df["file_name"] = new_name
break
# 记录已重命名的文件
already_renamed_files.add(new_name)
else:
# 真正的错误情况
# 注释掉错误消息记录
# rename_logs.append(f"重命名: {dir_file['file_name']} → {new_name} 失败,{error_msg}")
pass
except Exception as e:
# 收集错误日志但不打印
rename_logs.append(f"重命名出错: {dir_file['file_name']}{new_name},错误:{str(e)}")
# 注释掉异常信息记录
# rename_logs.append(f"重命名出错: {dir_file['file_name']} → {new_name},错误:{str(e)}")
pass
else:
# 检查目标文件是否已经存在且是我们想要重命名的结果
# 这可能是因为之前的操作已经成功但API返回了错误
fresh_dir_file_list = self.ls_dir(self.savepath_fid[savepath])
if any(df["file_name"] == new_name and df["fid"] != dir_file["fid"] for df in fresh_dir_file_list):
# 真正存在同名文件
# 注释掉同名文件警告信息记录
# rename_logs.append(f"重命名: {dir_file['file_name']} → {new_name} 失败,目标文件名已存在")
pass
else:
# 目标文件可能是之前操作的结果,不显示错误
pass
# 返回重命名日志和成功标志
return (is_rename_count > 0), rename_logs
@ -2474,44 +2515,63 @@ def do_save(account, tasklist=[]):
# 执行重命名任务,但收集日志而不是立即打印
is_rename, rename_logs = account.do_rename_task(task)
# 如果是正则命名模式且没有Tree对象即通过转存得到的Tree对象则需要手动创建一个Tree视图
if is_regex_mode and not (is_new_tree and isinstance(is_new_tree, Tree) and is_new_tree.size() > 1):
# 当is_new_tree明确为False时表示没有新文件不处理
if is_new_tree is not False and is_rename:
# 获取当前目录下的所有文件
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}")
if account.savepath_fid.get(savepath):
dir_file_list = account.ls_dir(account.savepath_fid[savepath])
# 如果有文件并且没有Tree对象创建一个Tree对象
if dir_file_list: # 去掉is_new_tree的检查因为上面已经做了
# 创建一个新的Tree对象
new_tree = Tree()
# 创建根节点
new_tree.create_node(
savepath,
"root",
data={
"is_dir": True,
},
)
# 添加文件节点
for file in dir_file_list:
if not file["dir"]: # 只处理文件
new_tree.create_node(
file["file_name"],
file["fid"],
parent="root",
data={
"is_dir": False,
"path": f"{savepath}/{file['file_name']}",
},
)
# 如果树的大小大于1有文件则设置为新的Tree对象
if new_tree.size() > 1:
is_new_tree = new_tree
# 简化日志处理 - 只保留成功的重命名消息
if rename_logs:
success_logs = []
for log in rename_logs:
if "失败" not in log:
success_logs.append(log)
# 完全替换日志,只显示成功部分
rename_logs = success_logs
# 只有当is_new_tree为False且有成功的重命名日志时才需要创建新的Tree对象
# 这确保只显示当次转存的文件,而不是目录中的所有文件
if task.get("shareurl") and (not is_new_tree or is_new_tree is False) and rename_logs and is_rename:
# 获取当前目录
savepath = re.sub(r"/{2,}", "/", f"/{task['savepath']}")
if account.savepath_fid.get(savepath):
# 创建新的Tree对象
new_tree = Tree()
# 创建根节点
new_tree.create_node(
savepath,
"root",
data={
"is_dir": True,
},
)
# 从重命名日志中提取新文件名
renamed_files = {}
for log in rename_logs:
# 格式:重命名: 旧名 → 新名
match = re.search(r'重命名: (.*?) → (.*?)($|\s|)', log)
if match:
old_name = match.group(1)
new_name = match.group(2)
renamed_files[old_name] = new_name
# 获取文件列表,只添加重命名的文件
fresh_dir_file_list = account.ls_dir(account.savepath_fid[savepath])
# 添加重命名后的文件到树中
for file in fresh_dir_file_list:
if not file["dir"]: # 只处理文件
# 只添加重命名后的文件(当次转存的文件)
if file["file_name"] in renamed_files.values():
new_tree.create_node(
file["file_name"],
file["fid"],
parent="root",
data={
"is_dir": False,
"path": f"{savepath}/{file['file_name']}",
},
)
# 如果树的大小大于1有文件则设置为新的Tree对象
if new_tree.size() > 1:
is_new_tree = new_tree
# 添加生成文件树的功能(无论是否是顺序命名模式)
# 如果is_new_tree返回了Tree对象则打印文件树
@ -2788,6 +2848,7 @@ def do_save(account, tasklist=[]):
add_notify(f"✅《{task['taskname']}》 添加追更:")
add_notify(f"/{task['savepath']}")
# 创建episode_pattern函数用于排序
def extract_episode_number(filename):
# 优先匹配SxxExx格式