fix(parser): handle movie results in search and rss

This commit is contained in:
Estrella Pan
2026-07-11 13:29:38 +02:00
parent 9f285fa63b
commit 64e29c2d5a
5 changed files with 47 additions and 10 deletions

View File

@@ -5,7 +5,7 @@ from module.conf.search_provider import get_provider
from module.database import Database, get_db
from module.downloader import DownloadClient
from module.manager import SeasonCollector
from module.models import APIResponse, Bangumi, RSSItem, RSSUpdate, Torrent
from module.models import APIResponse, Bangumi, Movie, RSSItem, RSSUpdate, Torrent
from module.rss import RSSAnalyser, RSSEngine
from module.security.api import get_current_user
@@ -185,14 +185,15 @@ analyser = RSSAnalyser()
@router.post(
"/analysis", response_model=Bangumi, dependencies=[Depends(get_current_user)]
"/analysis",
response_model=Bangumi | Movie,
dependencies=[Depends(get_current_user)],
)
async def analysis(rss: RSSItem):
data = await analyser.link_to_data(rss)
if isinstance(data, Bangumi):
if isinstance(data, (Bangumi, Movie)):
return data
else:
return u_response(data)
return u_response(data)
@router.post(

View File

@@ -4,7 +4,7 @@ from collections import OrderedDict
from typing import TypeAlias
from module.conf import settings
from module.models import Bangumi, RSSItem, Torrent
from module.models import Bangumi, Movie, RSSItem, Torrent
from module.network import RequestContent
from module.parser.analyser.tmdb_parser import tmdb_parser
from module.rss import RSSAnalyser
@@ -109,8 +109,8 @@ class SearchTorrent:
yield json.dumps(bangumi.dict(), separators=(",", ":"))
@staticmethod
def special_url(data: Bangumi, site: str) -> RSSItem:
keywords = [getattr(data, key) for key in SEARCH_KEY if getattr(data, key)]
def special_url(data: Bangumi | Movie, site: str) -> RSSItem:
keywords = [value for key in SEARCH_KEY if (value := getattr(data, key, None))]
url = search_url(site, keywords)
return url

View File

@@ -8,7 +8,7 @@ from fastapi.testclient import TestClient
from module.api import v1
from module.database import get_db
from module.models import Bangumi, ResponseModel, RSSItem, RSSUpdate, Torrent
from module.models import Bangumi, Movie, ResponseModel, RSSItem, RSSUpdate, Torrent
from module.security.api import get_current_user
from test.factories import make_bangumi, make_rss_item, make_torrent
@@ -307,6 +307,20 @@ class TestAnalysis:
data = response.json()
assert data["official_title"] == "Parsed Anime"
def test_analysis_returns_movie(self, authed_client):
"""POST /rss/analysis preserves a parsed movie response."""
movie = Movie(official_title="Parsed Movie", title_raw="Parsed Movie")
with patch("module.api.rss.analyser") as mock_analyser:
mock_analyser.link_to_data = AsyncMock(return_value=movie)
response = authed_client.post(
"/api/v1/rss/analysis",
json={"url": "https://mikanani.me/RSS/link", "parser": "mikan"},
)
assert response.status_code == 200
assert response.json()["official_title"] == "Parsed Movie"
# ---------------------------------------------------------------------------
# POST /rss/collect

View File

@@ -7,7 +7,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from module.conf import settings
from module.models import Bangumi, RSSItem
from module.models import Bangumi, Movie, RSSItem
from module.searcher.provider import search_url
# ---------------------------------------------------------------------------
@@ -165,6 +165,24 @@ class TestSpecialUrl:
# Only title_raw should be in the URL
assert "Test" in result.url
def test_supports_movie_without_season_fields(self):
"""Movie search results do not expose Bangumi-only season fields."""
from module.searcher.searcher import SearchTorrent
movie = Movie(
official_title="Movie Title",
title_raw="Movie Title",
group_name="MovieGroup",
dpi="1080p",
)
with patch(
"module.searcher.provider.SEARCH_CONFIG",
{"mikan": "https://mikanani.me/RSS/Search?searchstr=%s"},
):
result = SearchTorrent.special_url(movie, "mikan")
assert "Movie" in result.url
# ---------------------------------------------------------------------------
# _poster_cache: bounded LRU + reset_cache()

View File

@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from module.conf import settings
from module.models import Bangumi
from module.models.bangumi import Episode
from module.models.config import LLM, ExperimentalOpenAI
from module.parser import title_parser as title_parser_module
@@ -34,6 +35,7 @@ class TestTitleParser:
async def test_parse_without_llm(self):
result = await TitleParser.raw_parser(RAW_TITLE)
assert result is not None
assert isinstance(result, Bangumi)
assert result.group_name == "梦蓝字幕组"
assert result.title_raw == "New Doraemon"
assert result.dpi == "1080P"
@@ -47,6 +49,7 @@ class TestTitleParser:
async def test_parse_with_llm(self):
result = await TitleParser.raw_parser(RAW_TITLE)
assert result is not None
assert isinstance(result, Bangumi)
assert result.group_name == "梦蓝字幕组"
assert result.title_raw == "New Doraemon"
assert result.dpi == "1080P"
@@ -144,6 +147,7 @@ class TestRawParserLLMPrimaryMode:
result = await TitleParser.raw_parser("[Group] LLM Title Movie [1080P]")
assert result is not None
assert isinstance(result, Bangumi)
assert result.episode_type == "movie"
async def test_llm_failure_falls_back_to_regex(self):