""" Watchlist management routes for Ohm Stream Downloader API. """ import re import json from typing import List, Optional from fastapi import ( APIRouter, BackgroundTasks, Depends, HTTPException, Response, Request, Query, ) from fastapi.templating import Jinja2Templates from app.download_manager import DownloadManager from app.downloaders import get_downloader from app.models import DownloadRequest from app.models.auth import User from app.models.watchlist import ( WatchlistItem, WatchlistItemCreate, WatchlistItemUpdate, WatchlistSettings, WatchlistStatus, ) from app.routers.router_auth import get_current_user_from_token, get_optional_user router = APIRouter(prefix="/api/watchlist", tags=["watchlist"]) templates = Jinja2Templates(directory="templates") def get_download_manager() -> DownloadManager: from main import download_manager return download_manager @router.post("", response_model=WatchlistItem) async def add_to_watchlist( item_data: WatchlistItemCreate, response: Response, current_user: User = Depends(get_current_user_from_token), ): """Add an anime to the watchlist""" from main import watchlist_manager try: existing = watchlist_manager.get_by_anime_url( item_data.anime_url, current_user.id ) item = watchlist_manager.add(current_user.id, item_data) msg = ( f"'{item.anime_title}' ajouté à la watchlist" if not existing else f"'{item.anime_title}' est déjà dans la watchlist" ) toast_type = "success" if not existing else "info" response.headers["HX-Trigger"] = json.dumps( {"show-toast": {"message": msg, "type": toast_type}} ) return item except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error adding to watchlist: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.get("") async def get_watchlist( request: Request, status: Optional[WatchlistStatus] = None, html: bool = Query(False), current_user: Optional[User] = Depends(get_optional_user), ): from main import watchlist_manager is_htmx = request.headers.get("HX-Request") if current_user is None and (html or is_htmx): return templates.TemplateResponse( "components/login_prompt.html", {"request": request} ) if current_user is None: raise HTTPException(status_code=401, detail="Authentication required") items = watchlist_manager.get_all(user_id=current_user.id, status=status) if html or is_htmx: return templates.TemplateResponse( "components/watchlist_items_list.html", {"request": request, "items": items} ) return items @router.get("/settings", response_model=WatchlistSettings) async def get_watchlist_settings( current_user: User = Depends(get_current_user_from_token), ): """Get global watchlist settings""" from main import watchlist_manager return watchlist_manager.get_settings() @router.put("/settings", response_model=WatchlistSettings) async def update_watchlist_settings( settings: WatchlistSettings, response: Response, current_user: User = Depends(get_current_user_from_token), ): """Update global watchlist settings""" from main import auto_download_scheduler, watchlist_manager try: updated_settings = watchlist_manager.update_settings(settings) if auto_download_scheduler.is_running(): auto_download_scheduler.update_interval( updated_settings.check_interval_hours ) response.headers["HX-Trigger"] = json.dumps( { "show-toast": { "message": "Paramètres de la watchlist mis à jour", "type": "success", } } ) return updated_settings except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.get("/{item_id}", response_model=WatchlistItem) async def get_watchlist_item( item_id: str, current_user: User = Depends(get_current_user_from_token), ): """Get a specific watchlist item""" from main import watchlist_manager item = watchlist_manager.get_by_id(item_id) if not item or item.user_id != current_user.id: raise HTTPException(status_code=404, detail="Item not found") return item @router.put("/{item_id}", response_model=WatchlistItem) async def update_watchlist_item( item_id: str, update_data: WatchlistItemUpdate, response: Response, current_user: User = Depends(get_current_user_from_token), ): """Update a watchlist item""" from main import watchlist_manager item = watchlist_manager.get_by_id(item_id) if not item or item.user_id != current_user.id: raise HTTPException(status_code=404, detail="Item not found") updated_item = watchlist_manager.update(item_id, update_data) response.headers["HX-Trigger"] = json.dumps( { "show-toast": { "message": f"'{updated_item.anime_title}' mis à jour", "type": "success", } } ) return updated_item @router.delete("/{item_id}") async def delete_from_watchlist( item_id: str, response: Response, current_user: User = Depends(get_current_user_from_token), ): """Remove an anime from the watchlist""" from main import watchlist_manager item = watchlist_manager.get_by_id(item_id) if not item or item.user_id != current_user.id: raise HTTPException(status_code=404, detail="Item not found") title = item.anime_title if watchlist_manager.delete(item_id): response.headers["HX-Trigger"] = json.dumps( { "show-toast": { "message": f"'{title}' supprimé de la watchlist", "type": "info", } } ) # HTMX will handle removing the element if target is specified in the frontend return Response(status_code=204) raise HTTPException(status_code=500, detail="Failed to delete item") @router.post("/check", response_model=List) async def check_watchlist_now( background_tasks: BackgroundTasks, response: Response, current_user: User = Depends(get_current_user_from_token), ): """Trigger an immediate check for new episodes""" from main import auto_download_scheduler background_tasks.add_task(auto_download_scheduler.trigger_check_now) response.headers["HX-Trigger"] = json.dumps( { "show-toast": { "message": "Vérification de la watchlist lancée en arrière-plan", "type": "info", } } ) return {"status": "success", "message": "Check triggered"} @router.get("/stats/summary") async def get_watchlist_stats( current_user: User = Depends(get_current_user_from_token), ): """Get watchlist statistics for the user""" from main import watchlist_manager return watchlist_manager.get_stats(current_user.id)