mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-24 07:26:50 +00:00
feat: add video bit rename template field
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
识别音频编码
|
||||
|
||||
@@ -204,6 +204,8 @@ class TemplateContextBuilder:
|
||||
"releaseGroup": meta.resource_team,
|
||||
# 视频编码
|
||||
"videoCodec": meta.video_encode,
|
||||
# 视频位深
|
||||
"videoBit": meta.video_bit,
|
||||
# 音频编码
|
||||
"audioCodec": meta.audio_encode,
|
||||
# 流媒体平台
|
||||
|
||||
@@ -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] 优先级。
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user