feat: accelerate RSS parsing with Rust

This commit is contained in:
jxxghp
2026-05-22 21:31:18 +08:00
parent 052e1ca8e4
commit 4de4044a3e
15 changed files with 467 additions and 102 deletions

View File

@@ -9,6 +9,7 @@ from lxml import etree
from app.core.config import settings
from app.helper.browser import PlaywrightHelper
from app.log import logger
from app.utils import rust_accel
from app.utils.http import RequestUtils
from app.utils.string import StringUtils
@@ -227,6 +228,32 @@ class RssHelper:
},
}
@staticmethod
def __format_rust_items(items: List[dict]) -> List[dict]:
"""
将 Rust RSS 解析结果转换为原 Python XPath 解析返回结构。
"""
ret_array = []
for item in items:
pubdate = ""
pubdate_raw = item.get("pubdate_raw")
if pubdate_raw:
pubdate = StringUtils.get_time(pubdate_raw)
if pubdate is not None:
pubdate = pubdate.astimezone(tz=None)
tmp_dict = {
'title': item.get("title") or "",
'enclosure': item.get("enclosure") or "",
'size': item.get("size") or 0,
'description': item.get("description") or "",
'link': item.get("link") or "",
'pubdate': pubdate
}
if item.get("nickname"):
tmp_dict['nickname'] = item.get("nickname")
ret_array.append(tmp_dict)
return ret_array
def parse(self, url, proxy: bool = False,
timeout: Optional[int] = 15, headers: dict = None, ua: str = None) -> Union[List[dict], None, bool]:
"""
@@ -298,6 +325,12 @@ class RssHelper:
logger.error("RSS内容不是有效的XML格式")
return False
rust_items = rust_accel.parse_rss_items(ret_xml, self.MAX_RSS_ITEMS)
if rust_items is not None:
if len(rust_items) >= self.MAX_RSS_ITEMS:
logger.warning(f"RSS条目过多仅处理前{self.MAX_RSS_ITEMS}")
return self.__format_rust_items(rust_items)
# 使用lxml.etree解析XML
parser = None
try:

View File

@@ -11,7 +11,6 @@ from requests import Session
from app.core.config import settings
from app.helper.cloudflare import under_challenge
from app.log import logger
from app.utils import rust_accel
from app.utils.http import RequestUtils
from app.utils.site import SiteUtils
from app.utils.string import StringUtils
@@ -159,11 +158,8 @@ class SiteParserBase(metaclass=ABCMeta):
@staticmethod
def num_filesize(text) -> int:
"""
将站点页面中的文件大小文本转换为字节,优先使用 Rust 快路径
将站点页面中的文件大小文本转换为字节。
"""
rust_value = rust_accel.parse_filesize(text)
if rust_value is not None:
return rust_value
return StringUtils.num_filesize(text)
def parse(self):

View File

@@ -672,9 +672,6 @@ class SiteSpider:
"""
if not text or not filters or not isinstance(filters, list):
return text
rust_text = rust_accel.apply_indexer_text_filters(text, filters)
if rust_text is not None:
return rust_text
if not isinstance(text, str):
text = str(text)
for filter_item in filters:

View File

@@ -117,34 +117,6 @@ def filter_torrents(
return None
def apply_indexer_text_filters(text: Any, filters: Optional[List[dict]]) -> Optional[str]:
"""
使用 Rust 执行 indexer 文本过滤器,不可用或遇到不支持过滤器时返回 None。
"""
if not _moviepilot_rust or not filters or not isinstance(filters, list):
return None
try:
return _moviepilot_rust.apply_indexer_text_filters_fast(None if text is None else str(text), filters)
except BaseException as err:
_raise_non_rust_panic(err)
logger.debug(f"Rust 站点文本过滤失败,回退 Python{err}")
return None
def parse_filesize(text: Any) -> Optional[int]:
"""
使用 Rust 将文件大小文本转换为字节,不可用时返回 None。
"""
if not _moviepilot_rust:
return None
try:
return int(_moviepilot_rust.parse_filesize_fast(text))
except BaseException as err:
_raise_non_rust_panic(err)
logger.debug(f"Rust 文件大小解析失败,回退 Python{err}")
return None
def build_indexer_search_url(config: dict) -> Optional[str]:
"""
使用 Rust 根据普通 indexer 配置生成搜索 URL不可用时返回 None。
@@ -187,6 +159,20 @@ def parse_indexer_torrents(
return None
def parse_rss_items(xml_text: str, max_items: int) -> Optional[List[dict]]:
"""
使用 Rust 批量解析 RSS/Atom 条目,不可用或解析失败时返回 None。
"""
if not _moviepilot_rust:
return None
try:
return _moviepilot_rust.parse_rss_items_fast(xml_text or "", int(max_items or 0))
except BaseException as err:
_raise_non_rust_panic(err)
logger.debug(f"Rust RSS 条目解析失败,回退 Python{err}")
return None
def _coerce_media_type(value: Optional[str]) -> Optional[MediaType]:
"""
将 Rust 返回的媒体类型字符串转换为系统 MediaType。