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

View File

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

View File

@@ -1,6 +1,5 @@
import json import json
import pprint import pprint
from typing import List
from uuid import UUID from uuid import UUID
import psycopg.errors import psycopg.errors
@@ -8,17 +7,17 @@ from fastapi import APIRouter, Depends, status
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from pydantic import BaseModel from pydantic import BaseModel
from sqlmodel import select from sqlmodel import select
from tmdbsimple import TV, TV_Seasons
import auth import auth
import dowloadClients import dowloadClients
import indexer import indexer
import metadataProvider
from database import SessionDependency from database import SessionDependency
from database.torrents import Torrent from database.torrents import Torrent
from database.tv import Episode, Season, Show from database.tv import Season, Show
from indexer import IndexerQueryResult from indexer import IndexerQueryResult
from routers.users import Message from routers.users import Message
from tv import log, tmdb from tv import log
router = APIRouter( router = APIRouter(
prefix="/tv", prefix="/tv",
@@ -35,48 +34,19 @@ class ShowDetails(BaseModel):
status.HTTP_201_CREATED: {"model": Show, "description": "Successfully created show"}, status.HTTP_201_CREATED: {"model": Show, "description": "Successfully created show"},
status.HTTP_409_CONFLICT: {"model": Message, "description": "Show already exists"}, status.HTTP_409_CONFLICT: {"model": Message, "description": "Show already exists"},
}) })
def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb"): def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb", version: str = ""):
show_metadata = TV(show_id).info() 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 if res is not None:
year: str | None = show_metadata["first_air_date"] return JSONResponse(status_code=status.HTTP_409_CONFLICT, content={"message": "Show already exists"})
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,
)
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)) log.info("Adding show: " + json.dumps(show.model_dump(), default=str))
db.add(show) 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: try:
db.commit() db.commit()
db.refresh(show) 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( @router.post("/{show_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends(
auth.get_current_user)], response_model=list[Season]) auth.get_current_user)], response_model=list[Season])
def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent: IndexerQueryResult, ): def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent_id: UUID):
seasons: list[Season] = [] """
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: for season_number in torrent.season:
seasons.append( seasons.append(
db.exec(select(Season) db.exec(select(Season)
@@ -172,13 +151,55 @@ def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent: Inde
return seasons 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): def get_shows(db: SessionDependency):
""""""
return db.exec(select(Show)).unique().fetchall() return db.exec(select(Show)).unique().fetchall()
@router.get("/{show_id}", dependencies=[Depends(auth.get_current_user)], response_model=ShowDetails) @router.get("/{show_id}", dependencies=[Depends(auth.get_current_user)], response_model=ShowDetails)
def get_show(db: SessionDependency, show_id: UUID): 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() shows = db.execute(select(Show, Season).where(Show.id == show_id).join(Season).order_by(Season.number)).fetchall()
seasons = [] seasons = []
for show in shows: for show in shows:
@@ -191,5 +212,11 @@ def get_show(db: SessionDependency, show_id: UUID):
@router.get("/search") @router.get("/search")
def search_show(query: str): 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() search = tmdb.Search()
return search.tv(query=query) return search.tv(query=query)