Files
FastAnime/fastanime/cli/interactive/session.py
2025-07-06 22:23:14 +03:00

105 lines
3.6 KiB
Python

from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Optional
from pydantic import BaseModel, Field
if TYPE_CHECKING:
from ...core.config import AppConfig
from ...libs.anilist.api import AniListApi
from ...libs.anilist.types import AnilistBaseMediaDataSchema
from ...libs.anime.provider import AnimeProvider
# Import the dataclasses for type hinting
from ...libs.anime.types import Anime, SearchResult, SearchResults, Server
from ...libs.players.base import BasePlayer
from ...libs.selector.base import BaseSelector
logger = logging.getLogger(__name__)
# --- Nested State Models ---
class AnilistState(BaseModel):
"""Holds state related to AniList data and selections."""
results_data: dict | None = None
selected_anime: Optional[AnilistBaseMediaDataSchema] = None
class ProviderState(BaseModel):
"""Holds state related to the current anime provider, using specific dataclasses."""
search_results: Optional[SearchResults] = None
selected_search_result: Optional[SearchResult] = None
anime_details: Optional[Anime] = None
current_episode: Optional[str] = None
current_server: Optional[Server] = None
class NavigationState(BaseModel):
"""Holds state related to the UI navigation stack."""
current_page: int = 1
history_stack_class_names: list[str] = Field(default_factory=list)
class TrackingState(BaseModel):
"""Holds state for user progress tracking preferences."""
progress_mode: str = "prompt"
# --- Top-Level SessionState ---
class SessionState(BaseModel):
"""The root model for all serializable runtime state."""
anilist: AnilistState = Field(default_factory=AnilistState)
provider: ProviderState = Field(default_factory=ProviderState)
navigation: NavigationState = Field(default_factory=NavigationState)
tracking: TrackingState = Field(default_factory=TrackingState)
class Config:
arbitrary_types_allowed = True
class Session:
"""
Manages the entire runtime session for the interactive anilist command.
"""
def __init__(self, config: AppConfig, anilist_client: AniListApi) -> None:
self.config: AppConfig = config
self.state: SessionState = SessionState()
self.is_running: bool = True
self.anilist: AniListApi = anilist_client
self._initialize_components()
def _initialize_components(self) -> None:
"""Creates instances of core components based on the current config."""
from ...libs.anime.provider import create_provider
from ...libs.players import create_player
from ...libs.selector import create_selector
logger.debug("Initializing session components from configuration...")
self.selector: BaseSelector = create_selector(self.config)
self.provider: AnimeProvider = create_provider(self.config.general.provider)
self.player: BasePlayer = create_player(self.config.stream.player, self.config)
def change_provider(self, provider_name: str) -> None:
from ...libs.anime.provider import create_provider
self.config.general.provider = provider_name
self.provider = create_provider(provider_name)
logger.info(f"Provider changed to: {self.provider.__class__.__name__}")
def change_player(self, player_name: str) -> None:
from ...libs.players import create_player
self.config.stream.player = player_name
self.player = create_player(player_name, self.config)
logger.info(f"Player changed to: {self.player.__class__.__name__}")
def stop(self) -> None:
self.is_running = False