def is_final_result(result): """ Checks if the given result is good enough quality that we can stop searching for other ones. If the result is the highest quality in both the any/best quality lists then this function returns True, if not then it's False """ sickrage.app.log.debug( "Checking if we should keep searching after we've found " + result.name) show_obj = find_show(result.show_id) any_qualities, best_qualities = Quality.split_quality(show_obj.quality) # if there is a download that's higher than this then we definitely need to keep looking if best_qualities and result.quality < max(best_qualities): return False # if it does not match the shows black and white list its no good elif show_obj.is_anime and show_obj.release_groups.is_valid(result): return False # if there's no redownload that's higher (above) and this is the highest initial download then we're good elif any_qualities and result.quality in any_qualities: return True elif best_qualities and result.quality == max(best_qualities): return True # if we got here than it's either not on the lists, they're empty, or it's lower than the highest required else: return 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 is_first_best_match(result): """ Checks if the given result is a best quality match and if we want to archive the episode on first match. """ sickrage.app.log.debug("Checking if we should archive our first best quality match for episode " + result.name) show_obj = find_show(result.series_id, result.series_provider_id) any_qualities, best_qualities = Quality.split_quality(show_obj.quality) # if there is a re-download that's a match to one of our best qualities and we want to skip downloaded then we # are done if best_qualities and show_obj.skip_downloaded and result.quality in best_qualities: return True return False
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 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 pick_best_result(results, season_pack=False): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show_id: Show ID we check for :return: best result object """ results = results if isinstance(results, list) else [results] sickrage.app.log.debug("Picking the best result out of " + str([x.name for x in results])) best_result = None # find the best result for the current episode for cur_result in results: show_obj = find_show(cur_result.show_id) # build the black And white list if show_obj.is_anime: if not show_obj.release_groups.is_valid(cur_result): continue sickrage.app.log.info("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) any_qualities, best_qualities = Quality.split_quality(show_obj.quality) if cur_result.quality not in any_qualities + best_qualities: sickrage.app.log.debug( cur_result.name + " is a quality we know we don't want, rejecting it") continue # check if seeders meet out minimum requirements, disgard result if it does not if hasattr(cur_result.provider, 'minseed') and cur_result.seeders not in (-1, None): if int(cur_result.seeders) < min(cur_result.provider.minseed, 1): sickrage.app.log.info( "Discarding torrent because it doesn't meet the minimum seeders: {}. Seeders: " "{}".format(cur_result.name, cur_result.seeders)) continue # check if leechers meet out minimum requirements, disgard result if it does not if hasattr(cur_result.provider, 'minleech') and cur_result.leechers not in (-1, None): if int(cur_result.leechers) < min(cur_result.provider.minleech, 0): sickrage.app.log.info( "Discarding torrent because it doesn't meet the minimum leechers: {}. Leechers: " "{}".format(cur_result.name, cur_result.leechers)) continue if show_obj.rls_ignore_words and show_names.contains_at_least_one_word( cur_result.name, show_obj.rls_ignore_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on ignored words filter: " + show_obj.rls_ignore_words) continue if show_obj.rls_require_words and not show_names.contains_at_least_one_word( cur_result.name, show_obj.rls_require_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on required words filter: " + show_obj.rls_require_words) continue if not show_names.filter_bad_releases(cur_result.name, parse=False): sickrage.app.log.info( "Ignoring " + cur_result.name + " because its not a valid scene release that we want") continue if hasattr(cur_result, 'size'): if FailedHistory.has_failed(cur_result.name, cur_result.size, cur_result.provider.name): sickrage.app.log.info(cur_result.name + " has previously failed, rejecting it") continue # quality definition video file size constraints check try: if cur_result.size: quality_size = sickrage.app.config.quality_sizes[ cur_result.quality] if season_pack and not len(cur_result.episodes): episode_count = len([ x for x in show_obj.episodes if x.season == cur_result.season ]) file_size = float(cur_result.size / episode_count / 1000000) else: file_size = float(cur_result.size / len(cur_result.episodes) / 1000000) if file_size > quality_size: raise Exception( "Ignoring " + cur_result.name + " with size: {} based on quality size filter: {}". format(file_size, quality_size)) except Exception as e: sickrage.app.log.info(e) continue # verify result content # if not cur_result.provider.private: # if cur_result.type in ["nzb", "torrent"] and not cur_result.provider.get_content(cur_result.url): # if not sickrage.app.config.download_unverified_magnet_link and cur_result.url.startswith('magnet'): # sickrage.app.log.info("Ignoring {} because we are unable to verify the download url".format(cur_result.name)) # continue if not best_result: best_result = cur_result elif cur_result.quality in best_qualities and ( best_result.quality < cur_result.quality or best_result.quality not in best_qualities): best_result = cur_result elif cur_result.quality in any_qualities and best_result.quality not in best_qualities and best_result.quality < cur_result.quality: best_result = cur_result elif best_result.quality == cur_result.quality: if "proper" in cur_result.name.lower( ) or "repack" in cur_result.name.lower(): best_result = cur_result elif "internal" in best_result.name.lower( ) and "internal" not in cur_result.name.lower(): best_result = cur_result elif "xvid" in best_result.name.lower( ) and "x264" in cur_result.name.lower(): sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)") best_result = cur_result if best_result: sickrage.app.log.debug("Picked " + best_result.name + " as the best") else: sickrage.app.log.debug("No result picked.") return best_result
async def post(self, *args, **kwargs): skip_downloaded = self.get_argument('skip_downloaded', None) paused = self.get_argument('paused', None) default_ep_status = self.get_argument('default_ep_status', None) anime = self.get_argument('anime', None) sports = self.get_argument('sports', None) scene = self.get_argument('scene', None) flatten_folders = self.get_argument('flatten_folders', None) quality_preset = self.get_argument('quality_preset', None) subtitles = self.get_argument('subtitles', None) air_by_date = self.get_argument('air_by_date', None) any_qualities = self.get_arguments('anyQualities') best_qualities = self.get_arguments('bestQualities') to_edit = self.get_argument('toEdit', None) i = 0 dir_map = {} while True: cur_arg = self.get_argument('orig_root_dir_{}'.format(i), None) if not cur_arg: break end_dir = self.get_argument('new_root_dir_{}'.format(i)) dir_map[cur_arg] = end_dir i += 1 show_ids = to_edit.split("|") warnings, errors = [], [] for curShow in show_ids: cur_warnings = [] cur_errors = [] show_obj = find_show(int(curShow), session=self.db_session) if not show_obj: continue cur_root_dir = os.path.dirname(show_obj.location) cur_show_dir = os.path.basename(show_obj.location) if cur_root_dir in dir_map and cur_root_dir != dir_map[ cur_root_dir]: new_show_dir = os.path.join(dir_map[cur_root_dir], cur_show_dir) sickrage.app.log.info("For show " + show_obj.name + " changing dir from " + show_obj.location + " to " + new_show_dir) else: new_show_dir = show_obj.location if skip_downloaded == 'keep': new_skip_downloaded = show_obj.skip_downloaded else: new_skip_downloaded = True if skip_downloaded == 'enable' else False new_skip_downloaded = 'on' if new_skip_downloaded else 'off' if paused == 'keep': new_paused = show_obj.paused else: new_paused = True if paused == 'enable' else False new_paused = 'on' if new_paused else 'off' if default_ep_status == 'keep': new_default_ep_status = show_obj.default_ep_status else: new_default_ep_status = default_ep_status if anime == 'keep': new_anime = show_obj.anime else: new_anime = True if anime == 'enable' else False new_anime = 'on' if new_anime else 'off' if sports == 'keep': new_sports = show_obj.sports else: new_sports = True if sports == 'enable' else False new_sports = 'on' if new_sports else 'off' if scene == 'keep': new_scene = show_obj.is_scene else: new_scene = True if scene == 'enable' else False new_scene = 'on' if new_scene else 'off' if air_by_date == 'keep': new_air_by_date = show_obj.air_by_date else: new_air_by_date = True if air_by_date == 'enable' else False new_air_by_date = 'on' if new_air_by_date else 'off' if flatten_folders == 'keep': new_flatten_folders = show_obj.flatten_folders else: new_flatten_folders = True if flatten_folders == 'enable' else False new_flatten_folders = 'on' if new_flatten_folders else 'off' if subtitles == 'keep': new_subtitles = show_obj.subtitles else: new_subtitles = True if subtitles == 'enable' else False new_subtitles = 'on' if new_subtitles else 'off' if quality_preset == 'keep': any_qualities, best_qualities = Quality.split_quality( show_obj.quality) elif try_int(quality_preset, None): best_qualities = [] post_data = { 'show': curShow, 'location': new_show_dir, 'anyQualities': any_qualities, 'bestQualities': best_qualities, 'exceptions_list': [], 'defaultEpStatus': new_default_ep_status, 'skip_downloaded': new_skip_downloaded, 'flatten_folders': new_flatten_folders, 'paused': new_paused, 'sports': new_sports, 'subtitles': new_subtitles, 'anime': new_anime, 'scene': new_scene, 'air_by_date': new_air_by_date, 'directCall': 'true' } response = await TornadoHTTP().post(self.get_url("/home/editShow"), body=urlencode( post_data, True)) if response.body: cur_warnings += json_decode(response.body)['warnings'] cur_errors += json_decode(response.body)['errors'] if cur_warnings: sickrage.app.log.warning("Warnings: " + str(cur_warnings)) warnings.append('<b>%s:</b>\n<ul>' % show_obj.name + ' '.join( ['<li>%s</li>' % warning for warning in cur_warnings]) + "</ul>") if cur_errors: sickrage.app.log.error("Errors: " + str(cur_errors)) errors.append( '<b>%s:</b>\n<ul>' % show_obj.name + ' '.join(['<li>%s</li>' % error for error in cur_errors]) + "</ul>") if len(warnings) > 0: sickrage.app.alerts.message( _('{num_warnings:d} warning{plural} while saving changes:' ).format(num_warnings=len(warnings), plural="" if len(warnings) == 1 else "s"), " ".join(warnings)) if len(errors) > 0: sickrage.app.alerts.error( _('{num_errors:d} error{plural} while saving changes:').format( num_errors=len(errors), plural="" if len(errors) == 1 else "s"), " ".join(errors)) return self.redirect("/manage/")
async def post(self, *args, **kwargs): skip_downloaded = self.get_argument('skip_downloaded', None) scene = self.get_argument('scene', None) paused = self.get_argument('paused', None) default_ep_status = self.get_argument('default_ep_status', None) anime = self.get_argument('anime', None) flatten_folders = self.get_argument('flatten_folders', None) quality_preset = self.get_argument('quality_preset', None) subtitles = self.get_argument('subtitles', None) search_format = self.get_argument('search_format', None) any_qualities = self.get_arguments('anyQualities') best_qualities = self.get_arguments('bestQualities') to_edit = self.get_argument('toEdit', None) i = 0 dir_map = {} while True: cur_arg = self.get_argument('orig_root_dir_{}'.format(i), None) if not cur_arg: break end_dir = self.get_argument('new_root_dir_{}'.format(i)) dir_map[cur_arg] = end_dir i += 1 show_ids = to_edit.split("|") warnings, errors = [], [] for curShow in show_ids: cur_warnings = [] cur_errors = [] show_obj = find_show(int(curShow)) if not show_obj: continue cur_root_dir = os.path.dirname(show_obj.location) cur_show_dir = os.path.basename(show_obj.location) if cur_root_dir in dir_map and cur_root_dir != dir_map[cur_root_dir]: new_show_dir = os.path.join(dir_map[cur_root_dir], cur_show_dir) sickrage.app.log.info( "For show " + show_obj.name + " changing dir from " + show_obj.location + " to " + new_show_dir) else: new_show_dir = show_obj.location if skip_downloaded == 'keep': new_skip_downloaded = show_obj.skip_downloaded else: new_skip_downloaded = True if skip_downloaded == 'enable' else False new_skip_downloaded = 'on' if new_skip_downloaded else 'off' if scene == 'keep': new_scene = show_obj.scene else: new_scene = True if scene == 'enable' else False new_scene = 'on' if new_scene else 'off' if paused == 'keep': new_paused = show_obj.paused else: new_paused = True if paused == 'enable' else False new_paused = 'on' if new_paused else 'off' if default_ep_status == 'keep': new_default_ep_status = show_obj.default_ep_status else: new_default_ep_status = int(default_ep_status) if anime == 'keep': new_anime = show_obj.anime else: new_anime = True if anime == 'enable' else False new_anime = 'on' if new_anime else 'off' if search_format == 'keep': new_search_format = show_obj.search_format else: new_search_format = int(search_format) if flatten_folders == 'keep': new_flatten_folders = show_obj.flatten_folders else: new_flatten_folders = True if flatten_folders == 'enable' else False new_flatten_folders = 'on' if new_flatten_folders else 'off' if subtitles == 'keep': new_subtitles = show_obj.subtitles else: new_subtitles = True if subtitles == 'enable' else False new_subtitles = 'on' if new_subtitles else 'off' if quality_preset == 'keep': any_qualities, best_qualities = Quality.split_quality(show_obj.quality) elif try_int(quality_preset, None): best_qualities = [] status, message = edit_show(show=curShow, location=new_show_dir, any_qualities=any_qualities, best_qualities=best_qualities, exceptions_list=[], default_ep_status=new_default_ep_status, skip_downloaded=new_skip_downloaded, flatten_folders=new_flatten_folders, paused=new_paused, search_format=new_search_format, subtitles=new_subtitles, anime=new_anime, scene=new_scene, direct_call=True) if status is False: cur_warnings += json_decode(message)['warnings'] cur_errors += json_decode(message)['errors'] if cur_warnings: sickrage.app.log.warning("Warnings: " + str(cur_warnings)) warnings.append('<b>%s:</b>\n<ul>' % show_obj.name + ' '.join( ['<li>%s</li>' % warning for warning in cur_warnings]) + "</ul>") if cur_errors: sickrage.app.log.error("Errors: " + str(cur_errors)) errors.append('<b>%s:</b>\n<ul>' % show_obj.name + ' '.join( ['<li>%s</li>' % error for error in cur_errors]) + "</ul>") if len(warnings) > 0: sickrage.app.alerts.message( _('{num_warnings:d} warning{plural} while saving changes:').format(num_warnings=len(warnings), plural="" if len(warnings) == 1 else "s"), " ".join(warnings)) if len(errors) > 0: sickrage.app.alerts.error( _('{num_errors:d} error{plural} while saving changes:').format(num_errors=len(errors), plural="" if len(errors) == 1 else "s"), " ".join(errors)) return self.redirect("/manage/")