Files
MoviePilot/app/api/endpoints/anilist.py
2026-07-22 12:53:58 +08:00

170 lines
4.9 KiB
Python

from typing import Annotated, Optional
from fastapi import APIRouter, Depends, Query
from app import schemas
from app.chain.anilist import AniListChain
from app.core.context import MediaInfo
from app.core.security import verify_token
router = APIRouter()
PageParam = Annotated[int, Query(ge=1)]
CountParam = Annotated[int, Query(ge=1, le=50)]
def _serialize_medias(medias: list[MediaInfo]) -> list[schemas.MediaInfo]:
"""
将内部媒体对象转换为 REST 响应模型。
:param medias: 统一媒体信息列表
:return: REST 媒体响应列表
"""
return [schemas.MediaInfo(**media.to_dict()) for media in medias]
@router.get(
"/trending",
summary="查询 AniList 当前趋势榜",
response_model=list[schemas.MediaInfo],
)
async def anilist_trending(
page: PageParam = 1,
count: CountParam = 20,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaInfo]:
"""查询 AniList TRENDING NOW 榜单"""
medias = await AniListChain().async_trending(page=page, count=count)
return _serialize_medias(medias)
@router.get(
"/popular-this-season",
summary="查询 AniList 本季热门榜",
response_model=list[schemas.MediaInfo],
)
async def anilist_popular_this_season(
page: PageParam = 1,
count: CountParam = 20,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaInfo]:
"""查询 AniList POPULAR THIS SEASON 榜单"""
medias = await AniListChain().async_popular_this_season(page=page, count=count)
return _serialize_medias(medias)
@router.get(
"/discover",
summary="探索 AniList 动画",
response_model=list[schemas.MediaInfo],
)
async def anilist_discover(
page: PageParam = 1,
count: CountParam = 20,
search: Optional[str] = None,
genre: Optional[str] = None,
media_format: Optional[str] = Query(None, alias="format"),
season: Optional[str] = None,
season_year: Optional[int] = None,
status: Optional[str] = None,
country: Optional[str] = None,
sort: Optional[str] = None,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaInfo]:
"""按标题、类型、风格、季度、年份、状态、地区和排序探索 AniList 动画"""
medias = await AniListChain().async_discover(
page=page,
count=count,
search=search,
genre=genre,
media_format=media_format,
season=season,
season_year=season_year,
status=status,
country=country,
sort=sort,
)
return _serialize_medias(medias)
@router.get(
"/credits/{anilist_id}",
summary="查询 AniList 配音演员",
response_model=list[schemas.MediaPerson],
)
async def anilist_credits(
anilist_id: int,
page: PageParam = 1,
count: CountParam = 20,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaPerson]:
"""查询 AniList 动画的日语配音演员"""
return await AniListChain().async_credits(
anilist_id=anilist_id, page=page, count=count
)
@router.get(
"/recommend/{anilist_id}",
summary="查询 AniList 相关推荐",
response_model=list[schemas.MediaInfo],
)
async def anilist_recommendations(
anilist_id: int,
page: PageParam = 1,
count: CountParam = 20,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaInfo]:
"""查询 AniList 动画相关推荐"""
medias = await AniListChain().async_recommendations(
anilist_id=anilist_id, page=page, count=count
)
return _serialize_medias(medias)
@router.get(
"/person/{person_id}",
summary="查询 AniList 人物详情",
response_model=schemas.MediaPerson,
)
async def anilist_person(
person_id: int,
_: schemas.TokenPayload = Depends(verify_token),
) -> Optional[schemas.MediaPerson]:
"""根据 AniList 人物 ID 查询详情"""
return await AniListChain().async_person_detail(person_id=person_id)
@router.get(
"/person/credits/{person_id}",
summary="查询 AniList 人物作品",
response_model=list[schemas.MediaInfo],
)
async def anilist_person_credits(
person_id: int,
page: PageParam = 1,
count: CountParam = 20,
_: schemas.TokenPayload = Depends(verify_token),
) -> list[schemas.MediaInfo]:
"""查询 AniList 人物参与的动画作品"""
medias = await AniListChain().async_person_credits(
person_id=person_id, page=page, count=count
)
return _serialize_medias(medias)
@router.get(
"/{anilist_id}",
summary="查询 AniList 动画详情",
response_model=schemas.MediaInfo,
)
async def anilist_info(
anilist_id: int,
_: schemas.TokenPayload = Depends(verify_token),
) -> schemas.MediaInfo:
"""根据 AniList 媒体 ID 查询动画详情"""
info = await AniListChain().async_info(anilist_id)
if not info:
return schemas.MediaInfo()
return schemas.MediaInfo(**MediaInfo(anilist_info=info).to_dict())