""" Watchlist management routes for Ohm Stream Downloader API. """ import re from typing import List, Optional from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException 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"]) 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, current_user: User = Depends(get_current_user_from_token), ): """Add an anime to the watchlist""" from main import watchlist_manager try: item = watchlist_manager.create(current_user.id, item_data) return item except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) 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( status: Optional[WatchlistStatus] = None, current_user: User = Depends(get_current_user_from_token), ): """Get user's watchlist""" from main import watchlist_manager try: items = watchlist_manager.get_all(user_id=current_user.id, status=status) return items except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error getting watchlist: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @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 try: settings = watchlist_manager.get_settings() return settings except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error getting watchlist settings: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.put("/settings", response_model=WatchlistSettings) async def update_watchlist_settings( settings: WatchlistSettings, 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.restart() return updated_settings except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error updating watchlist settings: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.get("/stats") async def get_watchlist_stats( current_user: User = Depends(get_current_user_from_token), ): """Get watchlist statistics""" from main import watchlist_manager try: stats = watchlist_manager.get_stats(user_id=current_user.id) return stats except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error getting watchlist stats: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/check-all") async def check_all_watchlist_items( current_user: User = Depends(get_current_user_from_token), ): """Manually trigger a check for all due watchlist items""" from main import episode_checker, watchlist_manager try: results = await episode_checker.check_all_due() user_results = [] for result in results: item = watchlist_manager.get_by_id(result.watchlist_item_id) if item and item.user_id == current_user.id: user_results.append(result) return { "status": "success", "checked": len(user_results), "total_new_episodes": sum(r.new_episodes_found for r in user_results), "total_downloaded": sum(len(r.episodes_downloaded) for r in user_results), "results": user_results, } except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error checking all watchlist items: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.get("/scheduler/status") async def get_scheduler_status( current_user: User = Depends(get_current_user_from_token), ): """Get auto-download scheduler status""" from main import auto_download_scheduler, watchlist_manager try: return { "running": auto_download_scheduler.is_running(), "next_run": auto_download_scheduler.get_next_run_time(), "settings": watchlist_manager.get_settings(), } except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error getting scheduler status: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/scheduler/start") async def start_scheduler( current_user: User = Depends(get_current_user_from_token), ): """Start the auto-download scheduler""" from main import auto_download_scheduler try: if auto_download_scheduler.is_running(): return { "status": "already_running", "message": "Scheduler is already running", } auto_download_scheduler.start() return {"status": "started", "message": "Scheduler started successfully"} except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error starting scheduler: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/scheduler/stop") async def stop_scheduler( current_user: User = Depends(get_current_user_from_token), ): """Stop the auto-download scheduler""" from main import auto_download_scheduler try: if not auto_download_scheduler.is_running(): return {"status": "not_running", "message": "Scheduler is not running"} auto_download_scheduler.stop() return {"status": "stopped", "message": "Scheduler stopped successfully"} except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error stopping scheduler: {e}", exc_info=True) 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 try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") return item except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error getting watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.put("/{item_id}", response_model=WatchlistItem) async def update_watchlist_item( item_id: str, update_data: WatchlistItemUpdate, current_user: User = Depends(get_current_user_from_token), ): """Update a watchlist item""" from main import watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") updated_item = watchlist_manager.update(item_id, update_data) return updated_item except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error updating watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.delete("/{item_id}") async def delete_watchlist_item( item_id: str, current_user: User = Depends(get_current_user_from_token), ): """Delete an anime from the watchlist""" from main import watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") success = watchlist_manager.delete(item_id) if not success: raise HTTPException(status_code=500, detail="Failed to delete item") return {"status": "success", "message": "Item deleted from watchlist"} except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error deleting watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/{item_id}/check") async def check_watchlist_item( item_id: str, current_user: User = Depends(get_current_user_from_token), ): """Manually trigger a check for new episodes""" from main import episode_checker, watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") result = await episode_checker.manual_check(item_id) if not result: raise HTTPException(status_code=500, detail="Check failed") return result except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error checking watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/{item_id}/download-all") async def download_all_episodes( item_id: str, background_tasks: BackgroundTasks, current_user: User = Depends(get_current_user_from_token), ): """Download the LATEST SEASON episodes for a watchlist item""" from main import download_manager, watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") downloader = get_downloader(item.anime_url) latest_season_url = item.anime_url if hasattr(downloader, "get_seasons"): try: seasons = await downloader.get_seasons(item.anime_url) if seasons and len(seasons) > 0: latest_season = seasons[-1] latest_season_url = latest_season.get("url", item.anime_url) except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.warning(f"Could not fetch seasons, using default URL: {e}") episodes = await downloader.get_episodes(latest_season_url, item.lang) if not episodes: return { "status": "warning", "message": f"No episodes found for {item.anime_title}", "result": {"new_episodes_found": 0, "episodes_downloaded": []}, } task_ids = [] season_match = re.search(r"saison(\d+)", latest_season_url, re.IGNORECASE) season_num = season_match.group(1) if season_match else "1" anime_title_clean = ( item.anime_title.replace("/", "-").replace("\\", "-").strip() ) for episode in episodes: ep_num = episode.get("episode", "01") filename = f"{anime_title_clean} - S{season_num} - Episode {ep_num}.mp4" request = DownloadRequest(url=episode["url"], filename=filename) task = download_manager.create_task(request) task_ids.append(task.id) background_tasks.add_task(download_manager.start_download, task.id) watchlist_manager.update( item_id, {"last_episode_downloaded": len(episodes), "total_episodes": len(episodes)}, ) return { "status": "success", "message": f"Downloading {len(task_ids)} episodes from latest season for {item.anime_title}", "task_ids": task_ids, "total_episodes": len(episodes), "season_url": latest_season_url, } except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error downloading all episodes: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/{item_id}/pause", response_model=WatchlistItem) async def pause_watchlist_item( item_id: str, current_user: User = Depends(get_current_user_from_token), ): """Pause automatic downloading for a specific anime""" from main import watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") update_data = WatchlistItemUpdate(status=WatchlistStatus.PAUSED) updated_item = watchlist_manager.update(item_id, update_data) return updated_item except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error pausing watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e)) @router.post("/{item_id}/resume", response_model=WatchlistItem) async def resume_watchlist_item( item_id: str, current_user: User = Depends(get_current_user_from_token), ): """Resume automatic downloading for a paused anime""" from main import watchlist_manager try: item = watchlist_manager.get_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Watchlist item not found") if item.user_id != current_user.id: raise HTTPException(status_code=403, detail="Access denied") update_data = WatchlistItemUpdate(status=WatchlistStatus.ACTIVE) updated_item = watchlist_manager.update(item_id, update_data) return updated_item except HTTPException: raise except Exception as e: from logging import getLogger logger = getLogger(__name__) logger.error(f"Error resuming watchlist item: {e}", exc_info=True) raise HTTPException(status_code=500, detail=str(e))