diff --git a/media_manager/indexer/schemas.py b/media_manager/indexer/schemas.py index 6091998..d9b5ed0 100644 --- a/media_manager/indexer/schemas.py +++ b/media_manager/indexer/schemas.py @@ -30,13 +30,13 @@ class IndexerQueryResult(BaseModel): very_low_quality_pattern = r"\b(480p|480P|360p|360P)\b" if re.search(high_quality_pattern, self.title): - return Quality.high + return Quality.uhd elif re.search(medium_quality_pattern, self.title): - return Quality.medium + return Quality.fullhd elif re.search(low_quality_pattern, self.title): - return Quality.low + return Quality.hd elif re.search(very_low_quality_pattern, self.title): - return Quality.very_low + return Quality.sd return Quality.unknown diff --git a/media_manager/main.py b/media_manager/main.py index 7c790a4..b1e315e 100644 --- a/media_manager/main.py +++ b/media_manager/main.py @@ -1,4 +1,5 @@ import logging +import os import sys from logging.config import dictConfig @@ -64,7 +65,9 @@ if basic_config.DEVELOPMENT: else: log.info("Development Mode not activated!") -app = FastAPI(root_path="/api/v1") +base_path = os.getenv("API_BASE_PATH") or "/api/v1" +log.info("Base Path for API: %s", base_path) +app = FastAPI(root_path=base_path) if basic_config.DEVELOPMENT: origins = [ @@ -162,5 +165,7 @@ app.mount( name="static-images", ) +log.info("Hello World!") + if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=5049, log_config=LOGGING_CONFIG) diff --git a/media_manager/torrent/schemas.py b/media_manager/torrent/schemas.py index db5a861..0dcea43 100644 --- a/media_manager/torrent/schemas.py +++ b/media_manager/torrent/schemas.py @@ -8,10 +8,10 @@ TorrentId = typing.NewType("TorrentId", uuid.UUID) class Quality(Enum): - high = 1 - medium = 2 - low = 3 - very_low = 4 + uhd = 1 + fullhd = 2 + hd = 3 + sd = 4 unknown = 5 diff --git a/media_manager/torrent/service.py b/media_manager/torrent/service.py index 522c8b3..a0dca70 100644 --- a/media_manager/torrent/service.py +++ b/media_manager/torrent/service.py @@ -308,6 +308,7 @@ class TorrentService: ) media_manager.torrent.repository.delete_torrent(db=self.db, torrent_id=t.id) + # TODO: fix this, it probably does not work because it is a method of a class @repeat_every(seconds=3600) def import_all_torrents(self) -> list[Torrent]: log.info("Importing all torrents") diff --git a/media_manager/tv/repository.py b/media_manager/tv/repository.py index 44029c8..1a1ab65 100644 --- a/media_manager/tv/repository.py +++ b/media_manager/tv/repository.py @@ -289,3 +289,26 @@ def get_season_request( db: Session, season_request_id: SeasonRequestId ) -> SeasonRequestSchema: return SeasonRequestSchema.model_validate(db.get(SeasonRequest, season_request_id)) + + +def get_show_by_season_id( + db: Session, season_id: SeasonId +) -> ShowSchema | None: + """ + Retrieve a show by one of its season's ID. + + :param db: The database session. + :param season_id: The ID of the season to retrieve the show for. + :return: A ShowSchema object if found, otherwise None. + """ + stmt = ( + select(Show) + .join(Season, Show.id == Season.show_id) + .where(Season.id == season_id) + ) + + result = db.execute(stmt).unique().scalar_one_or_none() + if not result: + return None + + return ShowSchema.model_validate(result) diff --git a/media_manager/tv/service.py b/media_manager/tv/service.py index 07e3b4c..a89f3b0 100644 --- a/media_manager/tv/service.py +++ b/media_manager/tv/service.py @@ -1,9 +1,11 @@ from sqlalchemy.orm import Session +from fastapi_utils.tasks import repeat_every import media_manager.indexer.service import media_manager.metadataProvider import media_manager.torrent.repository import media_manager.tv.repository +from media_manager.database import SessionLocal from media_manager.indexer import IndexerQueryResult from media_manager.indexer.schemas import IndexerQueryResultId from media_manager.metadataProvider.schemas import MetaDataProviderShowSearchResult @@ -284,3 +286,70 @@ def download_torrent( ) add_season_file(db=db, season_file=season_file) return show_torrent + + +def download_approved_season_request( + db: Session, + season_request: SeasonRequest, + show_id: ShowId, +) -> bool: + if not season_request.authorized: + log.error(f"Season request {season_request.id} is not authorized for download") + raise ValueError( + f"Season request {season_request.id} is not authorized for download" + ) + log.info(f"Downloading approved season request {season_request.id}") + + season = get_season(db=db, season_id=season_request.season_id) + torrents = get_all_available_torrents_for_a_season(db=db, season_number=season.number, show_id=show_id) + available_torrents: list[IndexerQueryResult] = [] + for torrent in torrents: + if torrent.quality > season_request.wanted_quality or torrent.quality < season_request.min_quality or torrent.seeders < 3: + log.info( + f"Skipping torrent {torrent.title} with quality {torrent.quality} for season {season.id}, because it does not match the requested quality {season_request.wanted_quality}" + ) + else: + available_torrents.append(torrent) + log.info( + f"Taking torrent {torrent.title} with quality {torrent.quality} for season {season.id} into consideration") + + if len(available_torrents) == 0: + log.warning( + f"No torrents matching criteria were found (wanted quality: {season_request.wanted_quality}, min_quality: {season_request.min_quality} for season {season.id})") + return False + + available_torrents.sort() + + torrent = TorrentService(db=db).download(indexer_result=available_torrents[0]) + + season_file = SeasonFile( + season_id=season.id, + quality=torrent.quality, + torrent_id=torrent.id, + file_path_suffix="", + ) + add_season_file(db=db, season_file=season_file) + return True + + +def auto_download_all_approved_season_requests() -> None: + db: Session = SessionLocal + log.info(f"Auto downloading all approved season requests") + season_requests = media_manager.tv.repository.get_season_requests(db=db) + log.info(f"Found {len(season_requests)} season requests to process") + count = 0 + for season_request in season_requests: + if season_request.authorized: + log.info(f"Processing season request {season_request.id} for download") + show = media_manager.tv.repository.get_show_by_season_id(db=db, season_id=season_request.season_id) + if download_approved_season_request( + db=db, + season_request=season_request, + show_id=show.id + ): + count += 1 + else: + log.warning( + f"Failed to download season request {season_request.id} for show {show.name}" + ) + log.info(f"Auto downloaded {count} approved season requests") diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index fe0810a..71d218f 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -9,10 +9,10 @@ import {browser} from "$app/environment"; const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL; export const qualityMap: { [key: number]: string } = { - 1: 'high', - 2: 'medium', - 3: 'low', - 4: 'very low', + 1: '4K/UHD', + 2: '1080p/FullHD', + 3: '720p/HD', + 4: '480p/SD', 5: 'unknown' }; export const torrentStatusMap: { [key: number]: string } = {