Skip to content

Commit c46880b

Browse files
author
noone
committed
feat(meta): 添加视频帧率信息解析支持
- 在MetaBase基类中新增fps属性用于存储帧率信息 - 实现MetaVideo中帧率信息的识别和解析逻辑 - 为MetaAnime添加帧率提取功能,与MetaVideo保持一致 - 更新测试用例以验证帧率信息的正确解析 - 在元数据测试数据中增加fps字段的预期值
1 parent 51dd7f5 commit c46880b

File tree

5 files changed

+200
-74
lines changed

5 files changed

+200
-74
lines changed

app/core/meta/metaanime.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class MetaAnime(MetaBase):
1717
"""
1818
_anime_no_words = ['CHS&CHT', 'MP4', 'GB MP4', 'WEB-DL']
1919
_name_nostring_re = r"S\d{2}\s*-\s*S\d{2}|S\d{2}|\s+S\d{1,2}|EP?\d{2,4}\s*-\s*EP?\d{2,4}|EP?\d{2,4}|\s+EP?\d{1,4}|\s+GB"
20+
_fps_re = r"(\d{2,3})(?=FPS)"
2021

2122
def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
2223
super().__init__(title, subtitle, isfile)
@@ -173,6 +174,8 @@ def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
173174
self.audio_encode = anitopy_info.get("audio_term")
174175
if isinstance(self.audio_encode, list):
175176
self.audio_encode = self.audio_encode[0]
177+
# 帧率信息
178+
self.__init_anime_fps(anitopy_info, original_title)
176179
# 解析副标题,只要季和集
177180
self.init_subtitle(self.org_string)
178181
if not self._subtitle_flag and self.subtitle:
@@ -182,6 +185,20 @@ def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
182185
except Exception as e:
183186
logger.error(f"解析动漫信息失败:{str(e)} - {traceback.format_exc()}")
184187

188+
def __init_anime_fps(self, anitopy_info: dict, original_title: str):
189+
"""
190+
从原始标题中提取帧率信息,与MetaVideo保持完全一致的实现
191+
"""
192+
re_res = re.search(rf"({self._fps_re})", original_title, re.IGNORECASE)
193+
if re_res:
194+
fps_value = None
195+
if re_res.group(1): # FPS格式
196+
fps_value = re_res.group(1)
197+
198+
if fps_value and fps_value.isdigit():
199+
# 只存储纯数值
200+
self.fps = int(fps_value)
201+
185202
@staticmethod
186203
def __prepare_title(title: str):
187204
"""

app/core/meta/metabase.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class MetaBase(object):
6666
# 附加信息
6767
tmdbid: int = None
6868
doubanid: str = None
69+
# 帧率信息(纯数值)
70+
fps: Optional[int] = None
71+
6972

7073
# 副标题解析
7174
_subtitle_flag = False
@@ -448,6 +451,13 @@ def audio_term(self) -> str:
448451
"""
449452
return self.audio_encode or ""
450453

454+
@property
455+
def frame_rate(self) -> str:
456+
"""
457+
返回帧率信息
458+
"""
459+
return self.fps or ""
460+
451461
def is_in_season(self, season: Union[list, int, str]) -> bool:
452462
"""
453463
是否包含季
@@ -581,6 +591,9 @@ def merge(self, meta: Self):
581591
# 音频编码
582592
if not self.audio_encode:
583593
self.audio_encode = meta.audio_encode
594+
# 帧率信息
595+
if not self.fps:
596+
self.fps = meta.fps
584597
# Part
585598
if not self.part:
586599
self.part = meta.part

app/core/meta/metavideo.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class MetaVideo(MetaBase):
5353
_resources_pix_re2 = r"(^[248]+K)"
5454
_video_encode_re = r"^(H26[45])$|^(x26[45])$|^AVC$|^HEVC$|^VC\d?$|^MPEG\d?$|^Xvid$|^DivX$|^AV1$|^HDR\d*$|^AVS(\+|[23])$"
5555
_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$"
56-
56+
_fps_re = r"(\d{2,3})(?=FPS)"
5757
def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
5858
"""
5959
初始化
@@ -129,6 +129,9 @@ def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
129129
# 音频编码
130130
if self._continue_flag:
131131
self.__init_audio_encode(token)
132+
# 帧率
133+
if self._continue_flag:
134+
self.__init_fps(token)
132135
# 取下一个,直到没有为卡
133136
token = tokens.get_next()
134137
self._continue_flag = True
@@ -716,3 +719,25 @@ def __init_audio_encode(self, token: str):
716719
else:
717720
self.audio_encode = "%s %s" % (self.audio_encode, token)
718721
self._last_token = token
722+
723+
def __init_fps(self, token: str):
724+
"""
725+
识别帧率
726+
"""
727+
if not self.name:
728+
return
729+
730+
re_res = re.search(rf"({self._fps_re})", token, re.IGNORECASE)
731+
if re_res:
732+
self._continue_flag = False
733+
self._stop_name_flag = True
734+
self._last_token_type = "fps"
735+
# 提取帧率数值
736+
fps_value = None
737+
if re_res.group(1): # FPS格式
738+
fps_value = re_res.group(1)
739+
740+
if fps_value and fps_value.isdigit():
741+
# 只存储纯数值
742+
self.fps = int(fps_value)
743+
self._last_token = f"{self.fps}FPS"

0 commit comments

Comments
 (0)