def ex(e): """ :param e: The exception to convert into a unicode string :return: A unicode string from the exception text if it exists """ message = u'' if not e or not e.args: return message for arg in e.args: if arg is not None: if isinstance(arg, (str, unicode)): fixed_arg = ss(arg) else: try: fixed_arg = u'error %s' % ss(str(arg)) except Exception: fixed_arg = None if fixed_arg: if not message: message = fixed_arg else: message = '%s : %s' % (message, fixed_arg) return message
def ex(e): """ :param e: The exception to convert into a unicode string :return: A unicode string from the exception text if it exists """ message = u'' if not e or not e.args: return message for arg in e.args: if arg is not None: if isinstance(arg, (str, text_type)): fixed_arg = ss(arg) else: try: fixed_arg = u'error %s' % ss(str(arg)) except Exception: fixed_arg = None if fixed_arg: if not message: message = fixed_arg else: try: message = u'{} : {}'.format(message, fixed_arg) except UnicodeError: message = u'{} : {}'.format( text_type(message, errors='replace'), text_type(fixed_arg, errors='replace')) return message
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 = sickbeard.KODI_USERNAME if not password: password = sickbeard.KODI_PASSWORD if not host: logger.log(u'No KODI host passed, aborting update', logger.WARNING) 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"KODI encoded API command: " + enc_command, logger.DEBUG) url = 'http://%s/kodiCmds/kodiHttp/?%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 KODI (with auth header) via url: " + ss(url), logger.DEBUG) else: logger.log(u"Contacting KODI via url: " + ss(url), logger.DEBUG) response = urllib2.urlopen(req) result = response.read().decode(sickbeard.SYS_ENCODING) response.close() logger.log(u"KODI HTTP response: " + result.replace('\n', ''), logger.DEBUG) return result except Exception as e: logger.log( u"Warning: Couldn't contact KODI HTTP at " + ss(url) + " " + str(e), logger.WARNING) return False
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 = ss(arg) else: try: fixed_arg = u"error " + ss(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
def ex(e): """ :param e: The exception to convert into a six.text_type string :return: A six.text_type string from the exception text if it exists """ message = '' if not e or not e.args: return message for arg in e.args: if arg is not None: if isinstance(arg, six.string_types): fixed_arg = ss(arg) else: try: fixed_arg = 'error {0}'.format(ss(str(arg))) except Exception: fixed_arg = None if fixed_arg: if not message: message = fixed_arg else: try: message = '{0} : {1}'.format(message, fixed_arg) except UnicodeError: message = '{0} : {1}'.format( six.text_type(message, errors='replace'), six.text_type(fixed_arg, errors='replace')) return message
def processEpisode(self, proc_dir=None, nzbName=None, jobName=None, quiet=None, process_method=None, force=None, is_priority=None, delete_on='0', failed='0', type='auto', *args, **kwargs): nzb_name = nzbName def argToBool(argument): if isinstance(argument, basestring): _arg = argument.strip().lower() else: _arg = argument if _arg in ['1', 'on', 'true', True]: return True elif _arg in ['0', 'off', 'false', False]: return False return argument if not proc_dir: return self.redirect('/home/postprocess/') else: nzb_name = ss(nzb_name) if nzb_name else nzb_name result = processTV.processDir( ss(proc_dir), nzb_name, process_method=process_method, force=argToBool(force), is_priority=argToBool(is_priority), delete_on=argToBool(delete_on), failed=argToBool(failed), proc_type=type ) if quiet is not None and int(quiet) == 1: return result result = result.replace('\n', '<br>\n') return self._genericMessage('Postprocessing results', result)
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 = sickbeard.KODI_USERNAME if not password: password = sickbeard.KODI_PASSWORD if not host: logger.log(u'No KODI host passed, aborting update', logger.WARNING) return False for key in command: if isinstance(command[key], unicode): command[key] = command[key].encode('utf-8') enc_command = urllib.urlencode(command) logger.log(u"KODI encoded API command: " + enc_command, logger.DEBUG) url = 'http://%s/kodiCmds/kodiHttp/?%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 KODI (with auth header) via url: " + ss(url), logger.DEBUG) else: logger.log(u"Contacting KODI via url: " + ss(url), logger.DEBUG) try: response = urllib2.urlopen(req) except (httplib.BadStatusLine, urllib2.URLError) as e: logger.log(u"Couldn't contact KODI HTTP at %r : %r" % (url, ex(e)), logger.DEBUG) return False result = response.read().decode(sickbeard.SYS_ENCODING) response.close() logger.log(u"KODI HTTP response: " + result.replace('\n', ''), logger.DEBUG) return result except Exception as e: logger.log(u"Couldn't contact KODI HTTP at %r : %r" % (url, ex(e)), logger.DEBUG) return False
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 = sickbeard.KODI_USERNAME if not password: password = sickbeard.KODI_PASSWORD if not host: logger.log(u'No KODI host passed, aborting update', logger.WARNING) return False command = command.encode('utf-8') logger.log(u"KODI 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 KODI (with auth header) via url: " + ss(url), logger.DEBUG) else: logger.log(u"Contacting KODI via url: " + ss(url), logger.DEBUG) try: response = urllib2.urlopen(req) except (httplib.BadStatusLine, urllib2.URLError), e: if sickbeard.KODI_ALWAYS_ON: logger.log(u"Error while trying to retrieve KODI API version for " + host + ": " + ex(e), logger.WARNING) return False # parse the json result try: result = json.load(response) response.close() logger.log(u"KODI JSON response: " + str(result), logger.DEBUG) return result # need to return response for parsing except ValueError, e: logger.log(u"Unable to decode JSON: " + str(response.read()), logger.WARNING) return False
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 = sickbeard.KODI_USERNAME if not password: password = sickbeard.KODI_PASSWORD if not host: logger.log(u'No KODI host passed, aborting update', logger.WARNING) return False command = command.encode('utf-8') logger.log(u"KODI 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 KODI (with auth header) via url: " + ss(url), logger.DEBUG) else: logger.log(u"Contacting KODI via url: " + ss(url), logger.DEBUG) try: response = urllib2.urlopen(req) except (httplib.BadStatusLine, urllib2.URLError), e: logger.log(u"Error while trying to retrieve KODI API version for " + host + ": " + ex(e), logger.WARNING) return False # parse the json result try: result = json.load(response) response.close() logger.log(u"KODI JSON response: " + str(result), logger.DEBUG) return result # need to return response for parsing except ValueError, e: logger.log(u"Unable to decode JSON: " + str(response.read()), logger.WARNING) return False
def __str__(self): to_return = "" if self.series_name is not None: to_return += ss(self.series_name) if self.season_number is not None: to_return += 'S' + ss(self.season_number).zfill(2) if self.episode_numbers and len(self.episode_numbers): for e in self.episode_numbers: to_return += 'E' + ss(e).zfill(2) if self.is_air_by_date: to_return += ss(self.air_date) if self.ab_episode_numbers: to_return += ' [ABS: ' + ss(self.ab_episode_numbers) + ']' if self.version and self.is_anime is True: to_return += ' [ANIME VER: ' + ss(self.version) + ']' if self.release_group: to_return += ' [GROUP: ' + self.release_group + ']' to_return += ' [ABD: ' + ss(self.is_air_by_date) + ']' to_return += ' [ANIME: ' + ss(self.is_anime) + ']' to_return += ' [whichReg: ' + ss(self.which_regex) + ']' return to_return
def _parseEp(ep_name): ep_name = ss(ep_name) sep = ' - ' titles = ep_name.split(sep) logger.log('TITLES: {0}'.format(titles), logger.DEBUG) return titles
def test_email(self): """ Test email notifications """ email_notifier = EmailNotifier() # Per-show-email notifications were added early on and utilized a different format than the other notifiers. # Therefore, to test properly (and ensure backwards compatibility), this routine will test shows that use # both the old and the new storage methodology legacy_test_emails = "[email protected],[email protected],[email protected]" test_emails = "[email protected],[email protected],[email protected]" for show in self.legacy_shows: showid = self._get_showid_by_showname(show.name) self.mydb.action("UPDATE tv_shows SET notify_list = ? WHERE show_id = ?", [legacy_test_emails, showid]) for show in self.shows: showid = self._get_showid_by_showname(show.name) Home.saveShowNotifyList(show=showid, emails=test_emails) # Now, iterate through all shows using the email list generation routines that are used in the notifier proper shows = self.legacy_shows + self.shows for show in shows: for episode in show.episodes: ep_name = ss(episode._format_pattern('%SN - %Sx%0E - %EN - ') + episode.quality) # pylint: disable=protected-access show_name = email_notifier._parseEp(ep_name) # pylint: disable=protected-access recipients = email_notifier._generate_recipients(show_name) # pylint: disable=protected-access self._debug_spew("- Email Notifications for " + show.name + " (episode: " + episode.name + ") will be sent to:") for email in recipients: self._debug_spew("-- " + email.strip()) self._debug_spew("\n\r") return True
def _convert_number(org_number): """ Convert org_number into an integer org_number: integer or representation of a number: string or unicode Try force converting to int first, on error try converting from Roman numerals returns integer or 0 """ try: # try forcing to int if org_number: number = int(org_number) else: number = 0 except Exception: # on error try converting from Roman numerals roman_to_int_map = ( ('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1) ) roman_numeral = ss(org_number).upper() number = 0 index = 0 for numeral, integer in roman_to_int_map: while roman_numeral[index:index + len(numeral)] == numeral: number += integer index += len(numeral) return number
def test_prowl(self): """ Test prowl notifications """ prowl_notifier = ProwlNotifier() # Prowl per-show-notifications only utilize the new methodology for storage; therefore, the list of legacy_shows # will not be altered (to preserve backwards compatibility testing) test_prowl_apis = "11111111111111111111,22222222222222222222" for show in self.shows: showid = self._get_showid_by_showname(show.name) Home.saveShowNotifyList(show=showid, prowlAPIs=test_prowl_apis) # Now, iterate through all shows using the Prowl API generation routines that are used in the notifier proper for show in self.shows: for episode in show.episodes: ep_name = ss(episode._format_pattern('%SN - %Sx%0E - %EN - ')+episode.quality) # pylint: disable=protected-access show_name = prowl_notifier._parse_episode(ep_name) # pylint: disable=protected-access recipients = prowl_notifier._generate_recipients(show_name) # pylint: disable=protected-access self._debug_spew("- Prowl Notifications for "+show.name+" (episode: "+episode.name+") will be sent to:") for api in recipients: self._debug_spew("-- "+api.strip()) self._debug_spew("\n\r") return True
def _logHistoryItem(action, showid, season, episode, quality, resource, provider, version=-1): """ Insert a history item in DB :param action: action taken (snatch, download, etc) :param showid: showid this entry is about :param season: show season :param episode: show episode :param quality: media quality :param resource: resource used :param provider: provider used :param version: tracked version of file (defaults to -1) """ logDate = datetime.datetime.today().strftime(History.date_format) resource = ss(resource) main_db_con = db.DBConnection() main_db_con.action( "INSERT INTO history (action, date, showid, season, episode, quality, resource, provider, version) VALUES (?,?,?,?,?,?,?,?,?)", [ action, logDate, showid, season, episode, quality, resource, provider, version ])
def test_email(self): """ Test email notifications """ email_notifier = EmailNotifier() # Per-show-email notifications were added early on and utilized a different format than the other notifiers. # Therefore, to test properly (and ensure backwards compatibility), this routine will test shows that use # both the old and the new storage methodology legacy_test_emails = "[email protected],[email protected],[email protected]" test_emails = "[email protected],[email protected],[email protected]" for show in self.legacy_shows: showid = self._get_showid_by_showname(show.name) self.mydb.action("UPDATE tv_shows SET notify_list = ? WHERE show_id = ?", [legacy_test_emails, showid]) for show in self.shows: showid = self._get_showid_by_showname(show.name) Home.saveShowNotifyList(show=showid, emails=test_emails) # Now, iterate through all shows using the email list generation routines that are used in the notifier proper shows = self.legacy_shows+self.shows for show in shows: for episode in show.episodes: ep_name = ss(episode._format_pattern('%SN - %Sx%0E - %EN - ')+episode.quality) # pylint: disable=protected-access show_name = email_notifier._parseEp(ep_name) # pylint: disable=protected-access recipients = email_notifier._generate_recipients(show_name) # pylint: disable=protected-access self._debug_spew("- Email Notifications for "+show.name+" (episode: "+episode.name+") will be sent to:") for email in recipients: self._debug_spew("-- "+email.strip()) self._debug_spew("\n\r") return True
def _write_image(self, image_data, image_path, obj = None): """ Saves the data in image_data to the location image_path. Returns True/False to represent success or failure. image_data: binary image data to write to file image_path: file location to save the image to """ # don't bother overwriting it if ek(os.path.isfile, image_path): logger.log(u"Image already exists, not downloading", logger.DEBUG) return False image_dir = ek(os.path.dirname, image_path) if not image_data: logger.log(u"Unable to retrieve image to save in %s, skipping" % (ss(image_path)), logger.DEBUG) return False try: if not ek(os.path.isdir, image_dir): logger.log(u"Metadata dir didn't exist, creating it at " + image_dir, logger.DEBUG) ek(os.makedirs, image_dir) helpers.chmodAsParent(image_dir) outFile = ek(open, image_path, 'wb') outFile.write(image_data) outFile.close() helpers.chmodAsParent(image_path) except IOError, e: logger.log( u"Unable to write image to " + image_path + " - are you sure the show folder is writable? " + ex(e), logger.ERROR) return False
def test_prowl(self): """ Test prowl notifications """ prowl_notifier = ProwlNotifier() # Prowl per-show-notifications only utilize the new methodology for storage; therefore, the list of legacy_shows # will not be altered (to preserve backwards compatibility testing) test_prowl_apis = "11111111111111111111,22222222222222222222" for show in self.shows: showid = self._get_showid_by_showname(show.name) Home.saveShowNotifyList(show=showid, prowlAPIs=test_prowl_apis) # Now, iterate through all shows using the Prowl API generation routines that are used in the notifier proper for show in self.shows: for episode in show.episodes: ep_name = ss( episode._format_pattern('%SN - %Sx%0E - %EN - ') + episode.quality) # pylint: disable=protected-access show_name = prowl_notifier._parse_episode(ep_name) # pylint: disable=protected-access recipients = prowl_notifier._generate_recipients(show_name) # pylint: disable=protected-access self._debug_spew("- Prowl Notifications for " + show.name + " (episode: " + episode.name + ") will be sent to:") for api in recipients: self._debug_spew("-- " + api.strip()) self._debug_spew("\n\r") return True
def _send_to_kodi(command, host=None, username=None, password=None, dest_app="KODI"): # pylint: disable=too-many-arguments """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 = sickbeard.KODI_USERNAME if not password: password = sickbeard.KODI_PASSWORD if not host: logger.log('No {0} host passed, aborting update'.format(dest_app), logger.WARNING) return False for key in command: if isinstance(command[key], six.text_type): command[key] = command[key].encode('utf-8') enc_command = urllib.parse.urlencode(command) logger.log("{0} encoded API command: {1!r}".format(dest_app, enc_command), logger.DEBUG) # url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command) # maybe need for old plex? url = 'http://{0}/kodiCmds/kodiHttp/?{1}'.format(host, enc_command) try: req = urllib.request.Request(url) # if we have a password, use authentication if password: base64string = base64.encodestring('{0}:{1}'.format(username, password))[:-1] authheader = "Basic {0}".format(base64string) req.add_header("Authorization", authheader) logger.log("Contacting {0} (with auth header) via url: {1}".format(dest_app, ss(url)), logger.DEBUG) else: logger.log("Contacting {0} via url: {1}".format(dest_app, ss(url)), logger.DEBUG) try: response = urllib.request.urlopen(req) except (http_client.BadStatusLine, urllib.error.URLError) as e: logger.log("Couldn't contact {0} HTTP at {1!r} : {2!r}".format(dest_app, url, ex(e)), logger.DEBUG) return False result = response.read().decode(sickbeard.SYS_ENCODING) response.close() logger.log("{0} HTTP response: {1}".format(dest_app, result.replace('\n', '')), logger.DEBUG) return result except Exception as e: logger.log("Couldn't contact {0} HTTP at {1!r} : {2!r}".format(dest_app, url, ex(e)), logger.DEBUG) return False
def _parse_episode(ep_name): ep_name = ss(ep_name) sep = " - " titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logger.log("TITLES: %s" % titles, logger.DEBUG) return titles
def _parseEp(self, ep_name): ep_name = ss(ep_name) sep = " - " titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logging.debug("TITLES: %s" % titles) return titles
def _parseEp(self, ep_name): ep_name = ss(ep_name) sep = " - " titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logger.log("TITLES: %s" % titles, logger.DEBUG) return titles
def _parse_episode(ep_name): ep_name = ss(ep_name) sep = " - " titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logger.log("TITLES: {0}".format(titles), logger.DEBUG) return titles
def _parseEp(ep_name): ep_name = ss(ep_name) sep = ' - ' titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logger.log('TITLES: {}'.format(titles), logger.DEBUG) return titles
def _parseEp(ep_name): ep_name = ss(ep_name) sep = ' - ' titles = ep_name.split(sep) titles.sort(key=len, reverse=True) logger.log('TITLES: {0}'.format(titles), logger.DEBUG) return titles
def createNZBString(fileElements, xmlns): rootElement = etree.Element("nzb") if xmlns: rootElement.set("xmlns", xmlns) for curFile in fileElements: rootElement.append(stripNS(curFile, xmlns)) return etree.tostring(ss(rootElement))
def notify_subtitle_download(self, ep_name, lang, title='Downloaded subtitle:'): # pylint: disable=unused-argument ''' Send a notification that an subtitle was downloaded ep_name: The name of the episode that was downloaded lang: Subtitle language wanted ''' ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD: show = self._parseEp(ep_name) to = self._generate_recipients(show) if not to: logger.log( 'Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( '<body style="font-family:Helvetica, Arial, sans-serif;">' '<h3>SickRage Notification - Subtitle Downloaded</h3><br>' '<p>Show: <b>{}</b></p><br><p>Episode: <b>{}</b></p><br>' '<p>Language: <b>{}</b></p><br><br>' '<footer style="margin-top: 2.5em; padding: .7em 0; ' 'color: #777; border-top: #BBB solid 1px;">' 'Powered by SickRage.</footer></body>'.format( show, re.search('.+ - (.+?-.+) -.+', ep_name).group(1), lang), 'html')) except Exception: try: msg = MIMEText(ep_name + ': ' + lang) except Exception: msg = MIMEText('Episode Subtitle Downloaded') if sickbeard.EMAIL_SUBJECT: msg[b'Subject'] = '[ST] ' + sickbeard.EMAIL_SUBJECT else: msg[b'Subject'] = lang + ' Subtitle Downloaded: ' + ep_name msg[b'From'] = sickbeard.EMAIL_FROM msg[b'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 [{0}] for "{1}"'.format( to, ep_name), logger.DEBUG) else: logger.log( 'Download notification error: {0}'.format( self.last_err), logger.WARNING)
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 = Show.find(sickbeard.showList, indexer_id) try: parse_result = NameParser(showObj=showObj).parse(name) except (InvalidNameException, InvalidShowException) as error: logger.log(u"{}".format(error), 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( {str(episode) for episode in episodes if episode}) + "|" # get the current timestamp curTimestamp = int( time.mktime(datetime.datetime.today().timetuple())) # get quality of release quality = parse_result.quality name = ss(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 notify_snatch(self, ep_name, title='Snatched:'): # pylint: disable=unused-argument ''' Send a notification that an episode was snatched ep_name: The name of the episode that was snatched title: The title of the notification (optional) ''' ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSNATCH: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logger.log( 'Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( '<body style="font-family:Helvetica, Arial, sans-serif;">' '<h3>Medusa Notification - Snatched</h3><br>' '<p>Show: <b>{}</b></p><br><p>Episode: <b>{}</b></p><br><br>' '<footer style="margin-top: 2.5em; padding: .7em 0; ' 'color: #777; border-top: #BBB solid 1px;">' 'Powered by Medusa.</footer></body>'.format( show, re.search('.+ - (.+?-.+) -.+', ep_name).group(1)), 'html')) except Exception: try: msg = MIMEText(ep_name) except Exception: msg = MIMEText('Episode Snatched') if sickbeard.EMAIL_SUBJECT: msg[b'Subject'] = '[SN] ' + sickbeard.EMAIL_SUBJECT else: msg[b'Subject'] = 'Snatched: ' + ep_name msg[b'From'] = sickbeard.EMAIL_FROM msg[b'To'] = ','.join(to) msg[b'Date'] = formatdate(localtime=True) 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( 'Snatch notification sent to [{}] for "{}"'.format( to, ep_name), logger.DEBUG) else: logger.log( 'Snatch notification error: {}'.format(self.last_err), logger.WARNING)
def notify_subtitle_download(self, ep_name, lang, title="Downloaded subtitle:"): # pylint: disable=unused-argument """ Send a notification that an subtitle was downloaded ep_name: The name of the episode that was downloaded lang: Subtitle language wanted """ ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logger.log( u'Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( "<body style='font-family:Helvetica, Arial, sans-serif;'>" "<h3>SickRage Notification - Subtitle Downloaded</h3>\n" "<p>Show: <b>{}</b></p>\n<p>Episode: <b>{}</b></p>\n" "<p>Language: <b>{}</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>".format( show, re.search(".+ - (.+?-.+) -.+", ep_name).group(1), lang), 'html')) except Exception: try: msg = MIMEText(ep_name + ": " + lang) except Exception: msg = MIMEText("Episode Subtitle Downloaded") msg['Subject'] = lang + ' Subtitle 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( u"Download notification sent to [%s] for '%s'" % (to, ep_name), logger.DEBUG) else: logger.log( u"Download notification error: %s" % self.last_err, logger.WARNING)
def notify_snatch(self, ep_name): ep_name = ss(ep_name) if sickbeard.PROWL_NOTIFY_ONSNATCH: show = self._parse_episode(ep_name) recipients = self._generate_recipients(show) if len(recipients) == 0: logger.log('Skipping prowl notify because there are no configured recipients', logger.DEBUG) else: for api in recipients: self._send_prowl(prowl_api=api, prowl_priority=None, event=common.notifyStrings[common.NOTIFY_SNATCH], message=ep_name + " :: " + time.strftime(sickbeard.DATE_PRESET + " " + sickbeard.TIME_PRESET))
def notify_subtitle_download(self, ep_name, lang): ep_name = ss(ep_name) if sickbeard.PROWL_NOTIFY_ONSUBTITLEDOWNLOAD: show = self._parse_episode(ep_name) recipients = self._generate_recipients(show) if len(recipients) == 0: logger.log('Skipping prowl notify because there are no configured recipients', logger.DEBUG) else: for api in recipients: self._send_prowl(prowl_api=api, prowl_priority=None, event=common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD], message=ep_name + " [" + lang + "] :: " + time.strftime(sickbeard.DATE_PRESET + " " + sickbeard.TIME_PRESET))
def prepareFailedName(release): """Standardizes release name for failed DB""" fixed = urllib.unquote(release) if fixed.endswith(".nzb"): fixed = fixed.rpartition(".")[0] fixed = re.sub(r"[\.\-\+\ ]", "_", fixed) fixed = ss(fixed) return fixed
def prepareFailedName(release): """Standardizes release name for failed DB""" fixed = urllib.parse.unquote(release) if fixed.endswith(".nzb"): fixed = fixed.rpartition(".")[0] fixed = re.sub(r"[\.\-\+\ ]", "_", fixed) fixed = ss(fixed) return fixed
def notify_download(self, ep_name, title='Completed:'): # pylint: disable=unused-argument ''' 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 = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONDOWNLOAD: show = self._parseEp(ep_name) to = self._generate_recipients(show) if not to: logger.log( 'Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( '<body style="font-family:Helvetica, Arial, sans-serif;">' '<h3>SickRage Notification - Downloaded</h3>' '<p>Show: <b>{0}</b></p><p>Episode Number: <b>{1}</b></p><p>Episode: <b>{2}</b></p><p>Quality: <b>{3}</b></p>' '<h5 style="margin-top: 2.5em; padding: .7em 0; ' 'color: #777; border-top: #BBB solid 1px;">' 'Powered by SickRage.</h5></body>'.format( show[0], show[1], show[2], show[3]), 'html')) except Exception: try: msg = MIMEText(ep_name) except Exception: msg = MIMEText('Episode Downloaded') if sickbeard.EMAIL_SUBJECT: msg[b'Subject'] = '[DL] ' + sickbeard.EMAIL_SUBJECT else: msg[b'Subject'] = 'Downloaded: ' + ep_name msg[b'From'] = sickbeard.EMAIL_FROM msg[b'To'] = ','.join(to) msg[b'Date'] = formatdate(localtime=True) 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 [{0}] for "{1}"'.format( to, ep_name), logger.DEBUG) else: logger.log( 'Download notification error: {0}'.format( self.last_err), logger.WARNING)
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) parse_result = myParser.parse(name) except InvalidNameException: logging.debug("Unable to parse the filename " + name + " into a valid episode") return None except InvalidShowException: logging.debug("Unable to parse the filename " + name + " into a valid show") 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 = ss(name) # get release group release_group = parse_result.release_group # get version version = parse_result.version logging.debug("Added RSS item: [" + name + "] to cache: [" + self.providerID + "]") 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 notify_subtitle_download(self, ep_name, lang, title="Downloaded subtitle:"): """ Send a notification that an subtitle was downloaded ep_name: The name of the episode that was downloaded lang: Subtitle language wanted """ ep_name = ss(ep_name) if sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logger.log( u'Skipping email notify because there are no configured recipients', logger.WARNING) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( "<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickRage Notification - Subtitle 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<p>Language: <b>" + lang + "</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: try: msg = MIMEText(ep_name + ": " + lang) except: msg = MIMEText("Episode Subtitle Downloaded") msg['Subject'] = lang + ' Subtitle 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( u"Download notification sent to [%s] for '%s'" % (to, ep_name), logger.DEBUG) else: logger.log( u"Download notification ERROR: %s" % self.last_err, logger.ERROR)
def notify_snatch(self, ep_name, title="Snatched:"): """ Send a notification that an episode was snatched ep_name: The name of the episode that was snatched title: The title of the notification (optional) """ ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSNATCH: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logger.log(u"Skipping email notify because there are no configured recipients", logger.DEBUG) else: try: msg = MIMEMultipart("alternative") msg.attach( MIMEText( "<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickRage Notification - Snatched</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: try: msg = MIMEText(ep_name) except: msg = MIMEText("Episode Snatched") msg["Subject"] = "Snatched: " + ep_name msg["From"] = sickbeard.EMAIL_FROM msg["To"] = ",".join(to) msg["Date"] = formatdate(localtime=True) 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(u"Snatch notification sent to [%s] for '%s'" % (to, ep_name), logger.DEBUG) else: logger.log(u"Snatch notification ERROR: %s" % self.last_err, logger.ERROR)
def notify_subtitle_download(self, ep_name, lang, title="Downloaded subtitle:"): """ Send a notification that an subtitle was downloaded ep_name: The name of the episode that was downloaded lang: Subtitle language wanted """ ep_name = ss(ep_name) if sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logging.warning( 'Skipping email notify because there are no configured recipients' ) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( "<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SiCKRAGE Notification - Subtitle 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<p>Language: <b>" + lang + "</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: try: msg = MIMEText(ep_name + ": " + lang) except: msg = MIMEText("Episode Subtitle Downloaded") msg[b'Subject'] = lang + ' Subtitle Downloaded: ' + ep_name msg[b'From'] = sickbeard.EMAIL_FROM msg[b'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): logging.debug( "Download notification sent to [%s] for '%s'" % (to, ep_name)) else: logging.error("Download notification ERROR: %s" % self.last_err)
def notify_download(self, ep_name): ep_name = ss(ep_name) if sickbeard.PROWL_NOTIFY_ONDOWNLOAD: show = self._parse_episode(ep_name) recipients = self._generate_recipients(show) if not recipients: logger.log("Skipping prowl notify because there are no configured recipients", logger.DEBUG) else: for api in recipients: self._send_prowl( prowl_api=api, prowl_priority=None, event=common.notifyStrings[common.NOTIFY_DOWNLOAD], message=ep_name + " :: " + time.strftime(sickbeard.DATE_PRESET + " " + sickbeard.TIME_PRESET), )
def notify_snatch(self, ep_name, title="Snatched:"): """ Send a notification that an episode was snatched ep_name: The name of the episode that was snatched title: The title of the notification (optional) """ ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSNATCH: show = self._parseEp(ep_name) to = self._generate_recipients(show) if len(to) == 0: logger.log( u'Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach( MIMEText( "<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickRage Notification - Snatched</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: try: msg = MIMEText(ep_name) except: msg = MIMEText("Episode Snatched") msg['Subject'] = 'Snatched: ' + ep_name msg['From'] = sickbeard.EMAIL_FROM msg['To'] = ','.join(to) msg['Date'] = formatdate(localtime=True) 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( u"Snatch notification sent to [%s] for '%s'" % (to, ep_name), logger.DEBUG) else: logger.log( u"Snatch notification ERROR: %s" % self.last_err, logger.ERROR)
def create_nzb_string(file_elements, xmlns): """ Extract extra info from file_elements. :param file_elements: to be processed :param xmlns: the xml namespace to be used :return: string containing all extra info extracted from the file_elements """ root_element = ETree.Element("nzb") if xmlns: root_element.set("xmlns", xmlns) for cur_file in file_elements: root_element.append(strip_xmlns(cur_file, xmlns)) return ETree.tostring(ss(root_element))
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 = Show.find(sickbeard.showList, indexer_id) try: parse_result = NameParser(showObj=showObj).parse(name) except (InvalidNameException, InvalidShowException) as error: logger.log(u"{}".format(error), 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({str(episode) for episode in episodes if episode}) + "|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) # get quality of release quality = parse_result.quality name = ss(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 notify_snatch(self, ep_name, title='Snatched:'): # pylint: disable=unused-argument """ Send a notification that an episode was snatched ep_name: The name of the episode that was snatched title: The title of the notification (optional) """ ep_name = ss(ep_name) if sickbeard.USE_EMAIL and sickbeard.EMAIL_NOTIFY_ONSNATCH: show = self._parseEp(ep_name) to = self._generate_recipients(show) if not to: logger.log('Skipping email notify because there are no configured recipients', logger.DEBUG) else: try: msg = MIMEMultipart('alternative') msg.attach(MIMEText( '<body style="font-family:Helvetica, Arial, sans-serif;">' '<h3>Medusa Notification - Snatched</h3><br>' '<p>Show: <b>{}</b></p><br><p>Episode: <b>{}</b></p><br><br>' '<footer style="margin-top: 2.5em; padding: .7em 0; ' 'color: #777; border-top: #BBB solid 1px;">' 'Powered by Medusa.</footer></body>'.format (show, re.search('.+ - (.+?-.+) -.+', ep_name).group(1)), 'html')) except Exception: try: msg = MIMEText(ep_name) except Exception: msg = MIMEText('Episode Snatched') if sickbeard.EMAIL_SUBJECT: msg[b'Subject'] = '[SN] ' + sickbeard.EMAIL_SUBJECT else: msg[b'Subject'] = 'Snatched: ' + ep_name msg[b'From'] = sickbeard.EMAIL_FROM msg[b'To'] = ','.join(to) msg[b'Date'] = formatdate(localtime=True) 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('Snatch notification sent to [{}] for "{}"'.format(to, ep_name), logger.DEBUG) else: logger.log('Snatch notification error: {}'.format(self.last_err), logger.WARNING)
def _checkAuthFromData(self, data): """ Checks that the returned data is valid Returns: _check_auth if valid otherwise False if there is an error """ if data.find_all('categories') + data.find_all('item'): return self._check_auth() try: err_desc = data.error.attrs['description'] if not err_desc: raise except (AttributeError, TypeError): return self._check_auth() logger.log(ss(err_desc)) return False
def _check_auth_from_data(self, data): """ Checks that the returned data is valid Returns: _check_auth if valid otherwise False if there is an error """ if data('categories') + data('item'): return self._check_auth() try: err_desc = data.error.attrs['description'] if not err_desc: raise AttributeError except (AttributeError, TypeError): return self._check_auth() logger.log(ss(err_desc)) return False
def _checkAuthFromData(self, data): """ Checks that the returned data is valid Returns: _check_auth if valid otherwise False if there is an error """ if data.findAll('categories') + data.findAll('item'): return self._check_auth() try: err_desc = data.error.attrs['description'] if not err_desc: raise except (AssertionError, AttributeError, ValueError): return self._check_auth() # This is all we should really need, the code is irrelevant # Provider name is the thread name, and this should INFO, # DEBUG hides from the user, WARNING nags the user, ERROR spams the tracker logger.log(ss(err_desc)) return False