"""JellyStat REST API — watch history, genre summary, and user summary.""" from __future__ import annotations import asyncpg from fastapi import APIRouter, Depends, Query from gateway.jellystat.db import get_pool from gateway.jellystat.models import ( GenreSummaryResponse, UserSummaryResponse, WatchHistoryResponse, ) router = APIRouter(prefix="/jellystat", tags=["jellystat"]) DEFAULT_WINDOW_MINUTES = 10080 # 7 days # --------------------------------------------------------------------------- # GET /jellystat/history/{user_id} # --------------------------------------------------------------------------- @router.get("/history/{user_id}", response_model=WatchHistoryResponse) async def get_watch_history( user_id: str, minutes: int = Query( default=DEFAULT_WINDOW_MINUTES, ge=1, description="Time window in minutes" ), pool: asyncpg.Pool = Depends(get_pool), ): """Return watch history grouped by title, ordered by most-watched first.""" rows = await pool.fetch( "SELECT * FROM fn_user_watch_history($1, $2)", user_id, minutes ) return WatchHistoryResponse( user_id=user_id, window_minutes=minutes, items=[ { "title": r["title"], "watch_time_sec": float(r["watch_time_sec"]), "media_type": r["media_type"], } for r in rows ], ) # --------------------------------------------------------------------------- # GET /jellystat/genres/{user_id} # --------------------------------------------------------------------------- @router.get("/genres/{user_id}", response_model=GenreSummaryResponse) async def get_genre_summary( user_id: str, minutes: int = Query( default=DEFAULT_WINDOW_MINUTES, ge=1, description="Time window in minutes" ), pool: asyncpg.Pool = Depends(get_pool), ): """Return total watch time per genre, ordered by most-watched first.""" rows = await pool.fetch( "SELECT * FROM fn_user_genre_summary($1, $2)", user_id, minutes ) return GenreSummaryResponse( user_id=user_id, window_minutes=minutes, genres=[ {"genre": r["genre"], "watch_time_sec": float(r["watch_time_sec"])} for r in rows ], ) # --------------------------------------------------------------------------- # GET /jellystat/summary/{user_id} # --------------------------------------------------------------------------- @router.get("/summary/{user_id}", response_model=UserSummaryResponse) async def get_user_summary( user_id: str, pool: asyncpg.Pool = Depends(get_pool), ): """Return all-time summary: total watch time, most-watched titles, top genres.""" rows = await pool.fetch("SELECT * FROM fn_user_summary($1)", user_id) # fn_user_summary returns key-value rows — build a dict # asyncpg already deserialises JSONB → Python objects metrics: dict[str, object] = {r["metric"]: r["value"] for r in rows} top_genres_raw = metrics.get("top_genres", []) top_genres: list[str] = top_genres_raw if isinstance(top_genres_raw, list) else [] return UserSummaryResponse( user_id=user_id, total_watch_time_sec=float(metrics.get("total_watch_time", 0)), most_watched_series=metrics.get("most_watched_series"), most_watched_movie=metrics.get("most_watched_movie"), total_last_30d_sec=float(metrics.get("total_last_30d", 0)), total_last_7d_sec=float(metrics.get("total_last_7d", 0)), top_genres=top_genres, )