2025-12-22 00:42:27 +08:00
|
|
|
import parseTorrentName from 'parse-torrent-name';
|
|
|
|
|
|
|
|
|
|
export interface ParsedVideoInfo {
|
|
|
|
|
episode?: number;
|
|
|
|
|
season?: number;
|
|
|
|
|
title?: string;
|
2026-01-03 16:40:39 +08:00
|
|
|
isOVA?: boolean;
|
2025-12-22 00:42:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析视频文件名
|
|
|
|
|
*/
|
|
|
|
|
export function parseVideoFileName(fileName: string): ParsedVideoInfo {
|
|
|
|
|
try {
|
|
|
|
|
const parsed = parseTorrentName(fileName);
|
|
|
|
|
|
|
|
|
|
// 如果 parse-torrent-name 成功解析出集数,直接返回
|
|
|
|
|
if (parsed.episode) {
|
|
|
|
|
return {
|
|
|
|
|
episode: parsed.episode,
|
|
|
|
|
season: parsed.season,
|
|
|
|
|
title: parsed.title,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('parse-torrent-name 解析失败:', fileName, error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 降级方案:使用多种正则模式提取集数
|
|
|
|
|
// 按优先级排序:更具体的模式优先
|
2026-01-03 16:40:39 +08:00
|
|
|
const patterns: Array<{ pattern: RegExp; isOVA?: boolean }> = [
|
|
|
|
|
// OVA01, OVA 01, ova01, ova 01 (OVA特殊处理) - 最优先
|
|
|
|
|
{ pattern: /OVA\s*(\d+(?:\.\d+)?)/i, isOVA: true },
|
2025-12-22 00:42:27 +08:00
|
|
|
// S01E01, s01e01, S01E01.5 (支持小数) - 最具体
|
2026-01-03 16:40:39 +08:00
|
|
|
{ pattern: /[Ss]\d+[Ee](\d+(?:\.\d+)?)/ },
|
|
|
|
|
// [01], (01), [01.5], (01.5) (支持小数,但要排除中文括号内容) - 很具体
|
|
|
|
|
{ pattern: /[\[\(](\d+(?:\.\d+)?)[\]\)]/ },
|
2025-12-22 00:42:27 +08:00
|
|
|
// E01, E1, e01, e1, E01.5 (支持小数)
|
2026-01-03 16:40:39 +08:00
|
|
|
{ pattern: /[Ee](\d+(?:\.\d+)?)/ },
|
2025-12-22 00:42:27 +08:00
|
|
|
// 第01集, 第1集, 第01话, 第1话, 第1.5集 (支持小数)
|
2026-01-03 16:40:39 +08:00
|
|
|
{ pattern: /第(\d+(?:\.\d+)?)[集话]/ },
|
2025-12-22 00:42:27 +08:00
|
|
|
// _01_, -01-, _01.5_, -01.5- (支持小数)
|
2026-01-03 16:40:39 +08:00
|
|
|
{ pattern: /[_\-](\d+(?:\.\d+)?)[_\-]/ },
|
2025-12-22 00:42:27 +08:00
|
|
|
// 01.mp4, 001.mp4, 01.5.mp4 (纯数字开头,支持小数) - 最不具体
|
2026-01-03 16:40:39 +08:00
|
|
|
{ pattern: /^(\d+(?:\.\d+)?)[^\d.]/ },
|
2025-12-22 00:42:27 +08:00
|
|
|
];
|
|
|
|
|
|
2026-01-03 16:40:39 +08:00
|
|
|
for (const { pattern, isOVA } of patterns) {
|
2025-12-22 00:42:27 +08:00
|
|
|
const match = fileName.match(pattern);
|
|
|
|
|
if (match && match[1]) {
|
|
|
|
|
const episode = parseFloat(match[1]);
|
|
|
|
|
if (episode > 0 && episode < 10000) { // 合理的集数范围
|
2026-01-03 16:40:39 +08:00
|
|
|
return { episode, isOVA };
|
2025-12-22 00:42:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果所有模式都失败,返回空对象(调用方会处理)
|
|
|
|
|
return {};
|
|
|
|
|
}
|