mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Match guessed's entries to tmdb's entries
This commit is contained in:
parent
47f6c66435
commit
f26dce64ef
@ -3,6 +3,8 @@ from logging import getLogger
|
||||
|
||||
from aiohttp import ClientSession
|
||||
|
||||
from .models.movie import Movie
|
||||
from .models.serie import Serie
|
||||
from .models.videos import Video, VideoCreated, VideoInfo
|
||||
|
||||
logger = getLogger(__name__)
|
||||
@ -10,33 +12,32 @@ logger = getLogger(__name__)
|
||||
|
||||
class KyooClient:
|
||||
def __init__(self) -> None:
|
||||
self._api_key: str = os.environ.get("KYOO_APIKEY") # type: ignore
|
||||
if not self._api_key:
|
||||
api_key = os.environ.get("KYOO_APIKEY")
|
||||
if not api_key:
|
||||
print("Missing environment variable 'KYOO_APIKEY'.")
|
||||
exit(2)
|
||||
self._url = os.environ.get("KYOO_URL", "http://api:3567/api")
|
||||
|
||||
async def __aenter__(self):
|
||||
self._client = ClientSession(
|
||||
base_url=os.environ.get("KYOO_URL", "http://api:3567/api"),
|
||||
headers={
|
||||
"User-Agent": "kyoo",
|
||||
"User-Agent": "kyoo scanner v5",
|
||||
"X-API-KEY": api_key,
|
||||
},
|
||||
)
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self):
|
||||
await self._client.close()
|
||||
|
||||
async def get_videos_info(self) -> VideoInfo:
|
||||
async with self._client.get(
|
||||
f"{self._url}/videos",
|
||||
) as r:
|
||||
async with self._client.get("/videos") as r:
|
||||
r.raise_for_status()
|
||||
return VideoInfo(**await r.json())
|
||||
|
||||
async def create_videos(self, videos: list[Video]) -> list[VideoCreated]:
|
||||
async with self._client.post(
|
||||
f"{self._url}/videos",
|
||||
"videos",
|
||||
json=[x.model_dump_json() for x in videos],
|
||||
) as r:
|
||||
r.raise_for_status()
|
||||
@ -44,85 +45,21 @@ class KyooClient:
|
||||
|
||||
async def delete_videos(self, videos: list[str] | set[str]):
|
||||
async with self._client.delete(
|
||||
f"{self._url}/videos",
|
||||
"videos",
|
||||
json=videos,
|
||||
) as r:
|
||||
r.raise_for_status()
|
||||
|
||||
# async def link_collection(
|
||||
# self, collection: str, type: Literal["movie"] | Literal["show"], id: str
|
||||
# ):
|
||||
# async with self.client.put(
|
||||
# f"{self._url}/collections/{collection}/{type}/{id}",
|
||||
# headers={"X-API-Key": self._api_key},
|
||||
# ) as r:
|
||||
# # Allow 409 and continue as if it worked.
|
||||
# if not r.ok and r.status != 409:
|
||||
# logger.error(f"Request error: {await r.text()}")
|
||||
# r.raise_for_status()
|
||||
#
|
||||
# async def post(self, path: str, *, data: dict[str, Any]) -> str:
|
||||
# logger.debug(
|
||||
# "Sending %s: %s",
|
||||
# path,
|
||||
# jsons.dumps(
|
||||
# data,
|
||||
# key_transformer=jsons.KEY_TRANSFORMER_CAMELCASE,
|
||||
# jdkwargs={"indent": 4},
|
||||
# ),
|
||||
# )
|
||||
# async with self.client.post(
|
||||
# f"{self._url}/{path}",
|
||||
# json=data,
|
||||
# headers={"X-API-Key": self._api_key},
|
||||
# ) as r:
|
||||
# # Allow 409 and continue as if it worked.
|
||||
# if not r.ok and r.status != 409:
|
||||
# logger.error(f"Request error: {await r.text()}")
|
||||
# r.raise_for_status()
|
||||
# ret = await r.json()
|
||||
# return ret["id"]
|
||||
#
|
||||
# async def delete(
|
||||
# self,
|
||||
# path: str,
|
||||
# ):
|
||||
# logger.info("Deleting %s", path)
|
||||
#
|
||||
# async with self.client.delete(
|
||||
# f"{self._url}/paths?recursive=true&path={quote(path)}",
|
||||
# headers={"X-API-Key": self._api_key},
|
||||
# ) as r:
|
||||
# if not r.ok:
|
||||
# logger.error(f"Request error: {await r.text()}")
|
||||
# r.raise_for_status()
|
||||
#
|
||||
# async def get(self, path: str):
|
||||
# async with self.client.get(
|
||||
# f"{self._url}/{path}",
|
||||
# headers={"X-API-Key": self._api_key},
|
||||
# ) as r:
|
||||
# if not r.ok:
|
||||
# logger.error(f"Request error: {await r.text()}")
|
||||
# r.raise_for_status()
|
||||
# return await r.json()
|
||||
#
|
||||
# async def put(self, path: str, *, data: dict[str, Any]):
|
||||
# logger.debug(
|
||||
# "Sending %s: %s",
|
||||
# path,
|
||||
# jsons.dumps(
|
||||
# data,
|
||||
# key_transformer=jsons.KEY_TRANSFORMER_CAMELCASE,
|
||||
# jdkwargs={"indent": 4},
|
||||
# ),
|
||||
# )
|
||||
# async with self.client.put(
|
||||
# f"{self._url}/{path}",
|
||||
# json=data,
|
||||
# headers={"X-API-Key": self._api_key},
|
||||
# ) as r:
|
||||
# # Allow 409 and continue as if it worked.
|
||||
# if not r.ok and r.status != 409:
|
||||
# logger.error(f"Request error: {await r.text()}")
|
||||
# r.raise_for_status()
|
||||
async def create_movie(self, movie: Movie):
|
||||
async with self._client.post(
|
||||
"movies",
|
||||
json=movie.model_dump_json(),
|
||||
) as r:
|
||||
r.raise_for_status()
|
||||
|
||||
async def create_serie(self, serie: Serie):
|
||||
async with self._client.post(
|
||||
"series",
|
||||
json=serie.model_dump_json(),
|
||||
) as r:
|
||||
r.raise_for_status()
|
||||
|
@ -36,7 +36,10 @@ class Provider(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
async def find_movie(
|
||||
self, title: str, year: int | None, external_id: dict[str, str]
|
||||
self,
|
||||
title: str,
|
||||
year: int | None,
|
||||
external_id: dict[str, str],
|
||||
) -> Movie:
|
||||
ret = await self.get_movie(external_id)
|
||||
if ret is not None:
|
||||
@ -54,7 +57,10 @@ class Provider(ABC):
|
||||
return ret
|
||||
|
||||
async def find_serie(
|
||||
self, title: str, year: int | None, external_id: dict[str, str]
|
||||
self,
|
||||
title: str,
|
||||
year: int | None,
|
||||
external_id: dict[str, str],
|
||||
) -> Serie:
|
||||
ret = await self.get_serie(external_id)
|
||||
if ret is not None:
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from logging import getLogger
|
||||
from typing import Literal
|
||||
|
||||
from .client import KyooClient
|
||||
@ -7,6 +8,8 @@ from .models.videos import Guess
|
||||
from .providers.composite import CompositeProvider
|
||||
from .utils import Model
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Request(Model):
|
||||
kind: Literal["episode", "movie"]
|
||||
@ -33,21 +36,45 @@ async def enqueue(requests: list[Request]):
|
||||
class RequestProcessor:
|
||||
def __init__(self, client: KyooClient, providers: CompositeProvider):
|
||||
self._client = client
|
||||
self._providers = providers
|
||||
|
||||
async def process_scan_requests(self):
|
||||
# select for update skip_locked limit 1
|
||||
request: Request = ...
|
||||
|
||||
if request.kind == "movie":
|
||||
movie = await providers.get_movie(
|
||||
request.title, request.year, request.external_id
|
||||
movie = await self._providers.find_movie(
|
||||
request.title,
|
||||
request.year,
|
||||
request.external_id,
|
||||
)
|
||||
movie.videos = request.videos
|
||||
movie.videos = [x.id for x in request.videos]
|
||||
await self._client.create_movie(movie)
|
||||
else:
|
||||
serie = await providers.get_serie(request.title, request.year)
|
||||
# for vid in request.videos:
|
||||
# for ep in vid.episodes:
|
||||
# entry = next(x for x in series.entries if (ep.season is None or x.season == ep.season), None)
|
||||
serie = await self._providers.find_serie(
|
||||
request.title,
|
||||
request.year,
|
||||
request.external_id,
|
||||
)
|
||||
for vid in request.videos:
|
||||
for ep in vid.episodes:
|
||||
entry = next(
|
||||
(
|
||||
x
|
||||
for x in serie.entries
|
||||
if (ep.season is None and x.order == ep.episode)
|
||||
or (
|
||||
x.season_number == ep.season
|
||||
and x.episode_number == ep.episode
|
||||
)
|
||||
),
|
||||
None,
|
||||
)
|
||||
if entry is None:
|
||||
logger.warning(
|
||||
f"Couldn't match entry for {serie.slug} {ep.season or 'abs'}-e{ep.episode}."
|
||||
)
|
||||
continue
|
||||
entry.videos.append(vid.id)
|
||||
await self._client.create_serie(serie)
|
||||
# delete request
|
||||
|
Loading…
x
Reference in New Issue
Block a user