feat: add subtitle search functionality and related data handling

This commit is contained in:
jxxghp
2026-06-09 06:46:26 +08:00
parent 738d92445a
commit e3c5a94c52
12 changed files with 1105 additions and 36 deletions

View File

@@ -5,7 +5,7 @@ from fastapi import APIRouter, Depends, Body
from app import schemas
from app.chain.download import DownloadChain
from app.chain.media import MediaChain
from app.core.context import MediaInfo, Context, TorrentInfo
from app.core.context import MediaInfo, Context, SubtitleInfo, TorrentInfo
from app.core.metainfo import MetaInfo
from app.core.security import verify_token
from app.db.models.user import User
@@ -114,6 +114,33 @@ def add(
return schemas.Response(success=True, data={"download_id": did})
@router.post("/subtitle", summary="下载字幕", response_model=schemas.Response)
def download_subtitle(
subtitle_in: schemas.SubtitleInfo,
tmdbid: Annotated[int | None, Body()] = None,
doubanid: Annotated[str | None, Body()] = None,
save_path: Annotated[str | None, Body()] = None,
current_user: User = Depends(get_current_active_user),
) -> Any:
"""
下载字幕资源。
"""
subtitle_info = SubtitleInfo()
subtitle_info.from_dict(subtitle_in.model_dump())
success, message, saved_files = DownloadChain().download_subtitle(
subtitle=subtitle_info,
tmdbid=tmdbid,
doubanid=doubanid,
save_path=save_path,
username=current_user.name,
)
return schemas.Response(
success=success,
message=message,
data={"files": saved_files} if saved_files else None,
)
@router.get("/start/{hashString}", summary="开始任务", response_model=schemas.Response)
def start(
hashString: str,

View File

@@ -150,13 +150,16 @@ async def search_latest_context(_: schemas.TokenPayload = Depends(verify_token))
查询上次搜索结果及其对应的搜索参数。
"""
search_chain = SearchChain()
torrents = await search_chain.async_last_search_results() or []
params = await search_chain.async_last_search_params() or {}
if params.get("result_type") == "subtitle":
results = await search_chain.async_last_subtitle_search_results() or []
else:
results = await search_chain.async_last_search_results() or []
return schemas.Response(
success=True,
data={
"params": params,
"results": [torrent.to_dict() for torrent in torrents],
"results": [result.to_dict() for result in results],
},
)
@@ -600,6 +603,46 @@ async def search_by_title(
)
@router.get("/subtitle/title/stream", summary="渐进式模糊搜索字幕")
async def search_subtitle_by_title_stream(
request: Request,
keyword: Optional[str] = None,
page: Optional[int] = 0,
sites: Optional[str] = None,
_: schemas.TokenPayload = Depends(verify_resource_token),
) -> Any:
"""
根据名称渐进式模糊搜索站点字幕资源返回格式为SSE。
"""
event_source = SearchChain().async_search_subtitles_by_title_stream(
title=keyword, page=page, sites=_parse_site_list(sites), cache_local=True
)
return StreamingResponse(
_stream_search_events(request, event_source), media_type="text/event-stream"
)
@router.get("/subtitle/title", summary="模糊搜索字幕", response_model=schemas.Response)
async def search_subtitle_by_title(
keyword: Optional[str] = None,
page: Optional[int] = 0,
sites: Optional[str] = None,
_: schemas.TokenPayload = Depends(verify_token),
) -> Any:
"""
根据名称模糊搜索站点字幕资源,支持分页。
"""
subtitles = await SearchChain().async_search_subtitles_by_title(
title=keyword, page=page, sites=_parse_site_list(sites), cache_local=True
)
if not subtitles:
return schemas.Response(success=False, message="未搜索到任何字幕")
return schemas.Response(
success=True, data=[subtitle.to_dict() for subtitle in subtitles]
)
@router.post("/recommend", summary="AI推荐资源", response_model=schemas.Response)
async def recommend_search_results(
filtered_indices: Optional[List[int]] = Body(