mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-12 16:02:35 +08:00
feat: add Rust acceleration for core parsing
This commit is contained in:
@@ -11,6 +11,7 @@ from app.schemas.types import MediaType
|
||||
from app.utils.string import StringUtils
|
||||
from app.utils.tokens import Tokens
|
||||
from app.core.meta.streamingplatform import StreamingPlatforms
|
||||
from app.utils import rust_accel
|
||||
|
||||
|
||||
class MetaVideo(MetaBase):
|
||||
@@ -102,59 +103,61 @@ class MetaVideo(MetaBase):
|
||||
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)
|
||||
# 拆分tokens
|
||||
tokens = Tokens(title)
|
||||
# 实例化StreamingPlatforms对象
|
||||
streaming_platforms = StreamingPlatforms()
|
||||
media_exts = settings.RMT_MEDIAEXT + settings.RMT_SUBEXT + settings.RMT_AUDIOEXT
|
||||
# 解析名称、年份、季、集、资源类型、分辨率等
|
||||
token = tokens.get_next()
|
||||
while token:
|
||||
self._index += 1 # 更新当前处理的token索引
|
||||
# Part
|
||||
self.__init_part(token, tokens)
|
||||
# 标题
|
||||
if self._continue_flag:
|
||||
self.__init_name(token, media_exts)
|
||||
# 年份
|
||||
if self._continue_flag:
|
||||
self.__init_year(token)
|
||||
# 分辨率
|
||||
if self._continue_flag:
|
||||
self.__init_resource_pix(token)
|
||||
# 季
|
||||
if self._continue_flag:
|
||||
self.__init_season(token)
|
||||
# 集
|
||||
if self._continue_flag:
|
||||
self.__init_episode(token)
|
||||
# 资源类型
|
||||
if self._continue_flag:
|
||||
self.__init_resource_type(token)
|
||||
# 流媒体平台
|
||||
if self._continue_flag:
|
||||
self.__init_web_source(token, tokens, streaming_platforms)
|
||||
# 视频编码
|
||||
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)
|
||||
# 帧率
|
||||
if self._continue_flag:
|
||||
self.__init_fps(token)
|
||||
# 取下一个,直到没有为卡
|
||||
rust_parse = rust_accel.parse_video_title(title, isfile=isfile, media_exts=media_exts)
|
||||
if not self.__apply_rust_parse(rust_parse):
|
||||
# 拆分tokens
|
||||
tokens = Tokens(title)
|
||||
# 实例化StreamingPlatforms对象
|
||||
streaming_platforms = StreamingPlatforms()
|
||||
# 解析名称、年份、季、集、资源类型、分辨率等
|
||||
token = tokens.get_next()
|
||||
self._continue_flag = True
|
||||
# 合成质量
|
||||
if self._effect:
|
||||
self._effect.reverse()
|
||||
self.resource_effect = " ".join(self._effect)
|
||||
if self._source:
|
||||
self.resource_type = self._source.strip()
|
||||
while token:
|
||||
self._index += 1 # 更新当前处理的token索引
|
||||
# Part
|
||||
self.__init_part(token, tokens)
|
||||
# 标题
|
||||
if self._continue_flag:
|
||||
self.__init_name(token, media_exts)
|
||||
# 年份
|
||||
if self._continue_flag:
|
||||
self.__init_year(token)
|
||||
# 分辨率
|
||||
if self._continue_flag:
|
||||
self.__init_resource_pix(token)
|
||||
# 季
|
||||
if self._continue_flag:
|
||||
self.__init_season(token)
|
||||
# 集
|
||||
if self._continue_flag:
|
||||
self.__init_episode(token)
|
||||
# 资源类型
|
||||
if self._continue_flag:
|
||||
self.__init_resource_type(token)
|
||||
# 流媒体平台
|
||||
if self._continue_flag:
|
||||
self.__init_web_source(token, tokens, streaming_platforms)
|
||||
# 视频编码
|
||||
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)
|
||||
# 帧率
|
||||
if self._continue_flag:
|
||||
self.__init_fps(token)
|
||||
# 取下一个,直到没有为卡
|
||||
token = tokens.get_next()
|
||||
self._continue_flag = True
|
||||
# 合成质量
|
||||
if self._effect:
|
||||
self._effect.reverse()
|
||||
self.resource_effect = " ".join(self._effect)
|
||||
if self._source:
|
||||
self.resource_type = self._source.strip()
|
||||
# 提取原盘DIY
|
||||
if self.resource_type and "BluRay" in self.resource_type:
|
||||
if (self.subtitle and re.findall(r'D[Ii]Y', self.subtitle)) \
|
||||
@@ -185,6 +188,62 @@ class MetaVideo(MetaBase):
|
||||
if not self.video_bit:
|
||||
self.video_bit = self.extract_video_bit(self.video_encode)
|
||||
|
||||
def __apply_rust_parse(self, rust_parse: Optional[dict]) -> bool:
|
||||
"""
|
||||
应用 Rust 主识别结果;成功时跳过 Python token 主循环。
|
||||
"""
|
||||
if not rust_parse or not rust_parse.get("complete"):
|
||||
return False
|
||||
self.cn_name = rust_parse.get("cn_name")
|
||||
self.en_name = rust_parse.get("en_name")
|
||||
if rust_parse.get("year"):
|
||||
self.year = str(rust_parse.get("year"))
|
||||
self.part = rust_parse.get("part")
|
||||
self.__merge_rust_parse(rust_parse)
|
||||
media_type = rust_parse.get("type")
|
||||
if media_type == "tv":
|
||||
self.type = MediaType.TV
|
||||
elif media_type == "movie":
|
||||
self.type = MediaType.MOVIE
|
||||
return True
|
||||
|
||||
def __merge_rust_parse(self, rust_parse: Optional[dict]) -> None:
|
||||
"""
|
||||
合并 Rust 预解析结果,仅补齐 Python 识别未命中的资源字段。
|
||||
"""
|
||||
if not rust_parse:
|
||||
return
|
||||
if not self.year and rust_parse.get("year"):
|
||||
self.year = str(rust_parse.get("year"))
|
||||
if self.begin_season is None and rust_parse.get("begin_season") is not None:
|
||||
self.begin_season = int(rust_parse.get("begin_season"))
|
||||
self.type = MediaType.TV
|
||||
if self.end_season is None and rust_parse.get("end_season") is not None:
|
||||
self.end_season = int(rust_parse.get("end_season"))
|
||||
if not self.total_season and rust_parse.get("total_season"):
|
||||
self.total_season = int(rust_parse.get("total_season"))
|
||||
if self.begin_episode is None and rust_parse.get("begin_episode") is not None:
|
||||
self.begin_episode = int(rust_parse.get("begin_episode"))
|
||||
self.type = MediaType.TV
|
||||
if self.end_episode is None and rust_parse.get("end_episode") is not None:
|
||||
self.end_episode = int(rust_parse.get("end_episode"))
|
||||
if not self.total_episode and rust_parse.get("total_episode"):
|
||||
self.total_episode = int(rust_parse.get("total_episode"))
|
||||
if not self.resource_pix and rust_parse.get("resource_pix"):
|
||||
self.resource_pix = rust_parse.get("resource_pix")
|
||||
if not self.resource_type and rust_parse.get("resource_type"):
|
||||
self.resource_type = rust_parse.get("resource_type")
|
||||
if not self.resource_effect and rust_parse.get("resource_effect"):
|
||||
self.resource_effect = rust_parse.get("resource_effect")
|
||||
if not self.video_encode and rust_parse.get("video_encode"):
|
||||
self.video_encode = rust_parse.get("video_encode")
|
||||
if not self.video_bit and rust_parse.get("video_bit"):
|
||||
self.video_bit = rust_parse.get("video_bit")
|
||||
if not self.audio_encode and rust_parse.get("audio_encode"):
|
||||
self.audio_encode = rust_parse.get("audio_encode")
|
||||
if self.fps is None and rust_parse.get("fps") is not None:
|
||||
self.fps = int(rust_parse.get("fps"))
|
||||
|
||||
@staticmethod
|
||||
def __get_title_from_description(description: str) -> Optional[str]:
|
||||
"""
|
||||
|
||||
@@ -12,6 +12,7 @@ from app.core.meta.infopath import (
|
||||
from app.core.meta.words import WordsMatcher
|
||||
from app.log import logger
|
||||
from app.schemas.types import MediaType
|
||||
from app.utils import rust_accel
|
||||
|
||||
|
||||
_ANIME_BRACKET_RE = re.compile(r'【[+0-9XVPI-]+】\s*【', re.IGNORECASE)
|
||||
@@ -168,6 +169,9 @@ def is_anime(name: str) -> bool:
|
||||
:param name: 名称
|
||||
:return: 是否动漫
|
||||
"""
|
||||
rust_result = rust_accel.is_anime(name)
|
||||
if rust_result is not None:
|
||||
return rust_result
|
||||
if not name:
|
||||
return False
|
||||
if _ANIME_BRACKET_RE.search(name):
|
||||
@@ -185,6 +189,9 @@ def find_metainfo(title: str) -> Tuple[str, dict]:
|
||||
"""
|
||||
从标题中提取媒体信息
|
||||
"""
|
||||
rust_result = rust_accel.find_metainfo(title)
|
||||
if rust_result is not None:
|
||||
return rust_result
|
||||
metainfo = _empty_metainfo()
|
||||
if not title:
|
||||
return title, metainfo
|
||||
|
||||
Reference in New Issue
Block a user