Exemple #1
0
    def _send_to_xbmc(self, command, host=None, username=None, password=None):
        """Handles communication to XBMC servers via HTTP API

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

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

        """

        # fill in omitted parameters
        if not username:
            username = sickbeard.XBMC_USERNAME
        if not password:
            password = sickbeard.XBMC_PASSWORD

        if not host:
            logger.log(u'No XBMC host passed, aborting update', logger.DEBUG)
            return False

        for key in command:
            if type(command[key]) == unicode:
                command[key] = command[key].encode('utf-8')

        enc_command = urllib.urlencode(command)
        logger.log(u"XBMC encoded API command: " + enc_command, logger.DEBUG)

        url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command)
        try:
            req = urllib2.Request(url)
            # if we have a password, use authentication
            if password:
                base64string = base64.encodestring('%s:%s' %
                                                   (username, password))[:-1]
                authheader = "Basic %s" % base64string
                req.add_header("Authorization", authheader)
                logger.log(
                    u"Contacting XBMC (with auth header) via url: " +
                    toUnicode(url), logger.DEBUG)
            else:
                logger.log(u"Contacting XBMC via url: " + toUnicode(url),
                           logger.DEBUG)

            response = urllib2.urlopen(req)
            result = response.read().decode(sickbeard.SYS_ENCODING)
            response.close()

            logger.log(u"XBMC HTTP response: " + result.replace('\n', ''),
                       logger.DEBUG)
            return result

        except (urllib2.URLError, IOError), e:
            logger.log(
                u"Warning: Couldn't contact XBMC HTTP at " + toUnicode(url) +
                " " + ex(e), logger.WARNING)
            return False
Exemple #2
0
def ex(e):
    """
    Returns a unicode string from the exception text if it exists.
    """

    e_message = u""

    if not e or not e.args:
        return e_message

    for arg in e.args:

        if arg is not None:
            if isinstance(arg, (str, unicode)):
                fixed_arg = toUnicode(arg)

            else:
                try:
                    fixed_arg = u"error " + toUnicode(str(arg))

                except:
                    fixed_arg = None

            if fixed_arg:
                if not e_message:
                    e_message = fixed_arg

                else:
                    e_message = e_message + " : " + fixed_arg

    return e_message
Exemple #3
0
def ex(e):
    """
    Returns a unicode string from the exception text if it exists.
    """

    e_message = u""

    if not e or not e.args:
        return e_message

    for arg in e.args:

        if arg is not None:
            if isinstance(arg, (str, unicode)):
                fixed_arg = toUnicode(arg)

            else:
                try:
                    fixed_arg = u"error " + toUnicode(str(arg))

                except:
                    fixed_arg = None

            if fixed_arg:
                if not e_message:
                    e_message = fixed_arg

                else:
                    e_message = e_message + " : " + fixed_arg

    return e_message
Exemple #4
0
    def _send_to_xbmc_json(self, command, host=None, username=None, password=None):
        """Handles communication to XBMC servers via JSONRPC

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

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

        """

        # fill in omitted parameters
        if not username:
            username = sickbeard.XBMC_USERNAME
        if not password:
            password = sickbeard.XBMC_PASSWORD

        if not host:
            logger.log(u'No XBMC host passed, aborting update', logger.DEBUG)
            return False

        command = command.encode('utf-8')
        logger.log(u"XBMC JSON command: " + command, logger.DEBUG)

        url = 'http://%s/jsonrpc' % (host)
        try:
            req = urllib2.Request(url, command)
            req.add_header("Content-type", "application/json")
            # if we have a password, use authentication
            if password:
                base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
                authheader = "Basic %s" % base64string
                req.add_header("Authorization", authheader)
                logger.log(u"Contacting XBMC (with auth header) via url: " + toUnicode(url), logger.DEBUG)
            else:
                logger.log(u"Contacting XBMC via url: " + toUnicode(url), logger.DEBUG)

            try:
                response = urllib2.urlopen(req)
            except urllib2.URLError, e:
                logger.log(u"Error while trying to retrieve XBMC API version for " + host + ": " + ex(e),
                           logger.WARNING)
                return False

            # parse the json result
            try:
                result = json.load(response)
                response.close()
                logger.log(u"XBMC JSON response: " + str(result), logger.DEBUG)
                return result  # need to return response for parsing
            except ValueError, e:
                logger.log(u"Unable to decode JSON: " + response, logger.WARNING)
                return False
Exemple #5
0
    def _send_to_xbmc(self, command, host=None, username=None, password=None):
        """Handles communication to XBMC servers via HTTP API

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

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

        """

        # fill in omitted parameters
        if not username:
            username = sickbeard.XBMC_USERNAME
        if not password:
            password = sickbeard.XBMC_PASSWORD

        if not host:
            logger.log(u'No XBMC host passed, aborting update', logger.DEBUG)
            return False

        for key in command:
            if type(command[key]) == unicode:
                command[key] = command[key].encode('utf-8')

        enc_command = urllib.urlencode(command)
        logger.log(u"XBMC encoded API command: " + enc_command, logger.DEBUG)

        url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command)
        try:
            req = urllib2.Request(url)
            # if we have a password, use authentication
            if password:
                base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
                authheader = "Basic %s" % base64string
                req.add_header("Authorization", authheader)
                logger.log(u"Contacting XBMC (with auth header) via url: " + toUnicode(url), logger.DEBUG)
            else:
                logger.log(u"Contacting XBMC via url: " + toUnicode(url), logger.DEBUG)

            response = urllib2.urlopen(req)
            result = response.read().decode(sickbeard.SYS_ENCODING)
            response.close()

            logger.log(u"XBMC HTTP response: " + result.replace('\n', ''), logger.DEBUG)
            return result

        except (urllib2.URLError, IOError), e:
            logger.log(u"Warning: Couldn't contact XBMC HTTP at " + toUnicode(url) + " " + ex(e),
                       logger.WARNING)
            return False
Exemple #6
0
    def notify_download(self, ep_name, title="Completed:"):
        """
        Send a notification that an episode was downloaded
        
        ep_name: The name of the episode that was downloaded
        title: The title of the notification (optional)
        """
        ep_name = toUnicode(ep_name)

        if sickbeard.EMAIL_NOTIFY_ONDOWNLOAD:
            show = self._parseEp(ep_name)
            to = self._generate_recepients(show)
            if len(to) == 0:
                logger.log('Skipping email notify because there are no configured recepients', logger.WARNING)
            else:
                try:
                    msg = MIMEMultipart('alternative')
                    msg.attach(MIMEText(
                        "<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickRage Notification - Downloaded</h3>\n<p>Show: <b>" + re.search(
                            "(.+?) -.+", ep_name).group(1) + "</b></p>\n<p>Episode: <b>" + re.search(
                            ".+ - (.+?-.+) -.+", ep_name).group(
                            1) + "</b></p>\n\n<footer style='margin-top: 2.5em; padding: .7em 0; color: #777; border-top: #BBB solid 1px;'>Powered by SickRage.</footer></body>",
                        'html'))
                except:
                    msg = MIMEText(ep_name)

                msg['Subject'] = 'Downloaded: ' + ep_name
                msg['From'] = sickbeard.EMAIL_FROM
                msg['To'] = ','.join(to)
                if self._sendmail(sickbeard.EMAIL_HOST, sickbeard.EMAIL_PORT, sickbeard.EMAIL_FROM, sickbeard.EMAIL_TLS,
                                  sickbeard.EMAIL_USER, sickbeard.EMAIL_PASSWORD, to, msg):
                    logger.log("Download notification sent to [%s] for '%s'" % (to, ep_name), logger.DEBUG)
                else:
                    logger.log("Download notification ERROR: %s" % self.last_err, logger.ERROR)
Exemple #7
0
    def _parseEp(self, ep_name):
        ep_name = toUnicode(ep_name)

        sep = " - "
        titles = ep_name.split(sep)
        titles.sort(key=len, reverse=True)
        logger.log("TITLES: %s" % titles, logger.DEBUG)
        return titles
Exemple #8
0
def _logHistoryItem(action, showid, season, episode, quality, resource, provider, version=-1):
    logDate = datetime.datetime.today().strftime(dateFormat)
    resource = toUnicode(resource)

    myDB = db.DBConnection()
    myDB.action(
        "INSERT INTO history (action, date, showid, season, episode, quality, resource, provider, version) VALUES (?,?,?,?,?,?,?,?,?)",
        [action, logDate, showid, season, episode, quality, resource, provider, version])
Exemple #9
0
def createNZBString(fileElements, xmlns):
    rootElement = etree.Element("nzb")
    if xmlns:
        rootElement.set("xmlns", xmlns)

    for curFile in fileElements:
        rootElement.append(stripNS(curFile, xmlns))

    return xml.etree.ElementTree.tostring(toUnicode(rootElement))
Exemple #10
0
def prepareFailedName(release):
    """Standardizes release name for failed DB"""

    fixed = urllib.unquote(release)
    if (fixed.endswith(".nzb")):
        fixed = fixed.rpartition(".")[0]

    fixed = re.sub("[\.\-\+\ ]", "_", fixed)
    fixed = toUnicode(fixed)

    return fixed
Exemple #11
0
    def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0):

        # check if we passed in a parsed result or should we try and create one
        if not parse_result:

            # create showObj from indexer_id if available
            showObj=None
            if indexer_id:
                showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)

            try:
                myParser = NameParser(showObj=showObj, convert=True)
                parse_result = myParser.parse(name)
            except InvalidNameException:
                logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG)
                return None
            except InvalidShowException:
                logger.log(u"Unable to parse the filename " + name + " into a valid show", logger.DEBUG)
                return None

            if not parse_result or not parse_result.series_name:
                return None

        # if we made it this far then lets add the parsed result to cache for usager later on
        season = parse_result.season_number if parse_result.season_number else 1
        episodes = parse_result.episode_numbers

        if season and episodes:
            # store episodes as a seperated string
            episodeText = "|" + "|".join(map(str, episodes)) + "|"

            # get the current timestamp
            curTimestamp = int(time.mktime(datetime.datetime.today().timetuple()))

            # get quality of release
            quality = parse_result.quality

            name = toUnicode(name)

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.log(u"Added RSS item: [" + name + "] to cache: [" + self.providerID + "]", logger.DEBUG)

            return [
                "INSERT OR IGNORE INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)",
                [name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group, version]]
def update_scene_exceptions(indexer_id, scene_exceptions, season=-1):
    """
    Given a indexer_id, and a list of all show scene exceptions, update the db.
    """
    global exceptionsCache
    myDB = db.DBConnection('cache.db')
    myDB.action('DELETE FROM scene_exceptions WHERE indexer_id=? and season=?', [indexer_id, season])

    logger.log(u"Updating scene exceptions", logger.MESSAGE)
    
    # A change has been made to the scene exception list. Let's clear the cache, to make this visible
    if indexer_id in exceptionsCache:
        exceptionsCache[indexer_id] = {}
        exceptionsCache[indexer_id][season] = scene_exceptions

    for cur_exception in scene_exceptions:
        cur_exception = toUnicode(cur_exception)

        myDB.action("INSERT INTO scene_exceptions (indexer_id, show_name, season) VALUES (?,?,?)",
                    [indexer_id, cur_exception, season])
Exemple #13
0
                logger.log(u"Error while trying to retrieve XBMC API version for " + host + ": " + ex(e),
                           logger.WARNING)
                return False

            # parse the json result
            try:
                result = json.load(response)
                response.close()
                logger.log(u"XBMC JSON response: " + str(result), logger.DEBUG)
                return result  # need to return response for parsing
            except ValueError, e:
                logger.log(u"Unable to decode JSON: " + response, logger.WARNING)
                return False

        except IOError, e:
            logger.log(u"Warning: Couldn't contact XBMC JSON API at " + toUnicode(url) + " " + ex(e),
                       logger.WARNING)
            return False

    def _update_library_json(self, host=None, showName=None):
        """Handles updating XBMC host via HTTP JSON-RPC

        Attempts to update the XBMC video library for a specific tv show if passed,
        otherwise update the whole library if enabled.

        Args:
            host: XBMC webserver host:port
            showName: Name of a TV show to specifically target the library update for

        Returns:
            Returns True or False
Exemple #14
0
    def _send_to_xbmc_json(self,
                           command,
                           host=None,
                           username=None,
                           password=None):
        """Handles communication to XBMC servers via JSONRPC

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

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

        """

        # fill in omitted parameters
        if not username:
            username = sickbeard.XBMC_USERNAME
        if not password:
            password = sickbeard.XBMC_PASSWORD

        if not host:
            logger.log(u'No XBMC host passed, aborting update', logger.DEBUG)
            return False

        command = command.encode('utf-8')
        logger.log(u"XBMC JSON command: " + command, logger.DEBUG)

        url = 'http://%s/jsonrpc' % (host)
        try:
            req = urllib2.Request(url, command)
            req.add_header("Content-type", "application/json")
            # if we have a password, use authentication
            if password:
                base64string = base64.encodestring('%s:%s' %
                                                   (username, password))[:-1]
                authheader = "Basic %s" % base64string
                req.add_header("Authorization", authheader)
                logger.log(
                    u"Contacting XBMC (with auth header) via url: " +
                    toUnicode(url), logger.DEBUG)
            else:
                logger.log(u"Contacting XBMC via url: " + toUnicode(url),
                           logger.DEBUG)

            try:
                response = urllib2.urlopen(req)
            except urllib2.URLError, e:
                logger.log(
                    u"Error while trying to retrieve XBMC API version for " +
                    host + ": " + ex(e), logger.WARNING)
                return False

            # parse the json result
            try:
                result = json.load(response)
                response.close()
                logger.log(u"XBMC JSON response: " + str(result), logger.DEBUG)
                return result  # need to return response for parsing
            except ValueError, e:
                logger.log(u"Unable to decode JSON: " + response,
                           logger.WARNING)
                return False
def retrieve_exceptions():
    """
    Looks up the exceptions on github, parses them into a dict, and inserts them into the
    scene_exceptions table in cache.db. Also clears the scene name cache.
    """
    global exception_dict, anidb_exception_dict, xem_exception_dict

    # exceptions are stored on github pages
    for indexer in sickbeard.indexerApi().indexers:
        if shouldRefresh(sickbeard.indexerApi(indexer).name):
            logger.log(u"Checking for scene exception updates for " + sickbeard.indexerApi(indexer).name + "")

            url = sickbeard.indexerApi(indexer).config['scene_url']

            url_data = helpers.getURL(url)
            if url_data is None:
                # When urlData is None, trouble connecting to github
                logger.log(u"Check scene exceptions update failed. Unable to get URL: " + url, logger.ERROR)
                continue

            else:
                setLastRefresh(sickbeard.indexerApi(indexer).name)

                # each exception is on one line with the format indexer_id: 'show name 1', 'show name 2', etc
                for cur_line in url_data.splitlines():
                    cur_line = cur_line.decode('utf-8')
                    indexer_id, sep, aliases = cur_line.partition(':')  # @UnusedVariable

                    if not aliases:
                        continue

                    indexer_id = int(indexer_id)

                    # regex out the list of shows, taking \' into account
                    # alias_list = [re.sub(r'\\(.)', r'\1', x) for x in re.findall(r"'(.*?)(?<!\\)',?", aliases)]
                    alias_list = [{re.sub(r'\\(.)', r'\1', x): -1} for x in re.findall(r"'(.*?)(?<!\\)',?", aliases)]
                    exception_dict[indexer_id] = alias_list
                    del alias_list
                del url_data

    # XEM scene exceptions
    _xem_exceptions_fetcher()
    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]

    # AniDB scene exceptions
    _anidb_exceptions_fetcher()
    for anidb_ex in anidb_exception_dict:
        if anidb_ex in exception_dict:
            exception_dict[anidb_ex] = exception_dict[anidb_ex] + anidb_exception_dict[anidb_ex]
        else:
            exception_dict[anidb_ex] = anidb_exception_dict[anidb_ex]

    changed_exceptions = False

    # write all the exceptions we got off the net into the database
    myDB = db.DBConnection('cache.db')
    for cur_indexer_id in exception_dict:

        # get a list of the existing exceptions for this ID
        existing_exceptions = [x["show_name"] for x in
                               myDB.select("SELECT * FROM scene_exceptions WHERE indexer_id = ?", [cur_indexer_id])]

        if not cur_indexer_id in exception_dict:
            continue

        for cur_exception_dict in exception_dict[cur_indexer_id]:
            cur_exception, curSeason = cur_exception_dict.items()[0]

            # if this exception isn't already in the DB then add it
            if cur_exception not in existing_exceptions:

                cur_exception = toUnicode(cur_exception)

                myDB.action("INSERT INTO scene_exceptions (indexer_id, show_name, season) VALUES (?,?,?)",
                            [cur_indexer_id, cur_exception, curSeason])
                changed_exceptions = True

    # since this could invalidate the results of the cache we clear it out after updating
    if changed_exceptions:
        logger.log(u"Updated scene exceptions")
    else:
        logger.log(u"No scene exceptions update needed")

    # cleanup
    exception_dict.clear()
    anidb_exception_dict.clear()
    xem_exception_dict.clear()
Exemple #16
0
            # parse the json result
            try:
                result = json.load(response)
                response.close()
                logger.log(u"XBMC JSON response: " + str(result), logger.DEBUG)
                return result  # need to return response for parsing
            except ValueError, e:
                logger.log(u"Unable to decode JSON: " + response,
                           logger.WARNING)
                return False

        except IOError, e:
            logger.log(
                u"Warning: Couldn't contact XBMC JSON API at " +
                toUnicode(url) + " " + ex(e), logger.WARNING)
            return False

    def _update_library_json(self, host=None, showName=None):
        """Handles updating XBMC host via HTTP JSON-RPC

        Attempts to update the XBMC video library for a specific tv show if passed,
        otherwise update the whole library if enabled.

        Args:
            host: XBMC webserver host:port
            showName: Name of a TV show to specifically target the library update for

        Returns:
            Returns True or False
Exemple #17
0
    def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0):

        # check if we passed in a parsed result or should we try and create one
        if not parse_result:

            # create showObj from indexer_id if available
            showObj = None
            if indexer_id:
                showObj = helpers.findCertainShow(sickbeard.showList,
                                                  indexer_id)

            try:
                myParser = NameParser(showObj=showObj, convert=True)
                parse_result = myParser.parse(name)
            except InvalidNameException:
                logger.log(
                    u"Unable to parse the filename " + name +
                    " into a valid episode", logger.DEBUG)
                return None
            except InvalidShowException:
                logger.log(
                    u"Unable to parse the filename " + name +
                    " into a valid show", logger.DEBUG)
                return None

            if not parse_result or not parse_result.series_name:
                return None

        # if we made it this far then lets add the parsed result to cache for usager later on
        season = parse_result.season_number if parse_result.season_number else 1
        episodes = parse_result.episode_numbers

        if season and episodes:
            # store episodes as a seperated string
            episodeText = "|" + "|".join(map(str, episodes)) + "|"

            # get the current timestamp
            curTimestamp = int(
                time.mktime(datetime.datetime.today().timetuple()))

            # get quality of release
            quality = parse_result.quality

            name = toUnicode(name)

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.log(
                u"Added RSS item: [" + name + "] to cache: [" +
                self.providerID + "]", logger.DEBUG)

            return [
                "INSERT OR IGNORE INTO [" + self.providerID +
                "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)",
                [
                    name, season, episodeText, parse_result.show.indexerid,
                    url, curTimestamp, quality, release_group, version
                ]
            ]