def mark_failed(series_id, series_provider_id, season, episode): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = "" show_object = find_show(series_id, series_provider_id) if not show_object: return log_str try: episode_object = show_object.get_episode(season, episode) quality = Quality.split_composite_status(episode_object.status)[1] episode_object.status = Quality.composite_status( EpisodeStatus.FAILED, quality) episode_object.save() except EpisodeNotFoundException as e: sickrage.app.log.warning( "Unable to get episode, please set its status manually: {}". format(e)) return log_str
def process(self): """ Do the actual work :return: True """ self._log("Failed download detected: (" + str(self.nzb_name) + ", " + str(self.dir_name) + ")") release_name = show_names.determine_release_name( self.dir_name, self.nzb_name) if release_name is None: self._log("Warning: unable to find a valid release name.", sickrage.app.log.WARNING) raise FailedPostProcessingFailedException() try: parsed = NameParser(False).parse(release_name) except InvalidNameException: self._log("Error: release name is invalid: " + release_name, sickrage.app.log.DEBUG) raise FailedPostProcessingFailedException() except InvalidShowException: self._log( "Error: unable to parse release name " + release_name + " into a valid show", sickrage.app.log.DEBUG) raise FailedPostProcessingFailedException() if parsed.show.paused: self._log( "Warning: skipping failed processing for {} because the show is paused" .format(release_name), sickrage.app.log.DEBUG) raise FailedPostProcessingFailedException() sickrage.app.log.debug("name_parser info: ") sickrage.app.log.debug(" - " + str(parsed.series_name)) sickrage.app.log.debug(" - " + str(parsed.season_number)) sickrage.app.log.debug(" - " + str(parsed.episode_numbers)) sickrage.app.log.debug(" - " + str(parsed.extra_info)) sickrage.app.log.debug(" - " + str(parsed.release_group)) sickrage.app.log.debug(" - " + str(parsed.air_date)) for episode in parsed.episode_numbers: try: episode_obj = parsed.show.get_episode(parsed.season_number, episode) except EpisodeNotFoundException as e: continue cur_status, cur_quality = Quality.split_composite_status( episode_obj.status) if cur_status not in {SNATCHED, SNATCHED_BEST, SNATCHED_PROPER}: continue sickrage.app.search_queue.put( FailedSearchTask(parsed.show, episode_obj.season, episode_obj.episode)) return True
def task(self, force=False): """ Runs the failed searcher, queuing selected episodes for search that have failed to snatch :param force: Force search """ if self.running or not sickrage.app.config.failed_snatches.enable and not force: return try: self.running = True # set thread name threading.currentThread().setName(self.name) # trim failed download history FailedHistory.trim_history() sickrage.app.log.info("Searching for failed snatches") failed_snatches = False for snatched_episode_obj in [ x for x in self.snatched_episodes() if (x.series_id, x.season, x.episode) not in self.downloaded_releases() ]: show_object = find_show( snatched_episode_obj.series_id, snatched_episode_obj.series_provider_id) episode_object = show_object.get_episode( snatched_episode_obj.season, snatched_episode_obj.episode) if episode_object.show.paused: continue cur_status, cur_quality = Quality.split_composite_status( episode_object.status) if cur_status not in { EpisodeStatus.SNATCHED, EpisodeStatus.SNATCHED_BEST, EpisodeStatus.SNATCHED_PROPER }: continue sickrage.app.search_queue.put( FailedSearchTask(show_object.series_id, show_object.series_provider_id, episode_object.season, episode_object.episode, True)) failed_snatches = True if not failed_snatches: sickrage.app.log.info("No failed snatches found") finally: self.running = False
def _get_wanted(show, from_date): """ Get a list of episodes that we want to download :param show: Show these episodes are from :param fromDate: Search from a certain date :return: list of wanted episodes """ wanted = [] any_qualities, best_qualities = Quality.split_quality(show.quality) all_qualities = list(set(any_qualities + best_qualities)) sickrage.app.log.debug( "Seeing if we need anything for today from {}".format(show.name)) # check through the list of statuses to see if we want any for episode_object in show.episodes: if not episode_object.season > 0 or not episode_object.airdate >= from_date: continue cur_status, cur_quality = Quality.split_composite_status( episode_object.status) # if we need a better one then say yes if cur_status not in (EpisodeStatus.WANTED, EpisodeStatus.DOWNLOADED, EpisodeStatus.SNATCHED, EpisodeStatus.SNATCHED_PROPER): continue if cur_status != EpisodeStatus.WANTED: if best_qualities: if cur_quality in best_qualities: continue elif cur_quality != Qualities.UNKNOWN and cur_quality > max( best_qualities): continue else: if cur_quality in any_qualities: continue elif cur_quality != Qualities.UNKNOWN and cur_quality > max( any_qualities): continue # skip upgrading quality of downloaded episodes if enabled if cur_status == EpisodeStatus.DOWNLOADED and show.skip_downloaded: continue wanted += [(episode_object.season, episode_object.episode)] return wanted
def get_overview(self, epStatus): epStatus = try_int(epStatus) or UNKNOWN if epStatus == WANTED: return Overview.WANTED elif epStatus in (UNAIRED, UNKNOWN): return Overview.UNAIRED elif epStatus in (SKIPPED, IGNORED): return Overview.SKIPPED elif epStatus in Quality.ARCHIVED: return Overview.GOOD elif epStatus in Quality.FAILED: return Overview.WANTED elif epStatus in Quality.SNATCHED: return Overview.SNATCHED elif epStatus in Quality.SNATCHED_PROPER: return Overview.SNATCHED_PROPER elif epStatus in Quality.SNATCHED_BEST: return Overview.SNATCHED_BEST elif epStatus in Quality.DOWNLOADED: anyQualities, bestQualities = Quality.split_quality(self.quality) epStatus, curQuality = Quality.split_composite_status(epStatus) if bestQualities: maxBestQuality = max(bestQualities) minBestQuality = min(bestQualities) else: maxBestQuality = None minBestQuality = None # elif epStatus == DOWNLOADED and curQuality == Quality.UNKNOWN: # return Overview.QUAL # if they don't want re-downloads then we call it good if they have anything if maxBestQuality is None: return Overview.GOOD # if the want only first match and already have one call it good elif self.skip_downloaded and curQuality in bestQualities: return Overview.GOOD # if they want only first match and current quality is higher than minimal best quality call it good elif self.skip_downloaded and minBestQuality is not None and curQuality > minBestQuality: return Overview.GOOD # if they have one but it's not the best they want then mark it as qual elif curQuality < maxBestQuality: return Overview.QUAL # if it's >= maxBestQuality then it's good else: return Overview.GOOD else: sickrage.app.log.error( 'Could not parse episode status into a valid overview status: {}' .format(epStatus))
def log_failed(show_id, season, episode, release, provider=None, session=None): """ Log a failed download :param epObj: Episode object :param release: Release group :param provider: Provider used for snatch """ show_object = find_show(show_id, session=session) episode_object = show_object.get_episode(season, episode) status, quality = Quality.split_composite_status(episode_object.status) action = Quality.composite_status(FAILED, quality) History._log_history_item(action, show_id, season, episode, quality, release, provider, session=session)
def run(self, force=False, session=None): """ Runs the failed searcher, queuing selected episodes for search that have failed to snatch :param force: Force search """ if self.amActive or not sickrage.app.config.use_failed_snatcher and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history FailedHistory.trim_history() sickrage.app.log.info("Searching for failed snatches") failed_snatches = False for snatched_episode_obj in [ x for x in self.snatched_episodes() if (x.showid, x.season, x.episode) not in self.downloaded_releases() ]: show_object = find_show(snatched_episode_obj.showid, session=session) episode_object = show_object.get_episode( snatched_episode_obj.season, snatched_episode_obj.episode) if episode_object.show.paused: continue cur_status, cur_quality = Quality.split_composite_status( episode_object.status) if cur_status not in {SNATCHED, SNATCHED_BEST, SNATCHED_PROPER}: continue sickrage.app.io_loop.add_callback( sickrage.app.search_queue.put, FailedQueueItem(episode_object.showid, episode_object.season, episode_object.episode, True)) failed_snatches = True if not failed_snatches: sickrage.app.log.info("No failed snatches found") self.amActive = False
def log_subtitle(show_id, season, episode, status, subtitle): """ Log download of subtitle :param showid: Showid of download :param season: Show season :param episode: Show episode :param status: Status of download :param subtitleResult: Result object """ resource = subtitle.language.opensubtitles provider = subtitle.provider_name status, quality = Quality.split_composite_status(status) action = Quality.composite_status(SUBTITLED, quality) History._log_history_item(action, show_id, season, episode, quality, resource, provider)
def _get_wanted(show, from_date): any_qualities, best_qualities = Quality.split_quality(show.quality) sickrage.app.log.debug( "Seeing if we need anything that's older then today for {}".format( show.name)) # check through the list of statuses to see if we want any wanted = [] for episode_object in show.episodes: if not episode_object.season > 0 or not datetime.date.today( ) > episode_object.airdate > from_date: continue cur_status, cur_quality = Quality.split_composite_status( episode_object.status) # if we need a better one then say yes if cur_status not in { EpisodeStatus.WANTED, EpisodeStatus.DOWNLOADED, EpisodeStatus.SNATCHED, EpisodeStatus.SNATCHED_PROPER }: continue if cur_status != EpisodeStatus.WANTED: if best_qualities: if cur_quality in best_qualities: continue elif cur_quality != Qualities.UNKNOWN and cur_quality > max( best_qualities): continue elif any_qualities: if cur_quality in any_qualities: continue elif cur_quality != Qualities.UNKNOWN and cur_quality > max( any_qualities): continue # skip upgrading quality of downloaded episodes if enabled if cur_status == EpisodeStatus.DOWNLOADED and show.skip_downloaded: continue wanted += [(episode_object.season, episode_object.episode)] return wanted
def _get_proper_list(self): """ Walk providers for propers """ session = sickrage.app.main_db.session() propers = {} final_propers = [] search_date = datetime.datetime.today() - datetime.timedelta(days=2) orig_thread_name = threading.currentThread().getName() for show in get_show_list(): wanted = self._get_wanted(show, search_date) if not wanted: sickrage.app.log.debug("Nothing needs to be downloaded for {}, skipping".format(show.name)) continue self._lastProperSearch = self._get_last_proper_search(show.indexer_id) # for each provider get a list of the for providerID, providerObj in sickrage.app.search_providers.sort(randomize=sickrage.app.config.randomize_providers).items(): # check provider type and provider is enabled if not sickrage.app.config.use_nzbs and providerObj.type in [NZBProvider.type, NewznabProvider.type]: continue elif not sickrage.app.config.use_torrents and providerObj.type in [TorrentProvider.type, TorrentRssProvider.type]: continue elif not providerObj.is_enabled: continue threading.currentThread().setName(orig_thread_name + " :: [" + providerObj.name + "]") sickrage.app.log.info("Searching for any new PROPER releases from " + providerObj.name) try: for season, episode in wanted: for x in providerObj.find_propers(show.indexer_id, season, episode): if not re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', x.name, re.I): sickrage.app.log.debug('Found a non-proper, we have caught and skipped it.') continue name = self._generic_name(x.name) if name not in propers: sickrage.app.log.debug("Found new proper: " + x.name) x.provider = providerObj propers[name] = x except AuthException as e: sickrage.app.log.warning("Authentication error: {}".format(e)) continue except Exception as e: sickrage.app.log.debug("Error while searching " + providerObj.name + ", skipping: {}".format(e)) sickrage.app.log.debug(traceback.format_exc()) continue threading.currentThread().setName(orig_thread_name) self._set_last_proper_search(show.indexer_id, datetime.datetime.today().toordinal()) # take the list of unique propers and get it sorted by sorted_propers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True) for curProper in sorted_propers: try: parse_result = NameParser(False).parse(curProper.name) except InvalidNameException: sickrage.app.log.debug("Unable to parse the filename " + curProper.name + " into a valid episode") continue except InvalidShowException: sickrage.app.log.debug("Unable to parse the filename " + curProper.name + " into a valid show") continue if not parse_result.series_name: continue if not parse_result.episode_numbers: sickrage.app.log.debug("Ignoring " + curProper.name + " because it's for a full season rather than specific episode") continue show = find_show(parse_result.indexer_id) sickrage.app.log.debug("Successful match! Result " + parse_result.original_name + " matched to show " + show.name) # set the indexer_id in the db to the show's indexer_id curProper.indexer_id = parse_result.indexer_id # set the indexer in the db to the show's indexer curProper.indexer = show.indexer # populate our Proper instance curProper.season = parse_result.season_number if parse_result.season_number is not None else 1 curProper.episode = parse_result.episode_numbers[0] curProper.release_group = parse_result.release_group curProper.version = parse_result.version curProper.quality = Quality.name_quality(curProper.name, parse_result.is_anime) curProper.content = None # filter release best_result = pick_best_result(curProper) if not best_result: sickrage.app.log.debug("Proper " + curProper.name + " were rejected by our release filters.") continue # only get anime proper if it has release group and version if show.is_anime: if not best_result.release_group and best_result.version == -1: sickrage.app.log.debug("Proper " + best_result.name + " doesn't have a release group and version, ignoring it") continue # check if we actually want this proper (if it's the right quality) dbData = session.query(MainDB.TVEpisode).filter_by(showid=best_result.indexer_id, season=best_result.season, episode=best_result.episode).one_or_none() if not dbData: continue # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones) old_status, old_quality = Quality.split_composite_status(int(dbData.status)) if old_status not in (DOWNLOADED, SNATCHED) or old_quality != best_result.quality: continue # check if we actually want this proper (if it's the right release group and a higher version) if show.is_anime: old_version = int(dbData.version) old_release_group = dbData.release_group if not -1 < old_version < best_result.version: continue sickrage.app.log.info("Found new anime v" + str(best_result.version) + " to replace existing v" + str(old_version)) if old_release_group != best_result.release_group: sickrage.app.log.info("Skipping proper from release group: {}, does not match existing release " "group: {}".format(best_result.release_group, old_release_group)) continue # if the show is in our list and there hasn't been a proper already added for that particular episode # then add it to our list of propers if best_result.indexer_id != -1 and (best_result.indexer_id, best_result.season, best_result.episode) not in map( operator.attrgetter('indexer_id', 'season', 'episode'), final_propers): sickrage.app.log.info("Found a proper that we need: " + str(best_result.name)) final_propers.append(best_result) return final_propers
def want_episode(self, season, episode, quality, manualSearch=False, downCurQuality=False): try: episode_object = self.get_episode(season, episode) except EpisodeNotFoundException: sickrage.app.log.debug( "Unable to find a matching episode in database, ignoring found episode" ) return False sickrage.app.log.debug( "Checking if found episode %s S%02dE%02d is wanted at quality %s" % (self.name, episode_object.season or 0, episode_object.episode or 0, Quality.qualityStrings[quality])) # if the quality isn't one we want under any circumstances then just say no any_qualities, best_qualities = Quality.split_quality(self.quality) sickrage.app.log.debug("Any, Best = [{}] [{}] Found = [{}]".format( self.qualitiesToString(any_qualities), self.qualitiesToString(best_qualities), self.qualitiesToString([quality]))) if quality not in any_qualities + best_qualities or quality is UNKNOWN: sickrage.app.log.debug( "Don't want this quality, ignoring found episode") return False ep_status = int(episode_object.status) ep_status_text = statusStrings[ep_status] sickrage.app.log.debug("Existing episode status: " + str(ep_status) + " (" + ep_status_text + ")") # if we know we don't want it then just say no if ep_status in Quality.ARCHIVED + [UNAIRED, SKIPPED, IGNORED ] and not manualSearch: sickrage.app.log.debug( "Existing episode status is unaired/skipped/ignored/archived, ignoring found episode" ) return False cur_status, cur_quality = Quality.split_composite_status(ep_status) # if it's one of these then we want it as long as it's in our allowed initial qualities if ep_status == WANTED: sickrage.app.log.debug( "Existing episode status is WANTED, getting found episode") return True elif manualSearch: if (downCurQuality and quality >= cur_quality) or (not downCurQuality and quality > cur_quality): sickrage.app.log.debug( "Usually ignoring found episode, but forced search allows the quality, getting found episode" ) return True # if we are re-downloading then we only want it if it's in our bestQualities list and better than what we # have, or we only have one bestQuality and we do not have that quality yet if ep_status in Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_PROPER and quality in best_qualities and ( quality > cur_quality or cur_quality not in best_qualities): sickrage.app.log.debug( "Episode already exists but the found episode quality is wanted more, getting found episode" ) return True elif cur_quality == UNKNOWN and manualSearch: sickrage.app.log.debug( "Episode already exists but quality is Unknown, getting found episode" ) return True else: sickrage.app.log.debug( "Episode already exists and the found episode has same/lower quality, ignoring found episode" ) sickrage.app.log.debug( "None of the conditions were met, ignoring found episode") return False
def refresh_dir(self): # make sure the show dir is where we think it is unless dirs are created on the fly if not os.path.isdir( self.location ) and not sickrage.app.config.create_missing_show_dirs: return False # load from dir try: self.load_episodes_from_dir() except Exception as e: sickrage.app.log.debug( "Error searching dir for episodes: {}".format(e)) sickrage.app.log.debug(traceback.format_exc()) # run through all locations from DB, check that they exist sickrage.app.log.debug( str(self.indexer_id) + ": Loading all episodes with a location from the database") for curEp in self.episodes: if curEp.location == '': continue curLoc = os.path.normpath(curEp.location) season = int(curEp.season) episode = int(curEp.episode) # if the path doesn't exist or if it's not in our show dir if not os.path.isfile(curLoc) or not os.path.normpath( curLoc).startswith(os.path.normpath(self.location)): # check if downloaded files still exist, update our data if this has changed if not sickrage.app.config.skip_removed_files: # if it used to have a file associated with it and it doesn't anymore then set it to # EP_DEFAULT_DELETED_STATUS if curEp.location and curEp.status in Quality.DOWNLOADED: if sickrage.app.config.ep_default_deleted_status == ARCHIVED: __, oldQuality = Quality.split_composite_status( curEp.status) new_status = Quality.composite_status( ARCHIVED, oldQuality) else: new_status = sickrage.app.config.ep_default_deleted_status sickrage.app.log.debug( "%s: Location for S%02dE%02d doesn't exist, " "removing it and changing our status to %s" % (self.indexer_id, season or 0, episode or 0, statusStrings[new_status])) curEp.status = new_status curEp.subtitles = '' curEp.subtitles_searchcount = 0 curEp.subtitles_lastsearch = 0 curEp.location = '' curEp.hasnfo = False curEp.hastbn = False curEp.release_name = '' else: if curEp.status in Quality.ARCHIVED: __, oldQuality = Quality.split_composite_status( curEp.status) curEp.status = Quality.composite_status( DOWNLOADED, oldQuality) # the file exists, set its modify file stamp if sickrage.app.config.airdate_episodes: curEp.airdateModifyStamp()
def make_ep_from_file(self, filename): if not os.path.isfile(filename): sickrage.app.log.info( str(self.indexer_id) + ": That isn't even a real file dude... " + filename) return None sickrage.app.log.debug( str(self.indexer_id) + ": Creating episode object from " + filename) try: parse_result = NameParser(validate_show=False).parse( filename, skip_scene_detection=True) except InvalidNameException: sickrage.app.log.debug("Unable to parse the filename " + filename + " into a valid episode") return None except InvalidShowException: sickrage.app.log.debug("Unable to parse the filename " + filename + " into a valid show") return None if not len(parse_result.episode_numbers): sickrage.app.log.info("parse_result: " + str(parse_result)) sickrage.app.log.warning("No episode number found in " + filename + ", ignoring it") return None # for now lets assume that any episode in the show dir belongs to that show season = parse_result.season_number if parse_result.season_number is not None else 1 root_ep = None for curEpNum in parse_result.episode_numbers: episode = int(curEpNum) sickrage.app.log.debug("%s: %s parsed to %s S%02dE%02d" % (self.indexer_id, filename, self.name, season or 0, episode or 0)) check_quality_again = False try: episode_obj = self.get_episode(season, episode) except EpisodeNotFoundException: object_session(self).add( TVEpisode( **{ 'showid': self.indexer_id, 'indexer': self.indexer, 'season': season, 'episode': episode, 'location': filename })) object_session(self).commit() episode_obj = self.get_episode(season, episode) # if there is a new file associated with this ep then re-check the quality if episode_obj.location and os.path.normpath( episode_obj.location) != os.path.normpath(filename): sickrage.app.log.debug( "The old episode had a different file associated with it, I will re-check " "the quality based on the new filename " + filename) check_quality_again = True # if the sizes are the same then it's probably the same file old_size = episode_obj.file_size episode_obj.location = filename same_file = old_size and episode_obj.file_size == old_size episode_obj.checkForMetaFiles() if root_ep is None: root_ep = episode_obj else: if episode_obj not in root_ep.related_episodes: root_ep.related_episodes.append(episode_obj) # if it's a new file then if not same_file: episode_obj.release_name = '' # if they replace a file on me I'll make some attempt at re-checking the quality unless I know it's the # same file if check_quality_again and not same_file: new_quality = Quality.name_quality(filename, self.is_anime) sickrage.app.log.debug("Since this file has been renamed") episode_obj.status = Quality.composite_status( DOWNLOADED, new_quality) # check for status/quality changes as long as it's a new file elif not same_file and is_media_file( filename ) and episode_obj.status not in Quality.DOWNLOADED + Quality.ARCHIVED + [ IGNORED ]: old_status, old_quality = Quality.split_composite_status( episode_obj.status) new_quality = Quality.name_quality(filename, self.is_anime) new_status = None # if it was snatched and now exists then set the status correctly if old_status == SNATCHED and old_quality <= new_quality: sickrage.app.log.debug( "STATUS: this ep used to be snatched with quality " + Quality.qualityStrings[old_quality] + " but a file exists with quality " + Quality.qualityStrings[new_quality] + " so I'm setting the status to DOWNLOADED") new_status = DOWNLOADED # if it was snatched proper and we found a higher quality one then allow the status change elif old_status == SNATCHED_PROPER and old_quality < new_quality: sickrage.app.log.debug( "STATUS: this ep used to be snatched proper with quality " + Quality.qualityStrings[old_quality] + " but a file exists with quality " + Quality.qualityStrings[new_quality] + " so I'm setting the status to DOWNLOADED") new_status = DOWNLOADED elif old_status not in (SNATCHED, SNATCHED_PROPER): new_status = DOWNLOADED if new_status is not None: sickrage.app.log.debug( "STATUS: we have an associated file, so setting the status from " + str(episode_obj.status) + " to DOWNLOADED/" + str( Quality.status_from_name(filename, anime=self.is_anime))) episode_obj.status = Quality.composite_status( new_status, new_quality) # creating metafiles on the root should be good enough if root_ep: root_ep.create_meta_files() object_session(self).commit() return root_ep
def _replace_map(self): """ Generates a replacement map for this episode which maps all possible custom naming patterns to the correct value for this episode. Returns: A dict with patterns as the keys and their replacement values as the values. """ ep_name = self._ep_name() def dot(name): return sanitize_scene_name(name) def us(name): return re.sub('[ -]', '_', name) def release_name(name): if name: name = remove_non_release_groups(remove_extension(name)) return name def release_group(show_id, name): from sickrage.core.nameparser import NameParser, InvalidNameException, InvalidShowException if name: name = remove_non_release_groups(remove_extension(name)) try: parse_result = NameParser(name, show_id=show_id, naming_pattern=True).parse(name) if parse_result.release_group: return parse_result.release_group except (InvalidNameException, InvalidShowException) as e: sickrage.app.log.debug("Unable to get parse release_group: {}".format(e)) return '' __, epQual = Quality.split_composite_status(self.status) if sickrage.app.config.naming_strip_year: show_name = re.sub(r"\(\d+\)$", "", self.show.name).rstrip() else: show_name = self.show.name # try to get the release group rel_grp = {"SiCKRAGE": 'SiCKRAGE'} if hasattr(self, 'location'): # from the location name rel_grp['location'] = release_group(self.show.indexer_id, self.location) if not rel_grp['location']: del rel_grp['location'] if hasattr(self, '_release_group'): # from the release group field in db rel_grp['database'] = self.release_group if not rel_grp['database']: del rel_grp['database'] if hasattr(self, 'release_name'): # from the release name field in db rel_grp['release_name'] = release_group(self.show.indexer_id, self.release_name) if not rel_grp['release_name']: del rel_grp['release_name'] # use release_group, release_name, location in that order if 'database' in rel_grp: relgrp = 'database' elif 'release_name' in rel_grp: relgrp = 'release_name' elif 'location' in rel_grp: relgrp = 'location' else: relgrp = 'SiCKRAGE' # try to get the release encoder to comply with scene naming standards encoder = Quality.scene_quality_from_name(self.release_name.replace(rel_grp[relgrp], ""), epQual) if encoder: sickrage.app.log.debug("Found codec for '" + show_name + ": " + ep_name + "'.") return { '%SN': show_name, '%S.N': dot(show_name), '%S_N': us(show_name), '%EN': ep_name, '%E.N': dot(ep_name), '%E_N': us(ep_name), '%QN': Quality.qualityStrings[epQual], '%Q.N': dot(Quality.qualityStrings[epQual]), '%Q_N': us(Quality.qualityStrings[epQual]), '%SQN': Quality.sceneQualityStrings[epQual] + encoder, '%SQ.N': dot(Quality.sceneQualityStrings[epQual] + encoder), '%SQ_N': us(Quality.sceneQualityStrings[epQual] + encoder), '%SY': str(self.show.startyear), '%S': str(self.season), '%0S': '%02d' % self.season, '%E': str(self.episode), '%0E': '%02d' % self.episode, '%XS': str(self.scene_season), '%0XS': '%02d' % self.scene_season, '%XE': str(self.scene_episode), '%0XE': '%02d' % self.scene_episode, '%AB': '%(#)03d' % {'#': self.absolute_number}, '%XAB': '%(#)03d' % {'#': self.scene_absolute_number}, '%RN': release_name(self.release_name), '%RG': rel_grp[relgrp], '%CRG': rel_grp[relgrp].upper(), '%AD': str(self.airdate).replace('-', ' '), '%A.D': str(self.airdate).replace('-', '.'), '%A_D': us(str(self.airdate)), '%A-D': str(self.airdate), '%Y': str(self.airdate.year), '%M': str(self.airdate.month), '%D': str(self.airdate.day), '%0M': '%02d' % self.airdate.month, '%0D': '%02d' % self.airdate.day, '%RT': "PROPER" if self.is_proper else "", }