diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f0b7618f..461683ec 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -104,7 +104,7 @@ services: - "4389:4389" environment: - KYOO_URL=${KYOO_URL:-http://api:3567/api} - - JWKS_URL="http://auth:4568/.well-known/jwks.json" + - JWKS_URL=http://auth:4568/.well-known/jwks.json - JWT_ISSUER=${PUBLIC_URL} volumes: - ./scanner:/app diff --git a/scanner/scanner/__init__.py b/scanner/scanner/__init__.py index 0ac4f040..53a149ff 100644 --- a/scanner/scanner/__init__.py +++ b/scanner/scanner/__init__.py @@ -30,7 +30,6 @@ async def lifespan(_): # creating the processor makes it listen to requests event in pg async with ( get_db() as db, - KyooClient() as client, ): scanner = Scanner(client, RequestCreator(db)) # there's no way someone else used the same id, right? diff --git a/scanner/scanner/client.py b/scanner/scanner/client.py index f6d630f9..113a894a 100644 --- a/scanner/scanner/client.py +++ b/scanner/scanner/client.py @@ -4,6 +4,8 @@ from types import TracebackType from aiohttp import ClientSession +from scanner.utils import Singleton + from .models.movie import Movie from .models.serie import Serie from .models.videos import Resource, Video, VideoCreated, VideoInfo @@ -11,7 +13,7 @@ from .models.videos import Resource, Video, VideoCreated, VideoInfo logger = getLogger(__name__) -class KyooClient: +class KyooClient(metaclass=Singleton): def __init__(self) -> None: api_key = os.environ.get("KYOO_APIKEY") if not api_key: diff --git a/scanner/scanner/fsscan.py b/scanner/scanner/fsscan.py index c2e4c289..1a1fea2a 100644 --- a/scanner/scanner/fsscan.py +++ b/scanner/scanner/fsscan.py @@ -20,8 +20,8 @@ logger = getLogger(__name__) class Scanner: def __init__( self, - client: Annotated[KyooClient, Depends], - requests: Annotated[RequestCreator, Depends], + client: Annotated[KyooClient, Depends(KyooClient)], + requests: Annotated[RequestCreator, Depends(RequestCreator)], ): self._client = client self._requests = requests diff --git a/scanner/scanner/providers/themoviedatabase.py b/scanner/scanner/providers/themoviedatabase.py index 6c7a71f9..d3de61ca 100644 --- a/scanner/scanner/providers/themoviedatabase.py +++ b/scanner/scanner/providers/themoviedatabase.py @@ -19,13 +19,13 @@ from ..models.season import Season, SeasonTranslation from ..models.serie import SearchSerie, Serie, SerieStatus, SerieTranslation from ..models.staff import Character, Person, Role, Staff from ..models.studio import Studio, StudioTranslation -from ..utils import clean, to_slug +from ..utils import Singleton, clean, to_slug from .provider import Provider, ProviderError logger = getLogger(__name__) -class TheMovieDatabase(Provider): +class TheMovieDatabase(Provider, metaclass=Singleton): THEMOVIEDB_API_ACCESS_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjOWYzMjhhMDEwMTFiMjhmMjI0ODM3MTczOTVmYzNmYSIsIm5iZiI6MTU4MTYzMTExOS44NjgsInN1YiI6IjVlNDVjNjhmODNlZTY3MDAxMTFmMmU5NiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.CeXrQwgB3roCAVs-Z2ayLRx99VIJbym7XSpcRjGzyLA" def __init__(self) -> None: diff --git a/scanner/scanner/requests.py b/scanner/scanner/requests.py index e607692b..ee348682 100644 --- a/scanner/scanner/requests.py +++ b/scanner/scanner/requests.py @@ -6,7 +6,7 @@ from typing import Annotated, Literal from asyncpg import Connection from fastapi import Depends -from pydantic import Field +from pydantic import Field, TypeAdapter from .client import KyooClient from .database import get_db @@ -46,7 +46,7 @@ class RequestCreator: do update set videos = videos || excluded.videos """, - (x.model_dump() for x in requests), + TypeAdapter(list[Request]).dump_python(requests), ) _ = await self._database.execute("notify scanner.requests") diff --git a/scanner/scanner/routers/routes.py b/scanner/scanner/routers/routes.py index eed3cfc5..6354e0df 100644 --- a/scanner/scanner/routers/routes.py +++ b/scanner/scanner/routers/routes.py @@ -12,10 +12,11 @@ router = APIRouter() "/scan", status_code=204, response_description="Scan started.", + response_model=None, ) async def trigger_scan( tasks: BackgroundTasks, - # scanner: Annotated[Scanner, Depends], + scanner: Annotated[Scanner, Depends(Scanner)], _: Annotated[None, Security(validate_bearer, scopes=["scanner.trigger"])], ): """ diff --git a/scanner/scanner/utils.py b/scanner/scanner/utils.py index 0f015497..8cf6f9e3 100644 --- a/scanner/scanner/utils.py +++ b/scanner/scanner/utils.py @@ -1,4 +1,5 @@ -from typing import Annotated, Any, Callable +from abc import ABC, ABCMeta +from typing import Annotated, Any, Callable, override from langcodes import Language as BaseLanguage from pydantic import AliasGenerator, BaseModel, ConfigDict, GetJsonSchemaHandler @@ -15,6 +16,16 @@ def clean(val: str) -> str | None: return val or None +class Singleton(ABCMeta, type): + _instances = {} + + @override + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + class Model(BaseModel): model_config = ConfigDict( use_enum_values=True,