cleanup
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from typing import List, Optional
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel
|
||||
@@ -24,40 +24,76 @@ class AnimeDetail(BaseModel):
|
||||
@router.get("/", response_model=List[AnimeSummary])
|
||||
async def list_anime(
|
||||
_auth: dict = Depends(require_auth),
|
||||
series_app=Depends(get_series_app)
|
||||
):
|
||||
"""List series with missing episodes using the core SeriesApp."""
|
||||
series_app: Any = Depends(get_series_app),
|
||||
) -> List[AnimeSummary]:
|
||||
"""List library series that still have missing episodes.
|
||||
|
||||
Args:
|
||||
_auth: Ensures the caller is authenticated (value unused).
|
||||
series_app: Core `SeriesApp` instance provided via dependency.
|
||||
|
||||
Returns:
|
||||
List[AnimeSummary]: Summary entries describing missing content.
|
||||
|
||||
Raises:
|
||||
HTTPException: When the underlying lookup fails.
|
||||
"""
|
||||
try:
|
||||
series = series_app.List.GetMissingEpisode()
|
||||
result = []
|
||||
for s in series:
|
||||
missing = 0
|
||||
try:
|
||||
missing = len(s.episodeDict) if getattr(s, "episodeDict", None) is not None else 0
|
||||
except Exception:
|
||||
missing = 0
|
||||
result.append(AnimeSummary(id=getattr(s, "key", getattr(s, "folder", "")), title=getattr(s, "name", ""), missing_episodes=missing))
|
||||
return result
|
||||
summaries: List[AnimeSummary] = []
|
||||
for serie in series:
|
||||
episodes_dict = getattr(serie, "episodeDict", {}) or {}
|
||||
missing_episodes = len(episodes_dict)
|
||||
key = getattr(serie, "key", getattr(serie, "folder", ""))
|
||||
title = getattr(serie, "name", "")
|
||||
summaries.append(
|
||||
AnimeSummary(
|
||||
id=key,
|
||||
title=title,
|
||||
missing_episodes=missing_episodes,
|
||||
)
|
||||
)
|
||||
return summaries
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to retrieve anime list")
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to retrieve anime list",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.post("/rescan")
|
||||
async def trigger_rescan(series_app=Depends(get_series_app)):
|
||||
"""Trigger a rescan of local series data using SeriesApp.ReScan."""
|
||||
async def trigger_rescan(series_app: Any = Depends(get_series_app)) -> dict:
|
||||
"""Kick off a background rescan of the local library.
|
||||
|
||||
Args:
|
||||
series_app: Core `SeriesApp` instance provided via dependency.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Status payload communicating whether the rescan
|
||||
launched successfully.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the rescan command is unsupported or fails.
|
||||
"""
|
||||
try:
|
||||
# SeriesApp.ReScan expects a callback; pass a no-op
|
||||
if hasattr(series_app, "ReScan"):
|
||||
series_app.ReScan(lambda *args, **kwargs: None)
|
||||
return {"success": True, "message": "Rescan started"}
|
||||
else:
|
||||
raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Rescan not available")
|
||||
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
||||
detail="Rescan not available",
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to start rescan")
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to start rescan",
|
||||
) from exc
|
||||
|
||||
|
||||
class SearchRequest(BaseModel):
|
||||
@@ -65,56 +101,107 @@ class SearchRequest(BaseModel):
|
||||
|
||||
|
||||
@router.post("/search", response_model=List[AnimeSummary])
|
||||
async def search_anime(request: SearchRequest, series_app=Depends(get_series_app)):
|
||||
"""Search for new anime by query text using the SeriesApp loader."""
|
||||
async def search_anime(
|
||||
request: SearchRequest,
|
||||
series_app: Any = Depends(get_series_app),
|
||||
) -> List[AnimeSummary]:
|
||||
"""Search the provider for additional series matching a query.
|
||||
|
||||
Args:
|
||||
request: Incoming payload containing the search term.
|
||||
series_app: Core `SeriesApp` instance provided via dependency.
|
||||
|
||||
Returns:
|
||||
List[AnimeSummary]: Discovered matches returned from the provider.
|
||||
|
||||
Raises:
|
||||
HTTPException: When provider communication fails.
|
||||
"""
|
||||
try:
|
||||
matches = []
|
||||
matches: List[Any] = []
|
||||
if hasattr(series_app, "search"):
|
||||
# SeriesApp.search is synchronous in core; call directly
|
||||
matches = series_app.search(request.query)
|
||||
|
||||
result = []
|
||||
for m in matches:
|
||||
# matches may be dicts or objects
|
||||
if isinstance(m, dict):
|
||||
mid = m.get("key") or m.get("id") or ""
|
||||
title = m.get("title") or m.get("name") or ""
|
||||
missing = int(m.get("missing", 0)) if m.get("missing") is not None else 0
|
||||
summaries: List[AnimeSummary] = []
|
||||
for match in matches:
|
||||
if isinstance(match, dict):
|
||||
identifier = match.get("key") or match.get("id") or ""
|
||||
title = match.get("title") or match.get("name") or ""
|
||||
missing = match.get("missing")
|
||||
missing_episodes = int(missing) if missing is not None else 0
|
||||
else:
|
||||
mid = getattr(m, "key", getattr(m, "id", ""))
|
||||
title = getattr(m, "title", getattr(m, "name", ""))
|
||||
missing = int(getattr(m, "missing", 0))
|
||||
result.append(AnimeSummary(id=mid, title=title, missing_episodes=missing))
|
||||
identifier = getattr(match, "key", getattr(match, "id", ""))
|
||||
title = getattr(match, "title", getattr(match, "name", ""))
|
||||
missing_episodes = int(getattr(match, "missing", 0))
|
||||
|
||||
return result
|
||||
summaries.append(
|
||||
AnimeSummary(
|
||||
id=identifier,
|
||||
title=title,
|
||||
missing_episodes=missing_episodes,
|
||||
)
|
||||
)
|
||||
|
||||
return summaries
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Search failed")
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Search failed",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get("/{anime_id}", response_model=AnimeDetail)
|
||||
async def get_anime(anime_id: str, series_app=Depends(get_series_app)):
|
||||
"""Return detailed info about a series from SeriesApp.List."""
|
||||
async def get_anime(
|
||||
anime_id: str,
|
||||
series_app: Any = Depends(get_series_app)
|
||||
) -> AnimeDetail:
|
||||
"""Return detailed information about a specific series.
|
||||
|
||||
Args:
|
||||
anime_id: Provider key or folder name of the requested series.
|
||||
series_app: Core `SeriesApp` instance provided via dependency.
|
||||
|
||||
Returns:
|
||||
AnimeDetail: Detailed series metadata including episode list.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the anime cannot be located or retrieval fails.
|
||||
"""
|
||||
try:
|
||||
series = series_app.List.GetList()
|
||||
found = None
|
||||
for s in series:
|
||||
if getattr(s, "key", None) == anime_id or getattr(s, "folder", None) == anime_id:
|
||||
found = s
|
||||
for serie in series:
|
||||
matches_key = getattr(serie, "key", None) == anime_id
|
||||
matches_folder = getattr(serie, "folder", None) == anime_id
|
||||
if matches_key or matches_folder:
|
||||
found = serie
|
||||
break
|
||||
|
||||
if not found:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Series not found")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Series not found",
|
||||
)
|
||||
|
||||
episodes = []
|
||||
epdict = getattr(found, "episodeDict", {}) or {}
|
||||
for season, eps in epdict.items():
|
||||
for e in eps:
|
||||
episodes.append(f"{season}-{e}")
|
||||
episodes: List[str] = []
|
||||
episode_dict = getattr(found, "episodeDict", {}) or {}
|
||||
for season, episode_numbers in episode_dict.items():
|
||||
for episode in episode_numbers:
|
||||
episodes.append(f"{season}-{episode}")
|
||||
|
||||
return AnimeDetail(id=getattr(found, "key", getattr(found, "folder", "")), title=getattr(found, "name", ""), episodes=episodes, description=getattr(found, "description", None))
|
||||
return AnimeDetail(
|
||||
id=getattr(found, "key", getattr(found, "folder", "")),
|
||||
title=getattr(found, "name", ""),
|
||||
episodes=episodes,
|
||||
description=getattr(found, "description", None),
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to retrieve series details")
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to retrieve series details",
|
||||
) from exc
|
||||
|
||||
Reference in New Issue
Block a user