Files
ohm_streaming/app/routers/router_watchlist.py
T
root 5c7116557d
CI / Test (Python 3.11) (push) Has been cancelled
CI / Test (Python 3.12) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Summary (push) Has been cancelled
feat: frontend modernization with HTMX, Alpine.js and Plyr (Phase 3)
- Integrated HTMX for server-driven UI updates and fragments
- Adopted Alpine.js for global reactive state and tab management
- Replaced legacy player with Plyr.io for premium streaming experience
- Implemented real-time download polling via HTMX
- Added server-sent Toast notification system
- Fixed navigation and authentication scoping issues
2026-03-24 11:10:22 +00:00

185 lines
6.4 KiB
Python

"""
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
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("", response_model=List[WatchlistItem])
async def get_watchlist(
request: Request,
status: Optional[WatchlistStatus] = None,
html: bool = Query(False),
current_user: User = Depends(get_current_user_from_token),
):
"""Get user's watchlist (supports HTML for HTMX)"""
from main import watchlist_manager
items = watchlist_manager.get_all(user_id=current_user.id, status=status)
if html or request.headers.get("HX-Request"):
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)