feat: add video bit rename template field

This commit is contained in:
jxxghp
2026-05-20 18:20:18 +08:00
parent 7cc037c683
commit 8a375e022c
6 changed files with 100 additions and 0 deletions

View File

@@ -170,6 +170,8 @@ class MetaAnime(MetaBase):
self.video_encode = anitopy_info.get("video_term")
if isinstance(self.video_encode, list):
self.video_encode = self.video_encode[0]
# 视频位深
self.video_bit = self.extract_video_bit(original_title) or self.extract_video_bit(self.video_encode)
# 音频编码
self.audio_encode = anitopy_info.get("audio_term")
if isinstance(self.audio_encode, list):

View File

@@ -61,6 +61,8 @@ class MetaBase(object):
web_source: Optional[str] = None
# 视频编码
video_encode: Optional[str] = None
# 视频位深
video_bit: Optional[str] = None
# 音频编码
audio_encode: Optional[str] = None
# 应用的识别词信息
@@ -460,6 +462,22 @@ class MetaBase(object):
"""
return self.fps or None
@staticmethod
def extract_video_bit(value: Optional[str]) -> Optional[str]:
"""
从标题或编码文本中提取视频位深标签。
"""
if not value:
return None
bit_match = re.search(
r"(?<![A-Za-z0-9])(?P<bit>8|10|12|16)[\s._-]*bits?(?![A-Za-z0-9])",
value,
re.IGNORECASE,
)
if not bit_match:
return None
return f"{bit_match.group('bit')}bit"
def is_in_season(self, season: Union[list, int, str]) -> bool:
"""
是否包含季
@@ -593,6 +611,9 @@ class MetaBase(object):
# 视频编码
if not self.video_encode:
self.video_encode = meta.video_encode
# 视频位深
if not self.video_bit:
self.video_bit = meta.video_bit
# 音频编码
if not self.audio_encode:
self.audio_encode = meta.audio_encode

View File

@@ -54,6 +54,7 @@ class MetaVideo(MetaBase):
_video_encode_re = r"^(H26[45])$|^(x26[45])$|^AVC$|^HEVC$|^VC\d?$|^MPEG\d?$|^Xvid$|^DivX$|^AV1$|^HDR\d*$|^AVS(\+|[23])$"
_audio_encode_re = r"^DTS\d?$|^DTSHD$|^DTSHDMA$|^Atmos$|^TrueHD\d?$|^AC3$|^\dAudios?$|^DDP\d?$|^DD\+\d?$|^DD\d?$|^LPCM\d?$|^AAC\d?$|^FLAC\d?$|^HD\d?$|^MA\d?$|^HR\d?$|^Opus\d?$|^Vorbis\d?$|^AV[3S]A$"
_fps_re = r"(\d{2,3})(?=FPS)"
def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
"""
初始化
@@ -136,6 +137,9 @@ class MetaVideo(MetaBase):
# 视频编码
if self._continue_flag:
self.__init_video_encode(token)
# 视频位深
if self._continue_flag:
self.__init_video_bit(token)
# 音频编码
if self._continue_flag:
self.__init_audio_encode(token)
@@ -178,6 +182,8 @@ class MetaVideo(MetaBase):
self.resource_team = ReleaseGroupsMatcher().match(title=original_title) or None
# 自定义占位符
self.customization = CustomizationMatcher().match(title=original_title) or None
if not self.video_bit:
self.video_bit = self.extract_video_bit(self.video_encode)
@staticmethod
def __get_title_from_description(description: str) -> Optional[str]:
@@ -693,6 +699,27 @@ class MetaVideo(MetaBase):
else:
self.video_encode = f"{self.video_encode} 10bit"
def __init_video_bit(self, token: str):
"""
识别视频位深。
"""
if not self.name:
return
if not self.year \
and not self.resource_pix \
and not self.resource_type \
and not self.begin_season \
and not self.begin_episode:
return
video_bit = self.extract_video_bit(token)
if not video_bit:
return
self._continue_flag = False
self._stop_name_flag = True
self._last_token_type = "videobit"
if not self.video_bit:
self.video_bit = video_bit
def __init_audio_encode(self, token: str):
"""
识别音频编码

View File

@@ -204,6 +204,8 @@ class TemplateContextBuilder:
"releaseGroup": meta.resource_team,
# 视频编码
"videoCodec": meta.video_encode,
# 视频位深
"videoBit": meta.video_bit,
# 音频编码
"audioCodec": meta.audio_encode,
# 流媒体平台

View File

@@ -132,6 +132,21 @@ class MetaInfoTest(TestCase):
self.assertEqual(meta.episode, "E04")
self.assertEqual(meta.apply_words, custom_words)
def test_video_bit_extracted_for_video_title(self):
"""测试普通影视标题中的视频位深可单独识别"""
meta = MetaInfo(title="The 355 2022 BluRay 1080p DTS-HD MA5.1 X265.10bit-BeiTai")
self.assertEqual(meta.video_encode, "x265 10bit")
self.assertEqual(meta.video_bit, "10bit")
def test_video_bit_extracted_for_anime_title(self):
"""测试动漫标题中的视频位深可单独识别"""
meta = MetaInfo(
title="[云歌字幕组][7月新番][欢迎来到实力至上主义的教室 第二季][01]"
"[X264 10bit][1080p][简体中文].mp4"
)
self.assertEqual(meta.video_encode, "X264")
self.assertEqual(meta.video_bit, "10bit")
def test_emby_tmdbid_overrides_braced_metainfo_tmdbid(self):
"""
同时存在内嵌元信息和 Emby [tmdbid] 标签时,保持历史上的 [tmdbid] 优先级。

View File

@@ -67,6 +67,39 @@ class TemplateContextBuilderConcurrencyTest(unittest.TestCase):
# 第二次调用不应反向污染第一次的结果
self.assertEqual(first.get("marker"), 1)
def test_build_exposes_video_bit_from_meta(self):
"""
模板上下文应提供独立 videoBit 字段,避免用户只能从 videoCodec 中手工拆位深。
"""
meta = type("FakeMeta", (), {})()
meta.begin_episode = None
meta.title = "Movie.2024.1080p.x265.10bit.mkv"
meta.name = "Movie"
meta.en_name = "Movie"
meta.year = "2024"
meta.season_seq = ""
meta.season = ""
meta.episode_seqs = ""
meta.episode = ""
meta.part = None
meta.customization = None
meta.fps = None
meta.resource_type = None
meta.resource_effect = None
meta.edition = ""
meta.resource_pix = "1080p"
meta.resource_term = "1080p"
meta.resource_team = None
meta.video_encode = "x265 10bit"
meta.video_bit = "10bit"
meta.audio_encode = "AAC"
meta.web_source = None
context = TemplateContextBuilder().build(meta=meta)
self.assertEqual(context.get("videoCodec"), "x265 10bit")
self.assertEqual(context.get("videoBit"), "10bit")
if __name__ == "__main__":
unittest.main()