From fb4a26ba24252baec38044a619fc07929c904c45 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:25:31 +0100 Subject: [PATCH 01/10] renaming directory --- .devcontainer/Dockerfile | 15 --------- .devcontainer/devcontainer.json | 31 ------------------- .gitignore | 4 +-- .../src/auth/__init__.py | 9 +++--- {MediaManager => backend}/src/auth/oidc.py | 0 .../src/auth/password.py | 17 +++++----- .../src/database/torrents.py | 0 {MediaManager => backend}/src/database/tv.py | 0 .../src/database/users.py | 0 .../src/dowloadClients/__init__.py | 0 .../dowloadClients/genericDownloadClient.py | 0 .../src/dowloadClients/qbittorrent.py | 0 .../src/indexer/__init__.py | 0 .../src/indexer/generic.py | 0 .../src/indexer/prowlarr.py | 0 {MediaManager => backend}/src/main.py | 0 .../src/metadataProvider/__init__.py | 0 .../abstractMetaDataProvider.py | 0 .../src/metadataProvider/tmdb.py | 0 {MediaManager => backend}/src/ml/__init__.py | 4 +-- {MediaManager => backend}/src/ml/_testing.py | 5 ++- .../src/ml/test__init__.py | 0 .../src/requirements.txt | 0 .../src/routers/__init__.py | 0 .../src/routers/users.py | 11 +++---- {MediaManager => backend}/src/tv/__init__.py | 0 {MediaManager => backend}/src/tv/router.py | 0 27 files changed, 22 insertions(+), 74 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/devcontainer.json rename {MediaManager => backend}/src/auth/__init__.py (90%) rename {MediaManager => backend}/src/auth/oidc.py (100%) rename {MediaManager => backend}/src/auth/password.py (77%) rename {MediaManager => backend}/src/database/torrents.py (100%) rename {MediaManager => backend}/src/database/tv.py (100%) rename {MediaManager => backend}/src/database/users.py (100%) rename {MediaManager => backend}/src/dowloadClients/__init__.py (100%) rename {MediaManager => backend}/src/dowloadClients/genericDownloadClient.py (100%) rename {MediaManager => backend}/src/dowloadClients/qbittorrent.py (100%) rename {MediaManager => backend}/src/indexer/__init__.py (100%) rename {MediaManager => backend}/src/indexer/generic.py (100%) rename {MediaManager => backend}/src/indexer/prowlarr.py (100%) rename {MediaManager => backend}/src/main.py (100%) rename {MediaManager => backend}/src/metadataProvider/__init__.py (100%) rename {MediaManager => backend}/src/metadataProvider/abstractMetaDataProvider.py (100%) rename {MediaManager => backend}/src/metadataProvider/tmdb.py (100%) rename {MediaManager => backend}/src/ml/__init__.py (97%) rename {MediaManager => backend}/src/ml/_testing.py (94%) rename {MediaManager => backend}/src/ml/test__init__.py (100%) rename {MediaManager => backend}/src/requirements.txt (100%) rename {MediaManager => backend}/src/routers/__init__.py (100%) rename {MediaManager => backend}/src/routers/users.py (83%) rename {MediaManager => backend}/src/tv/__init__.py (100%) rename {MediaManager => backend}/src/tv/router.py (100%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 9340893..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM mcr.microsoft.com/devcontainers/python:1-3.11-bullseye - -ENV PYTHONUNBUFFERED 1 - -# [Optional] If your requirements rarely change, uncomment this section to add them to the image. -# COPY requirements.txt /tmp/pip-tmp/ -# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \ -# && rm -rf /tmp/pip-tmp - -# [Optional] Uncomment this section to install additional OS packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends - - - diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 516f8b4..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,31 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/postgres -{ - "name": "Python 3 & PostgreSQL", - "dockerComposeFile": "./docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // This can be used to network with other containers or the host. - // "forwardPorts": [5000, 5432], - - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "pip install --user -r ./MediaManager/src/requirements.txt", - - // Configure tool-specific properties. - "customizations" : { - "jetbrains" : { - "settings": { - "com.intellij:app:HttpConfigurable.use_proxy_pac": true - }, - "backend" : "PyCharm" - } - }, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} diff --git a/.gitignore b/.gitignore index bfd1cf9..71a0421 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .idea venv MediaManager.iml -MediaManager/res -MediaManager/res/.env +backend/res +backend/res/.env docker-compose.yml \ No newline at end of file diff --git a/MediaManager/src/auth/__init__.py b/backend/src/auth/__init__.py similarity index 90% rename from MediaManager/src/auth/__init__.py rename to backend/src/auth/__init__.py index dd2ec28..ee42b32 100644 --- a/MediaManager/src/auth/__init__.py +++ b/backend/src/auth/__init__.py @@ -2,7 +2,7 @@ import logging from datetime import datetime, timedelta, timezone import jwt -from fastapi import Depends, HTTPException, status, APIRouter +from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jwt.exceptions import InvalidTokenError from pydantic import BaseModel @@ -12,7 +12,6 @@ from database import SessionDependency from database.users import User - class Token(BaseModel): access_token: str token_type: str @@ -42,7 +41,7 @@ async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_sc payload = jwt.decode(token, config.jwt_signing_key, algorithms=[config.jwt_signing_algorithm]) log.debug("jwt payload: " + payload.__str__()) user_uid: str = payload.get("sub") - log.debug("jwt payload sub (user uid): " + user_uid) + log.debug("jwt payload sub (USER uid): " + user_uid) if user_uid is None: raise credentials_exception token_data = TokenData(uid=user_uid) @@ -53,10 +52,10 @@ async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_sc user: User | None = db.get(User, token_data.uid) if user is None: - log.debug("user not found") + log.debug("USER not found") raise credentials_exception - log.debug("received user: " + user.__str__()) + log.debug("received USER: " + user.__str__()) return user diff --git a/MediaManager/src/auth/oidc.py b/backend/src/auth/oidc.py similarity index 100% rename from MediaManager/src/auth/oidc.py rename to backend/src/auth/oidc.py diff --git a/MediaManager/src/auth/password.py b/backend/src/auth/password.py similarity index 77% rename from MediaManager/src/auth/password.py rename to backend/src/auth/password.py index 3aea110..673751f 100644 --- a/MediaManager/src/auth/password.py +++ b/backend/src/auth/password.py @@ -1,15 +1,12 @@ from typing import Annotated -import hashlib - import bcrypt from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm -from sqlmodel import Session, select +from sqlmodel import select -import database -from auth import create_access_token, Token, router -from database import users, SessionDependency +from auth import Token, create_access_token, router +from database import SessionDependency from database.users import User @@ -27,9 +24,9 @@ def get_password_hash(password: str) -> str: def authenticate_user(db: SessionDependency, email: str, password: str) -> bool | User: """ - :param email: email of the user - :param password: password of the user - :return: if authentication succeeds, returns the user object with added name and lastname, otherwise or if the user doesn't exist returns False + :param email: email of the USER + :param password: PASSWORD of the USER + :return: if authentication succeeds, returns the USER object with added name and lastname, otherwise or if the USER doesn't exist returns False """ user: User | None = db.exec(select(User).where(User.email == email)).first() if not user: @@ -48,7 +45,7 @@ async def login_for_access_token( if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect email or password", + detail="Incorrect email or PASSWORD", headers={"WWW-Authenticate": "Bearer"}, ) # id needs to be converted because a UUID object isn't json serializable diff --git a/MediaManager/src/database/torrents.py b/backend/src/database/torrents.py similarity index 100% rename from MediaManager/src/database/torrents.py rename to backend/src/database/torrents.py diff --git a/MediaManager/src/database/tv.py b/backend/src/database/tv.py similarity index 100% rename from MediaManager/src/database/tv.py rename to backend/src/database/tv.py diff --git a/MediaManager/src/database/users.py b/backend/src/database/users.py similarity index 100% rename from MediaManager/src/database/users.py rename to backend/src/database/users.py diff --git a/MediaManager/src/dowloadClients/__init__.py b/backend/src/dowloadClients/__init__.py similarity index 100% rename from MediaManager/src/dowloadClients/__init__.py rename to backend/src/dowloadClients/__init__.py diff --git a/MediaManager/src/dowloadClients/genericDownloadClient.py b/backend/src/dowloadClients/genericDownloadClient.py similarity index 100% rename from MediaManager/src/dowloadClients/genericDownloadClient.py rename to backend/src/dowloadClients/genericDownloadClient.py diff --git a/MediaManager/src/dowloadClients/qbittorrent.py b/backend/src/dowloadClients/qbittorrent.py similarity index 100% rename from MediaManager/src/dowloadClients/qbittorrent.py rename to backend/src/dowloadClients/qbittorrent.py diff --git a/MediaManager/src/indexer/__init__.py b/backend/src/indexer/__init__.py similarity index 100% rename from MediaManager/src/indexer/__init__.py rename to backend/src/indexer/__init__.py diff --git a/MediaManager/src/indexer/generic.py b/backend/src/indexer/generic.py similarity index 100% rename from MediaManager/src/indexer/generic.py rename to backend/src/indexer/generic.py diff --git a/MediaManager/src/indexer/prowlarr.py b/backend/src/indexer/prowlarr.py similarity index 100% rename from MediaManager/src/indexer/prowlarr.py rename to backend/src/indexer/prowlarr.py diff --git a/MediaManager/src/main.py b/backend/src/main.py similarity index 100% rename from MediaManager/src/main.py rename to backend/src/main.py diff --git a/MediaManager/src/metadataProvider/__init__.py b/backend/src/metadataProvider/__init__.py similarity index 100% rename from MediaManager/src/metadataProvider/__init__.py rename to backend/src/metadataProvider/__init__.py diff --git a/MediaManager/src/metadataProvider/abstractMetaDataProvider.py b/backend/src/metadataProvider/abstractMetaDataProvider.py similarity index 100% rename from MediaManager/src/metadataProvider/abstractMetaDataProvider.py rename to backend/src/metadataProvider/abstractMetaDataProvider.py diff --git a/MediaManager/src/metadataProvider/tmdb.py b/backend/src/metadataProvider/tmdb.py similarity index 100% rename from MediaManager/src/metadataProvider/tmdb.py rename to backend/src/metadataProvider/tmdb.py diff --git a/MediaManager/src/ml/__init__.py b/backend/src/ml/__init__.py similarity index 97% rename from MediaManager/src/ml/__init__.py rename to backend/src/ml/__init__.py index 3d6aa68..8e9a6dc 100644 --- a/MediaManager/src/ml/__init__.py +++ b/backend/src/ml/__init__.py @@ -26,7 +26,7 @@ def get_season(nfo: str) -> int | None: format=NFO.model_json_schema(), messages=[ { - 'role': 'user', + 'role': 'USER', 'content': "Tell me which season the torrent with this description contains?" + " output a season number in json format, the season number is an integer" + @@ -58,7 +58,7 @@ def contains_season(season_number: int, string_to_analyze: str) -> bool: format=Contains.model_json_schema(), messages=[ { - 'role': 'user', + 'role': 'USER', 'content': "Does this torrent contain the season " + season_number.__str__() + " ?" + " output a boolean json format" + diff --git a/MediaManager/src/ml/_testing.py b/backend/src/ml/_testing.py similarity index 94% rename from MediaManager/src/ml/_testing.py rename to backend/src/ml/_testing.py index d120c35..b1e012d 100644 --- a/MediaManager/src/ml/_testing.py +++ b/backend/src/ml/_testing.py @@ -1,8 +1,7 @@ import json from datetime import datetime, timedelta -from ollama import ChatResponse -from ollama import chat +from ollama import ChatResponse, chat from pydantic import BaseModel @@ -19,7 +18,7 @@ while start_time > datetime.now(): format=NFO.model_json_schema() , messages=[ { - 'role': 'user', + 'role': 'USER', 'content': "which season does a torrent with the following NFO contain? output the season number, which is an integer in json please\n" + "The.Big.Bang.Theory.(2007).Season.9.S09.(1080p.BluRay.x265.HEVC.10bit.AAC.5.1.Vyndros)" diff --git a/MediaManager/src/ml/test__init__.py b/backend/src/ml/test__init__.py similarity index 100% rename from MediaManager/src/ml/test__init__.py rename to backend/src/ml/test__init__.py diff --git a/MediaManager/src/requirements.txt b/backend/src/requirements.txt similarity index 100% rename from MediaManager/src/requirements.txt rename to backend/src/requirements.txt diff --git a/MediaManager/src/routers/__init__.py b/backend/src/routers/__init__.py similarity index 100% rename from MediaManager/src/routers/__init__.py rename to backend/src/routers/__init__.py diff --git a/MediaManager/src/routers/users.py b/backend/src/routers/users.py similarity index 83% rename from MediaManager/src/routers/users.py rename to backend/src/routers/users.py index c276fe0..b9e1adc 100644 --- a/MediaManager/src/routers/users.py +++ b/backend/src/routers/users.py @@ -1,12 +1,11 @@ -from fastapi import APIRouter -from fastapi import Depends -from sqlalchemy.exc import IntegrityError +from fastapi import APIRouter, Depends from pydantic import BaseModel +from sqlalchemy.exc import IntegrityError from starlette.responses import JSONResponse from auth import get_current_user from auth.password import get_password_hash -from database import SessionDependency, get_session +from database import SessionDependency from database.users import User, UserCreate, UserPublic from routers import log @@ -35,9 +34,9 @@ async def create_user( db.commit() except IntegrityError as e: log.debug(e) - log.warning("Failed to create new user, User with this email already exists "+internal_user.model_dump().__str__()) + log.warning("Failed to create new USER, User with this email already exists " + internal_user.model_dump().__str__()) return JSONResponse(status_code=409, content={"message": "User with this email already exists"}) - log.info("Created new user "+internal_user.email) + log.info("Created new USER " + internal_user.email) return UserPublic(**internal_user.model_dump()) diff --git a/MediaManager/src/tv/__init__.py b/backend/src/tv/__init__.py similarity index 100% rename from MediaManager/src/tv/__init__.py rename to backend/src/tv/__init__.py diff --git a/MediaManager/src/tv/router.py b/backend/src/tv/router.py similarity index 100% rename from MediaManager/src/tv/router.py rename to backend/src/tv/router.py From 6f57e744e3e3c4916581405d3ab0b4edd7b38484 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:25:56 +0100 Subject: [PATCH 02/10] moving DbConfig Class --- {MediaManager => backend}/src/config/__init__.py | 12 ------------ {MediaManager => backend}/src/database/__init__.py | 9 ++++----- backend/src/database/config.py | 10 ++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) rename {MediaManager => backend}/src/config/__init__.py (78%) rename {MediaManager => backend}/src/database/__init__.py (66%) create mode 100644 backend/src/database/config.py diff --git a/MediaManager/src/config/__init__.py b/backend/src/config/__init__.py similarity index 78% rename from MediaManager/src/config/__init__.py rename to backend/src/config/__init__.py index 026be66..9ebeeac 100644 --- a/MediaManager/src/config/__init__.py +++ b/backend/src/config/__init__.py @@ -4,18 +4,6 @@ from typing import Literal from pydantic import BaseModel -class DbConfig(BaseModel): - host: str = os.getenv("DB_HOST") or "localhost" - port: int = int(os.getenv("DB_PORT") or 5432) - user: str = os.getenv("DB_USERNAME") or "MediaManager" - _password: str = os.getenv("DB_PASSWORD") or "MediaManager" - dbname: str = os.getenv("DB_NAME") or "MediaManager" - - @property - def password(self): - return self._password - - class TmdbConfig(BaseModel): api_key: str = os.getenv("TMDB_API_KEY") or None diff --git a/MediaManager/src/database/__init__.py b/backend/src/database/__init__.py similarity index 66% rename from MediaManager/src/database/__init__.py rename to backend/src/database/__init__.py index e591513..93eb361 100644 --- a/MediaManager/src/database/__init__.py +++ b/backend/src/database/__init__.py @@ -4,14 +4,13 @@ from typing import Annotated, Any, Generator from fastapi import Depends from sqlmodel import SQLModel, Session, create_engine -import config -from config import DbConfig +from database.config import DbConfig log = logging.getLogger(__name__) -config: DbConfig = config.get_db_config() +config = DbConfig() -db_url = "postgresql+psycopg" + "://" + config.user + ":" + config.password + "@" + config.host + ":" + str( - config.port) + "/" + config.dbname +db_url = "postgresql+psycopg" + "://" + config.USER + ":" + config.PASSWORD + "@" + config.HOST + ":" + str( + config.PORT) + "/" + config.DBNAME engine = create_engine(db_url, echo=False) diff --git a/backend/src/database/config.py b/backend/src/database/config.py new file mode 100644 index 0000000..7e00808 --- /dev/null +++ b/backend/src/database/config.py @@ -0,0 +1,10 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class DbConfig(BaseSettings): + model_config = SettingsConfigDict(env_prefix='DB') + HOST: str = "localhost" + PORT: int = 5432 + USER: str = "MediaManager" + PASSWORD: str = "MediaManager" + DBNAME: str = "MediaManager" From 8408cc77ad7b090bf427389ef42dce04e0e2799b Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:32:06 +0100 Subject: [PATCH 03/10] moving TmdbConfig Class --- backend/src/config/__init__.py | 4 ---- backend/src/metadataProvider/tmdb.py | 14 ++++++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/backend/src/config/__init__.py b/backend/src/config/__init__.py index 9ebeeac..c40179c 100644 --- a/backend/src/config/__init__.py +++ b/backend/src/config/__init__.py @@ -4,10 +4,6 @@ from typing import Literal from pydantic import BaseModel -class TmdbConfig(BaseModel): - api_key: str = os.getenv("TMDB_API_KEY") or None - - class BasicConfig(BaseModel): storage_directory: str = os.getenv("STORAGE_FILE_PATH") or "." diff --git a/backend/src/metadataProvider/tmdb.py b/backend/src/metadataProvider/tmdb.py index 8a94e97..3f39427 100644 --- a/backend/src/metadataProvider/tmdb.py +++ b/backend/src/metadataProvider/tmdb.py @@ -3,18 +3,24 @@ import mimetypes import requests import tmdbsimple +from pydantic_settings import BaseSettings from tmdbsimple import TV, TV_Seasons -import config from database.tv import Episode, Season, Show from metadataProvider.abstractMetaDataProvider import MetadataProvider, register_metadata_provider -config = config.TmdbConfig() + +class TmdbConfig(BaseSettings): + TMDB_API_KEY: str | None = None + + +config = TmdbConfig log = logging.getLogger(__name__) class TmdbMetadataProvider(MetadataProvider): name = "tmdb" + def get_show_metadata(self, id: int = None) -> Show: """ @@ -86,6 +92,6 @@ class TmdbMetadataProvider(MetadataProvider): tmdbsimple.API_KEY = api_key -if config.api_key is not None: +if config.TMDB_API_KEY is not None: log.info("Registering TMDB as metadata provider") - register_metadata_provider(metadata_provider=TmdbMetadataProvider(config.api_key)) + register_metadata_provider(metadata_provider=TmdbMetadataProvider(config.TMDB_API_KEY)) From 450514f549ed9c6d90f67efa18e4818a17eb48c7 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:36:06 +0100 Subject: [PATCH 04/10] moving AuthConfig Class --- backend/src/auth/__init__.py | 6 +++--- backend/src/auth/config.py | 13 +++++++++++++ backend/src/config/__init__.py | 15 +-------------- 3 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 backend/src/auth/config.py diff --git a/backend/src/auth/__init__.py b/backend/src/auth/__init__.py index ee42b32..8c941e4 100644 --- a/backend/src/auth/__init__.py +++ b/backend/src/auth/__init__.py @@ -7,7 +7,7 @@ from fastapi.security import OAuth2PasswordBearer from jwt.exceptions import InvalidTokenError from pydantic import BaseModel -from config import AuthConfig +from auth.config import AuthConfig from database import SessionDependency from database.users import User @@ -34,11 +34,11 @@ async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_sc detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) - config = AuthConfig() + auth_config = AuthConfig log.debug("token: " + token) try: - payload = jwt.decode(token, config.jwt_signing_key, algorithms=[config.jwt_signing_algorithm]) + payload = jwt.decode(token, auth_config.jwt_signing_key, algorithms=[auth_config.jwt_signing_algorithm]) log.debug("jwt payload: " + payload.__str__()) user_uid: str = payload.get("sub") log.debug("jwt payload sub (USER uid): " + user_uid) diff --git a/backend/src/auth/config.py b/backend/src/auth/config.py new file mode 100644 index 0000000..553f998 --- /dev/null +++ b/backend/src/auth/config.py @@ -0,0 +1,13 @@ +from pydantic_settings import BaseSettings + + +class AuthConfig(BaseSettings): + # to get a signing key run: + # openssl rand -hex 32 + jwt_signing_key: str + jwt_signing_algorithm: str = "HS256" + jwt_access_token_lifetime: int = 60 * 24 * 30 + + @property + def jwt_signing_key(self): + return self._jwt_signing_key diff --git a/backend/src/config/__init__.py b/backend/src/config/__init__.py index c40179c..6adda15 100644 --- a/backend/src/config/__init__.py +++ b/backend/src/config/__init__.py @@ -13,16 +13,7 @@ class ProwlarrConfig(BaseModel): url: str = os.getenv("PROWLARR_URL") -class AuthConfig(BaseModel): - # to get a signing key run: - # openssl rand -hex 32 - _jwt_signing_key: str = os.getenv("JWT_SIGNING_KEY") - jwt_signing_algorithm: str = "HS256" - jwt_access_token_lifetime: int = int(os.getenv("JWT_ACCESS_TOKEN_LIFETIME") or 60 * 24 * 30) - @property - def jwt_signing_key(self): - return self._jwt_signing_key class QbittorrentConfig(BaseModel): @@ -37,8 +28,4 @@ class DownloadClientConfig(BaseModel): class MachineLearningConfig(BaseModel): - model_name: str = os.getenv("OLLAMA_MODEL_NAME") or "qwen2.5:0.5b" - - -def get_db_config() -> DbConfig: - return DbConfig() + model_name: str = os.getenv("OLLAMA_MODEL_NAME") or "qwen2.5:0.5b" \ No newline at end of file From 89f53040edf314d7f1b2547386bbb89648119895 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:44:14 +0100 Subject: [PATCH 05/10] refactor download client class --- backend/src/config/__init__.py | 9 --------- backend/src/dowloadClients/__init__.py | 6 +++--- backend/src/dowloadClients/config.py | 5 +++++ backend/src/dowloadClients/qbittorrent.py | 10 +++++++++- 4 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 backend/src/dowloadClients/config.py diff --git a/backend/src/config/__init__.py b/backend/src/config/__init__.py index 6adda15..c4f0716 100644 --- a/backend/src/config/__init__.py +++ b/backend/src/config/__init__.py @@ -1,5 +1,4 @@ import os -from typing import Literal from pydantic import BaseModel @@ -16,16 +15,8 @@ class ProwlarrConfig(BaseModel): -class QbittorrentConfig(BaseModel): - host: str = os.getenv("QBITTORRENT_HOST") or "localhost" - port: int = os.getenv("QBITTORRENT_PORT") or 8080 - username: str = os.getenv("QBITTORRENT_USERNAME") or "admin" - password: str = os.getenv("QBITTORRENT_PASSWORD") or "adminadmin" -class DownloadClientConfig(BaseModel): - client: Literal['qbit'] = os.getenv("DOWNLOAD_CLIENT") or "qbit" - class MachineLearningConfig(BaseModel): model_name: str = os.getenv("OLLAMA_MODEL_NAME") or "qwen2.5:0.5b" \ No newline at end of file diff --git a/backend/src/dowloadClients/__init__.py b/backend/src/dowloadClients/__init__.py index e31891a..3220a4f 100644 --- a/backend/src/dowloadClients/__init__.py +++ b/backend/src/dowloadClients/__init__.py @@ -1,10 +1,10 @@ -from config import DownloadClientConfig +from dowloadClients.config import DownloadClientConfig from dowloadClients.qbittorrent import QbittorrentClient config = DownloadClientConfig() # TODO: add more elif when implementing more download clients -if config.client == "qbit": +if config.download_client == "qbit": client = QbittorrentClient() else: - client = QbittorrentClient() + raise ValueError("Unknown download client") diff --git a/backend/src/dowloadClients/config.py b/backend/src/dowloadClients/config.py new file mode 100644 index 0000000..b3f3a51 --- /dev/null +++ b/backend/src/dowloadClients/config.py @@ -0,0 +1,5 @@ +from pydantic_settings import BaseSettings + + +class DownloadClientConfig(BaseSettings): + download_client: str = "qbit" diff --git a/backend/src/dowloadClients/qbittorrent.py b/backend/src/dowloadClients/qbittorrent.py index e730264..5ad90ee 100644 --- a/backend/src/dowloadClients/qbittorrent.py +++ b/backend/src/dowloadClients/qbittorrent.py @@ -1,13 +1,21 @@ import logging import qbittorrentapi +from pydantic_settings import BaseSettings, SettingsConfigDict -from config import QbittorrentConfig from database.torrents import Torrent from dowloadClients.genericDownloadClient import GenericDownloadClient log = logging.getLogger(__name__) + +class QbittorrentConfig(BaseSettings): + model_config = SettingsConfigDict(env_prefix='QBITTORRENT_') + host: str = "localhost" + port: int = 8080 + username: str = "admin" + + class QbittorrentClient(GenericDownloadClient): DOWNLOADING_STATE = ("allocating", "downloading", "metaDL", "pausedDL", "queuedDL", "stalledDL", "checkingDL", "forcedDL", "moving") From 9d3e6d6ebaff97af378e68430155eb087a22a898 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:14:31 +0100 Subject: [PATCH 06/10] refactor indexer module --- backend/src/config/__init__.py | 4 ---- backend/src/indexer/__init__.py | 4 ++-- backend/src/indexer/config.py | 8 ++++++++ backend/src/indexer/prowlarr.py | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 backend/src/indexer/config.py diff --git a/backend/src/config/__init__.py b/backend/src/config/__init__.py index c4f0716..1796724 100644 --- a/backend/src/config/__init__.py +++ b/backend/src/config/__init__.py @@ -6,10 +6,6 @@ from pydantic import BaseModel class BasicConfig(BaseModel): storage_directory: str = os.getenv("STORAGE_FILE_PATH") or "." -class ProwlarrConfig(BaseModel): - enabled: bool = bool(os.getenv("PROWLARR_ENABLED") or True) - api_key: str = os.getenv("PROWLARR_API_KEY") - url: str = os.getenv("PROWLARR_URL") diff --git a/backend/src/indexer/__init__.py b/backend/src/indexer/__init__.py index f1c6d9d..b4c4a11 100644 --- a/backend/src/indexer/__init__.py +++ b/backend/src/indexer/__init__.py @@ -1,7 +1,7 @@ import logging -import config from database.tv import Season +from indexer.config import ProwlarrConfig from indexer.generic import GenericIndexer, IndexerQueryResult from indexer.prowlarr import Prowlarr @@ -23,5 +23,5 @@ def search(query: str | Season) -> list[IndexerQueryResult]: indexers: list[GenericIndexer] = [] -if config.ProwlarrConfig().enabled: +if ProwlarrConfig.enabled: indexers.append(Prowlarr()) diff --git a/backend/src/indexer/config.py b/backend/src/indexer/config.py new file mode 100644 index 0000000..783d88a --- /dev/null +++ b/backend/src/indexer/config.py @@ -0,0 +1,8 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class ProwlarrConfig(BaseSettings): + model_config = SettingsConfigDict(env_prefix="PROWLARR_") + enabled: bool = True + api_key: str + url: str diff --git a/backend/src/indexer/prowlarr.py b/backend/src/indexer/prowlarr.py index 30f57bf..fb4b298 100644 --- a/backend/src/indexer/prowlarr.py +++ b/backend/src/indexer/prowlarr.py @@ -2,8 +2,8 @@ import logging import requests -from config import ProwlarrConfig from indexer import GenericIndexer, IndexerQueryResult +from indexer.config import ProwlarrConfig log = logging.getLogger(__name__) @@ -17,7 +17,7 @@ class Prowlarr(GenericIndexer): :param kwargs: Additional keyword arguments to pass to the superclass constructor. """ super().__init__(name='prowlarr') - config = ProwlarrConfig() + config = ProwlarrConfig self.api_key = config.api_key self.url = config.url From 7e1365479c8936bb2614368fda9cc5cc0cca1a74 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:56:18 +0100 Subject: [PATCH 07/10] refactor ml module --- backend/src/config.py | 5 +++++ backend/src/config/__init__.py | 18 ------------------ backend/src/ml/__init__.py | 9 +++++---- backend/src/ml/config.py | 5 +++++ 4 files changed, 15 insertions(+), 22 deletions(-) create mode 100644 backend/src/config.py delete mode 100644 backend/src/config/__init__.py create mode 100644 backend/src/ml/config.py diff --git a/backend/src/config.py b/backend/src/config.py new file mode 100644 index 0000000..405ed01 --- /dev/null +++ b/backend/src/config.py @@ -0,0 +1,5 @@ +from pydantic_settings import BaseSettings + + +class BasicConfig(BaseSettings): + storage_directory: str = "." diff --git a/backend/src/config/__init__.py b/backend/src/config/__init__.py deleted file mode 100644 index 1796724..0000000 --- a/backend/src/config/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from pydantic import BaseModel - - -class BasicConfig(BaseModel): - storage_directory: str = os.getenv("STORAGE_FILE_PATH") or "." - - - - - - - - - -class MachineLearningConfig(BaseModel): - model_name: str = os.getenv("OLLAMA_MODEL_NAME") or "qwen2.5:0.5b" \ No newline at end of file diff --git a/backend/src/ml/__init__.py b/backend/src/ml/__init__.py index 8e9a6dc..5cc938c 100644 --- a/backend/src/ml/__init__.py +++ b/backend/src/ml/__init__.py @@ -6,7 +6,7 @@ from typing import List from ollama import ChatResponse, chat from pydantic import BaseModel -import config +from ml.config import MachineLearningConfig class NFO(BaseModel): @@ -22,7 +22,7 @@ def get_season(nfo: str) -> int | None: for i in range(0, 5): responses.append(chat( - model=config.model_name, + model=config.ollama_model_name, format=NFO.model_json_schema(), messages=[ { @@ -54,7 +54,7 @@ def contains_season(season_number: int, string_to_analyze: str) -> bool: for i in range(0, 3): responses.append(chat( - model=config.model_name, + model=config.ollama_model_name, format=Contains.model_json_schema(), messages=[ { @@ -79,5 +79,6 @@ def contains_season(season_number: int, string_to_analyze: str) -> bool: log.debug(f"according to AI {string_to_analyze} contains season {season_number} {most_common[0][0]}") return most_common[0][0] -config = config.MachineLearningConfig() + +config = MachineLearningConfig log = logging.getLogger(__name__) diff --git a/backend/src/ml/config.py b/backend/src/ml/config.py new file mode 100644 index 0000000..804cfea --- /dev/null +++ b/backend/src/ml/config.py @@ -0,0 +1,5 @@ +from pydantic_settings import BaseSettings + + +class MachineLearningConfig(BaseSettings): + ollama_model_name: str = "qwen2.5:0.5b" From e00f0b5a54b3cf26c1649fdf27cbb1669771bc6d Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:38:41 +0100 Subject: [PATCH 08/10] cleanup code --- backend/src/auth/__init__.py | 2 +- backend/src/dowloadClients/__init__.py | 1 - backend/src/dowloadClients/genericDownloadClient.py | 1 - backend/src/main.py | 4 ++-- backend/src/metadataProvider/abstractMetaDataProvider.py | 4 ++-- backend/src/metadataProvider/tmdb.py | 4 ++-- backend/src/tv/router.py | 2 +- backend/src/{routers => users}/__init__.py | 0 backend/src/{routers/users.py => users/routers.py} | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) rename backend/src/{routers => users}/__init__.py (100%) rename backend/src/{routers/users.py => users/routers.py} (98%) diff --git a/backend/src/auth/__init__.py b/backend/src/auth/__init__.py index 8c941e4..565a0a8 100644 --- a/backend/src/auth/__init__.py +++ b/backend/src/auth/__init__.py @@ -61,7 +61,7 @@ async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_sc def create_access_token(data: dict, expires_delta: timedelta | None = None): to_encode = data.copy() - config = AuthConfig() + config = AuthConfig if expires_delta: expire = datetime.now(timezone.utc) + expires_delta else: diff --git a/backend/src/dowloadClients/__init__.py b/backend/src/dowloadClients/__init__.py index 3220a4f..16b1e0c 100644 --- a/backend/src/dowloadClients/__init__.py +++ b/backend/src/dowloadClients/__init__.py @@ -3,7 +3,6 @@ from dowloadClients.qbittorrent import QbittorrentClient config = DownloadClientConfig() -# TODO: add more elif when implementing more download clients if config.download_client == "qbit": client = QbittorrentClient() else: diff --git a/backend/src/dowloadClients/genericDownloadClient.py b/backend/src/dowloadClients/genericDownloadClient.py index e9580b7..a1211ac 100644 --- a/backend/src/dowloadClients/genericDownloadClient.py +++ b/backend/src/dowloadClients/genericDownloadClient.py @@ -9,7 +9,6 @@ class GenericDownloadClient(object): raise ValueError('name cannot be None') self.name = name - # TODO: change Torrents type to SeasonTorrents|MovieTorrents def download(self, torrent: TorrentMixin) -> TorrentMixin: """ downloads a torrent diff --git a/backend/src/main.py b/backend/src/main.py index 7fa9454..44e2111 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -14,7 +14,7 @@ from fastapi import FastAPI import database.users import tv.router from auth import password -from routers import users +from users import routers LOGGING_CONFIG = { "version": 1, @@ -44,7 +44,7 @@ dictConfig(LOGGING_CONFIG) database.init_db() app = FastAPI(root_path="/api/v1") -app.include_router(users.router, tags=["users"]) +app.include_router(routers.router, tags=["users"]) app.include_router(password.router, tags=["authentication"]) app.include_router(tv.router.router, tags=["tv"]) diff --git a/backend/src/metadataProvider/abstractMetaDataProvider.py b/backend/src/metadataProvider/abstractMetaDataProvider.py index 7a47c0a..862d89e 100644 --- a/backend/src/metadataProvider/abstractMetaDataProvider.py +++ b/backend/src/metadataProvider/abstractMetaDataProvider.py @@ -7,7 +7,7 @@ from database.tv import Show log = logging.getLogger(__name__) -class MetadataProvider(ABC): +class AbstractMetadataProvider(ABC): storage_path = config.BasicConfig().storage_directory @property @abstractmethod @@ -26,6 +26,6 @@ class MetadataProvider(ABC): metadata_providers = {} -def register_metadata_provider(metadata_provider: MetadataProvider): +def register_metadata_provider(metadata_provider: AbstractMetadataProvider): log.info("Registering metadata provider:" + metadata_provider.name) metadata_providers[metadata_provider.name] = metadata_provider diff --git a/backend/src/metadataProvider/tmdb.py b/backend/src/metadataProvider/tmdb.py index 3f39427..f3f4195 100644 --- a/backend/src/metadataProvider/tmdb.py +++ b/backend/src/metadataProvider/tmdb.py @@ -7,7 +7,7 @@ from pydantic_settings import BaseSettings from tmdbsimple import TV, TV_Seasons from database.tv import Episode, Season, Show -from metadataProvider.abstractMetaDataProvider import MetadataProvider, register_metadata_provider +from metadataProvider.abstractMetaDataProvider import AbstractMetadataProvider, register_metadata_provider class TmdbConfig(BaseSettings): @@ -18,7 +18,7 @@ config = TmdbConfig log = logging.getLogger(__name__) -class TmdbMetadataProvider(MetadataProvider): +class TmdbMetadataProvider(AbstractMetadataProvider): name = "tmdb" def get_show_metadata(self, id: int = None) -> Show: diff --git a/backend/src/tv/router.py b/backend/src/tv/router.py index f566e94..879d4e2 100644 --- a/backend/src/tv/router.py +++ b/backend/src/tv/router.py @@ -16,8 +16,8 @@ from database import SessionDependency from database.torrents import Torrent from database.tv import Season, Show from indexer import IndexerQueryResult -from routers.users import Message from tv import log +from users.routers import Message router = APIRouter( prefix="/tv", diff --git a/backend/src/routers/__init__.py b/backend/src/users/__init__.py similarity index 100% rename from backend/src/routers/__init__.py rename to backend/src/users/__init__.py diff --git a/backend/src/routers/users.py b/backend/src/users/routers.py similarity index 98% rename from backend/src/routers/users.py rename to backend/src/users/routers.py index b9e1adc..471d875 100644 --- a/backend/src/routers/users.py +++ b/backend/src/users/routers.py @@ -7,7 +7,7 @@ from auth import get_current_user from auth.password import get_password_hash from database import SessionDependency from database.users import User, UserCreate, UserPublic -from routers import log +from users import log router = APIRouter( prefix="/users", From 1a558361f45dab301d8ea4ed1b2c31e88f1e4816 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:45:30 +0100 Subject: [PATCH 09/10] cleanup code --- backend/src/auth/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/auth/__init__.py b/backend/src/auth/__init__.py index 565a0a8..ec6df94 100644 --- a/backend/src/auth/__init__.py +++ b/backend/src/auth/__init__.py @@ -61,11 +61,11 @@ async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_sc def create_access_token(data: dict, expires_delta: timedelta | None = None): to_encode = data.copy() - config = AuthConfig + auth_config = AuthConfig if expires_delta: expire = datetime.now(timezone.utc) + expires_delta else: - expire = datetime.now(timezone.utc) + timedelta(minutes=config.jwt_access_token_lifetime) + expire = datetime.now(timezone.utc) + timedelta(minutes=auth_config.jwt_access_token_lifetime) to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, config.jwt_signing_key, algorithm=config.jwt_signing_algorithm) + encoded_jwt = jwt.encode(to_encode, auth_config.jwt_signing_key, algorithm=auth_config.jwt_signing_algorithm) return encoded_jwt From 11c45a9d57c4bb12cbcf6667d3452e57d07cb311 Mon Sep 17 00:00:00 2001 From: maxDorninger <97409287+maxDorninger@users.noreply.github.com> Date: Fri, 28 Mar 2025 15:22:36 +0100 Subject: [PATCH 10/10] rename SessionDependency to DbSessionDependency --- backend/src/auth/__init__.py | 6 ++++-- backend/src/auth/password.py | 6 +++--- backend/src/database/__init__.py | 2 +- backend/src/indexer/generic.py | 1 + backend/src/tv/router.py | 20 ++++++++++---------- backend/src/users/routers.py | 4 ++-- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/backend/src/auth/__init__.py b/backend/src/auth/__init__.py index ec6df94..8b5520d 100644 --- a/backend/src/auth/__init__.py +++ b/backend/src/auth/__init__.py @@ -8,10 +8,12 @@ from jwt.exceptions import InvalidTokenError from pydantic import BaseModel from auth.config import AuthConfig -from database import SessionDependency +from database import DbSessionDependency from database.users import User +# TODO: evaluate FASTAPI-Users package + class Token(BaseModel): access_token: str token_type: str @@ -28,7 +30,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/token") router = APIRouter() -async def get_current_user(db: SessionDependency, token: str = Depends(oauth2_scheme)) -> User: +async def get_current_user(db: DbSessionDependency, token: str = Depends(oauth2_scheme)) -> User: credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", diff --git a/backend/src/auth/password.py b/backend/src/auth/password.py index 673751f..7e7537f 100644 --- a/backend/src/auth/password.py +++ b/backend/src/auth/password.py @@ -6,7 +6,7 @@ from fastapi.security import OAuth2PasswordRequestForm from sqlmodel import select from auth import Token, create_access_token, router -from database import SessionDependency +from database import DbSessionDependency from database.users import User @@ -21,7 +21,7 @@ def get_password_hash(password: str) -> str: return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") -def authenticate_user(db: SessionDependency, email: str, password: str) -> bool | User: +def authenticate_user(db: DbSessionDependency, email: str, password: str) -> bool | User: """ :param email: email of the USER @@ -39,7 +39,7 @@ def authenticate_user(db: SessionDependency, email: str, password: str) -> bool @router.post("/token") async def login_for_access_token( form_data: Annotated[OAuth2PasswordRequestForm, Depends()], - db: SessionDependency, + db: DbSessionDependency, ) -> Token: user = authenticate_user(db,form_data.username, form_data.password) if not user: diff --git a/backend/src/database/__init__.py b/backend/src/database/__init__.py index 93eb361..7ad61e9 100644 --- a/backend/src/database/__init__.py +++ b/backend/src/database/__init__.py @@ -23,5 +23,5 @@ def get_session() -> Generator[Session, Any, None]: with Session(engine) as session: yield session -SessionDependency = Annotated[Session, Depends(get_session)] +DbSessionDependency = Annotated[Session, Depends(get_session)] diff --git a/backend/src/indexer/generic.py b/backend/src/indexer/generic.py index 8eef87f..086fd93 100644 --- a/backend/src/indexer/generic.py +++ b/backend/src/indexer/generic.py @@ -7,6 +7,7 @@ from pydantic import BaseModel, computed_field from database.torrents import QualityMixin, Torrent +# TODO: use something like strategy pattern to make sorting more user customizable class IndexerQueryResult(BaseModel, QualityMixin): id: UUID = pydantic.Field(default_factory=uuid4) title: str diff --git a/backend/src/tv/router.py b/backend/src/tv/router.py index 879d4e2..dbd4396 100644 --- a/backend/src/tv/router.py +++ b/backend/src/tv/router.py @@ -12,7 +12,7 @@ import auth import dowloadClients import indexer import metadataProvider -from database import SessionDependency +from database import DbSessionDependency from database.torrents import Torrent from database.tv import Season, Show from indexer import IndexerQueryResult @@ -34,7 +34,7 @@ class ShowDetails(BaseModel): status.HTTP_201_CREATED: {"model": Show, "description": "Successfully created show"}, status.HTTP_409_CONFLICT: {"model": Message, "description": "Show already exists"}, }) -def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb", version: str = ""): +def add_show(db: DbSessionDependency, show_id: int, metadata_provider: str = "tmdb", version: str = ""): res = db.exec(select(Show). where(Show.external_id == show_id). where(Show.metadata_provider == metadata_provider). @@ -59,14 +59,14 @@ def add_show(db: SessionDependency, show_id: int, metadata_provider: str = "tmdb @router.delete("/{show_id}", status_code=status.HTTP_200_OK) -def delete_show(db: SessionDependency, show_id: UUID): +def delete_show(db: DbSessionDependency, show_id: UUID): db.delete(db.get(Show, show_id)) db.commit() @router.patch("/{show_id}/{season_id}", status_code=status.HTTP_200_OK, dependencies=[Depends(auth.get_current_user)], response_model=Season) -def add_season(db: SessionDependency, season_id: UUID): +def add_season(db: DbSessionDependency, season_id: UUID): """ adds requested flag to a season """ @@ -81,7 +81,7 @@ def add_season(db: SessionDependency, season_id: UUID): @router.delete("/{show_id}/{season_id}", status_code=status.HTTP_200_OK, dependencies=[Depends(auth.get_current_user)], response_model=Show) -def delete_season(db: SessionDependency, show_id: UUID, season: int): +def delete_season(db: DbSessionDependency, show_id: UUID, season: int): """ removes requested flag from a season """ @@ -96,7 +96,7 @@ def delete_season(db: SessionDependency, show_id: UUID, season: int): @router.get("/{show_id}/{season_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends( auth.get_current_user)], response_model=list[IndexerQueryResult]) -def get_season_torrents(db: SessionDependency, show_id: UUID, season_id: UUID): +def get_season_torrents(db: DbSessionDependency, show_id: UUID, season_id: UUID): season = db.get(Season, season_id) if season is None: @@ -121,7 +121,7 @@ def get_season_torrents(db: SessionDependency, show_id: UUID, season_id: UUID): @router.post("/{show_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends( auth.get_current_user)], response_model=list[Season]) -def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent_id: UUID): +def download_seasons_torrent(db: DbSessionDependency, show_id: UUID, torrent_id: UUID): """ downloads torrents for a show season, links the torrent for all seasons the torrent contains @@ -153,7 +153,7 @@ def download_seasons_torrent(db: SessionDependency, show_id: UUID, torrent_id: U @router.post("/{show_id}/{season_id}/torrent", status_code=status.HTTP_200_OK, dependencies=[Depends( auth.get_current_user)], response_model=list[Season]) -def delete_seasons_torrent(db: SessionDependency, show_id: UUID, season_id: UUID, torrent_id: UUID): +def delete_seasons_torrent(db: DbSessionDependency, show_id: UUID, season_id: UUID, torrent_id: UUID): """ downloads torrents for a season, links the torrent only to the specified season this means that multiple torrents can contain a season but you can choose from one which the content should be @@ -186,13 +186,13 @@ def delete_seasons_torrent(db: SessionDependency, show_id: UUID, season_id: UUID @router.get("/", dependencies=[Depends(auth.get_current_user)], response_model=list[Show]) -def get_shows(db: SessionDependency): +def get_shows(db: DbSessionDependency): """""" return db.exec(select(Show)).unique().fetchall() @router.get("/{show_id}", dependencies=[Depends(auth.get_current_user)], response_model=ShowDetails) -def get_show(db: SessionDependency, show_id: UUID): +def get_show(db: DbSessionDependency, show_id: UUID): """ :param show_id: diff --git a/backend/src/users/routers.py b/backend/src/users/routers.py index 471d875..8046f3b 100644 --- a/backend/src/users/routers.py +++ b/backend/src/users/routers.py @@ -5,7 +5,7 @@ from starlette.responses import JSONResponse from auth import get_current_user from auth.password import get_password_hash -from database import SessionDependency +from database import DbSessionDependency from database.users import User, UserCreate, UserPublic from users import log @@ -24,7 +24,7 @@ class Message(BaseModel): 201: {"model": UserPublic, "description": "User created successfully"} }) async def create_user( - db: SessionDependency, + db: DbSessionDependency, user: UserCreate = Depends(UserCreate), ): internal_user = User(name=user.name, lastname=user.lastname, email=user.email,