Files
ohm_streaming/app/routers/router_recommendations.py
root c921aafadd feat: filtre par type pour recommandations et sorties (#14)
- Parametre content_type sur /api/recommendations et /api/releases/latest
- Section anime: filtre content_type=anime sur releases
- Section series: filtre content_type=series sur recommendations et releases
- Nettoyage emojis dans titres de section

Closes #14
2026-04-02 22:42:36 +00:00

180 lines
5.5 KiB
Python

"""
Recommendations and releases routes for Ohm Stream Downloader API.
"""
import hashlib
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Request, Query, HTTPException, Depends
from fastapi.templating import Jinja2Templates
from app.recommendation_engine import RecommendationEngine
from app.models.auth import User
from app.routers.router_auth import get_optional_user, get_current_user_from_token
router = APIRouter(prefix="/api", tags=["recommendations"])
templates = Jinja2Templates(directory="templates")
# Add custom filters to Jinja2
def hash_filter(s):
return hashlib.md5(s.encode()).hexdigest()[:10]
templates.env.filters["hash"] = hash_filter
@router.get("/recommendations")
async def get_recommendations(
request: Request,
limit: int = 15,
html: bool = Query(False),
content_type: Optional[str] = Query(None, description="Filter: 'anime', 'series', or None for all"),
current_user: Optional[User] = Depends(get_optional_user),
):
"""Get personalized anime recommendations based on download history"""
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")
engine = RecommendationEngine(download_dir="downloads")
try:
recommendations = await engine.get_personalized_recommendations(limit=limit)
# Filter by content_type if specified
if content_type and content_type != "all":
recommendations = [r for r in recommendations if r.get("content_type", r.get("type", "")) == content_type]
if html or is_htmx:
return templates.TemplateResponse(
"components/recommendations_list.html",
{"request": request, "recommendations": recommendations}
)
return {"recommendations": recommendations, "count": len(recommendations)}
except Exception as e:
import logging
logging.getLogger(__name__).error(f"Recommendations error: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
finally:
await engine.close()
@router.get("/releases/latest")
async def get_latest_releases(
request: Request,
limit: int = 20,
html: bool = Query(False),
content_type: Optional[str] = Query(None, description="Filter: 'anime', 'series', or None for all"),
):
"""Get latest anime releases"""
from app.recommendations import get_latest_releases_with_info
try:
releases = await get_latest_releases_with_info(limit=limit)
# Filter by content_type if specified
if content_type and content_type != "all":
releases = [r for r in releases if r.get("content_type", r.get("type", "")) == content_type]
if html or request.headers.get("HX-Request"):
return templates.TemplateResponse(
"components/releases_list.html",
{"request": request, "releases": releases}
)
return {
"releases": releases,
"count": len(releases),
"updated": datetime.now().isoformat(),
}
except Exception as e:
import logging
logging.getLogger(__name__).error(f"Latest releases error: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.get("/releases/seasonal")
async def get_seasonal_anime(
year: Optional[int] = None,
season: Optional[str] = None,
):
"""Get current/previously seasonal anime"""
from app.recommendations import AnimeReleasesFetcher
fetcher = AnimeReleasesFetcher()
try:
anime = await fetcher.get_seasonal_anime(year, season)
return {
"anime": anime,
"count": len(anime),
"year": year or datetime.now().year,
"season": season or "current",
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
await fetcher.close()
@router.get("/releases/scheduled")
async def get_scheduled_anime(day: Optional[str] = None):
"""Get anime scheduled for a specific day"""
from app.recommendations import AnimeReleasesFetcher
fetcher = AnimeReleasesFetcher()
try:
anime = await fetcher.get_scheduled_anime(day)
return {"anime": anime, "count": len(anime), "day": day or "today"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
await fetcher.close()
@router.get("/releases/top")
async def get_top_anime(
type: str = "tv",
limit: int = 15,
):
"""Get top rated anime"""
from app.recommendations import AnimeReleasesFetcher
fetcher = AnimeReleasesFetcher()
try:
anime = await fetcher.get_top_anime(type=type, limit=limit)
return {"anime": anime, "count": len(anime)}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
await fetcher.close()
@router.get("/stats/downloads")
async def get_download_statistics(
current_user: User = Depends(get_current_user_from_token),
):
"""Get download statistics and preferences"""
engine = RecommendationEngine(download_dir="downloads")
try:
stats = await engine.get_download_stats()
return stats
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
await engine.close()