d4d8d8a3b6
- Migrated monolithic main.py to feature-scoped routers in app/routers/ - Added GEMINI.md for project context and AI instructional guidelines - Updated README.md with a comprehensive modernization plan (SQL migration, robust scraping DSL, frontend modernization) - Improved authentication with cookie support and modular JS - Updated test suite and documentation
120 lines
3.3 KiB
Python
120 lines
3.3 KiB
Python
"""
|
|
Favorites management routes for Ohm Stream Downloader API.
|
|
"""
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
from fastapi.requests import Request
|
|
|
|
from app.favorites import get_favorites_manager
|
|
|
|
router = APIRouter(prefix="/api/favorites", tags=["favorites"])
|
|
|
|
|
|
@router.get("")
|
|
async def list_favorites(
|
|
sort_by: str = "created_at",
|
|
order: str = "desc",
|
|
filter_provider: str = None,
|
|
filter_genre: str = None,
|
|
):
|
|
"""List all favorite anime with optional sorting and filtering"""
|
|
fav_manager = get_favorites_manager()
|
|
favorites = await fav_manager.list_favorites(
|
|
sort_by=sort_by,
|
|
order=order,
|
|
filter_provider=filter_provider,
|
|
filter_genre=filter_genre,
|
|
)
|
|
return {
|
|
"favorites": favorites,
|
|
"total": len(favorites),
|
|
"filters": {
|
|
"sort_by": sort_by,
|
|
"order": order,
|
|
"provider": filter_provider,
|
|
"genre": filter_genre,
|
|
},
|
|
}
|
|
|
|
|
|
@router.post("")
|
|
async def add_favorite(request: Request):
|
|
"""Add an anime to favorites"""
|
|
data = await request.json()
|
|
|
|
required_fields = ["anime_id", "title", "url", "provider"]
|
|
for field in required_fields:
|
|
if field not in data:
|
|
raise HTTPException(
|
|
status_code=400, detail=f"Missing required field: {field}"
|
|
)
|
|
|
|
fav_manager = get_favorites_manager()
|
|
favorite = await fav_manager.add_favorite(
|
|
anime_id=data["anime_id"],
|
|
title=data["title"],
|
|
url=data["url"],
|
|
provider=data["provider"],
|
|
metadata=data.get("metadata"),
|
|
poster_url=data.get("poster_url"),
|
|
)
|
|
|
|
return {"status": "added", "favorite": favorite}
|
|
|
|
|
|
@router.delete("/{anime_id}")
|
|
async def remove_favorite(anime_id: str):
|
|
"""Remove an anime from favorites"""
|
|
fav_manager = get_favorites_manager()
|
|
removed = await fav_manager.remove_favorite(anime_id)
|
|
|
|
if not removed:
|
|
raise HTTPException(status_code=404, detail="Favorite not found")
|
|
|
|
return {"status": "removed", "anime_id": anime_id}
|
|
|
|
|
|
@router.get("/stats")
|
|
async def get_favorites_stats():
|
|
"""Get statistics about favorites"""
|
|
fav_manager = get_favorites_manager()
|
|
stats = await fav_manager.get_stats()
|
|
return stats
|
|
|
|
|
|
@router.get("/{anime_id}")
|
|
async def get_favorite(anime_id: str):
|
|
"""Get details of a specific favorite anime"""
|
|
fav_manager = get_favorites_manager()
|
|
favorite = await fav_manager.get_favorite(anime_id)
|
|
|
|
if not favorite:
|
|
raise HTTPException(status_code=404, detail="Favorite not found")
|
|
|
|
return {"favorite": favorite}
|
|
|
|
|
|
@router.post("/toggle")
|
|
async def toggle_favorite(request: Request):
|
|
"""Toggle an anime in favorites"""
|
|
data = await request.json()
|
|
|
|
required_fields = ["anime_id", "title", "url", "provider"]
|
|
for field in required_fields:
|
|
if field not in data:
|
|
raise HTTPException(
|
|
status_code=400, detail=f"Missing required field: {field}"
|
|
)
|
|
|
|
fav_manager = get_favorites_manager()
|
|
result = await fav_manager.toggle_favorite(
|
|
anime_id=data["anime_id"],
|
|
title=data["title"],
|
|
url=data["url"],
|
|
provider=data["provider"],
|
|
metadata=data.get("metadata"),
|
|
poster_url=data.get("poster_url"),
|
|
)
|
|
|
|
return result
|