mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-18 01:54:00 +02:00
feat: add automatic downloads for approved season requests
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 } = {
|
||||
|
||||
Reference in New Issue
Block a user