Source code for pycliarr.api.base_media

import logging
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, cast

from pycliarr.api.base_api import BaseCliApi, json_data, json_dict, json_list
from pycliarr.api.exceptions import CliArrError

log = logging.getLogger(__name__)


[docs]class BaseCliMediaApi(BaseCliApi): """Base class for media based API. Implement behavior common to media based apis (e.g. sonarr, radarr) """ # Default urls for commands. Some might need to be overriden by the childs. api_url_base = "/api/v3" api_url_calendar = f"{api_url_base}/calendar" api_url_command = f"{api_url_base}/command" api_url_diskspace = f"{api_url_base}/diskspace" api_url_item = f"{api_url_base}/item" api_url_itemlookup = f"{api_url_base}/item/lookup" api_url_systemstatus = f"{api_url_base}/system/status" api_url_queue = f"{api_url_base}/queue" api_url_history = f"{api_url_base}/history/" api_url_profile = f"{api_url_base}/qualityProfile" api_url_language_profile = f"{api_url_base}/languageProfile" api_url_rootfolder = f"{api_url_base}/rootfolder" api_url_log = f"{api_url_base}/log" api_url_systembackup = f"{api_url_base}/system/backup" api_url_wanted_missing = f"{api_url_base}/wanted/missing" api_url_blocklist = f"{api_url_base}/blocklist" api_url_notification = f"{api_url_base}/notification" api_url_tag = f"{api_url_base}/tag" api_url_exclusions = f"{api_url_base}/importlistexclusion" def __init__(self, *args: Any, default_root_folder_id: int = 0, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self._default_root_folder_id = default_root_folder_id @property def default_root_folder_id(self) -> int: return self._default_root_folder_id @default_root_folder_id.setter def default_root_folder_id(self, value: int) -> None: self._default_root_folder_id = value
[docs] def get_calendar(self, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None) -> json_data: """Retrieve info about when items were/will be downloaded. If start and end are not provided, retrieves movies airing today and tomorrow. Args: start_date (Optional[datetime]): Start date of events to retrieve end_date (Optional[datetime]): End date of events to retrieve Returns: json response """ url_params = {} if start_date and end_date: url_params["start"] = start_date.strftime("%Y-%m-%d") url_params["end"] = end_date.strftime("%Y-%m-%d") return self.request_get(self.api_url_calendar, url_params=url_params)
[docs] def get_command(self, cid: Optional[int] = None) -> json_data: """Query the status of a previously started command, or all currently running. Args: cid (Optional[int]) Unique ID of command Returns: json response """ url_path = f"{self.api_url_command}/{cid}" if cid else self.api_url_command return self.request_get(url_path)
def _sendCommand(self, data: json_data) -> json_data: return self.request_post(self.api_url_command, json_data=data)
[docs] def sync_rss(self) -> json_data: """Perform an RSS sync with all enabled indexers. Returns: json response """ return self._sendCommand({"name": "RssSync"})
[docs] def rename_files(self, file_ids: List[int]) -> json_data: """Rename the list of files provided. Args: file_ids (List[int]): List of ids of files to rename Returns: json response """ return self._sendCommand({"name": "RenameFiles", "files": file_ids})
[docs] def get_disk_space(self) -> json_data: """Retrieve info about the disk space on the server. Returns: json response """ return self.request_get(self.api_url_diskspace)
[docs] def get_root_folder(self) -> List[json_dict]: """Retrieve the server root folder. Returns: json response """ res = cast(json_list, self.request_get(self.api_url_rootfolder)) return res
[docs] def get_item(self, item_id: Optional[int] = None) -> json_data: """Get specified item, or all if no id provided from server collection. Args: item_id (Optional[int]) ID of item to get, all items by default Returns: json response """ url_path = f"{self.api_url_item}/{item_id}" if item_id else self.api_url_item return self.request_get(url_path)
[docs] def lookup_item(self, term: str) -> json_data: """Search for items Args: term (str): Lookup terms Returns: json response """ url_params = {"term": term} return self.request_get(self.api_url_itemlookup, url_params=url_params)
[docs] def add_item(self, json_data: json_data) -> json_data: """Adds a new item to collection Args: json_data: Dict representation of the item to add Returns: json response """ return self.request_post(self.api_url_item, json_data=json_data)
[docs] def delete_item(self, item_id: int, delete_files: bool = True, options: Dict[str, Any] = {}) -> json_data: """Delete the item with the given ID Args: item_id (int): Item to delete delete_files (bool): Optional. Also delete files. Default is False options (Dict[str, Any]): Optionally specify additional options Returns: json response """ data = {"deleteFiles": delete_files} data.update(options) url_path = f"{self.api_url_item}/{item_id}" return self.request_delete(url_path, data)
[docs] def edit_item(self, json_data: json_data, url_params: Optional[Dict[str, Any]] = None) -> json_data: """Edit an item from the collection Args: json_data: Dict representation of the item to add Returns: json response """ return self.request_put(self.api_url_item, json_data=json_data, url_params=url_params)
[docs] def get_system_status(self) -> json_data: """Return the System Status as json""" return self.request_get(self.api_url_systemstatus)
[docs] def get_quality_profiles(self) -> json_list: """Return the quality profiles""" return cast(json_list, self.request_get(self.api_url_profile))
[docs] def get_language_profiles(self) -> json_list: """Return the quality profiles""" return cast(json_list, self.request_get(self.api_url_language_profile))
def _get_queue( self, page: int = 1, sort_key: str = "progress", page_size: int = 20, sort_dir: str = "ascending", options: Dict[str, Any] = {}, ) -> 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 """ data = { "page": page, "pageSize": page_size, "sortKey": sort_key, "sortDirection": sort_dir, } data.update(options) return self.request_get(self.api_url_queue, url_params=data)
[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: return self._get_queue(page, sort_key, page_size, sort_dir)
[docs] def delete_queue(self, item_id: int, blacklist: Optional[bool] = None) -> json_data: """Delete an item from the queue and download client. Optionally blacklist item after deletion. Args: item_id (int): Item to delete blacklist (Optional[bool]): Optionally blacklist the item Returns: json response """ data = {} if blacklist: data["blacklist"] = blacklist return self.request_delete(f"{self.api_url_queue}/{item_id}", data)
[docs] def get_history( self, page: int = 1, sort_key: str = "date", page_size: int = 10, sort_dir: str = "asc", options: Dict[str, Any] = {}, ) -> json_data: """Get history (grabs/failures/completed) 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 Returns: json response """ data = { "page": page, "pageSize": page_size, "sortKey": sort_key, "sortDir": sort_dir, } data.update(options) return self.request_get(self.api_url_history, url_params=data)
[docs] def get_logs(self, page: int = 1, sort_key: str = "time", page_size: int = 10, sort_dir: str = "asc") -> json_data: """Get logs Args: page (int) - 1-indexed (1 default) sort_key (string) - title or time page_size (int) - Default: 10 sort_dir (string) - asc or desc - Default: asc Returns: json response """ data = { "page": page, "pageSize": page_size, "sortKey": sort_key, "sortDir": sort_dir, } return self.request_get(self.api_url_log, url_params=data)
[docs] def get_backup(self) -> json_data: """Return the backups as json""" return self.request_get(self.api_url_systembackup)
[docs] def get_wanted( self, page: int = 1, sort_key: str = "airDateUtc", page_size: int = 10, sort_dir: str = "asc" ) -> json_data: """Get Wanted / Missing episodes Args: sort_key (str): series.title or airDateUtc (default) page (int): 1-indexed Default: 1 page_size (int): Default: 10 sort_dir (str): asc or desc - Default: asc Returns: json response """ data = { "page": page, "pageSize": page_size, "sortKey": sort_key, "sortDir": sort_dir, } data.update({"sortKey": sort_key}) return self.request_get(self.api_url_wanted_missing, url_params=data)
[docs] def build_item_path(self, title: str, root_folder_id: int = 0) -> Path: """Build an item folder path using the root folder specified. Args: title (str): Title to add to root path. All invalid characters are removed 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 default root folder id will be used. If 0, the first root folder in the list is used. Returns: Full path of the serie in the format <root path>/<serie name> """ root_paths = self.get_root_folder() selected_root_folder_id = root_folder_id or self.default_root_folder_id print(f"{selected_root_folder_id} // {root_folder_id} // {self.default_root_folder_id}") root_path = root_paths[0] if not selected_root_folder_id else None for path in root_paths: if path["id"] == int(selected_root_folder_id): root_path = path if not root_path: raise CliArrError(f"Invalid root folder Id: {selected_root_folder_id}") return Path(root_path["path"]) / self.to_path(title)
[docs] def get_blocklist( self, page: int = 1, sort_key: str = "date", page_size: int = 20, sort_dir: str = "descending" ) -> json_data: """Get blocklisted releases Args: page (int) - 1-indexed (1 default) sort_key (string) - date page_size (int) - Default: 20 sort_dir (string) - ascending or descending - Default: descending """ data = { "page": page, "pageSize": page_size, "sortKey": sort_key, "sortDirection": sort_dir, } return self.request_get(self.api_url_blocklist, url_params=data)
[docs] def delete_blocklist(self, item_id: Optional[int] = None) -> json_data: """Remove the specified item from the blocklist, or all items if none specified Args: item_id (int): Item to delete, None to delete all items Returns: json response """ if item_id: return self.request_delete(self.api_url_blocklist, url_params={"id": item_id}) else: return self.request_delete(f"{self.api_url_blocklist}/bulk")
[docs] def get_notification(self, item_id: Optional[int] = None) -> json_data: """Get specified notification or all if none specified Args: item_id (int): id of the notification to get, or None to get all of them Returns: json response """ return self.request_get(f"{self.api_url_notification}/{item_id if item_id else ''}")
[docs] def delete_notification(self, item_id: int) -> json_data: """Remove the specified item from the blocklist, or all items if none specified Args: item_id (int): id of the notification to delete Returns: json response """ return self.request_delete(f"{self.api_url_notification}/{item_id}")
[docs] def put_notification(self, item_id: int, notification_data: json_data) -> json_data: """Create the specified notification Args: item_id (int): id of the notification to create notification_data (json_data): Json dict describing the notification formated as in https://radarr.video/docs/api/#/Notification/put-notification-id Returns: json response """ return self.request_put(f"{self.api_url_notification}/{item_id}", json_data=notification_data)
[docs] def get_tag(self, item_id: Optional[int] = None) -> json_data: """Get specified tag or all if none specified Args: item_id (int): id of the tag to get, or None to get all of them Returns: json response """ return self.request_get(f"{self.api_url_tag}/{item_id if item_id else ''}")
[docs] def get_tag_detail(self, item_id: Optional[int] = None) -> json_data: """Get specified tag detail or all if none specified Args: item_id (int): id of the tag to get, or None to get all of them Returns: json response """ return self.request_get(f"{self.api_url_tag}/detail/{item_id if item_id else ''}")
[docs] def delete_tag(self, item_id: int) -> json_data: """Remove the specified tag Args: item_id (int): id of the notification to delete Returns: json response """ return self.request_delete(f"{self.api_url_tag}/{item_id}")
[docs] def edit_tag(self, item_id: int, value: str) -> json_data: """Edit the specified tag Args: item_id (int): id of the tag to edit value (str): Tag label Returns: json response """ return self.request_put(f"{self.api_url_tag}/{item_id}", json_data={"id": item_id, "label": value})
[docs] def create_tag(self, value: str) -> json_data: """Create the specified tag Args: item_id (int): id of the tag to edit value (str): Tag label Returns: json response """ return self.request_post(self.api_url_tag, json_data={"id": 0, "label": value})
[docs] def get_exclusion(self, item_id: Optional[int] = None) -> json_data: """Get import list exclusions Args: item_id (int): id of the exclusion to get, or None to get all of them Returns: json response """ return self.request_get(f"{self.api_url_exclusions}/{item_id if item_id else ''}")
[docs] def delete_exclusion(self, item_id: int) -> json_data: """Remove the specified exclusions Args: item_id (int): id of the exclusions to delete Returns: json response """ return self.request_delete(f"{self.api_url_exclusions}/{item_id}")