Example #1
0
    def __init__(self, name, url, private):
        self.name = name

        # urls
        self._urls = {'base_url': url}

        # other options
        self.private = private
        self.supports_backlog = True
        self.supports_absolute_numbering = False
        self.anime_only = False
        self.search_mode = 'eponly'
        self.search_fallback = False
        self.enabled = False
        self.enable_daily = True
        self.enable_backlog = True
        self.cache = TVCache(self)
        self.proper_strings = ['PROPER|REPACK|REAL|RERIP']
        self.search_separator = ' '

        # cookies
        self.enable_cookies = False
        self.cookies = ''

        # web session
        self.session = WebSession(cloudflare=True)
Example #2
0
    def _request(self, method, url, lang=None, retries=3, **kwargs):
        self.config['headers'].update({'Content-type': 'application/json'})
        self.config['headers']['Authorization'] = 'Bearer {}'.format(self.jwt_token)
        self.config['headers'].update({'Accept-Language': lang or self.config['language']})
        self.config['headers'].update({'Accept': 'application/vnd.thetvdb.v{}'.format(self.config['api']['version'])})

        for i in range(0, retries):
            try:
                # get response from theTVDB
                resp = WebSession(cache=self.config['cache_enabled']).request(
                    method, urljoin(self.config['api']['base'], url), headers=self.config['headers'],
                    timeout=sickrage.app.config.indexer_timeout, **kwargs
                )
            except requests.exceptions.HTTPError as e:
                status_code = e.response.status_code
                error_message = e.response.text

                if 'application/json' in e.response.headers.get('content-type', ''):
                    error_message = e.response.json().get('Error', error_message)

                if status_code == 401:
                    raise tvdb_unauthorized(error_message)

                if i < retries - 1:
                    continue

                raise tvdb_error(error_message)

            return to_lowercase(resp.json())
Example #3
0
    def _request(self, method, url, lang=None, **kwargs):
        self.config['headers'].update({'Content-type': 'application/json'})

        if self.config['apitoken']:
            self.config['headers']['authorization'] = 'Bearer {}'.format(
                self.config['apitoken'])

        self.config['headers'].update(
            {'Accept-Language': lang or self.config['language']})

        # get response from theTVDB
        try:
            resp = WebSession(cache=self.config['cache_enabled']).request(
                method,
                urlparse.urljoin(self.config['api']['base'], url),
                headers=self.config['headers'],
                timeout=sickrage.app.config.indexer_timeout,
                **kwargs)
        except Exception as e:
            raise tvdb_error(e.message)

        # handle requests exceptions
        if resp.status_code == 401:
            raise tvdb_unauthorized(resp.json()['Error'])
        elif resp.status_code >= 400:
            raise tvdb_error(resp.json()['Error'])

        return to_lowercase(resp.json())
Example #4
0
    def _notify_emby(self, message, host=None, emby_apikey=None):
        """Handles notifying Emby host via HTTP API

        Returns:
            Returns True for no issue or False if there was an error

        """

        # fill in omitted parameters
        if not host:
            host = sickrage.app.config.emby_host
        if not emby_apikey:
            emby_apikey = sickrage.app.config.emby_apikey

        url = 'http://%s/emby/Notifications/Admin' % (host)
        values = {'Name': 'SiCKRAGE', 'Description': message,
                  'ImageUrl': 'https://www.sickrage.ca/favicon.ico'}
        data = json.dumps(values)

        headers = {
            'X-MediaBrowser-Token': emby_apikey,
            'Content-Type': 'application/json'
        }

        resp = WebSession().get(url, data=data, headers=headers)

        try:
            resp.raise_for_status()
            sickrage.app.log.debug('EMBY: HTTP response: {}'.format(resp.text.replace('\n', '')))
        except Exception as e:
            sickrage.app.log.warning('EMBY: Warning: Couldn\'t contact Emby at {}: {}'.format(url, e))
            return False

        return True
Example #5
0
    def sendNZB(nzb, session=None):
        """
        Sends an NZB to SABnzbd via the API.
        :param nzb: The NZBSearchResult object to send to SAB
        """

        show_object = find_show(nzb.show_id, session=session)
        if not show_object:
            return False

        category = sickrage.app.config.sab_category
        if show_object.is_anime:
            category = sickrage.app.config.sab_category_anime

        # if it aired more than 7 days ago, override with the backlog category IDs
        for episode__number in nzb.episodes:
            episode_object = show_object.get_episode(nzb.season, episode__number)
            if datetime.date.today() - episode_object.airdate > datetime.timedelta(days=7):
                category = sickrage.app.config.sab_category_anime_backlog if episode_object.show.is_anime else sickrage.app.config.sab_category_backlog

        # set up a dict with the URL params in it
        params = {'output': 'json'}
        if sickrage.app.config.sab_username:
            params['ma_username'] = sickrage.app.config.sab_username
        if sickrage.app.config.sab_password:
            params['ma_password'] = sickrage.app.config.sab_password
        if sickrage.app.config.sab_apikey:
            params['apikey'] = sickrage.app.config.sab_apikey

        if category:
            params['cat'] = category

        if nzb.priority:
            params['priority'] = 2 if sickrage.app.config.sab_forced else 1

        sickrage.app.log.info('Sending NZB to SABnzbd')
        url = urljoin(sickrage.app.config.sab_host, 'api')

        try:
            jdata = None

            if nzb.resultType == 'nzb':
                params['mode'] = 'addurl'
                params['name'] = nzb.url
                jdata = WebSession().get(url, params=params, verify=False).json()
            elif nzb.resultType == 'nzbdata':
                params['mode'] = 'addfile'
                multiPartParams = {'nzbfile': (nzb.name + '.nzb', nzb.extraInfo[0])}
                jdata = WebSession().get(url, params=params, file=multiPartParams, verify=False).json()

            if not jdata:
                raise Exception
        except Exception:
            sickrage.app.log.info('Error connecting to sab, no data returned')
            return False

        sickrage.app.log.debug('Result text from SAB: {}'.format(jdata))

        result, error_ = SabNZBd._check_sab_response(jdata)
        return result
Example #6
0
    def get_token(self, username=None, password=None, plex_server_token=None):
        if plex_server_token:
            self.headers['X-Plex-Token'] = plex_server_token

        if 'X-Plex-Token' in self.headers:
            return True

        if not (username and password):
            return True

        sickrage.app.log.debug('PLEX: fetching plex.tv credentials for user: '******'user[login]': username,
            'user[password]': password
        }

        resp = WebSession().post('https://plex.tv/users/sign_in.json', data=params, headers=self.headers)

        try:
            data = resp.json()
        except ValueError:
            sickrage.app.log.debug("PLEX: No data returned from plex.tv when attempting to fetch credentials")
            self.headers.pop('X-Plex-Token', '')
            return False

        if data and 'error' in data:
            sickrage.app.log.debug('PLEX: Error fetching credentials from from plex.tv for user %s: %s' % (username, data['error']))
            self.headers.pop('X-Plex-Token', '')
            return False
        elif data and 'user' in data:
            self.headers['X-Plex-Token'] = data['user']['authentication_token']

        return 'X-Plex-Token' in self.headers
Example #7
0
    def _send_to_plex(self, command, host, username=None, password=None):
        """Handles communication to Plex hosts via HTTP API

        Args:
            command: Dictionary of field/data pairs, encoded via urllib and passed to the legacy xbmcCmds HTTP API
            host: Plex host:port
            username: Plex API username
            password: Plex API password

        Returns:
            Returns 'OK' for successful commands or False if there was an error

        """

        # fill in omitted parameters
        if not username:
            username = sickrage.app.config.plex_client_username
        if not password:
            password = sickrage.app.config.plex_client_password

        if not host:
            sickrage.app.log.warning(
                'PLEX: No host specified, check your settings')
            return False

        enc_command = urlencode(command)
        sickrage.app.log.debug('PLEX: Encoded API command: ' + enc_command)

        url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command)

        headers = {}

        # if we have a password, use authentication
        if password:
            base64string = base64.b64encode(
                bytes('{}:{}'.format(username, password).replace('\n', ''),
                      'utf-8'))
            authheader = "Basic {}".format(base64string.decode('ascii'))
            headers['Authorization'] = authheader
            sickrage.app.log.debug(
                'PLEX: Contacting (with auth header) via url: ' + url)
        else:
            sickrage.app.log.debug('PLEX: Contacting via url: ' + url)

        try:
            resp = WebSession().get(url, headers=headers)
            resp.raise_for_status()
            result = resp.text

            sickrage.app.log.debug('PLEX: HTTP response: ' +
                                   result.replace('\n', ''))
            # could return result response = re.compile('<html><li>(.+\w)</html>').findall(result)
            return 'OK'
        except Exception as e:
            sickrage.app.log.warning(
                'PLEX: Warning: Couldn\'t contact Plex at {}: {}'.format(
                    url, e))
            return False
Example #8
0
def update_network_dict():
    """Update timezone information from SR repositories"""

    url = 'https://cdn.sickrage.ca/network_timezones/'

    try:
        url_data = WebSession().get(url).text
    except Exception:
        sickrage.app.log.warning(
            'Updating network timezones failed, this can happen from time to time. URL: %s'
            % url)
        return

    d = {}
    try:
        for line in url_data.splitlines():
            (key, val) = line.strip().rsplit(':', 1)
            if key is None or val is None:
                continue
            d[key] = val
    except (IOError, OSError):
        pass

    queries = []
    for network, timezone in d.items():
        existing = network in network_dict
        if not existing:
            try:
                sickrage.app.cache_db.get('network_timezones', network)
            except RecordNotFound:
                sickrage.app.cache_db.insert({
                    '_t': 'network_timezones',
                    'network_name': ss(network),
                    'timezone': timezone
                })
        elif network_dict[network] is not timezone:
            try:
                dbData = sickrage.app.cache_db.get('network_timezones',
                                                   network)
                dbData['timezone'] = timezone
                sickrage.app.cache_db.update(dbData)
            except RecordNotFound:
                continue

        if existing:
            del network_dict[network]

    for x in network_dict:
        try:
            sickrage.app.cache_db.delete(
                sickrage.app.cache_db.get('network_timezones', x))
        except RecordNotFound:
            continue

    load_network_dict()
Example #9
0
    def _check_for_new_version(self):
        from distutils.version import StrictVersion
        url = "https://pypi.python.org/pypi/{}/json".format('sickrage')
        resp = WebSession().get(url)
        versions = resp.json()["releases"].keys()
        versions.sort(key=StrictVersion, reverse=True)

        try:
            return versions[0]
        except Exception:
            return self._find_installed_version()
Example #10
0
    def _check_for_new_version(self):
        from distutils.version import LooseVersion
        url = "https://pypi.org/pypi/{}/json".format('sickrage')
        resp = WebSession().get(url)
        versions = resp.json()["releases"].keys()
        versions = [x for x in versions if 'dev' not in x]
        versions.sort(key=LooseVersion, reverse=True)

        try:
            return versions[0]
        except Exception:
            return self._find_installed_version()
Example #11
0
    def _send_to_kodi(self, command, host=None, username=None, password=None):
        """Handles communication to KODI servers via HTTP API

        Args:
            command: Dictionary of field/data pairs, encoded via urllib and passed to the KODI API via HTTP
            host: KODI webserver host:port
            username: KODI webserver username
            password: KODI webserver password

        Returns:
            Returns response.result for successful commands or False if there was an error

        """

        # fill in omitted parameters
        if not username:
            username = sickrage.app.config.kodi_username
        if not password:
            password = sickrage.app.config.kodi_password

        if not host:
            sickrage.app.log.warning('No KODI host passed, aborting update')
            return False

        enc_command = urlencode(command)
        sickrage.app.log.debug("KODI encoded API command: " + enc_command)

        url = 'http://%s/kodiCmds/kodiHttp/?%s' % (host, enc_command)

        headers = {}

        # if we have a password, use authentication
        if password:
            authheader = "Basic {}".format(
                base64.b64encode(
                    bytes('{}:{}'.format(username, password).replace('\n', ''),
                          'utf-8')).decode('ascii'))
            headers["Authorization"] = authheader
            sickrage.app.log.debug(
                "Contacting KODI (with auth header) via url: " + url)
        else:
            sickrage.app.log.debug("Contacting KODI via url: " + url)

        try:
            result = WebSession().get(url, headers=headers).text
        except Exception as e:
            sickrage.app.log.debug("Couldn't contact KODI HTTP at %r : %r" %
                                   (url, e))
            return False

        sickrage.app.log.debug("KODI HTTP response: " +
                               result.replace('\n', ''))
        return result
Example #12
0
    def _sendFreeMobileSMS(self, title, msg, id=None, apiKey=None):
        """
        Sends a SMS notification

        msg: The message to send (unicode)
        title: The title of the message
        userKey: The pushover user id to send the message to (or to subscribe with)

        returns: True if the message succeeded, False otherwise
        """

        if id is None:
            id = sickrage.app.config.freemobile_id

        if apiKey is None:
            apiKey = sickrage.app.config.freemobile_apikey

        sickrage.app.log.debug("Free Mobile in use with API KEY: " + apiKey)

        # build up the URL and parameters
        msg = msg.strip()
        msg_quoted = parse.quote(title + ": " + msg)
        URL = "https://smsapi.free-mobile.fr/sendmsg?user="******"&pass="******"&msg=" + msg_quoted

        resp = WebSession().get(URL)
        # send the request to Free Mobile
        try:
            resp.raise_for_status()
        except Exception as e:
            if resp.status_code == 400:
                message = "Missing parameter(s)."
                sickrage.app.log.error(message)
                return False, message
            if resp.status_code == 402:
                message = "Too much SMS sent in a short time."
                sickrage.app.log.error(message)
                return False, message
            if resp.status_code == 403:
                message = "API service isn't enabled in your account or ID / API key is incorrect."
                sickrage.app.log.error(message)
                return False, message
            if resp.status_code == 500:
                message = "Server error. Please retry in few moment."
                sickrage.app.log.error(message)
                return False, message

            message = "Error while sending SMS: {}".format(e)
            sickrage.app.log.error(message)
            return False, message

        message = "Free Mobile SMS successful."
        sickrage.app.log.info(message)
        return True, message
Example #13
0
    def _check_for_new_version(self):
        from distutils.version import LooseVersion
        url = "https://pypi.org/pypi/{}/json".format('sickrage')

        try:
            resp = WebSession().get(url)
            versions = resp.json()["releases"].keys()
            versions = [x for x in versions if 'dev' not in x]
            versions.sort(key=LooseVersion, reverse=True)
            return versions[0]
        except Exception:
            return self._find_installed_version()
Example #14
0
    def update_network_timezones(self):
        """Update timezone information from SR repositories"""

        session = sickrage.app.cache_db.session()

        network_timezones = {}

        try:
            url_data = WebSession().get('https://cdn.sickrage.ca/network_timezones/').text
        except Exception:
            sickrage.app.log.warning('Updating network timezones failed.')
            return

        try:
            for line in url_data.splitlines():
                (key, val) = line.strip().rsplit(':', 1)
                if all([key, val]):
                    network_timezones[key] = val
        except (IOError, OSError):
            pass

        for x in session.query(CacheDB.NetworkTimezone):
            if x.network_name not in network_timezones:
                session.query(CacheDB.NetworkTimezone).filter_by(network_name=x.network_name).delete()
                session.commit()

        sql_to_add = []
        sql_to_update = []

        for network, timezone in network_timezones.items():
            try:
                dbData = session.query(CacheDB.NetworkTimezone).filter_by(network_name=network).one()
                if dbData.timezone != timezone:
                    dbData.timezone = timezone
                    sql_to_update.append(dbData.as_dict())
            except orm.exc.NoResultFound:
                sql_to_add.append({
                    'network_name': network,
                    'timezone': timezone
                })

        if len(sql_to_add):
            session.bulk_insert_mappings(CacheDB.NetworkTimezone, sql_to_add)
            session.commit()

        if len(sql_to_update):
            session.bulk_update_mappings(CacheDB.NetworkTimezone, sql_to_update)
            session.commit()

        # cleanup
        del network_timezones
Example #15
0
    def notify_settings(self, host, dbloc, instance):
        """
        Retrieves the NMJv2 database location from Popcorn hour
        
        host: The hostname/IP of the Popcorn Hour server
        dbloc: 'local' for PCH internal harddrive. 'network' for PCH network shares
        instance: Allows for selection of different DB in case of multiple databases
        
        Returns: True if the settings were retrieved successfully, False otherwise
        """

        url_loc = "http://" + host + ":8008/file_operation?arg0=list_user_storage_file&arg1=&arg2=" + instance + "&arg3=20&arg4=true&arg5=true&arg6=true&arg7=all&arg8=name_asc&arg9=false&arg10=false"

        try:
            resp = WebSession().get(url_loc)

            response1 = resp.text
            xml = parseString(response1)
            time.sleep(300.0 / 1000.0)
            for node in xml.getElementsByTagName('path'):
                xmlTag = node.toxml()
                xmlData = xmlTag.replace('<path>',
                                         '').replace('</path>',
                                                     '').replace('[=]', '')
                url_db = "http://" + host + ":8008/metadata_database?arg0=check_database&arg1=" + xmlData
                respdb = WebSession().get(url_db)
                xmldb = parseString(respdb.text)
                returnvalue = xmldb.getElementsByTagName(
                    'returnValue')[0].toxml().replace('<returnValue>',
                                                      '').replace(
                                                          '</returnValue>', '')
                if returnvalue == "0":
                    DB_path = xmldb.getElementsByTagName(
                        'database_path')[0].toxml().replace(
                            '<database_path>',
                            '').replace('</database_path>',
                                        '').replace('[=]', '')
                    if dbloc == "local" and DB_path.find("localhost") > -1:
                        sickrage.app.config.nmjv2_host = host
                        sickrage.app.config.nmjv2_database = DB_path
                        return True
                    if dbloc == "network" and DB_path.find("://") > -1:
                        sickrage.app.config.nmjv2_host = host
                        sickrage.app.config.nmjv2_database = DB_path
                        return True
        except Exception as e:
            sickrage.app.log.warning(
                "Warning: Couldn't contact popcorn hour on host %s: %s" %
                (host, e))

        return False
Example #16
0
    def __init__(self, name, host=None, username=None, password=None):
        self.name = name
        self.username = sickrage.app.config.torrent_username if not username else username
        self.password = sickrage.app.config.torrent_password if not password else password
        self.host = sickrage.app.config.torrent_host if not host else host
        self.rpcurl = sickrage.app.config.torrent_rpcurl

        self.url = None
        self.auth = None
        self.last_time = time.time()

        self.session = WebSession(cache=False)

        self._response = None
Example #17
0
    def _sendProwl(self,
                   prowl_api=None,
                   prowl_priority=None,
                   event=None,
                   message=None,
                   force=False):

        if not sickrage.app.config.use_prowl and not force:
            return False

        if prowl_api is None:
            prowl_api = sickrage.app.config.prowl_api

        if prowl_priority is None:
            prowl_priority = sickrage.app.config.prowl_priority

        title = "SiCKRAGE"

        sickrage.app.log.debug(
            "PROWL: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, api=%s"
            % (event, message, prowl_priority, prowl_api))

        data = {
            'apikey': prowl_api,
            'application': title,
            'event': event,
            'description': message,
            'priority': prowl_priority
        }

        resp = WebSession().post(
            "https://api.prowlapp.com/publicapi/add",
            headers={'Content-type': "application/x-www-form-urlencoded"},
            data=urlencode(data))
        try:
            resp.raise_for_status()

            request_status = resp.status_code
            if request_status == 200:
                sickrage.app.log.info("Prowl notifications sent.")
                return True
            elif request_status == 401:
                sickrage.app.log.error("Prowl auth failed: %s" % resp.reason)
                return False
            else:
                sickrage.app.log.error("Prowl notification failed.")
                return False
        except Exception:
            sickrage.app.log.error("Prowl notification failed.")
            return False
Example #18
0
    def _sendBoxcar2(self, msg, title, accesstoken):
        """
        Sends a boxcar2 notification to the address provided

        msg: The message to send
        title: The title of the message
        accesstoken: to send to this device

        returns: True if the message succeeded, False otherwise
        """

        # build up the URL and parameters more info goes here -
        # https://boxcar.uservoice.com/knowledgebase/articles/306788-how-to-send-your-boxcar-account-a-notification
        msg = msg.strip()

        data = urlencode({
            'user_credentials':
            accesstoken,
            'notification[title]':
            "SiCKRAGE : " + title + ' : ' + msg,
            'notification[long_message]':
            msg,
            'notification[sound]':
            "notifier-2"
        })

        # send the request to boxcar2
        resp = WebSession().get(API_URL, data=data, timeout=60)

        try:
            resp.raise_for_status()
        except RequestException as e:
            # if we get an error back that doesn't have an error code then who knows what's really happening
            sickrage.app.log.warning(
                "Boxcar2 notification failed. Error code: {}".format(
                    resp.status_code))

            # HTTP status 404
            if resp.status_code == 404:
                sickrage.app.log.warning("Access token is invalid. Check it.")
                return False

            # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters
            elif resp.status_code == 400:
                sickrage.app.log.error("Wrong data send to boxcar2")
                return False

        sickrage.app.log.debug("Boxcar2 notification successful.")
        return True
Example #19
0
    def install_requirements(self, branch):
        requirements_url = "https://git.sickrage.ca/SiCKRAGE/sickrage/raw/{}/requirements.txt".format(branch)
        requirements_file = tempfile.NamedTemporaryFile(delete=False)

        try:
            requirements_file.write(WebSession().get(requirements_url).content)
        except Exception:
            requirements_file.close()
            os.unlink(requirements_file.name)
            return False

        output, __, exit_status = self._pip_cmd(self._pip3_path,
                                                'install --no-cache-dir -r {}'.format(requirements_file.name))

        if exit_status != 0:
            __, __, exit_status = self._pip_cmd(self._pip3_path,
                                                'install --no-cache-dir --user -r {}'.format(requirements_file.name))

        if exit_status == 0:
            requirements_file.close()
            os.unlink(requirements_file.name)
            return True

        sickrage.app.alerts.error(_('Updater'), _('Failed to update requirements'))

        sickrage.app.log.warning('Unable to update requirements')

        if output:
            output = output.decode("utf-8", "ignore").strip() if isinstance(output, bytes) else output.strip()
            sickrage.app.log.debug("PIP CMD OUTPUT: {}".format(output))

        requirements_file.close()
        os.unlink(requirements_file.name)

        return False
Example #20
0
def _xem_exceptions_fetcher(force=False):
    if should_refresh('xem') or force:
        sickrage.app.log.info("Checking for XEM scene exception updates")

        for indexer in IndexerApi().indexers:
            url = "http://thexem.de/map/allNames?origin=%s&seasonNumbers=1" % IndexerApi(indexer).config[
                'xem_origin']

            try:
                parsedJSON = WebSession().get(url, timeout=90).json()
            except Exception:
                sickrage.app.log.debug("Check scene exceptions update failed for " + IndexerApi(
                    indexer).name + ", Unable to get URL: " + url)
                continue

            if parsedJSON['result'] == 'failure':
                continue

            for indexer_id, names in parsedJSON['data'].items():
                try:
                    xem_exception_dict[int(indexer_id)] = names
                except Exception as e:
                    sickrage.app.log.warning(
                        "XEM: Rejected entry: indexer_id:{0}; names:{1}".format(indexer_id, names))
                    sickrage.app.log.debug("XEM: Rejected entry error message:{}".format(e))

        set_last_refresh('xem')

    for xem_ex in xem_exception_dict:
        if xem_ex in exception_dict:
            exception_dict[xem_ex] = exception_dict[xem_ex] + xem_exception_dict[xem_ex]
        else:
            exception_dict[xem_ex] = xem_exception_dict[xem_ex]

    return xem_exception_dict
Example #21
0
    def _check_for_new_version(self):
        git_version_url = "https://git.sickrage.ca/SiCKRAGE/sickrage/raw/{}/sickrage/version.txt"

        try:
            return WebSession().get(git_version_url.format(('master', 'develop')['dev' in self.version])).text
        except Exception:
            return self._find_installed_version()
Example #22
0
    def test_authentication(host=None, username=None, password=None, apikey=None):
        """
        Sends a simple API request to SAB to determine if the given connection information is connect
        :param host: The host where SAB is running (incl port)
        :param username: The username to use for the HTTP request
        :param password: The password to use for the HTTP request
        :param apikey: The API key to provide to SAB
        :return: A tuple containing the success boolean and a message
        """

        # build up the URL parameters
        params = {
            'mode': 'queue',
            'output': 'json',
            'ma_username': username,
            'ma_password': password,
            'apikey': apikey
        }

        url = urljoin(host, 'api')

        data = WebSession().get(url, params=params, verify=False).json()
        if not data:
            return False, data

        # check the result and determine if it's good or not
        result, sabText = SabNZBd._check_sab_response(data)
        if not result:
            return False, sabText

        return True, 'Success'
Example #23
0
    def _send_telegram_msg(self, title, msg, id=None, api_key=None):
        """
        Sends a Telegram notification

        :param title: The title of the notification to send
        :param msg: The message string to send
        :param id: The Telegram user/group id to send the message to
        :param api_key: Your Telegram bot API token

        :returns: True if the message succeeded, False otherwise
        """
        id = sickrage.app.config.telegram_id or id
        api_key = sickrage.app.config.telegram_apikey or api_key

        payload = {'chat_id': id, 'text': '{} : {}'.format(title, msg)}

        telegram_api = 'https://api.telegram.org/bot{}/{}'

        try:
            resp = WebSession().post(telegram_api.format(
                api_key, 'sendMessage'),
                                     json=payload).json()
            success = resp['ok']
            message = 'Telegram message sent successfully.' if success else '{} {}'.format(
                resp['error_code'], resp['description'])
        except Exception as e:
            success = False
            message = 'Error while sending Telegram message: {} '.format(e)

        sickrage.app.log.info(message)
        return success, message
Example #24
0
    def _sendPushalot(self, pushalot_authorizationtoken=None, event=None, message=None, force=False):
        if not sickrage.app.config.pushalot.enable and not force:
            return False

        sickrage.app.log.debug("Pushalot event: " + event)
        sickrage.app.log.debug("Pushalot message: " + message)
        sickrage.app.log.debug("Pushalot api: " + pushalot_authorizationtoken)

        data = {'AuthorizationToken': pushalot_authorizationtoken,
                'Title': event,
                'Body': message}

        try:
            WebSession().post("https://pushalot.com/api/sendmessage",
                              headers={'Content-type': "application/x-www-form-urlencoded"},
                              data=urlencode(data))
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 410:
                sickrage.app.log.warning("Pushalot auth failed: %s" % e.response.text)
                return False

            sickrage.app.log.error("Pushalot notification failed.")
            return False

        sickrage.app.log.debug("Pushalot notifications sent.")
        return True
Example #25
0
    def _check_for_new_version(self):
        git_version_url = "https://git.sickrage.ca/SiCKRAGE/sickrage/raw/master/sickrage/version.txt"

        try:
            return WebSession().get(git_version_url).text
        except Exception:
            return self._find_installed_version()
Example #26
0
    def fetch_popular_shows(self):
        """Get popular show information from IMDB"""

        popular_shows = []

        try:
            data = WebSession().get(self.url,
                                    headers={
                                        'Referer': 'http://akas.imdb.com/'
                                    },
                                    params=self.params).text
        except Exception:
            return None

        with bs4_parser(data) as soup:
            for row in soup.find_all("div", {"class": "lister-item"}):
                show = {}
                image_div = row.find("div", {"class": "lister-item-image"})
                if image_div:
                    image = image_div.find("img")
                    show['image_url_large'] = self.change_size(
                        image['loadlate'], 3)
                    show['imdb_tt'] = image['data-tconst']
                    show['image_path'] = posixpath.join(
                        'images', 'imdb_popular',
                        os.path.basename(show['image_url_large']))
                    self.cache_image(show['image_url_large'])

                content = row.find("div", {"class": "lister-item-content"})
                if content:
                    header = row.find("h3", {"class": "lister-item-header"})
                    if header:
                        a_tag = header.find("a")
                        if a_tag:
                            show['name'] = a_tag.get_text(strip=True)
                            show['imdb_url'] = "http://www.imdb.com" + a_tag[
                                "href"]
                            show['year'] = header.find(
                                "span", {
                                    "class": "lister-item-year"
                                }).contents[0].split(" ")[0][1:5]

                    imdb_rating = row.find("div",
                                           {"class": "ratings-imdb-rating"})
                    show['rating'] = imdb_rating[
                        'data-value'] if imdb_rating else None

                    votes = row.find("span", {"name": "nv"})
                    show['votes'] = votes['data-value'] if votes else None

                    outline = content.find_all("p", {"class": "text-muted"})
                    if outline and len(outline) >= 2:
                        show['outline'] = outline[1].contents[0].strip("\"")
                    else:
                        show['outline'] = ''

                    popular_shows.append(show)

            return popular_shows
Example #27
0
    def _sendPushbullet(self,
                        pushbullet_api=None,
                        pushbullet_device=None,
                        event=None,
                        message=None,
                        force=False):
        if not (sickrage.app.config.use_pushbullet or force):
            return False

        pushbullet_api = pushbullet_api or sickrage.app.config.pushbullet_api
        pushbullet_device = pushbullet_device or sickrage.app.config.pushbullet_device

        sickrage.app.log.debug("Pushbullet event: %r" % event)
        sickrage.app.log.debug("Pushbullet message: %r" % message)
        sickrage.app.log.debug("Pushbullet api: %r" % pushbullet_api)
        sickrage.app.log.debug("Pushbullet devices: %r" % pushbullet_device)

        post_data = {
            'title': event.encode('utf-8'),
            'body': message.encode('utf-8'),
            'type': 'note'
        }

        if pushbullet_device:
            post_data['device_iden'] = pushbullet_device.encode('utf8')

        headers = {
            'Content-Type': 'application/json',
            'Access-Token': pushbullet_api
        }

        try:
            response = WebSession().post(urljoin(self.url, 'pushes'),
                                         data=json.dumps(post_data),
                                         headers=headers)
        except Exception:
            sickrage.app.log.debug(
                'Pushbullet authorization failed with exception: %r' %
                traceback.format_exc())
            return False

        if response.status_code == 410:
            sickrage.app.log.debug('Pushbullet authorization failed')
            return False

        if not response.ok:
            sickrage.app.log.debug(
                'Pushbullet call failed with error code %r' %
                response.status_code)
            return False

        sickrage.app.log.debug("Pushbullet response: %r" % response.text)

        if not response.text:
            sickrage.app.log.error("Pushbullet notification failed.")
            return False

        sickrage.app.log.debug("Pushbullet notifications sent.")
        return (True, response.text)[event is self.TEST_EVENT or event is None]
Example #28
0
    def _send_to_kodi_json(self,
                           command,
                           host=None,
                           username=None,
                           password=None):
        """Handles communication to KODI servers via JSONRPC

        Args:
            command: Dictionary of field/data pairs, encoded via urllib and passed to the KODI JSON-RPC via HTTP
            host: KODI webserver host:port
            username: KODI webserver username
            password: KODI webserver password

        Returns:
            Returns response.result for successful commands or False if there was an error

        """

        # fill in omitted parameters
        if not username:
            username = sickrage.app.config.kodi_username
        if not password:
            password = sickrage.app.config.kodi_password

        if not host:
            sickrage.app.log.warning('No KODI host passed, aborting update')
            return False

        sickrage.app.log.debug("KODI JSON command: {!r}".format(command))

        url = 'http://%s/jsonrpc' % host

        headers = {"Content-type": "application/json"}

        # if we have a password, use authentication
        if password:
            authheader = "Basic {}".format(
                base64.b64encode(
                    bytes('{}:{}'.format(username, password).replace('\n', ''),
                          'utf-8')).decode('ascii'))
            headers["Authorization"] = authheader
            sickrage.app.log.debug(
                "Contacting KODI (with auth header) via url: " + url)
        else:
            sickrage.app.log.debug("Contacting KODI via url: " + url)

        try:
            result = WebSession().post(url, json=command,
                                       headers=headers).json()
            sickrage.app.log.debug("KODI JSON response: " + str(result))
            return result
        except Exception as e:
            if sickrage.app.config.kodi_always_on:
                sickrage.app.log.warning(
                    "Warning: Couldn't contact KODI JSON API at " + url +
                    " {}".format(e))

        return False
Example #29
0
    def _request(self, method, url, lang=None, retries=3, **kwargs):
        self.config['headers'].update({'Content-type': 'application/json'})
        self.config['headers']['Authorization'] = 'Bearer {}'.format(self.jwt_token)
        self.config['headers'].update({'Accept-Language': lang or self.config['language']})

        for i in range(0, retries):
            try:
                # get response from theTVDB
                resp = WebSession(cache=self.config['cache_enabled']).request(
                    method, urljoin(self.config['api']['base'], url), headers=self.config['headers'],
                    timeout=sickrage.app.config.indexer_timeout, **kwargs
                )
            except Exception as e:
                if i < retries - 1:
                    continue
                raise tvdb_error(e)

            # handle requests exceptions
            try:
                if resp.status_code == 401:
                    raise tvdb_unauthorized(resp.json()['Error'])
                elif resp.status_code >= 400:
                    if i < retries - 1:
                        continue
                    raise tvdb_error(resp.json()['Error'])
            except JSONDecodeError:
                try:
                    resp.raise_for_status()
                except RequestException as e:
                    if i < retries - 1:
                        continue
                    raise tvdb_error(e)

            return to_lowercase(resp.json())
Example #30
0
    def getRSSFeed(self, url, params=None):
        try:
            if self.provider.login():
                resp = WebSession().get(url, params=params).text
                return feedparser.parse(resp)
        except Exception as e:
            sickrage.app.log.debug("RSS Error: {}".format(e))

        return feedparser.FeedParserDict()
Example #31
0
    def update(self):
        """
        Downloads the latest source tarball from server and installs it over the existing version.
        """

        tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar.gz?ref={}'.format(('master', 'develop')['dev' in self.version])

        try:
            if not self.install_requirements(self.current_branch):
                return False

            with tempfile.TemporaryFile() as update_tarfile:
                sickrage.app.log.info("Downloading update from " + repr(tar_download_url))
                update_tarfile.write(WebSession().get(tar_download_url).content)
                update_tarfile.seek(0)

                with tempfile.TemporaryDirectory(prefix='sr_update_', dir=sickrage.app.data_dir) as unpack_dir:
                    sickrage.app.log.info("Extracting SiCKRAGE update file")
                    try:
                        tar = tarfile.open(fileobj=update_tarfile, mode='r:gz')
                        tar.extractall(unpack_dir)
                        tar.close()
                    except tarfile.ReadError:
                        sickrage.app.log.warning("Invalid update data, update failed: not a gzip file")
                        return False

                    # find update dir name
                    update_dir_contents = [x for x in os.listdir(unpack_dir) if os.path.isdir(os.path.join(unpack_dir, x))]
                    if len(update_dir_contents) != 1:
                        sickrage.app.log.warning("Invalid update data, update failed: " + str(update_dir_contents))
                        return False

                    # walk temp folder and move files to main folder
                    content_dir = os.path.join(unpack_dir, update_dir_contents[0])
                    sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.MAIN_DIR)
                    for dirname, __, filenames in os.walk(content_dir):
                        dirname = dirname[len(content_dir) + 1:]
                        for curfile in filenames:
                            old_path = os.path.join(content_dir, dirname, curfile)
                            new_path = os.path.join(sickrage.MAIN_DIR, dirname, curfile)

                            if os.path.isfile(new_path) and os.path.exists(new_path):
                                os.remove(new_path)

                            try:
                                shutil.move(old_path, new_path)
                            except IOError:
                                os.makedirs(os.path.dirname(new_path))
                                shutil.move(old_path, new_path)
        except Exception as e:
            sickrage.app.log.error("Error while trying to update: {}".format(e))
            return False

        # Notify update successful
        Notifiers.mass_notify_version_update(self.get_newest_version)

        return True
Example #32
0
    def _request(self, method, url, lang=None, **kwargs):
        self.config['headers'].update({'Content-type': 'application/json'})
        self.config['headers']['Authorization'] = 'Bearer {}'.format(self.jwt_token)
        self.config['headers'].update({'Accept-Language': lang or self.config['language']})

        # get response from theTVDB
        try:
            resp = WebSession(cache=self.config['cache_enabled']).request(
                method, urlparse.urljoin(self.config['api']['base'], url), headers=self.config['headers'],
                timeout=sickrage.app.config.indexer_timeout, **kwargs
            )
        except Exception as e:
            raise tvdb_error(str(e))

        # handle requests exceptions
        try:
            if resp.status_code == 401:
                raise tvdb_unauthorized(resp.json()['Error'])
            elif resp.status_code >= 400:
                raise tvdb_error(resp.json()['Error'])
        except JSONDecodeError:
            try:
                resp.raise_for_status()
            except RequestException as e:
                raise tvdb_error(str(e))

        return to_lowercase(resp.json())
Example #33
0
    def update_network_timezones(self):
        """Update timezone information from SR repositories"""

        network_timezones = {}

        try:
            url_data = WebSession().get('https://cdn.sickrage.ca/network_timezones/').text
        except Exception:
            sickrage.app.log.warning('Updating network timezones failed.')
            return

        try:
            for line in url_data.splitlines():
                (key, val) = line.strip().rsplit(':', 1)
                if all([key, val]):
                    network_timezones[key] = val
        except (IOError, OSError):
            pass

        for x in sickrage.app.cache_db.all('network_timezones'):
            if x['network_name'] not in network_timezones:
                sickrage.app.cache_db.delete(x)

        for network, timezone in network_timezones.items():
            dbData = sickrage.app.cache_db.get('network_timezones', network)
            if not dbData:
                sickrage.app.cache_db.insert({
                    '_t': 'network_timezones',
                    'network_name': ss(network),
                    'timezone': timezone
                })
            elif dbData['timezone'] != timezone:
                dbData['timezone'] = timezone
                sickrage.app.cache_db.update(dbData)

        # cleanup
        del network_timezones