feat: add automatic downloads for approved season requests

This commit is contained in:
maxDorninger
2025-05-31 13:45:44 +02:00
parent c89a5a19e8
commit 40c90d90ed
7 changed files with 111 additions and 13 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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")

View File

@@ -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)

View File

@@ -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")

View File

@@ -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 } = {