diff --git a/api/src/controllers/seed/images.ts b/api/src/controllers/seed/images.ts index 391c23dd..0961d44e 100644 --- a/api/src/controllers/seed/images.ts +++ b/api/src/controllers/seed/images.ts @@ -103,8 +103,8 @@ export const processImages = async () => { `); await tx.delete(mqueue).where(eq(mqueue.id, item.id)); - } catch (err) { - console.error("Failed to download image", img.url, err); + } catch (err: any) { + console.error("Failed to download image", img.url, err.message); await tx .update(mqueue) .set({ attempt: sql`${mqueue.attempt}+1` }) diff --git a/scanner/scanner/client.py b/scanner/scanner/client.py index 07bfeca4..37742c0d 100644 --- a/scanner/scanner/client.py +++ b/scanner/scanner/client.py @@ -59,22 +59,20 @@ class KyooClient(metaclass=Singleton): r.raise_for_status() async def create_movie(self, movie: Movie) -> Resource: - logger.debug("sending movie %s", movie.model_dump_json(by_alias=True)) async with self._client.post( "movies", data=movie.model_dump_json(by_alias=True), ) as r: r.raise_for_status() - return Resource(**await r.json()) + return Resource.model_validate(await r.json()) async def create_serie(self, serie: Serie) -> Resource: - logger.debug("sending serie %s", serie.model_dump_json(by_alias=True)) async with self._client.post( "series", data=serie.model_dump_json(by_alias=True), ) as r: r.raise_for_status() - return Resource(**await r.json()) + return Resource.model_validate(await r.json()) async def link_videos( self, @@ -89,7 +87,7 @@ class KyooClient(metaclass=Singleton): id=request.id, for_=[ For.Special(serie=show, special=ep.episode) - if ep.season is None + if ep.season is None or ep.season == 0 else For.Episode(serie=show, season=ep.season, episode=ep.episode) for ep in request.episodes ], @@ -103,4 +101,3 @@ class KyooClient(metaclass=Singleton): ), ) 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 a348bf25..0fe6aef7 100644 --- a/scanner/scanner/fsscan.py +++ b/scanner/scanner/fsscan.py @@ -11,8 +11,9 @@ from .client import KyooClient from .database import get_db from .identifiers.identify import identify from .models.metadataid import EpisodeId, MetadataId +from .models.request import Request from .models.videos import For, Video, VideoInfo -from .requests import Request, RequestCreator +from .requests import RequestCreator logger = getLogger(__name__) @@ -48,7 +49,6 @@ class FsScanner: self._info = await self._client.get_videos_info() - # TODO: handle unmatched to_register = videos - self._info.paths to_delete = self._info.paths - videos if remove_deleted else set() @@ -68,6 +68,11 @@ class FsScanner: if to_register: logger.info("Found %d new files to register.", len(to_register)) await self._register(to_register) + if self._info.unmatched: + logger.info( + "Retrying & updating %d unmatched files.", len(self._info.unmatched) + ) + await self._register(self._info.unmatched) logger.info("Scan finished for %s.", path) except Exception as e: @@ -160,7 +165,7 @@ class FsScanner: for slug in slugs: video.for_.append( For.Episode(serie=slug, season=ep.season, episode=ep.episode) - if ep.season is not None + if ep.season is not None and ep.season != 0 else For.Special(serie=slug, special=ep.episode) ) diff --git a/scanner/scanner/providers/themoviedatabase.py b/scanner/scanner/providers/themoviedatabase.py index 17e62f91..bb214512 100644 --- a/scanner/scanner/providers/themoviedatabase.py +++ b/scanner/scanner/providers/themoviedatabase.py @@ -182,7 +182,7 @@ class TheMovieDatabase(Provider): Language.get( f"{trans['iso_639_1']}-{trans['iso_3166_1']}" ): MovieTranslation( - name=clean(trans["data"]["name"]) + name=clean(trans["data"]["title"]) or ( clean(movie["original_title"]) if movie["original_language"] == trans["iso_639_1"] @@ -296,7 +296,9 @@ class TheMovieDatabase(Provider): else SerieStatus.AIRING if serie["in_production"] else SerieStatus.FINISHED, - runtime=serie["last_episode_to_air"]["runtime"], + runtime=serie["last_episode_to_air"]["runtime"] + if serie["last_episode_to_air"] + else None, start_air=datetime.strptime(serie["first_air_date"], "%Y-%m-%d").date() if serie["first_air_date"] else None, @@ -560,12 +562,12 @@ class TheMovieDatabase(Provider): return Collection( slug=to_slug(collection["name"]), # assume all parts are in the same language - original_language=Language.get(collection["part"][0]["original_language"]), + original_language=Language.get(collection["parts"][0]["original_language"]), genres=[ - y for x in collection["part"] for y in self._map_genres(x["genres"]) + y for x in collection["parts"] for y in self._map_genres(x["genre_ids"]) ], rating=round( - mean(float(x["vote_average"]) * 10 for x in collection["part"]) + mean(float(x["vote_average"]) * 10 for x in collection["parts"]) ), external_id={ self.name: MetadataId( @@ -577,9 +579,9 @@ class TheMovieDatabase(Provider): Language.get( f"{trans['iso_639_1']}-{trans['iso_3166_1']}" ): CollectionTranslation( - name=clean(trans["data"]["name"]) or collection["name"], + name=clean(trans["data"]["title"]) or collection["name"], latin_name=None, - description=trans["overview"], + description=trans["data"]["overview"], tagline=None, aliases=[], tags=[], @@ -664,7 +666,7 @@ class TheMovieDatabase(Provider): translations={ "en": StudioTranslation( name=company["name"], - logo=f"https://image.tmdb.org/t/p/original{company['logo_path']}" + logo=self._map_image(company["logo_path"]) if "logo_path" in company else None, ), diff --git a/scanner/scanner/requests.py b/scanner/scanner/requests.py index f4a6997c..5217b2b7 100644 --- a/scanner/scanner/requests.py +++ b/scanner/scanner/requests.py @@ -131,7 +131,14 @@ class RequestProcessor: request.pk, ) if finished and finished["videos"] != request.videos: - await self._client.link_videos(show.kind, show.slug, finished["videos"]) + videos = TypeAdapter(list[Request.Video]).validate_python( + finished["videos"] + ) + await self._client.link_videos( + "movie" if request.kind == "movie" else "serie", + show.slug, + videos, + ) except Exception as e: logger.error("Couldn't process request", exc_info=e) cur = await self._database.execute(