add ability to add different versions of the same show

This commit is contained in:
maxDorninger
2025-03-26 19:49:02 +01:00
parent f347a36767
commit 219f1d6571
3 changed files with 74 additions and 53 deletions

View File

@@ -8,7 +8,7 @@ from database.torrents import TorrentMixin
class Show(SQLModel, table=True):
__table_args__ = (UniqueConstraint("external_id", "metadata_provider"),)
__table_args__ = (UniqueConstraint("external_id", "metadata_provider", "version"),)
id: UUID = Field(primary_key=True, default_factory=uuid.uuid4)
external_id: int
metadata_provider: str
@@ -16,6 +16,7 @@ class Show(SQLModel, table=True):
overview: str
# For some shows the first_air_date isn't known, therefore it needs to be nullable
year: int | None
version: str = Field(default="")
seasons: list["Season"] = Relationship(back_populates="show", cascade_delete=True)

View File

@@ -1,10 +1,3 @@
import logging
import tmdbsimple as tmdb
from config import TvConfig
config = TvConfig()
log = logging.getLogger(__name__)
tmdb.API_KEY = config.api_key

View File

@@ -1,6 +1,5 @@
import json
import pprint
from typing import List
from uuid import UUID
import psycopg.errors
@@ -8,17 +7,17 @@ from fastapi import APIRouter, Depends, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from sqlmodel import select
from tmdbsimple import TV, TV_Seasons
import auth
import dowloadClients
import indexer
import metadataProvider
from database import SessionDependency
from database.torrents import Torrent
from database.tv import Episode, Season, Show
from database.tv import Season, Show
from indexer import IndexerQueryResult
from routers.users import Message
from tv import log, tmdb
from tv import log
router = APIRouter(
prefix="/tv",
@@ -35,48 +34,19 @@ class ShowDetails(BaseModel):
status.HTTP_201_CREATED: {"model": Show, "description": "Successfully created show"},
status.HTTP_409_CONFLICT: {"model": Message, "description": "Show already exists"},
})
def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb"):
show_metadata = TV(show_id).info()
def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb", version: str = ""):
res = db.exec(select(Show).
where(Show.external_id == show_id).
where(Show.metadata_provider == metadata_provider).
where(Show.version == version)).first()
# For some shows the first_air_date isn't known, therefore it needs to be nullable
year: str | None = show_metadata["first_air_date"]
if year:
year: int = int(year.split('-')[0])
else:
year = None
show = Show(
external_id=show_id,
metadata_provider=metadata_provider,
name=show_metadata["name"],
overview=show_metadata["overview"],
year=year,
)
if res is not None:
return JSONResponse(status_code=status.HTTP_409_CONFLICT, content={"message": "Show already exists"})
show = metadataProvider.get_show_metadata(id=show_id, provider=metadata_provider)
show.version = version
log.info("Adding show: " + json.dumps(show.model_dump(), default=str))
db.add(show)
db.commit()
for season in show_metadata["seasons"]:
season_metadata = TV_Seasons(tv_id=show_metadata["id"], season_number=season["season_number"]).info()
db.add(Season(
show_id=show.id,
number=int(season_metadata["season_number"]),
name=season_metadata["name"],
overview=season_metadata["overview"],
external_id=int(season_metadata["id"]))
)
db.commit()
for episode in season_metadata["episodes"]:
db.add(Episode(
show_id=show.id,
season_number=int(season_metadata["season_number"]),
title=episode["name"],
number=int(episode["episode_number"]),
external_id=int(episode["id"]),
))
try:
db.commit()
db.refresh(show)
@@ -151,8 +121,17 @@ def get_season_torrents(db: SessionDependency, show_id: UUID, season_id: UUID):
@router.post("/{show_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends(
auth.get_current_user)], response_model=list[Season])
def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent: IndexerQueryResult, ):
seasons: list[Season] = []
def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent_id: UUID):
"""
downloads torrents for a show season, links the torrent for all seasons the torrent contains
"""
torrent = db.get(Torrent, torrent_id)
if torrent is None:
return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"message": "Torrent not found"})
seasons = []
for season_number in torrent.season:
seasons.append(
db.exec(select(Season)
@@ -172,13 +151,55 @@ def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent: Inde
return seasons
@router.get("/", dependencies=[Depends(auth.get_current_user)], response_model=List[Show])
@router.post("/{show_id}/{season_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends(
auth.get_current_user)], response_model=list[Season])
def download_seasons_torrent(db: SessionDependency, show_id: UUID, season_id: UUID, torrent_id: UUID):
"""
downloads torrents for a season, links the torrent only to the specified season
this means that multiple torrents can contain a season but you can choose from one which the content should be
imported
"""
torrent = db.get(Torrent, torrent_id)
if torrent is None:
return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"message": "Torrent not found"})
seasons = []
for season_number in torrent.season:
seasons.append(
db.exec(select(Season)
.where(Season.show_id == show_id)
.where(Season.number == season_number)
).first()
)
torrent = torrent.download()
dowloadClients.client.download(Torrent)
for season in seasons:
season.requested = True
season.torrent_id = torrent.id
return seasons
@router.get("/", dependencies=[Depends(auth.get_current_user)], response_model=list[Show])
def get_shows(db: SessionDependency):
""""""
return db.exec(select(Show)).unique().fetchall()
@router.get("/{show_id}", dependencies=[Depends(auth.get_current_user)], response_model=ShowDetails)
def get_show(db: SessionDependency, show_id: UUID):
"""
:param show_id:
:type show_id:
:return:
:rtype:
"""
shows = db.execute(select(Show, Season).where(Show.id == show_id).join(Season).order_by(Season.number)).fetchall()
seasons = []
for show in shows:
@@ -191,5 +212,11 @@ def get_show(db: SessionDependency, show_id: UUID):
@router.get("/search")
def search_show(query: str):
"""
Searches for shows by title in the metadata provider.
:param query: The search query string.
:param db: The database connection object.
:return: A list of show objects that match the query.
"""
search = tmdb.Search()
return search.tv(query=query)