"""Pydantic models for Watchlist and Auto-Download system""" from pydantic import BaseModel, Field from typing import Optional, Literal from datetime import datetime from enum import Enum class WatchlistStatus(str, Enum): """Status of a watchlist item""" ACTIVE = "active" # Currently tracking for new episodes PAUSED = "paused" # Temporarily paused COMPLETED = "completed" # Anime completed, no longer tracking ARCHIVED = "archived" # Archived but kept for history class QualityPreference(str, Enum): """Preferred video quality""" AUTO = "auto" # Let provider decide P1080 = "1080p" # Full HD P720 = "720p" # HD P480 = "480p" # SD class WatchlistItem(BaseModel): """An anime being tracked for automatic episode downloads""" id: str = Field(..., description="Unique identifier (UUID)") user_id: str = Field(..., description="User ID who owns this watchlist item") anime_title: str = Field(..., description="Title of the anime") anime_url: str = Field(..., description="URL to the anime page") provider_id: str = Field(..., description="Provider ID (animesama, nekosama, etc.)") lang: Literal["vostfr", "vf"] = Field(default="vostfr", description="Language preference") # Tracking state last_checked: Optional[datetime] = Field(None, description="Last time we checked for new episodes") last_episode_downloaded: int = Field(default=0, description="Last episode number downloaded") total_episodes: Optional[int] = Field(None, description="Total episodes if known") # Settings auto_download: bool = Field(default=True, description="Automatically download new episodes") quality_preference: QualityPreference = Field(default=QualityPreference.AUTO, description="Preferred quality") status: WatchlistStatus = Field(default=WatchlistStatus.ACTIVE, description="Tracking status") # Metadata poster_image: Optional[str] = Field(None, description="URL to poster image") cover_image: Optional[str] = Field(None, description="URL to cover image") synopsis: Optional[str] = Field(None, description="Anime synopsis") genres: list[str] = Field(default_factory=list, description="Anime genres") # Timestamps added_at: datetime = Field(default_factory=datetime.now, description="When added to watchlist") updated_at: datetime = Field(default_factory=datetime.now, description="Last update time") class Config: json_encoders = { datetime: lambda v: v.isoformat() } class WatchlistItemCreate(BaseModel): """Model for creating a new watchlist item""" anime_title: str anime_url: str provider_id: str lang: Literal["vostfr", "vf"] = "vostfr" auto_download: bool = True quality_preference: QualityPreference = QualityPreference.AUTO # Optional metadata poster_image: Optional[str] = None cover_image: Optional[str] = None synopsis: Optional[str] = None genres: list[str] = [] class WatchlistItemUpdate(BaseModel): """Model for updating a watchlist item""" auto_download: Optional[bool] = None quality_preference: Optional[QualityPreference] = None status: Optional[WatchlistStatus] = None last_episode_downloaded: Optional[int] = None total_episodes: Optional[int] = None class NewEpisodeInfo(BaseModel): """Information about a newly detected episode""" episode_number: int episode_title: Optional[str] = None episode_url: str season_number: Optional[int] = None anime_title: str provider_id: str class AutoDownloadResult(BaseModel): """Result of an automatic download check""" watchlist_item_id: str anime_title: str new_episodes_found: int episodes_downloaded: list[int] = Field(default_factory=list) episodes_failed: list[tuple[int, str]] = Field(default_factory=list) # (episode_number, error_message) checked_at: datetime = Field(default_factory=datetime.now) class WatchlistSettings(BaseModel): """Global watchlist settings""" check_interval_hours: int = Field(default=6, ge=1, le=168, description="Check interval (1-168 hours)") auto_download_enabled: bool = Field(default=True, description="Global auto-download toggle") max_concurrent_auto_downloads: int = Field(default=2, ge=1, le=10, description="Max concurrent auto-downloads") notify_on_new_episodes: bool = Field(default=False, description="Send notifications for new episodes") include_completed_anime: bool = Field(default=False, description="Check completed anime too") class Config: json_schema_extra = { "example": { "check_interval_hours": 6, "auto_download_enabled": True, "max_concurrent_auto_downloads": 2, "notify_on_new_episodes": False, "include_completed_anime": False } }