MoviePilot元数据清洗工具:修复混乱的影视信息库
【免费下载链接】MoviePilot NAS媒体库自动化管理工具 项目地址: https://gitcode.com/gh_mirrors/mo/MoviePilot
引言:NAS媒体库的元数据痛点
你是否曾经遇到过这样的情况:辛苦下载的电影文件命名混乱,导致媒体服务器(如Plex、Emby、Jellyfin)无法正确识别?或者电视剧集数识别错误,导致播放顺序混乱?这些问题的根源在于元数据(Metadata) 的不规范。元数据是描述媒体文件的关键信息,包括标题、年份、季集、分辨率等。混乱的元数据不仅影响观看体验,还会导致媒体库管理困难。
MoviePilot作为一款NAS媒体库自动化管理工具,提供了强大的元数据清洗功能。本文将深入解析MoviePilot的元数据清洗工具,帮助你理解其工作原理、核心功能以及如何解决实际问题。
读完本文,你将能够:
- 理解元数据清洗的重要性及常见问题
- 掌握MoviePilot元数据清洗工具的核心功能
- 学会使用正则表达式和自定义规则处理复杂命名
- 解决电影、电视剧、动漫等不同类型媒体的元数据识别问题
- 通过实际案例优化你的媒体库元数据质量
元数据清洗的核心挑战
在深入技术细节之前,我们首先需要了解元数据清洗面临的主要挑战:
1. 命名格式混乱
影视文件的命名格式千差万别,常见问题包括:
- 多余信息:如广告、下载站点、字幕组等
- 缩写不统一:如"Season"缩写为"S"或"季"
- 年份表示混乱:如"2023-2024"或"23-24"
- 分辨率和编码信息混杂:如"1080p.H265.DDP5.1"
2. 多语言和特殊字符
- 中英文混合命名
- 特殊符号(如
[](){}+-)的滥用 - 拼音和汉字混用
3. 媒体类型多样性
不同类型的媒体(电影、电视剧、动漫、纪录片)有不同的命名习惯和元数据需求。
4. 错误数据传播
一旦元数据识别错误,如果不及时纠正,可能会导致整个媒体库的分类和组织出现问题。
MoviePilot元数据清洗工具架构
MoviePilot的元数据清洗功能主要由app/core/meta/目录下的几个核心模块组成:
核心类功能解析
- MetaBase: 媒体信息基类,定义了媒体文件的基本属性和通用方法。
- MetaVideo: 继承自MetaBase,专注于电影和电视剧的元数据解析。
- MetaAnime: 继承自MetaBase,针对动漫内容的特殊元数据解析。
- ReleaseGroupsMatcher: 识别发布组/字幕组信息。
- CustomizationMatcher: 处理自定义占位符。
- StreamingPlatforms: 识别流媒体平台信息。
元数据清洗流程详解
MoviePilot的元数据清洗流程可以分为以下几个关键步骤:
1. 预处理阶段
在解析元数据之前,MoviePilot会对原始文件名进行一系列预处理:
# 去掉名称中第1个[]的内容
title = re.sub(r'%s' % self._name_no_begin_re, "", title, count=1)
# 把xxxx-xxxx年份换成前一个年份
title = re.sub(r'([\s.]+)(\d{4})-(\d{4})', r'\1\2', title)
# 把大小去掉
title = re.sub(r'[0-9.]+\s*[MGT]i?B(?![A-Z]+)', "", title, flags=re.IGNORECASE)
# 把年月日去掉
title = re.sub(r'\d{4}[\s._-]\d{1,2}[\s._-]\d{1,2}', "", title)
2. Token拆分
预处理后的标题会被拆分成多个token,便于后续解析:
tokens = Tokens(title)
token = tokens.get_next()
while token:
# 处理每个token
token = tokens.get_next()
3. 核心信息识别
名称识别
名称识别是元数据解析的核心,MoviePilot能智能区分中文名称和英文名称:
if StringUtils.is_chinese(token):
# 含有中文,直接做为标题
self._last_token_type = "cnname"
if not self.cn_name:
self.cn_name = token
elif not self._stop_cnname_flag:
if re.search("%s" % self._name_movie_words, token, flags=re.IGNORECASE) \
or (not re.search("%s" % self._name_no_chinese_re, token, flags=re.IGNORECASE)
and not re.search("%s" % self._name_se_words, token, flags=re.IGNORECASE)):
self.cn_name = "%s %s" % (self.cn_name, token)
self._stop_cnname_flag = True
else:
# 英文或者英文+数字,拼装起来
if self.en_name:
self.en_name = "%s %s" % (self.en_name, token)
else:
self.en_name = token
self._last_token_type = "enname"
年份识别
年份识别主要通过匹配4位数字(1900-2050之间):
if token.isdigit() and len(token) == 4 and 1900 < int(token) < 2050:
if self.year:
if self.en_name:
self.en_name = "%s %s" % (self.en_name.strip(), self.year)
elif self.cn_name:
self.cn_name = "%s %s" % (self.cn_name, self.year)
self.year = token
self._last_token_type = "year"
self._continue_flag = False
self._stop_name_flag = True
分辨率识别
分辨率识别支持多种格式,如"1080p"、"2160p"、"4K"等:
re_res = re.findall(r"%s" % self._resources_pix_re, token, re.IGNORECASE)
if re_res:
self._last_token_type = "pix"
self._continue_flag = False
self._stop_name_flag = True
resource_pix = None
for pixs in re_res:
# 提取分辨率信息
if resource_pix and not self.resource_pix:
self.resource_pix = resource_pix.lower()
break
if self.resource_pix and self.resource_pix.isdigit() and self.resource_pix[-1] not in 'kpi':
self.resource_pix = "%sp" % self.resource_pix
季集识别
季集识别是电视剧元数据解析的关键,支持多种格式:
# 季识别示例
re_res = re.findall(r"%s" % self._season_re, token, re.IGNORECASE)
if re_res:
self._last_token_type = "season"
self.type = MediaType.TV
self._stop_name_flag = True
self._continue_flag = True
for se in re_res:
# 提取季信息
if self.begin_season is None:
self.begin_season = se
self.total_season = 1
else:
if se > self.begin_season:
self.end_season = se
self.total_season = (self.end_season - self.begin_season) + 1
# 集识别示例
re_res = re.findall(r"%s" % self._episode_re, token, re.IGNORECASE)
if re_res:
self._last_token_type = "episode"
self._continue_flag = False
self._stop_name_flag = True
self.type = MediaType.TV
for se in re_res:
# 提取集信息
if self.begin_episode is None:
self.begin_episode = se
self.total_episode = 1
else:
if se > self.begin_episode:
self.end_episode = se
self.total_episode = (self.end_episode - self.begin_episode) + 1
资源类型和编码识别
资源类型识别包括媒体来源(如BluRay、WEB-DL)和特效(如HDR、3D):
source_res = re.search(r"(%s)" % self._source_re, token, re.IGNORECASE)
if source_res:
self._last_token_type = "source"
self._continue_flag = False
self._stop_name_flag = True
if not self._source:
self._source = source_res.group(1)
self._last_token = self._source.upper()
return
effect_res = re.search(r"(%s)" % self._effect_re, token, re.IGNORECASE)
if effect_res:
self._last_token_type = "effect"
self._continue_flag = False
self._stop_name_flag = True
effect = effect_res.group(1)
if effect not in self._effect:
self._effect.append(effect)
self._last_token = effect.upper()
视频和音频编码识别:
# 视频编码识别
re_res = re.search(r"(%s)" % self._video_encode_re, token, re.IGNORECASE)
if re_res:
# 提取视频编码信息
if not self.video_encode:
self.video_encode = re_res.group(1).upper()
# 音频编码识别
re_res = re.search(r"(%s)" % self._audio_encode_re, token, re.IGNORECASE)
if re_res:
# 提取音频编码信息
if not self.audio_encode:
self.audio_encode = re_res.group(1)
4. 元数据合并与输出
解析完成后,MoviePilot会合并所有识别到的信息,并提供标准化的元数据输出:
def merge(self, meta: Self):
# 类型
if self.type == MediaType.UNKNOWN and meta.type != MediaType.UNKNOWN:
self.type = meta.type
# 名称
if not self.name:
self.cn_name = meta.cn_name
self.en_name = meta.en_name
# 年份
if not self.year:
self.year = meta.year
# 季
if (self.type == MediaType.TV and self.begin_season is None):
self.begin_season = meta.begin_season
self.end_season = meta.end_season
self.total_season = meta.total_season
# 其他属性...
def to_dict(self):
"""转为字典"""
dicts = vars(self).copy()
dicts["type"] = self.type.value if self.type else None
dicts["season_episode"] = self.season_episode
dicts["edition"] = self.edition
dicts["name"] = self.name
dicts["episode_list"] = self.episode_list
return dicts
实战案例:解决复杂命名问题
案例1:混乱的电影文件名
原始文件名:
[华语]【2023】流浪地球2.HD1080P.国语中字.BD中英双字.mkv
清洗过程:
- 预处理:去除
[华语]【2023】和.mkv后缀 - 名称识别:识别出中文名称"流浪地球2"
- 年份识别:从预处理后的字符串中提取"2023"
- 分辨率识别:识别出"1080P"
- 资源类型识别:识别出"BD"
清洗结果:
{
"cn_name": "流浪地球2",
"year": "2023",
"resource_pix": "1080p",
"resource_type": "BD",
"type": "MOVIE"
}
案例2:复杂的电视剧命名
原始文件名:
The.Greatest.Showman.2017.1080p.BluRay.x264.DTS-HD.MA.5.1-FGT.mkv
清洗过程:
- 预处理:去除文件后缀
- 名称识别:识别出英文名称"The Greatest Showman"
- 年份识别:提取"2017"
- 分辨率识别:识别出"1080p"
- 资源类型识别:识别出"BluRay"
- 视频编码识别:识别出"H264"
- 音频编码识别:识别出"DTS-HD MA 5.1"
- 发布组识别:识别出"FGT"
清洗结果:
{
"en_name": "The Greatest Showman",
"year": "2017",
"resource_pix": "1080p",
"resource_type": "BluRay",
"video_encode": "x264",
"audio_encode": "DTS-HD MA 5.1",
"resource_team": "FGT",
"type": "MOVIE"
}
案例3:多集电视剧识别
原始文件名:
权力的游戏.Game.of.Thrones.S01E01-E05.1080p.BluRay.x264.双语字幕.mkv
清洗过程:
- 预处理:去除多余信息
- 名称识别:同时识别中文名称"权力的游戏"和英文名称"Game of Thrones"
- 季集识别:识别出第1季第1-5集
- 分辨率识别:识别出"1080p"
- 资源类型识别:识别出"BluRay"
- 视频编码识别:识别出"H264"
清洗结果:
{
"cn_name": "权力的游戏",
"en_name": "Game of Thrones",
"begin_season": 1,
"end_season": 1,
"begin_episode": 1,
"end_episode": 5,
"resource_pix": "1080p",
"resource_type": "BluRay",
"video_encode": "x264",
"type": "TV"
}
案例4:动漫特殊处理
原始文件名:
[KTXP][进击的巨人 最终季][Attack on Titan Final Season][S04][1080p][HEVC-10bit AAC][CHS].mp4
清洗过程:
- 预处理:去除
[KTXP]和[CHS]等标签 - 名称识别:识别中文名称"进击的巨人 最终季"和英文名称"Attack on Titan Final Season"
- 季识别:识别出第4季
- 分辨率识别:识别出"1080p"
- 视频编码识别:识别出"HEVC-10bit"
- 音频编码识别:识别出"AAC"
- 发布组识别:识别出"KTXP"
清洗结果:
{
"cn_name": "进击的巨人 最终季",
"en_name": "Attack on Titan Final Season",
"begin_season": 4,
"end_season": 4,
"resource_pix": "1080p",
"video_encode": "HEVC-10bit",
"audio_encode": "AAC",
"resource_team": "KTXP",
"type": "TV"
}
高级应用:自定义元数据规则
MoviePilot允许用户通过自定义规则来处理特殊的命名格式。这主要通过CustomizationMatcher类实现:
class CustomizationMatcher:
def __init__(self):
# 初始化自定义规则
pass
def match(self, title=None):
# 应用自定义规则匹配元数据
pass
用户可以通过配置文件定义自己的匹配规则,例如处理特定站点的特殊命名格式。
性能优化与批量处理
对于大型媒体库,元数据清洗的性能至关重要。MoviePilot通过以下方式优化性能:
- 缓存机制:对流媒体平台等信息进行缓存,避免重复处理
- 增量更新:只处理新增或修改的文件
- 多线程处理:批量处理时利用多线程提高效率
总结与展望
MoviePilot的元数据清洗工具通过强大的正则表达式匹配和智能识别算法,能够解决绝大多数媒体文件的元数据混乱问题。其核心优势在于:
- 多语言支持:同时识别中文和英文名称
- 灵活的识别规则:支持多种命名格式
- 丰富的元数据提取:不仅提取基本信息,还包括分辨率、编码等详细属性
- 可扩展性:通过自定义规则处理特殊情况
未来,MoviePilot的元数据清洗功能可以进一步增强:
- AI辅助识别:引入机器学习模型提高复杂命名的识别准确率
- 用户贡献规则:建立社区驱动的规则库,共同优化识别能力
- 跨平台同步:与各大媒体服务器深度集成,实现元数据的自动同步和更新
通过掌握MoviePilot的元数据清洗工具,你可以轻松解决NAS媒体库的元数据混乱问题,打造一个规范、整洁、易于管理的个人媒体中心。
附录:常见问题与解决方案
Q1: 某些特殊命名的文件无法正确识别怎么办?
A1: 可以通过自定义规则(CustomizationMatcher)来处理特殊情况,或提交issue反馈给开发团队。
Q2: 如何手动修改已识别的元数据?
A2: MoviePilot提供了Web界面,允许用户手动编辑和修正元数据信息。
Q3: 元数据清洗会修改原始文件吗?
A3: 不会,元数据清洗只处理元数据信息,不会修改原始文件。
Q4: 支持哪些媒体服务器的元数据同步?
A4: 目前支持Plex、Emby、Jellyfin等主流媒体服务器的元数据同步。
Q5: 如何批量处理已有的媒体库?
A5: MoviePilot提供了"媒体库扫描"功能,可以批量处理已有文件的元数据。
【免费下载链接】MoviePilot NAS媒体库自动化管理工具 项目地址: https://gitcode.com/gh_mirrors/mo/MoviePilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



