diff --git a/media_manager/auth/router.py b/media_manager/auth/router.py index 985d2d1..2e1e410 100644 --- a/media_manager/auth/router.py +++ b/media_manager/auth/router.py @@ -30,23 +30,22 @@ def get_openid_router(): is_verified_by_default=True, redirect_url=None, ) - else: - # this is there, so that the appropriate routes are created even if OIDC is not configured, - # e.g. for generating the frontend's openapi client - return get_oauth_router( - oauth_client=OAuth2( - client_id="mock", - client_secret="mock", # noqa: S106 - authorize_endpoint="https://example.com/authorize", - access_token_endpoint="https://example.com/token", # noqa: S106 - ), - backend=openid_cookie_auth_backend, - get_user_manager=fastapi_users.get_user_manager, - state_secret=SECRET, - associate_by_email=False, - is_verified_by_default=False, - redirect_url=None, - ) + # this is there, so that the appropriate routes are created even if OIDC is not configured, + # e.g. for generating the frontend's openapi client + return get_oauth_router( + oauth_client=OAuth2( + client_id="mock", + client_secret="mock", # noqa: S106 + authorize_endpoint="https://example.com/authorize", + access_token_endpoint="https://example.com/token", # noqa: S106 + ), + backend=openid_cookie_auth_backend, + get_user_manager=fastapi_users.get_user_manager, + state_secret=SECRET, + associate_by_email=False, + is_verified_by_default=False, + redirect_url=None, + ) openid_config = MediaManagerConfig().auth.openid_connect @@ -67,5 +66,4 @@ def get_all_users(db: DbSessionDependency) -> list[UserRead]: def get_auth_metadata() -> AuthMetadata: if openid_config.enabled: return AuthMetadata(oauth_providers=[openid_config.name]) - else: - return AuthMetadata(oauth_providers=[]) + return AuthMetadata(oauth_providers=[]) diff --git a/media_manager/database/__init__.py b/media_manager/database/__init__.py index e47d911..e69ea7e 100644 --- a/media_manager/database/__init__.py +++ b/media_manager/database/__init__.py @@ -23,21 +23,20 @@ def build_db_url( host: str, port: int | str, dbname: str, -) -> str: - db_url = URL.create( +) -> URL: + return URL.create( "postgresql+psycopg", user, password, host, - port, + int(port), dbname, ) - return db_url def init_engine( db_config: Any | None = None, - url: str | None = None, + url: str | URL | None = None, ) -> Engine: """ Initialize the global SQLAlchemy engine and session factory. diff --git a/media_manager/indexer/schemas.py b/media_manager/indexer/schemas.py index 8c4bbe0..0d28c55 100644 --- a/media_manager/indexer/schemas.py +++ b/media_manager/indexer/schemas.py @@ -40,11 +40,11 @@ class IndexerQueryResult(BaseModel): if re.search(high_quality_pattern, self.title, re.IGNORECASE): return Quality.uhd - elif re.search(medium_quality_pattern, self.title, re.IGNORECASE): + if re.search(medium_quality_pattern, self.title, re.IGNORECASE): return Quality.fullhd - elif re.search(low_quality_pattern, self.title, re.IGNORECASE): + if re.search(low_quality_pattern, self.title, re.IGNORECASE): return Quality.hd - elif re.search(very_low_quality_pattern, self.title, re.IGNORECASE): + if re.search(very_low_quality_pattern, self.title, re.IGNORECASE): return Quality.sd return Quality.unknown diff --git a/media_manager/metadataProvider/dependencies.py b/media_manager/metadataProvider/dependencies.py index 682e8f2..502d4a6 100644 --- a/media_manager/metadataProvider/dependencies.py +++ b/media_manager/metadataProvider/dependencies.py @@ -15,13 +15,12 @@ def get_metadata_provider( ) -> AbstractMetadataProvider: if metadata_provider == "tmdb": return TmdbMetadataProvider() - elif metadata_provider == "tvdb": + if metadata_provider == "tvdb": return TvdbMetadataProvider() - else: - raise HTTPException( - status_code=400, - detail=f"Invalid metadata provider: {metadata_provider}. Supported providers are 'tmdb' and 'tvdb'.", - ) + raise HTTPException( + status_code=400, + detail=f"Invalid metadata provider: {metadata_provider}. Supported providers are 'tmdb' and 'tvdb'.", + ) metadata_provider_dep = Annotated[ diff --git a/media_manager/metadataProvider/tmdb.py b/media_manager/metadataProvider/tmdb.py index 16c1c0f..0fe3477 100644 --- a/media_manager/metadataProvider/tmdb.py +++ b/media_manager/metadataProvider/tmdb.py @@ -301,7 +301,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider): show_metadata["first_air_date"] ) - show = Show( + return Show( external_id=show_id, name=show_metadata["name"], overview=show_metadata["overview"], @@ -313,8 +313,6 @@ class TmdbMetadataProvider(AbstractMetadataProvider): imdb_id=imdb_id, ) - return show - @override def search_show( self, query: str | None = None, max_pages: int = 5 @@ -332,8 +330,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider): if not result_page["results"]: break - else: - results.extend(result_page["results"]) + results.extend(result_page["results"]) formatted_results = [] for result in results: @@ -408,7 +405,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider): movie_metadata["release_date"] ) - movie = Movie( + return Movie( external_id=movie_id, name=movie_metadata["title"], overview=movie_metadata["overview"], @@ -418,8 +415,6 @@ class TmdbMetadataProvider(AbstractMetadataProvider): imdb_id=imdb_id, ) - return movie - @override def search_movie( self, query: str | None = None, max_pages: int = 5 @@ -437,8 +432,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider): if not result_page["results"]: break - else: - results.extend(result_page["results"]) + results.extend(result_page["results"]) formatted_results = [] for result in results: diff --git a/media_manager/metadataProvider/tvdb.py b/media_manager/metadataProvider/tvdb.py index b95b9eb..a3d100b 100644 --- a/media_manager/metadataProvider/tvdb.py +++ b/media_manager/metadataProvider/tvdb.py @@ -59,9 +59,8 @@ class TvdbMetadataProvider(AbstractMetadataProvider): ) log.debug("Successfully downloaded poster image for show " + show.name) return True - else: - log.warning(f"image for show {show.name} could not be downloaded") - return False + log.warning(f"image for show {show.name} could not be downloaded") + return False @override def get_show_metadata( @@ -112,15 +111,11 @@ class TvdbMetadataProvider(AbstractMetadataProvider): episodes=episodes, ) ) - try: - year = series["year"] - except KeyError: - year = None - show = Show( + return Show( name=series["name"], overview=series["overview"], - year=year, + year=series.get("year"), external_id=series["id"], metadata_provider=self.name, seasons=seasons, @@ -128,8 +123,6 @@ class TvdbMetadataProvider(AbstractMetadataProvider): imdb_id=imdb_id, ) - return show - @override def search_show( self, query: str | None = None @@ -160,35 +153,34 @@ class TvdbMetadataProvider(AbstractMetadataProvider): except Exception as e: log.warning(f"Error processing search result: {e}") return formatted_results - else: - results = self.__get_trending_tv() - formatted_results = [] - for result in results: - try: - if result["type"] == "series": - try: - year = result["year"] - except KeyError: - year = None + results = self.__get_trending_tv() + formatted_results = [] + for result in results: + try: + if result["type"] == "series": + try: + year = result["year"] + except KeyError: + year = None - formatted_results.append( - MetaDataProviderSearchResult( - poster_path="https://artworks.thetvdb.com" - + result.get("image") - if result.get("image") - else None, - overview=result.get("overview"), - name=result["name"], - external_id=result["id"], - year=year, - metadata_provider=self.name, - added=False, - vote_average=None, - ) + formatted_results.append( + MetaDataProviderSearchResult( + poster_path="https://artworks.thetvdb.com" + + result.get("image") + if result.get("image") + else None, + overview=result.get("overview"), + name=result["name"], + external_id=result["id"], + year=year, + metadata_provider=self.name, + added=False, + vote_average=None, ) - except Exception as e: - log.warning(f"Error processing search result: {e}") - return formatted_results + ) + except Exception as e: + log.warning(f"Error processing search result: {e}") + return formatted_results @override def search_movie( @@ -226,37 +218,35 @@ class TvdbMetadataProvider(AbstractMetadataProvider): except Exception as e: log.warning(f"Error processing search result: {e}") return formatted_results - else: - results = self.__get_trending_movies() - results = results[0:20] - log.debug(f"got {len(results)} results from TVDB search") - formatted_results = [] - for result in results: - result = self.__get_movie(result["id"]) + results = self.__get_trending_movies() + results = results[0:20] + log.debug(f"got {len(results)} results from TVDB search") + formatted_results = [] + for result in results: + result = self.__get_movie(result["id"]) + try: try: - try: - year = result["year"] - except KeyError: - year = None + year = result["year"] + except KeyError: + year = None - formatted_results.append( - MetaDataProviderSearchResult( - poster_path="https://artworks.thetvdb.com" - + result.get("image") - if result.get("image") - else None, - overview=result.get("overview"), - name=result["name"], - external_id=result["id"], - year=year, - metadata_provider=self.name, - added=False, - vote_average=None, - ) + formatted_results.append( + MetaDataProviderSearchResult( + poster_path="https://artworks.thetvdb.com" + result.get("image") + if result.get("image") + else None, + overview=result.get("overview"), + name=result["name"], + external_id=result["id"], + year=year, + metadata_provider=self.name, + added=False, + vote_average=None, ) - except Exception as e: - log.warning(f"Error processing search result: {e}") - return formatted_results + ) + except Exception as e: + log.warning(f"Error processing search result: {e}") + return formatted_results @override def download_movie_poster_image(self, movie: Movie) -> bool: @@ -270,9 +260,8 @@ class TvdbMetadataProvider(AbstractMetadataProvider): ) log.info("Successfully downloaded poster image for show " + movie.name) return True - else: - log.warning(f"image for show {movie.name} could not be downloaded") - return False + log.warning(f"image for show {movie.name} could not be downloaded") + return False @override def get_movie_metadata( @@ -294,7 +283,7 @@ class TvdbMetadataProvider(AbstractMetadataProvider): if remote_id.get("type") == 2: imdb_id = remote_id.get("id") - movie = Movie( + return Movie( name=movie["name"], overview="Overviews are not supported with TVDB", year=movie.get("year"), @@ -302,5 +291,3 @@ class TvdbMetadataProvider(AbstractMetadataProvider): metadata_provider=self.name, imdb_id=imdb_id, ) - - return movie diff --git a/media_manager/metadataProvider/utils.py b/media_manager/metadataProvider/utils.py index 0725434..bff3cbd 100644 --- a/media_manager/metadataProvider/utils.py +++ b/media_manager/metadataProvider/utils.py @@ -8,8 +8,7 @@ from PIL import Image def get_year_from_date(first_air_date: str | None) -> int | None: if first_air_date: return int(first_air_date.split("-")[0]) - else: - return None + return None def download_poster_image(storage_path: Path, poster_url: str, uuid: UUID) -> bool: @@ -23,5 +22,4 @@ def download_poster_image(storage_path: Path, poster_url: str, uuid: UUID) -> bo original_image.save(image_file_path.with_suffix(".avif"), quality=50) original_image.save(image_file_path.with_suffix(".webp"), quality=50) return True - else: - return False + return False diff --git a/media_manager/movies/repository.py b/media_manager/movies/repository.py index 053e992..f78e0cf 100644 --- a/media_manager/movies/repository.py +++ b/media_manager/movies/repository.py @@ -313,8 +313,7 @@ class MovieRepository: stmt = delete(MovieFile).where(MovieFile.torrent_id == torrent_id) result = self.db.execute(stmt) self.db.commit() - deleted_count = result.rowcount - return deleted_count + return result.rowcount except SQLAlchemyError as e: self.db.rollback() log.error( diff --git a/media_manager/movies/service.py b/media_manager/movies/service.py index 2531171..a309ed8 100644 --- a/media_manager/movies/service.py +++ b/media_manager/movies/service.py @@ -260,16 +260,13 @@ class MovieService: :return: A list of indexer query results. """ if search_query_override: - torrents = self.indexer_service.search( - query=search_query_override, is_tv=False - ) - return torrents - else: - torrents = self.indexer_service.search_movie(movie=movie) + return self.indexer_service.search(query=search_query_override, is_tv=False) - return evaluate_indexer_query_results( - is_tv=False, query_results=torrents, media=movie - ) + torrents = self.indexer_service.search_movie(movie=movie) + + return evaluate_indexer_query_results( + is_tv=False, query_results=torrents, media=movie + ) def get_all_movies(self) -> list[Movie]: """ @@ -320,7 +317,7 @@ class MovieService: """ results = metadata_provider.search_movie() - filtered_results = [ + return [ result for result in results if not self.check_if_movie_exists( @@ -328,8 +325,6 @@ class MovieService: ) ] - return filtered_results - def get_public_movie_by_id(self, movie: Movie) -> PublicMovie: """ Get a public movie from a Movie object. @@ -376,12 +371,11 @@ class MovieService: """ if movie_file.torrent_id is None: return True - else: - torrent_file = self.torrent_service.get_torrent_by_id( - torrent_id=movie_file.torrent_id - ) - if torrent_file.imported: - return True + torrent_file = self.torrent_service.get_torrent_by_id( + torrent_id=movie_file.torrent_id + ) + if torrent_file.imported: + return True return False def get_movie_by_external_id( diff --git a/media_manager/torrent/download_clients/qbittorrent.py b/media_manager/torrent/download_clients/qbittorrent.py index ebc1a77..538c3c5 100644 --- a/media_manager/torrent/download_clients/qbittorrent.py +++ b/media_manager/torrent/download_clients/qbittorrent.py @@ -153,19 +153,17 @@ class QbittorrentDownloadClient(AbstractDownloadClient): if not info: log.warning(f"No information found for torrent: {torrent.id}") return TorrentStatus.unknown - else: - state: str = info[0]["state"] + state: str = info[0]["state"] - if state in self.DOWNLOADING_STATE: - return TorrentStatus.downloading - elif state in self.FINISHED_STATE: - return TorrentStatus.finished - elif state in self.ERROR_STATE: - return TorrentStatus.error - elif state in self.UNKNOWN_STATE: - return TorrentStatus.unknown - else: - return TorrentStatus.error + if state in self.DOWNLOADING_STATE: + return TorrentStatus.downloading + if state in self.FINISHED_STATE: + return TorrentStatus.finished + if state in self.ERROR_STATE: + return TorrentStatus.error + if state in self.UNKNOWN_STATE: + return TorrentStatus.unknown + return TorrentStatus.error def pause_torrent(self, torrent: Torrent) -> None: """ diff --git a/media_manager/torrent/download_clients/sabnzbd.py b/media_manager/torrent/download_clients/sabnzbd.py index 86da2ae..af83c6f 100644 --- a/media_manager/torrent/download_clients/sabnzbd.py +++ b/media_manager/torrent/download_clients/sabnzbd.py @@ -139,9 +139,8 @@ class SabnzbdDownloadClient(AbstractDownloadClient): """ if sabnzbd_status in self.DOWNLOADING_STATE: return TorrentStatus.downloading - elif sabnzbd_status in self.FINISHED_STATE: + if sabnzbd_status in self.FINISHED_STATE: return TorrentStatus.finished - elif sabnzbd_status in self.ERROR_STATE: + if sabnzbd_status in self.ERROR_STATE: return TorrentStatus.error - else: - return TorrentStatus.unknown + return TorrentStatus.unknown diff --git a/media_manager/torrent/manager.py b/media_manager/torrent/manager.py index 0b6fc67..e76dad2 100644 --- a/media_manager/torrent/manager.py +++ b/media_manager/torrent/manager.py @@ -82,11 +82,10 @@ class DownloadManager: msg = "No usenet download client configured" raise RuntimeError(msg) return self._usenet_client - else: - if not self._torrent_client: - msg = "No torrent download client configured" - raise RuntimeError(msg) - return self._torrent_client + if not self._torrent_client: + msg = "No torrent download client configured" + raise RuntimeError(msg) + return self._torrent_client def download(self, indexer_result: IndexerQueryResult) -> Torrent: """ diff --git a/media_manager/torrent/utils.py b/media_manager/torrent/utils.py index 5e3587b..5ef54d5 100644 --- a/media_manager/torrent/utils.py +++ b/media_manager/torrent/utils.py @@ -151,8 +151,7 @@ def get_torrent_hash(torrent: IndexerQueryResult) -> str: session=requests.Session(), timeout=MediaManagerConfig().indexers.prowlarr.timeout_seconds, ) - torrent_hash = str(libtorrent.parse_magnet_uri(final_url).info_hash) - return torrent_hash + return str(libtorrent.parse_magnet_uri(final_url).info_hash) except Exception as e: log.error(f"Failed to download torrent file: {e}") raise @@ -184,9 +183,7 @@ def remove_special_characters(filename: str) -> str: sanitized = re.sub(r"([<>:\"/\\|?*])", "", filename) # Remove leading and trailing dots or spaces - sanitized = sanitized.strip(" .") - - return sanitized + return sanitized.strip(" .") def remove_special_chars_and_parentheses(title: str) -> str: @@ -210,8 +207,7 @@ def remove_special_chars_and_parentheses(title: str) -> str: sanitized = remove_special_characters(sanitized) # Collapse multiple whitespace characters and trim the result - sanitized = re.sub(r"\s+", " ", sanitized).strip() - return sanitized + return re.sub(r"\s+", " ", sanitized).strip() def get_importable_media_directories(path: Path) -> list[Path]: @@ -224,15 +220,13 @@ def get_importable_media_directories(path: Path) -> list[Path]: unfiltered_dirs = [d for d in path.glob("*") if d.is_dir()] - media_dirs = [ + return [ media_dir for media_dir in unfiltered_dirs if media_dir.absolute() not in library_paths and not media_dir.name.startswith(".") ] - return media_dirs - def extract_external_id_from_string(input_string: str) -> tuple[str | None, int | None]: """ diff --git a/media_manager/tv/repository.py b/media_manager/tv/repository.py index c9b0b50..c0529b3 100644 --- a/media_manager/tv/repository.py +++ b/media_manager/tv/repository.py @@ -123,8 +123,7 @@ class TvRepository: stmt = ( select(func.count()).select_from(Episode).join(Season).join(SeasonFile) ) - total_count = self.db.execute(stmt).scalar_one_or_none() - return total_count + return self.db.execute(stmt).scalar_one_or_none() except SQLAlchemyError as e: log.error( f"Database error while calculating downloaded episodes count: {e}" @@ -394,8 +393,7 @@ class TvRepository: stmt = delete(SeasonFile).where(SeasonFile.torrent_id == torrent_id) result = self.db.execute(stmt) self.db.commit() - deleted_count = result.rowcount - return deleted_count + return result.rowcount except SQLAlchemyError as e: self.db.rollback() log.error( diff --git a/media_manager/tv/router.py b/media_manager/tv/router.py index 6bc2490..914cf16 100644 --- a/media_manager/tv/router.py +++ b/media_manager/tv/router.py @@ -165,8 +165,7 @@ def get_shows_with_torrents(tv_service: tv_service_dep) -> list[RichShowTorrent] """ Get all shows that are associated with torrents. """ - result = tv_service.get_all_shows_with_torrents() - return result + return tv_service.get_all_shows_with_torrents() @router.get( @@ -369,14 +368,13 @@ def delete_season_request( tv_service.delete_season_request(season_request_id=request_id) log.info(f"User {user.id} deleted season request {request_id}.") return None - else: - log.warning( - f"User {user.id} tried to delete season request {request_id} but is not authorized." - ) - return HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Not authorized to delete this request", - ) + log.warning( + f"User {user.id} tried to delete season request {request_id} but is not authorized." + ) + return HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not authorized to delete this request", + ) # ----------------------------------------------------------------------------- diff --git a/media_manager/tv/service.py b/media_manager/tv/service.py index 01c7bd1..6f7978f 100644 --- a/media_manager/tv/service.py +++ b/media_manager/tv/service.py @@ -254,24 +254,19 @@ class TvService: """ if search_query_override: - torrents = self.indexer_service.search( - query=search_query_override, is_tv=True - ) - return torrents - else: - show = self.tv_repository.get_show_by_id(show_id=show_id) + return self.indexer_service.search(query=search_query_override, is_tv=True) - torrents = self.indexer_service.search_season( - show=show, season_number=season_number - ) + show = self.tv_repository.get_show_by_id(show_id=show_id) - results = [ - torrent for torrent in torrents if season_number in torrent.season - ] + torrents = self.indexer_service.search_season( + show=show, season_number=season_number + ) - return evaluate_indexer_query_results( - is_tv=True, query_results=results, media=show - ) + results = [torrent for torrent in torrents if season_number in torrent.season] + + return evaluate_indexer_query_results( + is_tv=True, query_results=results, media=show + ) def get_all_shows(self) -> list[Show]: """ @@ -321,7 +316,7 @@ class TvService: """ results = metadata_provider.search_show() - filtered_results = [ + return [ result for result in results if not self.check_if_show_exists( @@ -329,8 +324,6 @@ class TvService: ) ] - return filtered_results - def get_public_show_by_id(self, show: Show) -> PublicShow: """ Get a public show from a Show object. @@ -378,16 +371,15 @@ class TvService: """ if season_file.torrent_id is None: return True - else: - try: - torrent_file = self.torrent_service.get_torrent_by_id( - torrent_id=season_file.torrent_id - ) + try: + torrent_file = self.torrent_service.get_torrent_by_id( + torrent_id=season_file.torrent_id + ) - if torrent_file.imported: - return True - except RuntimeError as e: - log.error(f"Error retrieving torrent, error: {e}") + if torrent_file.imported: + return True + except RuntimeError as e: + log.error(f"Error retrieving torrent, error: {e}") return False def get_show_by_external_id( diff --git a/ruff.toml b/ruff.toml index 66b384b..848c14f 100644 --- a/ruff.toml +++ b/ruff.toml @@ -5,7 +5,7 @@ line-ending = "lf" quote-style = "double" [lint] -# to be enabled: ANN, BLE, C90, CPY, D, DOC, DTZ, FBT, G, PL, RET, RSE, SLF, SIM, TC, TRY, UP +# to be enabled: ANN, BLE, C90, CPY, D, DOC, DTZ, FBT, G, PL, RSE, SLF, SIM, TC, TRY, UP extend-select = [ "A", "ARG", "ASYNC", "B", @@ -18,7 +18,7 @@ extend-select = [ "N", "PERF", "PGH", "PIE", "PT", "PTH", "PYI", "Q", - "RUF", + "RET", "RUF", "S", "SLOT", "T10", "T20", "TD", "TID", "W",