from pydantic.v1 import UUID4 from sqlalchemy.orm import Session import indexer.service import metadataProvider import torrent.repository import tv.repository from media_manager.indexer import IndexerQueryResult from media_manager.indexer.schemas import IndexerQueryResultId from media_manager.metadataProvider.schemas import MetaDataProviderShowSearchResult from media_manager.torrent.repository import get_seasons_files_of_torrent from media_manager.torrent.schemas import Torrent from media_manager.torrent.service import TorrentService from media_manager.tv import log from media_manager.tv.exceptions import MediaAlreadyExists from media_manager.tv.repository import add_season_file, get_season_files_by_season_id from media_manager.tv.schemas import ( Show, ShowId, SeasonRequest, SeasonFile, SeasonId, Season, RichShowTorrent, RichSeasonTorrent, PublicSeason, PublicShow, PublicSeasonFile, SeasonNumber, SeasonRequestId, RichSeasonRequest, ) def add_show(db: Session, external_id: int, metadata_provider: str) -> Show | None: if check_if_show_exists( db=db, external_id=external_id, metadata_provider=metadata_provider ): raise MediaAlreadyExists( f"Show with external ID {external_id} and" + f" metadata provider {metadata_provider} already exists" ) show_with_metadata = metadataProvider.get_show_metadata( id=external_id, provider=metadata_provider ) saved_show = tv.repository.save_show(db=db, show=show_with_metadata) return saved_show def add_season_request(db: Session, season_request: SeasonRequest) -> None: tv.repository.add_season_request(db=db, season_request=season_request) def get_season_request_by_id( db: Session, season_request_id: SeasonRequestId ) -> SeasonRequest | None: return tv.repository.get_season_request(db=db, season_request_id=season_request_id) def update_season_request(db: Session, season_request: SeasonRequest) -> None: tv.repository.delete_season_request(db=db, season_request_id=season_request.id) tv.repository.add_season_request(db=db, season_request=season_request) def delete_season_request(db: Session, season_request_id: SeasonRequestId) -> None: tv.repository.delete_season_request(db=db, season_request_id=season_request_id) def get_public_season_files_by_season_id( db: Session, season_id: SeasonId ) -> list[PublicSeasonFile]: season_files = get_season_files_by_season_id(db=db, season_id=season_id) public_season_files = [PublicSeasonFile.model_validate(x) for x in season_files] result = [] for season_file in public_season_files: if season_file_exists_on_file(db=db, season_file=season_file): season_file.downloaded = True result.append(season_file) return result def get_public_season_files_by_season_number( db: Session, season_number: SeasonNumber, show_id: ShowId ) -> list[PublicSeasonFile]: season = tv.repository.get_season_by_number( db=db, season_number=season_number, show_id=show_id ) return get_public_season_files_by_season_id(db=db, season_id=season.id) def check_if_show_exists( db: Session, external_id: int = None, metadata_provider: str = None, show_id: ShowId = None, ) -> bool: if external_id and metadata_provider: if tv.repository.get_show_by_external_id( external_id=external_id, metadata_provider=metadata_provider, db=db ): return True else: return False elif show_id: if tv.repository.get_show(show_id=show_id, db=db): return True else: return False else: raise ValueError( "External ID and metadata provider or Show ID must be provided" ) def get_all_available_torrents_for_a_season( db: Session, season_number: int, show_id: ShowId, search_query_override: str = None ) -> list[IndexerQueryResult]: log.debug( f"getting all available torrents for season {season_number} for show {show_id}" ) show = tv.repository.get_show(show_id=show_id, db=db) if search_query_override: search_query = search_query_override else: # TODO: add more Search query strings and combine all the results, like "season 3", "s03", "s3" search_query = show.name + " s" + str(season_number).zfill(2) torrents: list[IndexerQueryResult] = indexer.service.search( query=search_query, db=db ) if search_query_override: log.debug( f"Found with search query override {torrents.__len__()} torrents: {torrents}" ) return torrents result: list[IndexerQueryResult] = [] for torrent in torrents: if season_number in torrent.season: result.append(torrent) result.sort() return result def get_all_shows(db: Session) -> list[Show]: return tv.repository.get_shows(db=db) def search_for_show( query: str, metadata_provider: str, db: Session ) -> list[MetaDataProviderShowSearchResult]: results = metadataProvider.search_show(query, metadata_provider) for result in results: if check_if_show_exists( db=db, external_id=result.external_id, metadata_provider=metadata_provider ): result.added = True return results def get_popular_shows(metadata_provider: str, db: Session): results: list[MetaDataProviderShowSearchResult] = metadataProvider.search_show( provider=metadata_provider ) for result in results: if check_if_show_exists( db=db, external_id=result.external_id, metadata_provider=metadata_provider ): results.pop(results.index(result)) return results def get_public_show_by_id(db: Session, show_id: ShowId) -> PublicShow: show = tv.repository.get_show(show_id=show_id, db=db) seasons = [PublicSeason.model_validate(season) for season in show.seasons] for season in seasons: season.downloaded = is_season_downloaded(db=db, season_id=season.id) public_show = PublicShow.model_validate(show) public_show.seasons = seasons return public_show def get_show_by_id(db: Session, show_id: ShowId) -> Show: return tv.repository.get_show(show_id=show_id, db=db) def is_season_downloaded(db: Session, season_id: SeasonId) -> bool: season_files = get_season_files_by_season_id(db=db, season_id=season_id) for season_file in season_files: if season_file_exists_on_file(db=db, season_file=season_file): return True return False def season_file_exists_on_file(db: Session, season_file: SeasonFile) -> bool: if season_file.torrent_id is None: return True else: torrent_file = torrent.repository.get_torrent_by_id( db=db, torrent_id=season_file.torrent_id ) if torrent_file.imported: return True return False def get_show_by_external_id( db: Session, external_id: int, metadata_provider: str ) -> Show | None: return tv.repository.get_show_by_external_id( external_id=external_id, metadata_provider=metadata_provider, db=db ) def get_season(db: Session, season_id: SeasonId) -> Season: return tv.repository.get_season(season_id=season_id, db=db) def get_all_season_requests(db: Session) -> list[RichSeasonRequest]: return tv.repository.get_season_requests(db=db) def get_torrents_for_show(db: Session, show: Show) -> RichShowTorrent: show_torrents = tv.repository.get_torrents_by_show_id(db=db, show_id=show.id) rich_season_torrents = [] for show_torrent in show_torrents: seasons = tv.repository.get_seasons_by_torrent_id( db=db, torrent_id=show_torrent.id ) season_files = get_seasons_files_of_torrent(db=db, torrent_id=show_torrent.id) file_path_suffix = season_files[0].file_path_suffix season_torrent = RichSeasonTorrent( torrent_id=show_torrent.id, torrent_title=show_torrent.title, status=show_torrent.status, quality=show_torrent.quality, imported=show_torrent.imported, seasons=seasons, file_path_suffix=file_path_suffix, ) rich_season_torrents.append(season_torrent) return RichShowTorrent( show_id=show.id, name=show.name, year=show.year, metadata_provider=show.metadata_provider, torrents=rich_season_torrents, ) def get_all_shows_with_torrents(db: Session) -> list[RichShowTorrent]: shows = tv.repository.get_all_shows_with_torrents(db=db) return [get_torrents_for_show(show=show, db=db) for show in shows] def download_torrent( db: Session, public_indexer_result_id: IndexerQueryResultId, show_id: ShowId, override_show_file_path_suffix: str = "", ) -> Torrent: indexer_result = indexer.service.get_indexer_query_result( db=db, result_id=public_indexer_result_id ) show_torrent = TorrentService(db=db).download(indexer_result=indexer_result) for season_number in indexer_result.season: season = tv.repository.get_season_by_number( db=db, season_number=season_number, show_id=show_id ) season_file = SeasonFile( season_id=season.id, quality=indexer_result.quality, torrent_id=show_torrent.id, file_path_suffix=override_show_file_path_suffix, ) add_season_file(db=db, season_file=season_file) return show_torrent