mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-17 15:43:28 +02:00
This PR enables the ruff rule for return type annotations (ANN), and adds the ty package for type checking.
182 lines
6.5 KiB
Python
182 lines
6.5 KiB
Python
import logging
|
|
from dataclasses import dataclass
|
|
|
|
from requests import Response, Session
|
|
|
|
from media_manager.config import MediaManagerConfig
|
|
from media_manager.indexer.indexers.generic import GenericIndexer
|
|
from media_manager.indexer.indexers.torznab_mixin import TorznabMixin
|
|
from media_manager.indexer.schemas import IndexerQueryResult
|
|
from media_manager.movies.schemas import Movie
|
|
from media_manager.tv.schemas import Show
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass
|
|
class IndexerInfo:
|
|
id: int
|
|
name: str
|
|
|
|
supports_tv_search: bool
|
|
supports_tv_search_tmdb: bool
|
|
supports_tv_search_imdb: bool
|
|
supports_tv_search_tvdb: bool
|
|
supports_tv_search_season: bool
|
|
|
|
supports_movie_search: bool
|
|
supports_movie_search_tmdb: bool
|
|
supports_movie_search_imdb: bool
|
|
supports_movie_search_tvdb: bool
|
|
|
|
|
|
class Prowlarr(GenericIndexer, TorznabMixin):
|
|
def __init__(self) -> None:
|
|
"""
|
|
A subclass of GenericIndexer for interacting with the Prowlarr API.
|
|
"""
|
|
super().__init__(name="prowlarr")
|
|
self.config = MediaManagerConfig().indexers.prowlarr
|
|
|
|
def _call_prowlarr_api(self, path: str, parameters: dict | None = None) -> Response:
|
|
url = f"{self.config.url}/api/v1{path}"
|
|
headers = {"X-Api-Key": self.config.api_key}
|
|
with Session() as session:
|
|
return session.get(
|
|
url=url,
|
|
params=parameters,
|
|
timeout=self.config.timeout_seconds,
|
|
headers=headers,
|
|
)
|
|
|
|
def _newznab_search(
|
|
self, indexer: IndexerInfo, parameters: dict | None = None
|
|
) -> list[IndexerQueryResult]:
|
|
if parameters is None:
|
|
parameters = {}
|
|
|
|
parameters["limit"] = 10000
|
|
results = self._call_prowlarr_api(
|
|
path=f"/indexer/{indexer.id}/newznab", parameters=parameters
|
|
)
|
|
results = self.process_search_result(xml=results.content)
|
|
log.info(
|
|
f"Indexer {indexer.name} returned {len(results)} results for search: {parameters}"
|
|
)
|
|
return results
|
|
|
|
def _get_indexers(self) -> list[IndexerInfo]:
|
|
indexers = self._call_prowlarr_api(path="/indexer")
|
|
indexers = indexers.json()
|
|
indexer_info_list: list[IndexerInfo] = []
|
|
for indexer in indexers:
|
|
supports_tv_search = False
|
|
supports_movie_search = False
|
|
tv_search_params = []
|
|
movie_search_params = []
|
|
|
|
if not indexer["capabilities"].get("tvSearchParams"):
|
|
supports_tv_search = False
|
|
else:
|
|
supports_tv_search = True
|
|
tv_search_params = indexer["capabilities"]["tvSearchParams"]
|
|
|
|
if not indexer["capabilities"].get("movieSearchParams"):
|
|
supports_movie_search = False
|
|
else:
|
|
supports_movie_search = True
|
|
movie_search_params = indexer["capabilities"]["movieSearchParams"]
|
|
|
|
indexer_info = IndexerInfo(
|
|
id=indexer["id"],
|
|
name=indexer.get("name", "unknown"),
|
|
supports_tv_search=supports_tv_search,
|
|
supports_tv_search_tmdb="tmdbId" in tv_search_params,
|
|
supports_tv_search_imdb="imdbId" in tv_search_params,
|
|
supports_tv_search_tvdb="tvdbId" in tv_search_params,
|
|
supports_tv_search_season="season" in tv_search_params,
|
|
supports_movie_search=supports_movie_search,
|
|
supports_movie_search_tmdb="tmdbId" in movie_search_params,
|
|
supports_movie_search_imdb="imdbId" in movie_search_params,
|
|
supports_movie_search_tvdb="tvdbId" in movie_search_params,
|
|
)
|
|
indexer_info_list.append(indexer_info)
|
|
return indexer_info_list
|
|
|
|
def _get_tv_indexers(self) -> list[IndexerInfo]:
|
|
return [x for x in self._get_indexers() if x.supports_tv_search]
|
|
|
|
def _get_movie_indexers(self) -> list[IndexerInfo]:
|
|
return [x for x in self._get_indexers() if x.supports_movie_search]
|
|
|
|
def search(self, query: str, is_tv: bool) -> list[IndexerQueryResult]:
|
|
log.info(f"Searching for: {query}")
|
|
params = {
|
|
"q": query,
|
|
"t": "tvsearch" if is_tv else "movie",
|
|
}
|
|
raw_results = []
|
|
indexers = self._get_tv_indexers() if is_tv else self._get_movie_indexers()
|
|
|
|
for indexer in indexers:
|
|
raw_results.extend(self._newznab_search(parameters=params, indexer=indexer))
|
|
|
|
return raw_results
|
|
|
|
def search_season(
|
|
self, query: str, show: Show, season_number: int
|
|
) -> list[IndexerQueryResult]:
|
|
indexers = self._get_tv_indexers()
|
|
|
|
raw_results = []
|
|
|
|
for indexer in indexers:
|
|
log.debug("Preparing search for indexer: " + indexer.name)
|
|
search_params = {
|
|
"cat": "5000",
|
|
"q": query,
|
|
"t": "tvsearch",
|
|
}
|
|
|
|
if indexer.supports_tv_search_tmdb and show.metadata_provider == "tmdb":
|
|
search_params["tmdbid"] = show.external_id
|
|
if indexer.supports_tv_search_tvdb and show.metadata_provider == "tvdb":
|
|
search_params["tvdbid"] = show.external_id
|
|
if indexer.supports_tv_search_imdb:
|
|
search_params["imdbid"] = show.imdb_id
|
|
if indexer.supports_tv_search_season:
|
|
search_params["season"] = season_number
|
|
|
|
raw_results.extend(
|
|
self._newznab_search(parameters=search_params, indexer=indexer)
|
|
)
|
|
|
|
return raw_results
|
|
|
|
def search_movie(self, query: str, movie: Movie) -> list[IndexerQueryResult]:
|
|
indexers = self._get_movie_indexers()
|
|
|
|
raw_results = []
|
|
|
|
for indexer in indexers:
|
|
log.debug("Preparing search for indexer: " + indexer.name)
|
|
|
|
search_params = {
|
|
"cat": "2000",
|
|
"q": query,
|
|
"t": "movie",
|
|
}
|
|
|
|
if indexer.supports_movie_search_tmdb and movie.metadata_provider == "tmdb":
|
|
search_params["tmdbid"] = movie.external_id
|
|
if indexer.supports_movie_search_tvdb and movie.metadata_provider == "tvdb":
|
|
search_params["tvdbid"] = movie.external_id
|
|
if indexer.supports_movie_search_imdb:
|
|
search_params["imdbid"] = movie.imdb_id
|
|
|
|
raw_results.extend(
|
|
self._newznab_search(parameters=search_params, indexer=indexer)
|
|
)
|
|
|
|
return raw_results
|