From 3e69ea9c8b10041a4ce7362a6f242937ea75fc48 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 5 Jun 2025 11:14:44 +0200 Subject: [PATCH] Implement link videos on the scanner --- scanner/scanner/client.py | 36 +++++++++++++++++++++++++++++--- scanner/scanner/fsscan.py | 15 +++++++------ scanner/scanner/models/videos.py | 9 +++++++- scanner/scanner/requests.py | 2 +- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/scanner/scanner/client.py b/scanner/scanner/client.py index c1bb9cb7..e86aa90e 100644 --- a/scanner/scanner/client.py +++ b/scanner/scanner/client.py @@ -1,15 +1,16 @@ import os from logging import getLogger from types import TracebackType +from typing import Literal from aiohttp import ClientSession from pydantic import TypeAdapter -from scanner.utils import Singleton - from .models.movie import Movie from .models.serie import Serie -from .models.videos import Resource, Video, VideoCreated, VideoInfo +from .models.videos import For, Resource, Video, VideoCreated, VideoInfo, VideoLink +from .requests import Request +from .utils import Singleton logger = getLogger(__name__) @@ -74,3 +75,32 @@ class KyooClient(metaclass=Singleton): ) as r: r.raise_for_status() return Resource(**await r.json()) + + async def link_videos( + self, + kind: Literal["movie", "serie"], + show: str, + videos: list[Request.Video], + ): + def map_request(request: Request.Video): + if kind == "movie": + return VideoLink(id=request.id, for_=[For.Movie(movie=show)]) + return VideoLink( + id=request.id, + for_=[ + For.Special(serie=show, special=ep.episode) + if ep.season is None + else For.Episode(serie=show, season=ep.season, episode=ep.episode) + for ep in request.episodes + ], + ) + + async with self._client.post( + "videos", + data=TypeAdapter(list[VideoLink]).dump_json( + [map_request(x) for x in videos], + by_alias=True, + ), + ) as r: + r.raise_for_status() + return TypeAdapter(list[VideoCreated]).validate_json(await r.text()) diff --git a/scanner/scanner/fsscan.py b/scanner/scanner/fsscan.py index 00a2264e..a348bf25 100644 --- a/scanner/scanner/fsscan.py +++ b/scanner/scanner/fsscan.py @@ -1,6 +1,6 @@ -from contextlib import asynccontextmanager import os import re +from contextlib import asynccontextmanager from logging import getLogger from mimetypes import guess_file_type from os.path import dirname, exists, isdir, join @@ -157,13 +157,12 @@ class FsScanner: ) else: for ep in video.guess.episodes: - if ep.season is not None: - for slug in slugs: - video.for_.append( - For.Episode( - serie=slug, season=ep.season, episode=ep.episode - ) - ) + for slug in slugs: + video.for_.append( + For.Episode(serie=slug, season=ep.season, episode=ep.episode) + if ep.season is not None + else For.Special(serie=slug, special=ep.episode) + ) for k, v in video.guess.external_id.items(): video.for_.append( diff --git a/scanner/scanner/models/videos.py b/scanner/scanner/models/videos.py index 041df4f7..72a21a06 100644 --- a/scanner/scanner/models/videos.py +++ b/scanner/scanner/models/videos.py @@ -58,7 +58,7 @@ class For(Model): order: float class Special(Model): - serie: int + serie: str special: int @@ -78,3 +78,10 @@ class VideoCreated(Model): path: str guess: Guess entries: list[Resource] + + +class VideoLink(Model): + id: str + for_: list[ + For.Slug | For.ExternalId | For.Movie | For.Episode | For.Order | For.Special + ] diff --git a/scanner/scanner/requests.py b/scanner/scanner/requests.py index f691a3ba..17c9566a 100644 --- a/scanner/scanner/requests.py +++ b/scanner/scanner/requests.py @@ -146,7 +146,7 @@ class RequestProcessor: request.pk, ) if finished and finished["videos"] != request.videos: - await self._client.link_videos(show.slug, finished["videos"]) + await self._client.link_videos(show.kind, show.slug, finished["videos"]) except Exception as e: logger.error("Couldn't process request", exc_info=e) cur = await self._database.execute(