优化了剧集编号提取和文件排序的逻辑,修复了一些 BUG

Merge pull request #2 from x1ao4/dev
This commit is contained in:
x1ao4 2025-04-23 17:32:06 +08:00 committed by GitHub
commit 0743fe2576
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 609 additions and 234 deletions

View File

@ -509,7 +509,10 @@ def get_share_detail():
return None
# 构建剧集命名的正则表达式 (主要用于检测已命名文件)
if "[]" in episode_pattern:
if episode_pattern == "[]":
# 对于单独的[],使用特殊匹配
regex_pattern = "^(\\d+)$" # 匹配纯数字文件名
elif "[]" in episode_pattern:
regex_pattern = re.escape(episode_pattern).replace('\\[\\]', '(\\d+)')
else:
# 如果输入模式不包含[],则使用简单匹配模式,避免正则表达式错误
@ -563,7 +566,11 @@ def get_share_detail():
episode_num = extract_episode_number(file["file_name"])
if episode_num is not None:
# 生成预览文件名
file["file_name_re"] = episode_pattern.replace("[]", f"{episode_num:02d}") + file_ext
if episode_pattern == "[]":
# 对于单独的[],直接使用数字序号作为文件名
file["file_name_re"] = f"{episode_num:02d}{file_ext}"
else:
file["file_name_re"] = episode_pattern.replace("[]", f"{episode_num:02d}") + file_ext
else:
# 无法提取剧集号,标记为无法处理
file["file_name_re"] = "❌ 无法识别剧集号"

View File

@ -176,7 +176,7 @@
<div class="col-10">
<h2 style="display: inline-block;"><i class="bi bi-list-ol"></i> 剧集识别</h2>
<span class="badge badge-pill badge-light">
<a href="#" target="_blank" @click.prevent="alert('剧集识别说明:\n在任务配置中填写包含E[]的匹配表达式,如「剧名 - S01E[]」,将自动切换至剧集命名模式,自动识别文件名中的编号作为集编号,并替换[]部分。\n\n集编号匹配规则\n用于识别集编号的正则表达式多个表达式之间用竖线「|」分隔,每个表达式必须包含一个捕获组,用于提取剧集编号')">?</a>
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/正则处理教程#25-剧集命名" target="_blank">?</a>
</span>
</div>
</div>
@ -185,7 +185,7 @@
<div class="input-group-prepend">
<span class="input-group-text">集编号识别规则</span>
</div>
<input type="text" class="form-control" v-model="episodePatternsText" placeholder="多个正则表达式用竖线「|」分隔,如:(\\d+)|[Ee](\\d+)|第(\\d+)集">
<input type="text" class="form-control" v-model="episodePatternsText" placeholder="输入用于识别集编号的正则表达式,多个表达式用竖线「|」分隔,如:第(\d+)集|[Ee][Pp]?(\d+)|(\d+)[-_\\s]*4[Kk]">
</div>
</div>
@ -677,19 +677,17 @@
// 如果没有剧集识别模式,添加默认模式
if (!this.formData.episode_patterns || this.formData.episode_patterns.length === 0) {
this.formData.episode_patterns = [
{ name: 'EP_BASIC', description: '[]', regex: '(\\d+)' },
{ name: 'EP_4K', description: '[]-4K', regex: '(\\d+)[-_\\s]*4[Kk]' },
{ name: 'EP_HUA', description: '[]话', regex: '(\\d+)话' },
{ name: 'EP_E', description: 'E[]', regex: '[Ee](\\d+)' },
{ name: 'EP_EP', description: 'EP[]', regex: '[Ee][Pp](\\d+)' },
{ name: 'EP_DIHUA', description: '第[]话', regex: '第(\\d+)话' },
{ name: 'EP_DIJI', description: '第[]集', regex: '第(\\d+)集' },
{ name: 'EP_DIQI', description: '第[]期', regex: '第(\\d+)期' },
{ name: 'EP_4KSPACE', description: '[] 4K', regex: '(\\d+)\\s+4[Kk]' },
{ name: 'EP_4KUNDER', description: '[]_4K', regex: '(\\d+)[_\\s]4[Kk]' },
{ name: 'EP_BRACKET', description: '【[]】', regex: '【(\\d+)】' },
{ name: 'EP_DIHUA', description: '第[]话', regex: '第(\\d+)话' },
{ name: 'EP_JI', description: '[]集', regex: '(\\d+)集' },
{ name: 'EP_QI', description: '[]期', regex: '(\\d+)期' },
{ name: 'EP_HUA', description: '[]话', regex: '(\\d+)话' },
{ name: 'EP_E_EP', description: 'E/EP[]', regex: '[Ee][Pp]?(\\d+)' },
{ name: 'EP_4K', description: '[]-4K', regex: '(\\d+)[-_\\s]*4[Kk]' },
{ name: 'EP_SQUAREBRACKET', description: '方括号数字', regex: '\\[(\\d+)\\]' },
{ name: 'EP_UNDERSCORE', description: '_[]_', regex: '_?(\\d+)_' }
{ name: 'EP_BRACKET', description: '【[]】', regex: '【(\\d+)】' },
{ name: 'EP_UNDERSCORE', description: '_[]_', regex: '_?(\\d+)_?' }
];
}
}, 500);
@ -793,8 +791,10 @@
task.sequence_naming = task.pattern;
}
// 如果是剧集命名模式确保episode_naming字段已正确设置
if (task.use_episode_naming && task.pattern && task.pattern.includes('[]')) {
task.episode_naming = task.pattern;
if (task.use_episode_naming && task.pattern) {
if (task.pattern === "[]" || task.pattern.includes('[]')) {
task.episode_naming = task.pattern;
}
}
});
}
@ -840,7 +840,7 @@
if (newTask.taskname) {
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, newTask.taskname);
} else {
newTask.savepath = lastTask.taskname ? lastTask.savepath.replace(lastTask.taskname, 'TASKNAME') : lastTask.savepath;
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, 'TASKNAME') || lastTask.savepath;
}
}
}
@ -1220,8 +1220,8 @@
},
detectNamingMode(task) {
// 检测是否为顺序命名模式或剧集命名模式
const sequencePatterns = ['{}', 'E{}', 'EP{}', 'S\\d+E{}', '第{}集', '第{}话', '第{}期'];
const episodePatterns = ['[]', 'E[]', 'EP[]', 'S\\d+E[]', '第[]集', '第[]话', '第[]期'];
const sequencePatterns = ['{}集', '第{}期', '第{}话', '{}集', '{}期', '{}话', 'E{}', 'EP{}', 'S\\d+E{}', '[{}]', '【{}】', '_{}_'];
const episodePatterns = ['第{% raw %}[]{% endraw %}集', '第{% raw %}[]{% endraw %}期', '第{% raw %}[]{% endraw %}话', '{% raw %}[]{% endraw %}集', '{% raw %}[]{% endraw %}期', '{% raw %}[]{% endraw %}话', 'E{% raw %}[]{% endraw %}', 'EP{% raw %}[]{% endraw %}', 'S\\d+E{% raw %}[]{% endraw %}', '[{% raw %}[]{% endraw %}', '【{% raw %}[]{% endraw %}】', '_{% raw %}[]{% endraw %}_'];
let isSequenceNaming = false;
let isEpisodeNaming = false;
@ -1229,29 +1229,13 @@
// 保存当前值以支持撤销操作
const currentValue = task.pattern;
if (task.pattern) {
// 检查是否包含任何顺序命名模式
isSequenceNaming = sequencePatterns.some(pattern => {
const regexPattern = pattern.replace('{}', '\\{\\}');
return new RegExp(regexPattern).test(task.pattern);
});
if (task.pattern !== undefined) {
// 检查是否包含完整的{}占位符(确保不是分开的{和}
isSequenceNaming = task.pattern.includes('{}') && (!task.replace || task.replace === '');
// 或者用户直接输入包含{}的格式,且替换表达式为空
if (!isSequenceNaming && task.pattern.includes('{}') && (!task.replace || task.replace === '')) {
isSequenceNaming = true;
}
// 检查是否包含任何剧集命名模式
// 如果不是顺序命名模式,检查是否包含完整的[]占位符或就是单独的[]
if (!isSequenceNaming) {
isEpisodeNaming = episodePatterns.some(pattern => {
const regexPattern = pattern.replace('[]', '\\[\\]');
return new RegExp(regexPattern).test(task.pattern);
});
// 或者用户直接输入包含[]的格式,且替换表达式为空
if (!isEpisodeNaming && task.pattern.includes('[]') && (!task.replace || task.replace === '')) {
isEpisodeNaming = true;
}
isEpisodeNaming = (task.pattern === '[]' || task.pattern.includes('[]')) && (!task.replace || task.replace === '');
}
}

File diff suppressed because it is too large Load Diff