Source code for pycliarr.api.radarr

from pathlib import Path
from typing import Any, Dict, List, Optional, Union, cast

from pycliarr.api.base_api import BaseCliApiItem, json_data
from pycliarr.api.base_media import BaseCliMediaApi
from pycliarr.api.exceptions import RadarrCliError


[docs]class RadarrMovieItem(BaseCliApiItem): """Class for handling movie info.""" def _model(self) -> Dict[Any, Any]: """Define the model of items represented by this class.""" return { "title": "", "originalTitle": "", "sortTitle": "", "sizeOnDisk": 0, "overview": "", "inCinemas": None, "physicalRelease": None, "status": "", "images": [], "website": "", "downloaded": False, "year": 0, "hasFile": False, "youTubeTrailerId": "", "studio": "", "path": "", "rootFolderPath": "", "monitored": True, "minimumAvailability": "", "isAvailable": "", "folderName": "", "runtime": 0, "cleanTitle": "", "imdbId": "", "tmdbId": 0, "titleSlug": "", "certification": "", "genres": [], "tags": [], "added": None, "ratings": {}, "collection": {}, "alternateTitles": [], "qualityProfileId": 0, "secondaryYearSourceId": 0, "id": 0, }
[docs]class RadarrCli(BaseCliMediaApi): """Radar api client. Radarr API reference: https://github.com/Radarr/Radarr/wiki/API https://pub.dev/packages/radarr Note: Not all commands are implemented. Some commands available are implemented in BaseCliMediaApi: * get_calendar * get_command * get_quality_profiles * rename_files * get_disk_space * get_system_status * get_queue * delete_queue * get_history * get_logs * get_wanted * get_blocklist * delete_blocklist """ # Set api specific to radarr (differs from the default ones in BaseCliMediaApi) api_url_item = f"{BaseCliMediaApi.api_url_base}/movie" api_url_itemlookup = f"{BaseCliMediaApi.api_url_base}/movie/lookup" api_url_exclusions = f"{BaseCliMediaApi.api_url_base}/exclusions" # Keep using v1 for commands not available in v3 api_url_wanted_missing = "/api/wanted/missing"
[docs] def get_movie(self, movie_id: Optional[int] = None) -> Union[RadarrMovieItem, List[RadarrMovieItem]]: """Get specified movie, or all if no id provided from server collection. Args: movie_id (Optional[int]) ID of movie to get, all items by default Returns: ``RadarrMovieItem`` if a movie id is specified, or a list of ``RadarrMovieItem`` """ res = self.get_item(movie_id) if isinstance(res, list): return [RadarrMovieItem.from_dict(movie) for movie in res] else: return RadarrMovieItem.from_dict(res)
[docs] def lookup_movie( self, term: Optional[str] = None, imdb_id: Optional[str] = None, tmdb_id: Optional[int] = None ) -> Optional[Union[RadarrMovieItem, List[RadarrMovieItem]]]: """Search for a movie based on keyword, or imbd/tmdb id. If no imdb id is provided, tvdb id will be used. If neither of them is provided, the keyword will be used. One of ``term``, ``imdb_id``, or ``tmdb_id`` must be specified. Args: term (Optional[str]): Keywords to seach for imdb_id (Optional[str]): IMDB movie id tmdb_id (Optional[int]): TMDB movie id Returns: json response """ if tmdb_id: term = "tmdb:" + str(tmdb_id) elif imdb_id: term = "imdb:" + str(imdb_id) elif not term: raise RadarrCliError("Error, invalid parameters") res = self.lookup_item(str(term)) if not res: return None elif isinstance(res, list): if len(res) > 1: return [RadarrMovieItem.from_dict(movie) for movie in res] else: res = res[0] return RadarrMovieItem.from_dict(res)
[docs] def add_movie( self, quality: int, tmdb_id: Optional[int] = None, imdb_id: Optional[str] = None, movie_info: Optional[RadarrMovieItem] = None, monitored: bool = True, search: bool = True, path: Optional[str] = None, root_id: int = 0, ) -> json_data: """addMovie adds a new movie to collection. The movie description movie_info must be specified. If the IMDB or TMDB id is provided instead, it will be used to fetch the required movie description from TMDB. Args: quality: Quality profile to use, as retrieved by get_quality_profiles() imdbp_id (Optional[int]): IMDB id of the movie to add tmdb_id (Optional[int]): TMDB id of the movie to add movie_info (Optional[RadarrMovieItem]): Description of the movie to add monitored (bool): Whether to monitor the movie. Default is True search (bool): Whether to search for the movie once added. Default is True path (Optional[str]): Specify the path awhere the movie should be stored. Default is root[0]/<movie name> (<movie year>). root_id (Optional[int]): Specify the root folder to use. Ignored if a path is specified. Default is root[0]. Returns: json response """ # Get info from imdb/tmdb if needed: if tmdb_id or imdb_id: movie_info = cast(RadarrMovieItem, self.lookup_movie(tmdb_id=tmdb_id, imdb_id=imdb_id)) if not movie_info: raise RadarrCliError("Error, invalid parameters or invalid tmdb/imdb id") # Prepare movie info for adding movie_info.path = path or str(self.build_movie_path(movie_info, root_folder_id=root_id)) movie_info.qualityProfileId = quality movie_info.monitored = monitored movie_info.add_attribute("addOptions", {"searchForMovie": search}) return self.add_item(json_data=movie_info.to_dict())
[docs] def build_movie_path(self, movie_info: RadarrMovieItem, root_folder_id: int = 0) -> Path: """Build a movie folder path using the root folder specified. Args: serie_info (SonarrSerieItem) Item for which to build the path root_folder_id (int): Id of the root folder (can be retrieved with get_root_folder()) If the id is not found or not specified, the first root folder in the list is used. Returns: Full path of the serie in the format <root path>/<movie name> (<movie year>) """ return self.build_item_path( movie_info.title + (f" ({movie_info.year})" if movie_info.year else ""), root_folder_id )
[docs] def delete_movie(self, movie_id: int, delete_files: bool = True, add_exclusion: bool = False) -> json_data: """Delete the movie with the given ID Args: movie_id (int): Movie to delete delete_files (bool): Optional. Also delete files. Default is True add_exclusion: Optionally exclude the movie from further imdb/tmdb auto add Returns: json response """ options = {"addImportExclusion": add_exclusion} if add_exclusion else {} return self.delete_item(movie_id, delete_files, options)
[docs] def edit_movie( self, movie_info: RadarrMovieItem, move_files: bool = False, ) -> json_data: """Edit a movie from the collection. The movie description movie_info must be specified, usually by getting the information from get_movie() Args: movie_info (Optional[RadarrMovieItem]): Description of the movie to edit move_files (bool): Whether to move files after edition. Default is False Returns: json response """ return self.edit_item(json_data=movie_info.to_dict()) # , url_params={"moveFiles": False})
[docs] def refresh_movie(self, movie_id: Optional[int] = None) -> json_data: """Refresh movie information and rescan disk. Args: movie_id (Optional[int]): Movie to refresh, if not set all movies will be refreshed and scanned Returns: json response """ data: Dict[str, Any] = {"name": "RefreshMovie"} if movie_id: data["movieId"] = movie_id return self._sendCommand(data)
[docs] def rescan_movie(self, movie_id: Optional[int] = None) -> json_data: """Scan disk for any downloaded movie for all or specified movie. Args: movie_id (Optional[int]): Movie to refresh, if not set all movies will be refreshed and scanned Returns: json response """ data: Dict[str, Any] = {"name": "RescanMovie"} if movie_id: data["movieId"] = movie_id return self._sendCommand(data)
[docs] def create_exclusion(self, title: str, tmdb_id: int, year: int) -> json_data: """Create the specified exclusions Args: item_id (int): id of the exclusions to create Returns: json response """ return self.request_post( self.api_url_exclusions, json_data={"movieTitle": title, "tmdbId": tmdb_id, "movieYear": year} )
[docs] def get_queue( self, page: int = 1, sort_key: str = "progress", page_size: int = 20, sort_dir: str = "ascending", include_unknown: bool = True, ) -> json_data: """Get queue info (downloading/completed, ok/warning) as json Args: page (int) - 1-indexed (1 default) sort_key (string) - title or date page_size (int) - Default: 10 sort_dir (string) - asc or desc - Default: asc options (Dict[str, Any]={}): Optional additional options """ return self._get_queue( page, sort_key, page_size, sort_dir, options={"includeUnknownMovieItems": include_unknown} )