Source code for flexget.plugins.input.next_sonarr_episodes
import math
from urllib.parse import urlparse
from loguru import logger
from requests import RequestException
from flexget import plugin
from flexget.entry import Entry
from flexget.event import event
logger = logger.bind(name='next_sonarr_episodes')
[docs]
class NextSonarrEpisodes:
r"""Return the 1st missing episode of every show configures in Sonarr.
This can be used with the discover plugin or set_series_begin plugin to
get the relevant data from Sonarr.
Syntax::
next_sonarr_episodes:
base_url=<value> (Required)
port=<value> (Default is 80)
api_key=<value> (Required)
include_ended=<yes|no> (Default is yes)
only_monitored=<yes|no> (Default is yes)
page_size=<value> (Default is 50)
Page size determines the amount of results per each API call.
Higher value means a bigger response. Lower value means more calls.
Should be changed if there are performance issues.
Usage (Example with discover)::
discover_from_sonarr_task:
discover:
what:
- next_sonarr_episodes:
base_url: '{? credentials.sonarr.url ?}'
port: 8989
api_key: '{? credentials.sonarr.api_key ?}'
include_ended: false
from:
- kat:
verified: yes
all_series: yes
download: c:\bla\
Usage (Example with set_series_begin)::
set-series-begin-from-sonarr:
next_sonarr_episodes:
base_url: '{{ secrets.credentials.sonarr.url }}'
port: 8989
api_key: '{{ secrets.credentials.sonarr.api_key }}'
include_ended: false
accept_all: yes
set_series_begin: yes
"""
schema = {
'type': 'object',
'properties': {
'base_url': {'type': 'string'},
'port': {'type': 'number', 'default': 80},
'api_key': {'type': 'string'},
'include_ended': {'type': 'boolean', 'default': True},
'only_monitored': {'type': 'boolean', 'default': True},
'page_size': {'type': 'number', 'default': 50},
},
'required': ['api_key', 'base_url'],
'additionalProperties': False,
}
# Function that gets a page number and page size and returns the responding result json
[docs]
def get_page(self, task, config, page_number):
parsedurl = urlparse(config.get('base_url'))
url = '{}://{}:{}{}/api/v3/wanted/missing?page={}&pageSize={}&sortKey=series.title&sortdir=asc'.format(
parsedurl.scheme,
parsedurl.netloc,
config.get('port'),
parsedurl.path,
page_number,
config.get('page_size'),
)
headers = {'X-Api-Key': config['api_key']}
try:
json = task.requests.get(url, headers=headers).json()
except RequestException as e:
raise plugin.PluginError(
'Unable to connect to Sonarr at {}://{}:{}{}. Error: {}'.format(
parsedurl.scheme, parsedurl.netloc, config.get('port'), parsedurl.path, e
)
)
return json
[docs]
def on_task_input(self, task, config):
json = self.get_page(task, config, 1)
pages = math.ceil(
json['totalRecords'] / config.get('page_size')
) # Sets number of requested pages
current_series_id = 0 # Initializes current series parameter
for page in range(1, pages + 1):
json = self.get_page(task, config, page)
for record in json['records']:
# Verifies that we only get the first missing episode from a series
if current_series_id != record['seriesId']:
current_series_id = record['seriesId']
season = record['seasonNumber']
episode = record['episodeNumber']
entry = Entry(
url='',
series_name=record['series']['title'],
series_season=season,
series_episode=episode,
series_id=f'S{season:02d}E{episode:02d}',
tvdb_id=record['series'].get('tvdbId'),
tvrage_id=record['series'].get('tvRageId'),
tvmaze_id=record['series'].get('tvMazeId'),
title=record['series']['title'] + ' ' + f'S{season:02d}E{episode:02d}',
)
# Test mode logging
if entry and task.options.test:
logger.verbose('Test mode. Entry includes:')
for key, value in list(entry.items()):
logger.verbose(' {}: {}', key.capitalize(), value)
if entry.isvalid():
yield entry
else:
logger.error('Invalid entry created? {}', entry)
[docs]
@event('plugin.register')
def register_plugin():
plugin.register(NextSonarrEpisodes, 'next_sonarr_episodes', api_ver=2)