news 2026/10/20 12:38:14

媒体库文件整理:从正则解析到批量重命名的完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
媒体库文件整理:从正则解析到批量重命名的完整实战

dragonballsuper_093-2。这串字符扔到搜索引擎里,可能是一集动画的下载文件名,也可能是某个下载脚本留下的残缺记录。放到媒体服务器里,它就是一发很容易踩响的地雷:刮削器认不出剧名,播放器把 093 当成第93集,而后缀 -2 又让同一集内容被拆成两个条目。这篇文章不是来聊这部作品本身的,而是想聊清楚一件事:当你面对一大堆类似命名时,怎么从文件名解析开始,做批量重命名、字幕匹配和元数据整理,把“看着头疼”变成“扫一下就能用”。

适合谁看?家里存了几百集番剧、手动整理到崩溃的玩家,以及刚接触媒体库管理、想建立一套标准化流程的开发者。如果你之前只会把文件堆进文件夹,看完这篇文章,至少能写出一个帮你自动解析和改名的脚本。

1. 文件名里的三层信息:先把 dragonballsuper_093-2 拆明白

1.1 片名、集数、版本号,一个字段都不能少

如果把这个文件名当成一条数据,它实际包含三个信息块:dragonballsuper是作品标识,093是集数,-2是版本或分段标记。很多人觉得文件名只要“能认出来”就行,但媒体库的运作逻辑完全不是这样。它需要程序从文件名中提取出 title、season、episode 这些结构化字段,再去和在线数据库里的条目做匹配。你文件名里的信息越模糊,匹配就越容易错。

比如093这种三位补零写法,本身没毛病,但它没有声明这是第93集还是第9集的第三部分。-2更麻烦,它可能是 v2 修正版的意思,也可能是第二个分片的意思。同样一个字符串,在不同的下载场景里语义完全不同。所以第一步不是急着改名,而是先确认这三个字段的各自含义,再决定怎么整理。

1.2 分隔符的混乱才是真正的坑

dragonballsuper_093-2里面同时出现了下划线和连字符,这种混用非常常见。实际环境里你会看到更多变体:

常见混乱样例问题在哪
dragonballsuper_093-2.mkv下划线 + 连字符混用,版本号标识不明确
Dragon.Ball.Super.-.093.v2.mkv点号和连字符混用,集数补零加字母 v
[SubGroup] Dragon Ball Super 093 [720p].mkv多了发布组和画质信息,还会干扰解析
DBS_098_01.mkv把集数拆成两位加后缀,语义不明

如果你手动整理,看到这些也许还能猜个大概;但如果你想让脚本自动处理,就必须统一分隔符规则。媒体库最友好的格式是空格加连字符加空格,比如Dragon Ball Super - S01E93.mkv。原因很简单:在线影视数据库收录的标题通常就是带空格的自然写法,你的文件名越接近标准,刮削器匹配越准。

1.3 文件名不对,刮削全白费

我有一个很深的体会:文件名整理的工程量百分之八十都值在刮削这一步。你花力气把信息理顺,媒体服务器才可能在扫描时自动匹配到正确条目。如果文件名停留在dragonballsuper_093-2,媒体服务器的表现往往是:库里面多出一个叫 “dragonballsuper_093-2” 的独立条目,没有简介、没有海报、没有正确的集数顺序。你想手动修正,就得一集一集搜索匹配,几十集还能忍,几百集真的会崩溃。

反过来,如果文件名已经是Dragon Ball Super - S01E93.mkv,刮削器可以很轻松地在数据库里找到这部作品,自动补上海报、简介、演员表和片名。所以你花在解析和重命名上的时间,最终都会在刮削和日常播放里省回来。

2. 用正则从文件名里抽出标题、集数和版本号

2.1 为什么选择正则而不是手动改名

手动改名只有在文件数量个位数时才有效率。文件一多,人眼就会疲劳,很容易把 093 和 098 看串,把 v2 当成下一集。脚本处理则稳定得多,核心思路是把“命名规律”翻译成正则表达式。你不需要掌握正则的全部语法,只要会捕获分组和重复符号就能解决八成问题。

这里有个基本原则:不要试图写一个万能正则。文件来源不同、命名习惯不同,先观察十个典型样本,找出共同的模式段,再写针对性的表达式。比如dragonballsuper_093-2.mkv的共同模式是:开头是作品名,中间是数字集数,后面可能带版本号。那就照这个结构写。

2.2 解析脚本的逐步实现

我用一段简单的脚本演示核心逻辑:

import re from pathlib import Path filename = "dragonballsuper_093-2.mkv" # 非贪婪匹配作品名,然后匹配数字集数,再匹配可选的版本号 pattern = re.compile( r"^(?P<show>.+?)[ _.-]+(?P<episode>\d{1,3})(?:[ _.-]*(?P<version>v?\d*))?" r"\.(?P<ext>mkv|mp4|avi|mov)$", re.IGNORECASE ) m = pattern.match(filename) if m: show = m.group("show") # dragonballsuper episode = int(m.group("episode")) # 93 version = m.group("version") # "2" 或 None ext = m.group("ext") print(show, episode, version, ext)

这里的.+?是非贪婪匹配,它会尽量少地匹配字符,保证后面的数字能正常落到 episode 分组里。[ _.-]+用来吞掉下划线、空格、点号、连字符等常见分隔符,避免dragonballsuper_093-2和Dragon Ball Super - 093被当成完全不同的格式。最后一个非捕获组(?:...)?表示版本号可有可无。

2.3 边界情况与容错设计

上面的正则放到真实文件里,很快会遇到更多情况。比如文件叫dbs_s02e13.mkv,它有明确的季号和集号,上面的表达式就会把 show 匹配成dbs_s02e13吗?不会,因为.+?非贪婪,但后面要求匹配1-3位数字,看到dbs_s02e13时,正则会在dbs后面尝试匹配 e13,却没有对应分隔符,所以会继续扩展。结果可能是 show 匹配成dbs_s02e13,episode 匹配不到,最后 match 失败。因此对带季号的文件,应该单独写一个s(?P<season>\d+)e(?P<episode>\d+)分支。

还要处理歧义:093到底是第93集还是第9集第3部分?我认为不要猜,而是拿时长和文件大小做二次判断。如果是 24 分钟正片,多半是第93集;如果只有 3 分钟,多半是特典或者分片。脚本里把这些文件打上needs_review标记,输出到一个待确认清单,而不是自作主张改名。

3. 规范化重命名:让每一集都有唯一且标准的名字

3.1 推荐的目标命名格式与取舍

整理的最后一步就是执行重命名。我推荐的目标格式是:

剧名 - SxxEyy.mkv

例如:

Dragon Ball Super - S01E93.mkv

这不是唯一标准,但它是媒体库软件公认友好的一种。SxxEyy用两位数字表示季和集,排序不会乱;剧名用自然语言写法,刮削器容易匹配。如果你的片源是多季动画,务必先查清分季信息,不要把所有集数都塞进 S01。

有人会觉得保留093这种三位的也能排序,但三位数字在跨季时会出问题:E093如果被理解为第93集,而实际第9季第3集应该是S09E03,信息就错了。所以规范化的重点不是补零位数,而是把“季”和“集”拆开表达。

3.2 集号补零与版本后缀的规则

对于dragonballsuper_093-2这种文件,如果确认它就是第93集的 v2 修正版,我会把它改成Dragon Ball Super - S01E93 (v2).mkv。括号里的版本标识是给人类看的,媒体库依然会把它识别成第93集。如果确认-2是同一集拆出来的第二部分,情况就不同了:直接命名成Dragon Ball Super - S01E93.part2.mkv不一定被媒体库支持,最干净的做法是把两个分片无损拼接成一个文件,再统一命名成第93集。

拼接视频看起来是个额外动作,但它能彻底避免“一集内容在库里出现两次”的尴尬。如果你暂时不想动手拼接,也可以用子目录把两个分片放在一起,命名成Dragon Ball Super - S01E93 (part1).mkv和S01E93 (part2).mkv碰碰运气,但别对兼容性抱太高的期望。

注意:-2的语义必须在改名之前确认,否则很容易把版本号当集数,或者把分片当新的一集,最后媒体库的剧集列表直接错乱。

3.3 批量执行重命名的正确姿势

重命名脚本要遵循一个原则:先预览,后执行。我习惯先跑 dry-run,把所有旧名 -> 新名打印出来,扫一眼有没有明显错误,没问题再真正执行。脚本里用Path.rename就行,代码不复杂:

from pathlib import Path def normalize_file(path: Path) -> Path: # 这里省略解析过程,假设已经拿到 show / episode / version / ext show = "Dragon Ball Super" episode = 93 version = "v2" season = 1 new_name = f"{show} - S{season:02d}E{episode:02d}" if version: new_name += f" ({version})" new_name += f".{ext}" return path.with_name(new_name) for old_path in Path("downloads").glob("*.mkv"): new_path = normalize_file(old_path) print(f"{old_path.name} -> {new_path.name}") # 确认无误后去掉下面这行注释 # old_path.rename(new_path)

批量执行时要特别注意扩展名保留,代码里用with_name再拼接字符串,不会误删后缀。改完名字后,立即回到媒体库手动触发一次扫描,验证集数顺序和刮削结果,别等到下次播放才发现错乱。

4. 字幕与元数据匹配:文件改名之后还要做两件事

4.1 字幕文件名要和视频文件严格同步

改名之后,字幕文件的匹配经常被忽略。播放器加载外挂字幕时,默认逻辑是找和视频同名的字幕文件。你的字幕如果叫dragonballsuper_093-2.zh-CN.ass而视频已经改成Dragon Ball Super - S01E93.mkv,播放器就找不到字幕了。

规范做法是把字幕文件名改成和视频完全相同的 stem,再保留语言标识。比如:

Dragon Ball Super - S01E93.mkv Dragon Ball Super - S01E93.zh-CN.ass Dragon Ball Super - S01E93.en.srt

批量处理时,可以遍历视频文件,提取原来的集数信息,再去字幕目录里找包含相同集数字符串的文件,然后重命名。这一步最好和视频重命名放在同一个脚本里跑,避免流程脱节。

4.2 元数据刮削与人工修正

视频和字幕都规范后,就可以让媒体服务器去刮削元数据了。正常情况会识别出作品名、集数、海报和简介,但dragonballsuper这种没有空格的英文标题经常还是匹配不到。原因是数据库里的标准标题是Dragon Ball Super,中间有空格。遇到这种情况,就不要指望全自动了,在媒体库后台手动锁定正确的匹配条目,或者先通过脚本把文件名里的 show 统一改成标准标题。

如果你有几十个文件都是同一个作品,改一次 show 字段就够了,媒体库通常会把它们聚合到一个剧集条目下。集数顺序如果和在线数据库不一致,比如存在特别篇、总集篇,可以用元数据编辑器单独调整每集标题和序号。这一环节最花时间,但能保证你以后打开媒体库不会看到一片混乱。

4.3 批量生成元数据文件的思路

有些媒体库支持 NFO 文件,就是在视频旁边放一个 XML 文件,里面写着标题、简介、海报链接等信息。好处是刮削完全离线可读,坏处是写文件容易出错。如果决定用 NFO,可以写脚本遍历视频文件,把从文件名里解析出的 show、episode 填进模板,再调用在线数据库 API 补充标题。

注意不要对在线数据库发起高频请求,加个 sleep 和失败重试。没有 API 权限的话,就手动填基础字段。NFO 是锦上添花,不是必须项,先保证基础刮削能用,再考虑要不要生成。

5. 整理过程中容易翻车的几个隐藏细节

5.1 版本号 "-2" 到底是第2版还是分片?算错就串集

这个坑我踩过不止一次。文件名叫dragonballsuper_093-2,你说它是第93集第二版,可是它的时长只有 12 分钟,怎么可能是一集正片?反过来,如果它是正片但和另一部分合起来才是完整一集,你把它当成独立集放进去,媒体库就会多出一个不存在的第94集。所以要建立一个“待确认”目录,脚本解析出版本号后先不要直接改名,把这类文件单独输出来,人工看一眼时长再做决定。

如果你有多个来源的同一文件,可以通过比对文件大小和校验值确认是不是同一个内容。数值对不上就说明要么是不同版本,要么是不同分段。这个确认动作虽然笨,但能避免最尴尬的串集问题。

5.2 媒体库目录和下载目录分开,用硬链接而不是复制

很多人为了让媒体库文件整齐,会把文件复制到新目录,下载目录留原始文件。如果这些文件体积很大,复制意味着同一份数据占两份空间。正确的做法是在同一文件系统内使用硬链接:下载目录和媒体库目录都指向同一个文件数据块,删掉一个目录里的文件名不会影响另一个目录。这样既能让下载目录保持做种用的原始文件名,又能让媒体库用规范化的文件名。

硬链接有三个注意事项:第一,不能跨文件系统使用,下载目录和媒体库目录必须在同一分区或同一卷;第二,修改文件内容会同时影响两个链接,所以不要在媒体库目录里转码;第三,个别网盘同步工具不支持硬链接,同步时会把文件当作普通文件重新上传,要提前确认。

5.3 建立自检脚本,定期扫描命名合规性

整理一次只是开始,新下载的文件随时会破坏规矩。我最终的建议是写一个自检脚本,定期扫描媒体库目录,用正则校验每个文件名是否符合^[A-Za-z0-9 .\-]+ - S\d{2}E\d{2}这样的规范,不符合的列出报告。同时检查每个视频有没有匹配的字幕文件,缺少的也列出来。

这个脚本不需要多复杂,但能救你于火灾之中。你不需要每天跑,一周跑一次,或者在新文件入库后手动触发一次。到了这一步,你才算把文件整理从“体力活”升级成了“流程管理”。

我自己现在的习惯是:新下载的文件先进临时目录,跑一遍解析脚本,确认 show 和 episode 都识别正确,再让媒体库扫描。整套流程跑了大半年,媒体库再没出现过一集被拆成两半的情况。如果你也被类似文件名折磨过,建议从今天开始,先定一套自己的命名规范,然后写一个最简单的解析脚本,越早做越省心。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 12:37:35

集团型企业级AI智能体落地实践:从试点到规模化的关键路径

这两年只要聊企业级AI&#xff0c;Agent这个关键词几乎绕不开。尤其是集团型企业的数字化负责人&#xff0c;问的问题通常很直接&#xff1a;我们旗下十几家子公司、几十套业务系统&#xff0c;Agent到底能干什么&#xff0c;值不值得上&#xff1f;我跟过几个从试点到推广的项…

作者头像 李华
网站建设 2026/10/20 12:36:37

OpenCV模板匹配实战:原理、多目标与亚像素定位

平时做视觉项目&#xff0c;最常被问起的一个需求就是“给定一张图&#xff0c;帮我找出某个零件/字符/Logo在哪儿”。很多刚接触视觉的朋友第一反应是上深度学习&#xff0c;但实际项目中&#xff0c;很多工况根本用不着那么重的方案。基于 OpenCV 的模板匹配技术就是一个被低…

作者头像 李华
网站建设 2026/10/20 12:35:39

AI培训学什么?三大方向从入门到高阶技术栈全解析

1. AI培训到底在学什么&#xff1a;先把地图画清楚很多人第一次接触AI培训&#xff0c;脑子里冒出来的第一个问题就是&#xff1a;这玩意儿到底学什么&#xff1f;是学Python&#xff1f;是学调参&#xff1f;还是学怎么用现成的工具&#xff1f;这个问题之所以让人困惑&#x…

作者头像 李华
网站建设 2026/10/20 12:35:38

可复用企业级应用REA架构设计与微前端实践

前阵子在某个企业后端平台项目里&#xff0c;接了个代号叫“REA”的系统重构任务。一开始大家看到这个名字都挺懵&#xff0c;以为是哪个框架的新版本&#xff0c;后来开需求会才明白&#xff0c;REA 是 Reusable Enterprise Application 的缩写&#xff0c;简单说就是“可复用…

作者头像 李华
网站建设 2026/10/20 12:33:55

手写Tool Use三种方案:从面试题到生产级工具调用实现

1. 面试现场&#xff1a;为什么“手写 Tool Use”成了高频考题1.1 从一道面试题说起前阵子有个朋友去面一家做 AI 应用的公司&#xff0c;回来跟我吐槽&#xff1a;面试官没问八股&#xff0c;也没让手撕红黑树&#xff0c;直接甩了一句——“给你半小时&#xff0c;手写一个 T…

作者头像 李华
网站建设 2026/10/20 12:33:27

顺序栈:理解内存契约与算法边界的起点

1. 为什么从顺序栈开始学数据结构——它不是“过时的教具”&#xff0c;而是理解内存与算法边界的起点很多人看到“顺序栈”三个字&#xff0c;第一反应是&#xff1a;这不就是教材里那个用数组实现、早被链表和STL容器淘汰的玩具模型吗&#xff1f;我带过几届某高校的数据结构…

作者头像 李华