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 aiohttp import ClientSession
|
||||||
|
|
||||||
|
from .models.movie import Movie
|
||||||
|
from .models.serie import Serie
|
||||||
from .models.videos import Video, VideoCreated, VideoInfo
|
from .models.videos import Video, VideoCreated, VideoInfo
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
@ -10,33 +12,32 @@ logger = getLogger(__name__)
|
|||||||
|
|
||||||
class KyooClient:
|
class KyooClient:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._api_key: str = os.environ.get("KYOO_APIKEY") # type: ignore
|
api_key = os.environ.get("KYOO_APIKEY")
|
||||||
if not self._api_key:
|
if not api_key:
|
||||||
print("Missing environment variable 'KYOO_APIKEY'.")
|
print("Missing environment variable 'KYOO_APIKEY'.")
|
||||||
exit(2)
|
exit(2)
|
||||||
self._url = os.environ.get("KYOO_URL", "http://api:3567/api")
|
|
||||||
|
|
||||||
async def __aenter__(self):
|
|
||||||
self._client = ClientSession(
|
self._client = ClientSession(
|
||||||
|
base_url=os.environ.get("KYOO_URL", "http://api:3567/api"),
|
||||||
headers={
|
headers={
|
||||||
"User-Agent": "kyoo",
|
"User-Agent": "kyoo scanner v5",
|
||||||
|
"X-API-KEY": api_key,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __aexit__(self):
|
async def __aexit__(self):
|
||||||
await self._client.close()
|
await self._client.close()
|
||||||
|
|
||||||
async def get_videos_info(self) -> VideoInfo:
|
async def get_videos_info(self) -> VideoInfo:
|
||||||
async with self._client.get(
|
async with self._client.get("/videos") as r:
|
||||||
f"{self._url}/videos",
|
|
||||||
) as r:
|
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return VideoInfo(**await r.json())
|
return VideoInfo(**await r.json())
|
||||||
|
|
||||||
async def create_videos(self, videos: list[Video]) -> list[VideoCreated]:
|
async def create_videos(self, videos: list[Video]) -> list[VideoCreated]:
|
||||||
async with self._client.post(
|
async with self._client.post(
|
||||||
f"{self._url}/videos",
|
"videos",
|
||||||
json=[x.model_dump_json() for x in videos],
|
json=[x.model_dump_json() for x in videos],
|
||||||
) as r:
|
) as r:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
@ -44,85 +45,21 @@ class KyooClient:
|
|||||||
|
|
||||||
async def delete_videos(self, videos: list[str] | set[str]):
|
async def delete_videos(self, videos: list[str] | set[str]):
|
||||||
async with self._client.delete(
|
async with self._client.delete(
|
||||||
f"{self._url}/videos",
|
"videos",
|
||||||
json=videos,
|
json=videos,
|
||||||
) as r:
|
) as r:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
# async def link_collection(
|
async def create_movie(self, movie: Movie):
|
||||||
# self, collection: str, type: Literal["movie"] | Literal["show"], id: str
|
async with self._client.post(
|
||||||
# ):
|
"movies",
|
||||||
# async with self.client.put(
|
json=movie.model_dump_json(),
|
||||||
# f"{self._url}/collections/{collection}/{type}/{id}",
|
) as r:
|
||||||
# headers={"X-API-Key": self._api_key},
|
r.raise_for_status()
|
||||||
# ) as r:
|
|
||||||
# # Allow 409 and continue as if it worked.
|
async def create_serie(self, serie: Serie):
|
||||||
# if not r.ok and r.status != 409:
|
async with self._client.post(
|
||||||
# logger.error(f"Request error: {await r.text()}")
|
"series",
|
||||||
# r.raise_for_status()
|
json=serie.model_dump_json(),
|
||||||
#
|
) as r:
|
||||||
# async def post(self, path: str, *, data: dict[str, Any]) -> str:
|
r.raise_for_status()
|
||||||
# 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()
|
|
||||||
|
@ -36,7 +36,10 @@ class Provider(ABC):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
async def find_movie(
|
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:
|
) -> Movie:
|
||||||
ret = await self.get_movie(external_id)
|
ret = await self.get_movie(external_id)
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
@ -54,7 +57,10 @@ class Provider(ABC):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
async def find_serie(
|
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:
|
) -> Serie:
|
||||||
ret = await self.get_serie(external_id)
|
ret = await self.get_serie(external_id)
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from logging import getLogger
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from .client import KyooClient
|
from .client import KyooClient
|
||||||
@ -7,6 +8,8 @@ from .models.videos import Guess
|
|||||||
from .providers.composite import CompositeProvider
|
from .providers.composite import CompositeProvider
|
||||||
from .utils import Model
|
from .utils import Model
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Request(Model):
|
class Request(Model):
|
||||||
kind: Literal["episode", "movie"]
|
kind: Literal["episode", "movie"]
|
||||||
@ -33,21 +36,45 @@ async def enqueue(requests: list[Request]):
|
|||||||
class RequestProcessor:
|
class RequestProcessor:
|
||||||
def __init__(self, client: KyooClient, providers: CompositeProvider):
|
def __init__(self, client: KyooClient, providers: CompositeProvider):
|
||||||
self._client = client
|
self._client = client
|
||||||
|
self._providers = providers
|
||||||
|
|
||||||
async def process_scan_requests(self):
|
async def process_scan_requests(self):
|
||||||
# select for update skip_locked limit 1
|
# select for update skip_locked limit 1
|
||||||
request: Request = ...
|
request: Request = ...
|
||||||
|
|
||||||
if request.kind == "movie":
|
if request.kind == "movie":
|
||||||
movie = await providers.get_movie(
|
movie = await self._providers.find_movie(
|
||||||
request.title, request.year, request.external_id
|
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)
|
await self._client.create_movie(movie)
|
||||||
else:
|
else:
|
||||||
serie = await providers.get_serie(request.title, request.year)
|
serie = await self._providers.find_serie(
|
||||||
# for vid in request.videos:
|
request.title,
|
||||||
# for ep in vid.episodes:
|
request.year,
|
||||||
# entry = next(x for x in series.entries if (ep.season is None or x.season == ep.season), None)
|
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)
|
await self._client.create_serie(serie)
|
||||||
# delete request
|
# delete request
|
||||||
|
Loading…
x
Reference in New Issue
Block a user