From 9e741368342884ceb3a70f43a36759cf3f0ec25f Mon Sep 17 00:00:00 2001 From: p0psicles Date: Sun, 14 Feb 2021 12:48:19 +0100 Subject: [PATCH] Working example for pyMedusa when fork is 'medusa' (no api key) --- core/auto_process/managers/pymedusa.py | 33 +++++- core/auto_process/managers/sickbeard.py | 145 ++++++++++++++++++++++-- core/auto_process/tv.py | 31 +++-- 3 files changed, 187 insertions(+), 22 deletions(-) diff --git a/core/auto_process/managers/pymedusa.py b/core/auto_process/managers/pymedusa.py index 0a673217..e08b6173 100644 --- a/core/auto_process/managers/pymedusa.py +++ b/core/auto_process/managers/pymedusa.py @@ -1,11 +1,38 @@ +import requests + +from core import logger + from .sickbeard import SickBeard class PyMedusa(SickBeard): """PyMedusa class.""" - def __init__(self, config): - super(PyMedusa, self).__init__(config) + def __init__(self, sb_init): + super(PyMedusa, self).__init__(sb_init) + self.cfg = self.sb_init.config # in case we need something that's not already directly on self.sb_init. - def configure(): + def _configure(): """Configure pymedusa with config options.""" + + def _create_url(self): + if self.sb_init.apikey: + return '{0}{1}:{2}{3}/api/{4}/'.format(self.sb_init.protocol, self.sb_init.host, self.sb_init.port, self.sb_init.web_root, self.sb_init.apikey) + return '{0}{1}:{2}{3}/home/postprocess/processEpisode'.format(self.sb_init.protocol, self.sb_init.host, self.sb_init.port, self.sb_init.web_root) + + def api_call(self): + """Perform the api call with PyMedusa.""" + s = requests.Session() + + self._process_fork_prarams() + url = self._create_url() + + logger.debug('Opening URL: {0} with params: {1}'.format(url, self.sb_init.fork_params), self.sb_init.section) + if not self.sb_init.apikey and self.sb_init.username and self.sb_init.password: + login = '{0}{1}:{2}{3}/login'.format(self.sb_init.protocol, self.sb_init.host, self.sb_init.port, self.sb_init.web_root) + login_params = {'username': self.sb_init.username, 'password': self.sb_init.password} + r = s.get(login, verify=False, timeout=(30, 60)) + if r.status_code in [401, 403] and r.cookies.get('_xsrf'): + login_params['_xsrf'] = r.cookies.get('_xsrf') + s.post(login, data=login_params, stream=True, verify=False, timeout=(30, 60)) + return s.get(url, auth=(self.sb_init.username, self.sb_init.password), params=self.sb_init.fork_params, stream=True, verify=False, timeout=(30, 1800)) diff --git a/core/auto_process/managers/sickbeard.py b/core/auto_process/managers/sickbeard.py index ae97b349..19f256b8 100644 --- a/core/auto_process/managers/sickbeard.py +++ b/core/auto_process/managers/sickbeard.py @@ -7,8 +7,19 @@ from __future__ import ( unicode_literals, ) + +import copy + import core from core import logger +from core.utils import ( + convert_to_ascii, + flatten, + list_media_files, + remote_dir, + remove_dir, + server_responding, +) from oauthlib.oauth2 import LegacyApplicationClient @@ -44,7 +55,9 @@ class InitSickBeard(object): self.sso_username = cfg.get('sso_username', '') self.sso_password = cfg.get('sso_password', '') - self.fork = 'auto' + self.fork = '' + self.fork_params = None + self.fork_obj = None replace = { 'medusa': 'Medusa', @@ -161,7 +174,10 @@ class InitSickBeard(object): logger.info('{section}:{category} fork set to {fork}'.format (section=self.section, category=self.input_category, fork=fork[0])) core.FORK_SET = fork - return fork[0], fork[1] + self.fork, self.fork_params = fork[0], fork[1] + # This will create the fork object, and attach to self.fork_obj. + self._init_fork() + return self.fork, self.fork_params @staticmethod def _api_check(r, params, rem_params): @@ -272,24 +288,139 @@ class InitSickBeard(object): break if detected: + self.fork = fork logger.info('{section}:{category} fork auto-detection successful ...'.format (section=self.section, category=self.input_category)) elif rem_params: logger.info('{section}:{category} fork auto-detection found custom params {params}'.format (section=self.section, category=self.input_category, params=params)) - fork = ['custom', params] + self.fork = ['custom', params] else: logger.info('{section}:{category} fork auto-detection failed'.format (section=self.section, category=self.input_category)) - fork = list(core.FORKS.items())[list(core.FORKS.keys()).index(core.FORK_DEFAULT)] + self.fork = list(core.FORKS.items())[list(core.FORKS.keys()).index(core.FORK_DEFAULT)] return fork + def _init_fork(self): + from .pymedusa import PyMedusa + mapped_forks = { + 'Medusa': PyMedusa + } + logger.debug('Create object for fork {fork}'.format(fork=self.fork)) + if self.fork and mapped_forks.get(self.fork): + # Create the fork object and pass self (SickBeardInit) to it for all the data, like Config. + self.fork = mapped_forks[self.fork](self) + else: + logger.info('{section}:{category} Could not create a fork object for {fork}. Probaly class not added yet.'.format( + section=self.section, category=self.input_category, fork=self.fork) + ) + class SickBeard(object): """Sickbeard base class.""" - def __init__(self, config): + def __init__(self, sb_init): """SB constructor.""" - self.config = config - self.fork = 'auto' + self.sb_init = sb_init + self.failed = None + self.status = None + self.input_name = None + self.dir_name = None + + self.delete_failed = int(self.sb_init.config.get('delete_failed', 0)) + self.nzb_extraction_by = self.sb_init.config.get('nzbExtractionBy', 'Downloader') + self.process_method = self.sb_init.config.get('process_method') + self.remote_path = int(self.sb_init.config.get('remote_path', 0)) + self.wait_for = int(self.sb_init.config.get('wait_for', 2)) + self.force = int(self.sb_init.config.get('force', 0)) + self.delete_on = int(self.sb_init.config.get('delete_on', 0)) + self.ignore_subs = int(self.sb_init.config.get('ignore_subs', 0)) + + # get importmode, default to 'Move' for consistency with legacy + self.import_mode = self.sb_init.config.get('importMode', 'Move') + + def initialize(self, dir_name, input_name=None, failed=False, client_agent='manual'): + """We need to call this explicitely because we need some variables. + + We can't pass these directly through the constructor. + """ + self.dir_name = dir_name + self.input_name = input_name + self.failed = failed + self.status = int(self.failed) + if self.status > 0 and core.NOEXTRACTFAILED: + self.extract = 0 + else: + self.extract = int(self.sb_init.config.get('extract', 0)) + if client_agent == core.TORRENT_CLIENT_AGENT and core.USE_LINK == 'move-sym': + self.process_method = 'symlink' + + def _create_url(self): + if self.sb_init.apikey: + return '{0}{1}:{2}{3}/api/{4}/'.format(self.sb_init.protocol, self.sb_init.host, self.sb_init.port, self.sb_init.web_root, self.sb_init.apikey) + return '{0}{1}:{2}{3}/home/postprocess/processEpisode'.format(self.sb_init.protocol, self.sb_init.host, self.sb_init.port, self.sb_init.web_root) + + def _process_fork_prarams(self): + # configure SB params to pass + fork_params = self.sb_init.fork_params + fork_params['quiet'] = 1 + fork_params['proc_type'] = 'manual' + if self.input_name is not None: + fork_params['nzbName'] = self.input_name + + for param in copy.copy(fork_params): + if param == 'failed': + if self.failed > 1: + self.failed = 1 + fork_params[param] = self.failed + if 'proc_type' in fork_params: + del fork_params['proc_type'] + if 'type' in fork_params: + del fork_params['type'] + + if param == 'return_data': + fork_params[param] = 0 + if 'quiet' in fork_params: + del fork_params['quiet'] + + if param == 'type': + if 'type' in fork_params: # only set if we haven't already deleted for 'failed' above. + fork_params[param] = 'manual' + if 'proc_type' in fork_params: + del fork_params['proc_type'] + + if param in ['dir_name', 'dir', 'proc_dir', 'process_directory', 'path']: + fork_params[param] = self.dir_name + if self.remote_path: + fork_params[param] = remote_dir(self.dir_name) + + if param == 'process_method': + if self.process_method: + fork_params[param] = self.process_method + else: + del fork_params[param] + + if param in ['force', 'force_replace']: + if self.force: + fork_params[param] = self.force + else: + del fork_params[param] + + if param in ['delete_on', 'delete']: + if self.delete_on: + fork_params[param] = self.delete_on + else: + del fork_params[param] + + if param == 'ignore_subs': + if self.ignore_subs: + fork_params[param] = self.ignore_subs + else: + del fork_params[param] + + if param == 'force_next': + fork_params[param] = 1 + + # delete any unused params so we don't pass them to SB by mistake + [fork_params.pop(k) for k, v in list(fork_params.items()) if v is None] diff --git a/core/auto_process/tv.py b/core/auto_process/tv.py index e48e7bc5..41059a83 100644 --- a/core/auto_process/tv.py +++ b/core/auto_process/tv.py @@ -24,7 +24,7 @@ from core.auto_process.common import ( command_complete, completed_download_handling, ) -from core.forks import auto_fork +from core.auto_process.managers.sickbeard import InitSickBeard from core.plugins.downloaders.nzb.utils import report_nzb from core.plugins.subtitles import import_subs from core.scene_exceptions import process_all_exceptions @@ -36,7 +36,6 @@ from core.utils import ( remove_dir, server_responding, ) -from core.auto_process.managers.sickbeard import InitSickBeard requests.packages.urllib3.disable_warnings() @@ -63,6 +62,8 @@ def process(section, dir_name, input_name=None, failed=False, client_agent='manu if server_responding('{0}{1}:{2}{3}'.format(protocol, host, port, web_root)): # auto-detect correct fork + # During reactor we also return fork, fork_params. But these are also stored in the object. + # Should be changed after refactor. fork, fork_params = init_sickbeard.auto_fork() elif not username and not apikey and not sso_username: logger.info('No SickBeard / SiCKRAGE username or Sonarr apikey entered. Performing transcoder functions only') @@ -190,6 +191,9 @@ def process(section, dir_name, input_name=None, failed=False, client_agent='manu status_code=1, ) + # Part of the refactor + init_sickbeard.fork.initialize(dir_name, input_name, failed, client_agent='manual') + # configure SB params to pass fork_params['quiet'] = 1 fork_params['proc_type'] = 'manual' @@ -317,17 +321,20 @@ def process(section, dir_name, input_name=None, failed=False, client_agent='manu try: if section == 'SickBeard': - s = requests.Session() + if init_sickbeard.fork: + r = init_sickbeard.fork.api_call() + else: + s = requests.Session() - logger.debug('Opening URL: {0} with params: {1}'.format(url, fork_params), section) - if not apikey and username and password: - login = '{0}{1}:{2}{3}/login'.format(protocol, host, port, web_root) - login_params = {'username': username, 'password': password} - r = s.get(login, verify=False, timeout=(30, 60)) - if r.status_code in [401, 403] and r.cookies.get('_xsrf'): - login_params['_xsrf'] = r.cookies.get('_xsrf') - s.post(login, data=login_params, stream=True, verify=False, timeout=(30, 60)) - r = s.get(url, auth=(username, password), params=fork_params, stream=True, verify=False, timeout=(30, 1800)) + logger.debug('Opening URL: {0} with params: {1}'.format(url, fork_params), section) + if not apikey and username and password: + login = '{0}{1}:{2}{3}/login'.format(protocol, host, port, web_root) + login_params = {'username': username, 'password': password} + r = s.get(login, verify=False, timeout=(30, 60)) + if r.status_code in [401, 403] and r.cookies.get('_xsrf'): + login_params['_xsrf'] = r.cookies.get('_xsrf') + s.post(login, data=login_params, stream=True, verify=False, timeout=(30, 60)) + r = s.get(url, auth=(username, password), params=fork_params, stream=True, verify=False, timeout=(30, 1800)) elif section == 'SiCKRAGE': s = requests.Session()