feat: Add NFO UI features (Task 6)
- Extended AnimeSummary model with NFO fields (has_nfo, nfo_created_at, nfo_updated_at, tmdb_id, tvdb_id) - Updated list_anime endpoint to fetch and return NFO data from database - Added NFO status badges to series cards (green=exists, gray=missing) - Created nfo-manager.js module with createNFO, refreshNFO, viewNFO operations - Added NFO action buttons to series cards (Create/View/Refresh) - Integrated WebSocket handlers for real-time NFO events (creating, completed, failed) - Added CSS styles for NFO badges and action buttons - All 34 NFO API tests passing, all 32 anime endpoint tests passing - Documented in docs/task6_status.md (90% complete, NFO status page deferred)
This commit is contained in:
@@ -85,6 +85,11 @@ class AnimeSummary(BaseModel):
|
||||
missing_episodes: Episode dictionary mapping seasons to episode numbers
|
||||
has_missing: Boolean flag indicating if series has missing episodes
|
||||
link: Optional link to the series page (used when adding new series)
|
||||
has_nfo: Whether the series has NFO metadata
|
||||
nfo_created_at: ISO timestamp when NFO was created
|
||||
nfo_updated_at: ISO timestamp when NFO was last updated
|
||||
tmdb_id: The Movie Database (TMDB) ID
|
||||
tvdb_id: TheTVDB ID
|
||||
"""
|
||||
key: str = Field(
|
||||
...,
|
||||
@@ -114,6 +119,26 @@ class AnimeSummary(BaseModel):
|
||||
default="",
|
||||
description="Link to the series page (for adding new series)"
|
||||
)
|
||||
has_nfo: bool = Field(
|
||||
default=False,
|
||||
description="Whether the series has NFO metadata"
|
||||
)
|
||||
nfo_created_at: Optional[str] = Field(
|
||||
default=None,
|
||||
description="ISO timestamp when NFO was created"
|
||||
)
|
||||
nfo_updated_at: Optional[str] = Field(
|
||||
default=None,
|
||||
description="ISO timestamp when NFO was last updated"
|
||||
)
|
||||
tmdb_id: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The Movie Database (TMDB) ID"
|
||||
)
|
||||
tvdb_id: Optional[int] = Field(
|
||||
default=None,
|
||||
description="TheTVDB ID"
|
||||
)
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
@@ -125,7 +150,12 @@ class AnimeSummary(BaseModel):
|
||||
"folder": "beheneko the elf girls cat (2025)",
|
||||
"missing_episodes": {"1": [1, 2, 3, 4]},
|
||||
"has_missing": True,
|
||||
"link": "https://aniworld.to/anime/stream/beheneko"
|
||||
"link": "https://aniworld.to/anime/stream/beheneko",
|
||||
"has_nfo": True,
|
||||
"nfo_created_at": "2025-01-15T10:30:00Z",
|
||||
"nfo_updated_at": "2025-01-15T10:30:00Z",
|
||||
"tmdb_id": 12345,
|
||||
"tvdb_id": 67890
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +218,7 @@ async def list_anime(
|
||||
filter: Optional[str] = None,
|
||||
_auth: dict = Depends(require_auth),
|
||||
series_app: Any = Depends(get_series_app),
|
||||
anime_service: AnimeService = Depends(get_anime_service),
|
||||
) -> List[AnimeSummary]:
|
||||
"""List all library series with their missing episodes status.
|
||||
|
||||
@@ -282,6 +313,36 @@ async def list_anime(
|
||||
|
||||
series = series_app.list.GetList()
|
||||
summaries: List[AnimeSummary] = []
|
||||
|
||||
# Build a map of folder -> NFO data for efficient lookup
|
||||
nfo_map = {}
|
||||
try:
|
||||
# Get all series from database to fetch NFO metadata
|
||||
from src.server.database.connection import get_db_session
|
||||
session = get_db_session()
|
||||
from src.server.database.models import AnimeSeries as DBAnimeSeries
|
||||
|
||||
db_series_list = session.query(DBAnimeSeries).all()
|
||||
for db_series in db_series_list:
|
||||
nfo_created = (
|
||||
db_series.nfo_created_at.isoformat()
|
||||
if db_series.nfo_created_at else None
|
||||
)
|
||||
nfo_updated = (
|
||||
db_series.nfo_updated_at.isoformat()
|
||||
if db_series.nfo_updated_at else None
|
||||
)
|
||||
nfo_map[db_series.folder_name] = {
|
||||
"has_nfo": db_series.has_nfo or False,
|
||||
"nfo_created_at": nfo_created,
|
||||
"nfo_updated_at": nfo_updated,
|
||||
"tmdb_id": db_series.tmdb_id,
|
||||
"tvdb_id": db_series.tvdb_id,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not fetch NFO data from database: {e}")
|
||||
# Continue without NFO data if database query fails
|
||||
|
||||
for serie in series:
|
||||
# Get all properties from the serie object
|
||||
key = getattr(serie, "key", "")
|
||||
@@ -296,6 +357,9 @@ async def list_anime(
|
||||
# Determine if series has missing episodes
|
||||
has_missing = bool(episode_dict)
|
||||
|
||||
# Get NFO data from map
|
||||
nfo_data = nfo_map.get(folder, {})
|
||||
|
||||
summaries.append(
|
||||
AnimeSummary(
|
||||
key=key,
|
||||
@@ -304,6 +368,11 @@ async def list_anime(
|
||||
folder=folder,
|
||||
missing_episodes=missing_episodes,
|
||||
has_missing=has_missing,
|
||||
has_nfo=nfo_data.get("has_nfo", False),
|
||||
nfo_created_at=nfo_data.get("nfo_created_at"),
|
||||
nfo_updated_at=nfo_data.get("nfo_updated_at"),
|
||||
tmdb_id=nfo_data.get("tmdb_id"),
|
||||
tvdb_id=nfo_data.get("tvdb_id"),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user