def run(self, force=False): if self.amActive: return self.amActive = True # set thread name threading.currentThread().setName(self.name) piList = [] stale_should_update = [] update_datetime = datetime.datetime.now() update_date = update_datetime.date() if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() if sickrage.srCore.srConfig.SHOWUPDATE_STALE: # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal sql_result = main_db.MainDB().select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) # list of stale shows [stale_should_update.append(int(cur_result['indexer_id'])) for cur_result in sql_result] # start update process sickrage.srCore.srLogger.info("Performing daily updates for all shows") for curShow in sickrage.srCore.SHOWLIST: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update: try: piList.append( sickrage.srCore.SHOWQUEUE.updateShow(curShow, True)) except CantUpdateShowException as e: sickrage.srCore.srLogger.debug("Unable to update show: {}".format(e.message)) else: piList.append( sickrage.srCore.SHOWQUEUE.refreshShow(curShow, True)) except (CantUpdateShowException, CantRefreshShowException) as e: sickrage.srCore.srLogger.error("Daily show update failed: {}".format(e.message)) ProgressIndicators.setIndicator('dailyShowUpdates', QueueProgressIndicator("Daily Show Updates", piList)) sickrage.srCore.srLogger.info("Completed daily updates for all shows") self.amActive = False
def run(self, force=False): if self.amActive: return self.amActive = True update_datetime = datetime.datetime.now() update_date = update_datetime.date() if sickrage.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.LOGGER.info("Doing full update on all shows") # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal sql_result = main_db.MainDB().select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) for cur_result in sql_result: stale_should_update.append(int(cur_result[b'indexer_id'])) # start update process piList = [] for curShow in sickrage.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update: try: piList.append( sickrage.SHOWQUEUE.updateShow(curShow, True)) # @UndefinedVariable except CantUpdateShowException as e: sickrage.LOGGER.debug("Unable to update show: {0}".format(str(e))) else: sickrage.LOGGER.debug( "Not updating episodes for show " + curShow.name + " because it's marked as ended and last/next episode is not within the grace period.") piList.append( sickrage.SHOWQUEUE.refreshShow(curShow, True)) # @UndefinedVariable except (CantUpdateShowException, CantRefreshShowException) as e: sickrage.LOGGER.error("Automatic update failed: {}".format(e)) ProgressIndicators.setIndicator('dailyUpdate', QueueProgressIndicator("Daily Update", piList)) sickrage.LOGGER.info("Completed full update on all shows") self.amActive = False
def run(self, force=False): """ 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 or sickrage.app.developer) and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history FailedHistory.trimHistory() sickrage.app.log.info("Searching for failed snatches") show = None failed_snatches = False snatched_episodes = (x for x in sickrage.app.main_db.all('history') if x['action'] in Quality.SNATCHED + Quality.SNATCHED_BEST + Quality.SNATCHED_PROPER and 24 >= int((datetime.datetime.now() - datetime.datetime.strptime(x['date'], History.date_format)).total_seconds() / 3600) >= sickrage.app.config.failed_snatch_age) downloaded_releases = ((x['showid'], x['season'], x['episode']) for x in sickrage.app.main_db.all('history') if x['action'] in Quality.DOWNLOADED) episodes = [x for x in snatched_episodes if (x['showid'], x['season'], x['episode']) not in downloaded_releases] for episode in episodes: failed_snatches = True if not show or int(episode["showid"]) != show.indexerid: show = findCertainShow(int(episode["showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue ep_obj = show.get_episode(int(episode['season']), int(episode['episode'])) if isinstance(ep_obj, TVEpisode): curStatus, curQuality = Quality.splitCompositeStatus(ep_obj.status) if curStatus not in {SNATCHED, SNATCHED_BEST, SNATCHED_PROPER}: continue # put it on the queue sickrage.app.search_queue.put(FailedQueueItem(show, [ep_obj], True)) if not failed_snatches: sickrage.app.log.info("No failed snatches found") self.amActive = False
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 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 run(self): self.started = True try: sickrage.app.log.info("Starting failed download search for: [" + self.show.name + "]") for epObj in self.segment: sickrage.app.log.info("Marking episode as bad: [" + epObj.pretty_name() + "]") FailedHistory.markFailed(epObj) (release, provider) = FailedHistory.findFailedRelease(epObj) if release: FailedHistory.logFailed(release) History.logFailed(epObj, release, provider) FailedHistory.revertFailedEpisode(epObj) search_result = searchProviders(self.show, self.segment, manualSearch=True, downCurQuality=False) if search_result: for result in search_result: # just use the first result for now sickrage.app.log.info("Downloading " + result.name + " from " + result.provider.name) snatchEpisode(result) # give the CPU a break time.sleep(cpu_presets[sickrage.app.config.cpu_preset]) except Exception: sickrage.app.log.debug(traceback.format_exc()) finally: sickrage.app.log.info("Finished failed download search for: [" + self.show.name + "]") # Keep a list with the 100 last executed searches fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
def run(self): super(FailedQueueItem, self).run() self.started = True try: for epObj in self.segment: sickrage.srCore.srLogger.info("Marking episode as bad: [" + epObj.prettyName() + "]") FailedHistory.markFailed(epObj) (release, provider) = FailedHistory.findFailedRelease(epObj) if release: FailedHistory.logFailed(release) History.logFailed(epObj, release, provider) FailedHistory.revertFailedEpisode(epObj) sickrage.srCore.srLogger.info("Beginning failed download search for: [" + epObj.prettyName() + "]") # If it is wanted, self.downCurQuality doesnt matter # if it isnt wanted, we need to make sure to not overwrite the existing ep that we reverted to! searchResult = searchProviders(self.show, self.segment, True, False) if searchResult: for result in searchResult: # just use the first result for now sickrage.srCore.srLogger.info("Downloading " + result.name + " from " + result.provider.name) snatchEpisode(result) # give the CPU a break time.sleep(cpu_presets[sickrage.srCore.srConfig.CPU_PRESET]) except Exception: sickrage.srCore.srLogger.debug(traceback.format_exc()) ### Keep a list with the 100 last executed searches fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
def run(self, force=False): if self.amActive: return self.amActive = True # set thread name threading.currentThread().setName(self.name) update_timestamp = time.mktime(datetime.datetime.now().timetuple()) sqlResult = cache_db.CacheDB().select('SELECT `time` FROM lastUpdate WHERE provider = ?', ['theTVDB']) if sqlResult: last_update = sqlResult[0]['time'] else: last_update = time.mktime(datetime.datetime.min.timetuple()) cache_db.CacheDB().action('INSERT INTO lastUpdate (provider, `time`) VALUES (?, ?)', ['theTVDB', long(last_update)]) if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() # get indexer updated show ids updated_shows = srIndexerApi(1).indexer(**srIndexerApi(1).api_params.copy()).updated(long(last_update)) # start update process piList = [] for curShow in sickrage.srCore.SHOWLIST: try: curShow.nextEpisode() if curShow.indexerid in set(d["id"] for d in updated_shows or {}): piList.append(sickrage.srCore.SHOWQUEUE.updateShow(curShow, True)) else: piList.append(sickrage.srCore.SHOWQUEUE.refreshShow(curShow, False)) except (CantUpdateShowException, CantRefreshShowException) as e: continue ProgressIndicators.setIndicator('dailyShowUpdates', QueueProgressIndicator("Daily Show Updates", piList)) cache_db.CacheDB().action('UPDATE lastUpdate SET `time` = ? WHERE provider=?', [long(update_timestamp), 'theTVDB']) self.amActive = False
def run(self): self.started = True show_object = find_show(self.show_id) episode_object = show_object.get_episode(self.season, self.episode) try: sickrage.app.log.info("Starting failed download search for: [" + episode_object.name + "]") sickrage.app.log.info("Marking episode as bad: [" + episode_object.pretty_name() + "]") FailedHistory.mark_failed(self.show_id, self.season, self.episode) (release, provider) = FailedHistory.find_failed_release( self.show_id, self.season, self.episode) if release: FailedHistory.log_failed(release) History.log_failed(self.show_id, self.season, self.episode, release, provider) FailedHistory.revert_failed_episode(self.show_id, self.season, self.episode) search_result = search_providers(self.show_id, self.season, self.episode, manualSearch=True, downCurQuality=False) if search_result: snatch = all([(search_result.show_id, search_result.season, episode) not in sickrage.app.search_queue.SNATCH_HISTORY for episode in search_result.episodes]) if snatch: [ sickrage.app.search_queue.fifo( sickrage.app.search_queue.SNATCH_HISTORY, (search_result.show_id, search_result.season, episode), sickrage.app.search_queue.SNATCH_HISTORY_SIZE) for episode in search_result.episodes ] sickrage.app.log.info("Downloading " + search_result.name + " from " + search_result.provider.name) snatch_episode(search_result) except Exception: sickrage.app.log.debug(traceback.format_exc()) finally: sickrage.app.log.info("Finished failed download search for: [" + show_object.name + "]") sickrage.app.search_queue.fifo( sickrage.app.search_queue.MANUAL_SEARCH_HISTORY, self, sickrage.app.search_queue.MANUAL_SEARCH_HISTORY_SIZE)
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive or sickrage.DEVELOPER and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() # queue episode for daily search sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem()) self.amActive = False
def run(self, force=False): if self.amActive: return self.amActive = True # set thread name threading.currentThread().setName(self.name) piList = [] stale_should_update = [] update_datetime = datetime.datetime.now() update_date = update_datetime.date() if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() if sickrage.srCore.srConfig.SHOWUPDATE_STALE: # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal sql_result = main_db.MainDB().select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) # list of stale shows [ stale_should_update.append(int(cur_result['indexer_id'])) for cur_result in sql_result ] # start update process sickrage.srCore.srLogger.info("Performing daily updates for all shows") for curShow in sickrage.srCore.SHOWLIST: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update( update_date=update_date ) or curShow.indexerid in stale_should_update: try: piList.append( sickrage.srCore.SHOWQUEUE.updateShow( curShow, True)) except CantUpdateShowException as e: sickrage.srCore.srLogger.debug( "Unable to update show: {}".format(e.message)) else: piList.append( sickrage.srCore.SHOWQUEUE.refreshShow(curShow, True)) except (CantUpdateShowException, CantRefreshShowException) as e: sickrage.srCore.srLogger.error( "Daily show update failed: {}".format(e.message)) ProgressIndicators.setIndicator( 'dailyShowUpdates', QueueProgressIndicator("Daily Show Updates", piList)) sickrage.srCore.srLogger.info("Completed daily updates for all shows") self.amActive = False
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive or sickrage.srCore.srConfig.DEVELOPER and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.srCore.srLogger.info("{}: Searching for new released episodes".format(self.name)) curDate = datetime.date.today() curDate += datetime.timedelta(days=2) if tz_updater.load_network_dict(): curDate += datetime.timedelta(days=1) curTime = datetime.datetime.now(tz_updater.sr_timezone) show = None episodes = [x['doc'] for x in sickrage.srCore.mainDB.db.all('tv_episodes', with_doc=True) if x['doc']['status'] == UNAIRED and x['doc']['season'] > 0 and curDate.toordinal() >= x['doc']['airdate'] > 1] for episode in episodes: if not show or int(episode["showid"]) != show.indexerid: show = findCertainShow(sickrage.srCore.SHOWLIST, int(episode["showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time( episode['airdate'], show.airs, show.network, dateOnly=True ).astimezone(tz_updater.sr_timezone) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep = show.getEpisode(int(episode['season']), int(episode['episode'])) with ep.lock: if ep.season == 0: sickrage.srCore.srLogger.info( "New episode {} airs today, setting status to SKIPPED because is a special season".format( ep.prettyName())) ep.status = SKIPPED else: sickrage.srCore.srLogger.info( "New episode {} airs today, setting to default episode status for this show: {}".format( ep.prettyName(), statusStrings[ep.show.default_ep_status])) ep.status = ep.show.default_ep_status ep.saveToDB() else: sickrage.srCore.srLogger.info("{}: No new released episodes found".format(self.name)) # queue episode for daily search sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem()) self.amActive = False
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows 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])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.app.log.info("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.app.log.debug( cur_result.name + " is a quality we know we don't want, rejecting it") continue # check if seeders and leechers meet out minimum requirements, disgard result if it does not if hasattr(cur_result.provider, 'minseed') and hasattr( cur_result.provider, 'minleech'): if cur_result.seeders not in ( -1, None) and cur_result.leechers not in (-1, None): if int(cur_result.seeders) < int( cur_result.provider.minseed) or int( cur_result.leechers) < int( cur_result.provider.minleech): sickrage.app.log.info( 'Discarding torrent because it does not meet the minimum provider ' 'setting S:{} L:{}. Result has S:{} L:{}', cur_result.provider.minseed, cur_result.provider.minleech, cur_result.seeders, cur_result.leechers) continue if show.rls_ignore_words and show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_ignore_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_require_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(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 sickrage.app.config.use_failed_downloads and FailedHistory.hasFailed( 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: quality_size = sickrage.app.config.quality_sizes[ cur_result.quality] for file, file_size in cur_result.files.items(): if not file.decode('utf-8').endswith(tuple(video_exts)): continue file_size = float(file_size / 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.message) continue # verify result content cur_result = _verify_result(cur_result) if not cur_result.content: sickrage.app.log.info( "Ignoring " + cur_result.name + " because it does not have valid download url") continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower( ) or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower( ) and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower( ) and "x264" in cur_result.name.lower(): sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.app.log.debug("Picked " + bestResult.name + " as the best") else: sickrage.app.log.debug("No result picked.") return bestResult
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive or sickrage.app.developer and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.app.config.use_failed_downloads: FailedHistory.trimHistory() sickrage.app.log.info("Searching for new released episodes") curDate = datetime.date.today() curDate += datetime.timedelta(days=2) if tz_updater.load_network_dict(): curDate += datetime.timedelta(days=1) curTime = datetime.datetime.now(sickrage.app.tz) show = None episodes = [ x['doc'] for x in sickrage.app.main_db.db.all('tv_episodes', with_doc=True) if x['doc']['status'] == common.UNAIRED and x['doc']['season'] > 0 and curDate.toordinal() >= x['doc']['airdate'] > 1 ] new_episodes = False for episode in episodes: if not show or int(episode["showid"]) != show.indexerid: show = findCertainShow(sickrage.app.showlist, int(episode["showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time( episode['airdate'], show.airs, show.network, dateOnly=True).astimezone(sickrage.app.tz) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep_obj = show.getEpisode(int(episode['season']), int(episode['episode'])) with ep_obj.lock: ep_obj.status = show.default_ep_status if ep_obj.season else common.SKIPPED sickrage.app.log.info( 'Setting status ({status}) for show airing today: {name} {special}' .format( name=ep_obj.pretty_name(), status=common.statusStrings[ep_obj.status], special='(specials are not supported)' if not ep_obj.season else '', )) ep_obj.saveToDB() new_episodes = True if not new_episodes: sickrage.app.log.info("No new released episodes found") # queue episode for daily search sickrage.app.search_queue.put(DailySearchQueueItem()) self.amActive = False
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows 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])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.app.log.info( "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.app.log.debug(cur_result.name + " is a quality we know we don't want, rejecting it") continue # check if seeders and leechers meet out minimum requirements, disgard result if it does not if hasattr(cur_result.provider, 'minseed') and hasattr(cur_result.provider, 'minleech'): if cur_result.seeders not in (-1, None) and cur_result.leechers not in (-1, None): if int(cur_result.seeders) < int(cur_result.provider.minseed) or int(cur_result.leechers) < int(cur_result.provider.minleech): sickrage.app.log.info('Discarding torrent because it does not meet the minimum provider ' 'setting S:{} L:{}. Result has S:{} L:{}', cur_result.provider.minseed, cur_result.provider.minleech, cur_result.seeders, cur_result.leechers) continue if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words): sickrage.app.log.info( "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words): sickrage.app.log.info( "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(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 sickrage.app.config.use_failed_downloads and FailedHistory.hasFailed(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: quality_size = sickrage.app.config.quality_sizes[cur_result.quality] for file, file_size in cur_result.files.items(): if not file.decode('utf-8').endswith(tuple(video_exts)): continue file_size = float(file_size / 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.message) continue # verify result content cur_result = _verify_result(cur_result) if not cur_result.content: sickrage.app.log.info( "Ignoring " + cur_result.name + " because it does not have valid download url") continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower(): sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.app.log.debug("Picked " + bestResult.name + " as the best") else: sickrage.app.log.debug("No result picked.") return bestResult
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows 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])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.app.log.info("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: 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) < int(cur_result.provider.minseed): 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) < int(cur_result.provider.minleech): 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.rls_ignore_words and show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_ignore_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_require_words): sickrage.app.log.info("Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(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.hasFailed(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] file_size = float(cur_result.size / 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(str(e)) continue # verify result content if not cur_result.provider.private: if cur_result.resultType in [ "nzb", "torrent" ] and not cur_result.provider.get_content(cur_result.url): if sickrage.app.config.download_unverified_magnet_link and cur_result.url.startswith( 'magnet'): # Attempt downloading unverified torrent magnet link pass else: sickrage.app.log.info( "Ignoring {} because we are unable to verify the download url" .format(cur_result.name)) continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower( ) or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower( ) and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower( ) and "x264" in cur_result.name.lower(): sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.app.log.debug("Picked " + bestResult.name + " as the best") else: sickrage.app.log.debug("No result picked.") return bestResult
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.srCore.srConfig.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.srCore.srConfig.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickrage.srCore.srConfig.NZB_METHOD == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.srCore.srConfig.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.srCore.srLogger.error( "Unknown NZB action specified in config: " + sickrage.srCore.srConfig.NZB_METHOD) elif result.resultType == "torrent": if sickrage.srCore.srConfig.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if all([not result.content, not result.url.startswith('magnet:')]): result.content = sickrage.srCore.srWebSession.get(result.url).content if any([result.content, result.url.startswith('magnet:')]): # add public trackers to magnet url for non-private torrent providers if not result.provider.private and result.url.startswith('magnet:'): result.url += '&tr='.join( [x.strip() for x in sickrage.srCore.srConfig.TORRENT_TRACKERS.split(',') if x.strip()]) client = getClientIstance(sickrage.srCore.srConfig.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: sickrage.srCore.srLogger.warning("Torrent file content is empty") else: sickrage.srCore.srLogger.error("Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.logSnatch(result) sickrage.srCore.srNotifications.message('Episode snatched', result.name) History.logSnatch(result) # don't notify when we re-download an episode trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) # save episode to DB curEpObj.saveToDB() if curEpObj.status not in Quality.DOWNLOADED: try: srNotifiers.notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.srCore.srLogger.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.srCore.notifiersDict['trakt'].trakt_episode_data_generate(trakt_data) if sickrage.srCore.srConfig.USE_TRAKT and sickrage.srCore.srConfig.TRAKT_SYNC_WATCHLIST: sickrage.srCore.srLogger.debug( "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str( result.show.name) + " to Traktv Watchlist") if data: sickrage.srCore.notifiersDict['trakt'].update_watchlist(result.show, data_episode=data, update="add") return True
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.srCore.srLogger.info("Searching for new released episodes ...") curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal() if tz_updater.load_network_dict(): curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal() curTime = datetime.datetime.now(tz_updater.sr_timezone) show = None for dbData in [x['doc'] for x in sickrage.srCore.mainDB.db.all('tv_episodes', with_doc=True) if x['doc']['status'] in [UNAIRED, WANTED] and x['doc']['season'] > 0 and curDate >= x['doc']['airdate'] > 1]: try: if not show or int(dbData['showid']) != show.indexerid: show = findCertainShow(sickrage.srCore.SHOWLIST, int(dbData['showid'])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue except MultipleShowObjectsException: sickrage.srCore.srLogger.info("ERROR: expected to find a single show matching " + str(dbData['showid'])) continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time(dbData['airdate'], show.airs, show.network, dateOnly=True).astimezone(tz_updater.sr_timezone) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep = show.getEpisode(int(dbData['season']), int(dbData['episode'])) with ep.lock: if ep.season == 0: sickrage.srCore.srLogger.info( "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season") ep.status = SKIPPED else: sickrage.srCore.srLogger.info( "New episode %s airs today, setting to default episode status for this show: %s" % ( ep.prettyName(), statusStrings[ep.show.default_ep_status])) ep.status = ep.show.default_ep_status ep.saveToDB() else: sickrage.srCore.srLogger.info("No new released episodes found ...") # queue episode for daily search sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem()) self.amActive = False
def snatch_episode(result, end_status=EpisodeStatus.SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param end_status: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False show_object = find_show(result.series_id, result.series_provider_id) result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.app.config.general.allow_high_priority: # if it aired recently make it high priority for episode_number in result.episodes: if date.today() - show_object.get_episode(result.season, episode_number).airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None: end_status = EpisodeStatus.SNATCHED_PROPER # get result content result.content = result.provider.get_content(result.url) dlResult = False if result.provider_type in (SearchProviderType.NZB, SearchProviderType.NZBDATA): if sickrage.app.config.general.nzb_method == NzbMethod.BLACKHOLE: dlResult = result.provider.download_result(result) elif sickrage.app.config.general.nzb_method == NzbMethod.SABNZBD: dlResult = SabNZBd.sendNZB(result) elif sickrage.app.config.general.nzb_method == NzbMethod.NZBGET: is_proper = True if end_status == EpisodeStatus.SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) elif sickrage.app.config.general.nzb_method == NzbMethod.DOWNLOAD_STATION: client = get_client_instance(sickrage.app.config.general.nzb_method.value, client_type='nzb')() dlResult = client.sendNZB(result) elif result.provider_type in (SearchProviderType.TORRENT, SearchProviderType.TORZNAB): # add public trackers to torrent result if not result.provider.private: result = result.provider.add_trackers(result) if sickrage.app.config.general.torrent_method == TorrentMethod.BLACKHOLE: dlResult = result.provider.download_result(result) else: if any([result.content, result.url.startswith('magnet:')]): client = get_client_instance(sickrage.app.config.general.torrent_method.value, client_type='torrent')() dlResult = client.send_torrent(result) else: sickrage.app.log.warning("Torrent file content is empty") else: sickrage.app.log.error("Unknown result type, unable to download it (%r)" % result.provider_type.display_name) # no download results found if not dlResult: return False FailedHistory.log_snatch(result) History.log_snatch(result) sickrage.app.alerts.message(_('Episode snatched'), result.name) trakt_data = [] for episode_number in result.episodes: episode_obj = show_object.get_episode(result.season, episode_number) if is_first_best_match(result): episode_obj.status = Quality.composite_status(EpisodeStatus.SNATCHED_BEST, result.quality) else: episode_obj.status = Quality.composite_status(end_status, result.quality) episode_obj.save() # don't notify when we re-download an episode if episode_obj.status not in EpisodeStatus.composites(EpisodeStatus.DOWNLOADED): try: NotificationProvider.mass_notify_snatch(episode_obj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except Exception: sickrage.app.log.debug("Failed to send snatch notification") trakt_data.append((episode_obj.season, episode_obj.episode)) data = sickrage.app.notification_providers['trakt'].trakt_episode_data_generate(trakt_data) if sickrage.app.config.trakt.enable and sickrage.app.config.trakt.sync_watchlist: if data: sickrage.app.notification_providers['trakt'].update_watchlist(show_object, data_episode=data, update="add") return True
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive or sickrage.app.developer and not force: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.app.config.use_failed_downloads: FailedHistory.trimHistory() sickrage.app.log.info("Searching for new released episodes") curDate = datetime.date.today() curDate += datetime.timedelta(days=2) if tz_updater.load_network_dict(): curDate += datetime.timedelta(days=1) curTime = datetime.datetime.now(sickrage.app.tz) show = None episodes = [x['doc'] for x in sickrage.app.main_db.db.all('tv_episodes', with_doc=True) if x['doc']['status'] == common.UNAIRED and x['doc']['season'] > 0 and curDate.toordinal() >= x['doc']['airdate'] > 1] new_episodes = False for episode in episodes: if not show or int(episode["showid"]) != show.indexerid: show = findCertainShow(sickrage.app.showlist, int(episode["showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time( episode['airdate'], show.airs, show.network, dateOnly=True ).astimezone(sickrage.app.tz) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep_obj = show.getEpisode(int(episode['season']), int(episode['episode'])) with ep_obj.lock: ep_obj.status = show.default_ep_status if ep_obj.season else common.SKIPPED sickrage.app.log.info('Setting status ({status}) for show airing today: {name} {special}'.format( name=ep_obj.pretty_name(), status=common.statusStrings[ep_obj.status], special='(specials are not supported)' if not ep_obj.season else '', )) ep_obj.saveToDB() new_episodes = True if not new_episodes: sickrage.app.log.info("No new released episodes found") # queue episode for daily search sickrage.app.search_queue.put(DailySearchQueueItem()) self.amActive = False
def run(self): self.started = True sickrage.app.search_queue.TASK_HISTORY[self.id] = { 'season': self.season, 'episode': self.episode } show_object = find_show(self.series_id, self.series_provider_id) if not show_object: return episode_object = show_object.get_episode(self.season, self.episode) try: sickrage.app.log.info("Starting failed download search for: [" + episode_object.name + "]") WebSocketMessage( 'SEARCH_QUEUE_STATUS_UPDATED', { 'seriesSlug': show_object.slug, 'episodeId': episode_object.episode_id, 'searchQueueStatus': episode_object.search_queue_status }).push() sickrage.app.log.info("Marking episode as bad: [" + episode_object.pretty_name() + "]") FailedHistory.mark_failed(self.series_id, self.series_provider_id, self.season, self.episode) (release, provider) = FailedHistory.find_failed_release( self.series_id, self.series_provider_id, self.season, self.episode) if release: FailedHistory.log_failed(release) History.log_failed(self.series_id, self.series_provider_id, self.season, self.episode, release, provider) FailedHistory.revert_failed_episode(self.series_id, self.series_provider_id, self.season, self.episode) search_result = search_providers(self.series_id, self.series_provider_id, self.season, self.episode, manualSearch=True, downCurQuality=False) if search_result: snatch = all([(search_result.series_id, search_result.season, episode) not in sickrage.app.search_queue.SNATCH_HISTORY for episode in search_result.episodes]) if snatch: [ sickrage.app.search_queue.SNATCH_HISTORY.append( (search_result.series_id, search_result.season, episode)) for episode in search_result.episodes ] sickrage.app.log.info("Downloading " + search_result.name + " from " + search_result.provider.name) snatch_episode(search_result) except Exception: sickrage.app.log.debug(traceback.format_exc()) finally: WebSocketMessage( 'SEARCH_QUEUE_STATUS_UPDATED', { 'seriesSlug': show_object.slug, 'episodeId': episode_object.episode_id, 'searchQueueStatus': episode_object.search_queue_status }).push() sickrage.app.log.info("Finished failed download search for: [" + show_object.name + "]")
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.app.config.allow_high_priority: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER # get result content result.content = result.provider.get_content(result.url) dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.app.config.nzb_method == "blackhole": dlResult = result.provider.download_result(result) elif sickrage.app.config.nzb_method == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.app.config.nzb_method == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.app.log.error("Unknown NZB action specified in config: " + sickrage.app.config.nzb_method) elif result.resultType in ("torrent", "torznab"): # add public trackers to torrent result if not result.provider.private: result = result.provider.add_trackers(result) if sickrage.app.config.torrent_method == "blackhole": dlResult = result.provider.download_result(result) else: if any([result.content, result.url.startswith('magnet:')]): client = getClientIstance(sickrage.app.config.torrent_method)() dlResult = client.send_torrent(result) else: sickrage.app.log.warning("Torrent file content is empty") else: sickrage.app.log.error("Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False FailedHistory.logSnatch(result) sickrage.app.alerts.message(_('Episode snatched'), result.name) History.logSnatch(result) # don't notify when we re-download an episode trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) # save episode to DB curEpObj.save_to_db() if curEpObj.status not in Quality.DOWNLOADED: try: Notifiers.mass_notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.app.log.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.app.notifier_providers['trakt'].trakt_episode_data_generate(trakt_data) if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist: sickrage.app.log.debug( "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str( result.show.name) + " to Traktv Watchlist") if data: sickrage.app.notifier_providers['trakt'].update_watchlist(result.show, data_episode=data, update="add") return True
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows 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])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.app.log.info( "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: 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.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words): sickrage.app.log.info( "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words): sickrage.app.log.info( "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(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.hasFailed(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] file_size = float(cur_result.size / 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(str(e)) continue # verify result content if not cur_result.provider.private: if cur_result.resultType in ["nzb", "torrent"] and not cur_result.provider.get_content(cur_result.url): if sickrage.app.config.download_unverified_magnet_link and cur_result.url.startswith('magnet'): # Attempt downloading unverified torrent magnet link pass else: sickrage.app.log.info( "Ignoring {} because we are unable to verify the download url".format(cur_result.name)) continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower(): sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.app.log.debug("Picked " + bestResult.name + " as the best") else: sickrage.app.log.debug("No result picked.") return bestResult
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive: return self.amActive = True # trim failed download history if sickrage.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.LOGGER.info("Searching for new released episodes ...") if tz_updater.network_dict: curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal() else: curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal() curTime = datetime.datetime.now(tz_updater.sr_timezone) sqlResults = main_db.MainDB().select( "SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND (airdate <= ? AND airdate > 1)", [UNAIRED, curDate]) sql_l = [] show = None for sqlEp in sqlResults: try: if not show or int(sqlEp[b"showid"]) != show.indexerid: show = findCertainShow(sickrage.showList, int(sqlEp[b"showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue except MultipleShowObjectsException: sickrage.LOGGER.info("ERROR: expected to find a single show matching " + str(sqlEp[b'showid'])) continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time(sqlEp[b'airdate'], show.airs, show.network).astimezone( tz_updater.sr_timezone) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep = show.getEpisode(int(sqlEp[b"season"]), int(sqlEp[b"episode"])) with ep.lock: if ep.season == 0: sickrage.LOGGER.info( "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season") ep.status = SKIPPED else: sickrage.LOGGER.info("New episode %s airs today, setting to default episode status for this show: %s" % ( ep.prettyName(), statusStrings[ep.show.default_ep_status])) ep.status = ep.show.default_ep_status sql_l.append(ep.get_sql()) if len(sql_l) > 0: main_db.MainDB().mass_action(sql_l) else: sickrage.LOGGER.info("No new released episodes found ...") # queue episode for daily search dailysearch_queue_item = DailySearchQueueItem() sickrage.SEARCHQUEUE.add_item(dailysearch_queue_item) self.amActive = False
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive: return self.amActive = True # trim failed download history if sickrage.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.LOGGER.info("Searching for new released episodes ...") if tz_updater.network_dict: curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal() else: curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal() curTime = datetime.datetime.now(tz_updater.sr_timezone) sqlResults = main_db.MainDB().select( "SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND (airdate <= ? AND airdate > 1)", [UNAIRED, curDate]) sql_l = [] show = None for sqlEp in sqlResults: try: if not show or int(sqlEp[b"showid"]) != show.indexerid: show = findCertainShow(sickrage.showList, int(sqlEp[b"showid"])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue except MultipleShowObjectsException: sickrage.LOGGER.info( "ERROR: expected to find a single show matching " + str(sqlEp[b'showid'])) continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time( sqlEp[b'airdate'], show.airs, show.network).astimezone(tz_updater.sr_timezone) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep = show.getEpisode(int(sqlEp[b"season"]), int(sqlEp[b"episode"])) with ep.lock: if ep.season == 0: sickrage.LOGGER.info( "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season" ) ep.status = SKIPPED else: sickrage.LOGGER.info( "New episode %s airs today, setting to default episode status for this show: %s" % (ep.prettyName(), statusStrings[ep.show.default_ep_status])) ep.status = ep.show.default_ep_status sql_l.append(ep.get_sql()) if len(sql_l) > 0: main_db.MainDB().mass_action(sql_l) else: sickrage.LOGGER.info("No new released episodes found ...") # queue episode for daily search dailysearch_queue_item = DailySearchQueueItem() sickrage.SEARCHQUEUE.add_item(dailysearch_queue_item) self.amActive = False
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows we check for :return: best result object """ results = results if isinstance(results, list) else [results] sickrage.LOGGER.debug("Picking the best result out of " + str([x.name for x in results])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.LOGGER.info("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.LOGGER.debug( cur_result.name + " is a quality we know we don't want, rejecting it") continue if show.rls_ignore_words and show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_ignore_words): sickrage.LOGGER.info("Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord( cur_result.name, cur_result.show.rls_require_words): sickrage.LOGGER.info("Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(cur_result.name, parse=False): sickrage.LOGGER.info( "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it" ) continue if hasattr(cur_result, 'size'): if sickrage.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed( cur_result.name, cur_result.size, cur_result.provider.name): sickrage.LOGGER.info(cur_result.name + " has previously failed, rejecting it") continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower( ) or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower( ) and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower( ) and "x264" in cur_result.name.lower(): sickrage.LOGGER.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.LOGGER.debug("Picked " + bestResult.name + " as the best") else: sickrage.LOGGER.debug("No result picked.") return bestResult
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows we check for :return: best result object """ results = results if isinstance(results, list) else [results] sickrage.srCore.srLogger.debug("Picking the best result out of " + str([x.name for x in results])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.srCore.srLogger.info( "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.srCore.srLogger.debug(cur_result.name + " is a quality we know we don't want, rejecting it") continue if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(cur_result.name, parse=False): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it") continue if hasattr(cur_result, 'size'): if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(cur_result.name, cur_result.size, cur_result.provider.name): sickrage.srCore.srLogger.info(cur_result.name + " has previously failed, rejecting it") continue # quality definition video file size constraints check try: quality_size = sickrage.srCore.srConfig.QUALITY_SIZES[cur_result.quality] for file, file_size in cur_result.files.items(): if not file.endswith(tuple(video_exts)): continue file_size = float(file_size / 1000000) if file_size > quality_size: raise Exception( "Ignoring " + cur_result.name + " with size: {} based on quality size filter: {}, ignoring it".format( file_size, quality_size) ) except Exception as e: sickrage.srCore.srLogger.info(e.message) continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower(): sickrage.srCore.srLogger.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.srCore.srLogger.debug("Picked " + bestResult.name + " as the best") else: sickrage.srCore.srLogger.debug("No result picked.") return bestResult
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta( days=7): result.priority = 1 if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickrage.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickrage.NZB_METHOD == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.LOGGER.error("Unknown NZB action specified in config: " + sickrage.NZB_METHOD) dlResult = False # TORRENTs can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickrage.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith('magnet'): result.content = result.provider.getURL(result.url, needBytes=True) if result.content or result.url.startswith('magnet'): client = getClientIstance(sickrage.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: sickrage.LOGGER.warning("Torrent file content is empty") dlResult = False else: sickrage.LOGGER.error( "Unknown result type, unable to download it (%r)" % result.resultType) dlResult = False if not dlResult: return False if sickrage.USE_FAILED_DOWNLOADS: FailedHistory.logSnatch(result) notifications.message('Episode snatched', result.name) History.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus( SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus( endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: try: notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.LOGGER.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.NOTIFIERS.trakt_notifier.trakt_episode_data_generate( trakt_data) if sickrage.USE_TRAKT and sickrage.TRAKT_SYNC_WATCHLIST: sickrage.LOGGER.debug("Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist") if data: sickrage.NOTIFIERS.trakt_notifier.update_watchlist( result.show, data_episode=data, update="add") if len(sql_l) > 0: main_db.MainDB().mass_action(sql_l) return True
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 series_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.series_id, cur_result.series_provider_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 " + cur_result.quality.display_name) 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 cur_result.provider.custom_settings.get('minseed', 0) and cur_result.seeders not in (-1, None): if int(cur_result.seeders) < min(cur_result.provider.custom_settings.get('minseed', 0), 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 cur_result.provider.custom_settings.get('minleech', 0) and cur_result.leechers not in (-1, None): if int(cur_result.leechers) < min(cur_result.provider.custom_settings.get('minleech', 0), 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_min = sickrage.app.config.quality_sizes[cur_result.quality.name].min_size quality_size_max = sickrage.app.config.quality_sizes[cur_result.quality.name].max_size if quality_size_min != 0 and quality_size_max != 0: 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 quality_size_min > file_size > quality_size_max: raise Exception("Ignoring " + cur_result.name + " with size {}".format(file_size)) except Exception as e: sickrage.app.log.info(e) continue # verify result content # if not cur_result.provider.private: # if cur_result.provider_type in ["nzb", "torrent"] and not cur_result.provider.get_content(cur_result.url): # if not sickrage.app.config.general.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
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows we check for :return: best result object """ results = results if isinstance(results, list) else [results] sickrage.srCore.srLogger.debug("Picking the best result out of " + str([x.name for x in results])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.srCore.srLogger.info( "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.srCore.srLogger.debug(cur_result.name + " is a quality we know we don't want, rejecting it") continue if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(cur_result.name, parse=False): sickrage.srCore.srLogger.info( "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it") continue if hasattr(cur_result, 'size'): if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(cur_result.name, cur_result.size, cur_result.provider.name): sickrage.srCore.srLogger.info(cur_result.name + " has previously failed, rejecting it") continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower(): sickrage.srCore.srLogger.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.srCore.srLogger.debug("Picked " + bestResult.name + " as the best") else: sickrage.srCore.srLogger.debug("No result picked.") return bestResult
def run(self, force=False): """ Runs the daily searcher, queuing selected episodes for search :param force: Force search """ if self.amActive: return self.amActive = True # set thread name threading.currentThread().setName(self.name) # trim failed download history if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.trimHistory() sickrage.srCore.srLogger.info( "Searching for new released episodes ...") curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal() if tz_updater.load_network_dict(): curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal() curTime = datetime.datetime.now(tz_updater.sr_timezone) show = None for dbData in [ x['doc'] for x in MainDB().db.all('tv_episodes', with_doc=True) if x['doc']['status'] in [UNAIRED, WANTED] and x['doc']['season'] > 0 and curDate >= x['doc']['airdate'] > 1 ]: try: if not show or int(dbData['showid']) != show.indexerid: show = findCertainShow(sickrage.srCore.SHOWLIST, int(dbData['showid'])) # for when there is orphaned series in the database but not loaded into our showlist if not show or show.paused: continue except MultipleShowObjectsException: sickrage.srCore.srLogger.info( "ERROR: expected to find a single show matching " + str(dbData['showid'])) continue if show.airs and show.network: # This is how you assure it is always converted to local time air_time = tz_updater.parse_date_time( dbData['airdate'], show.airs, show.network, dateOnly=True).astimezone(tz_updater.sr_timezone) # filter out any episodes that haven't started airing yet, # but set them to the default status while they are airing # so they are snatched faster if air_time > curTime: continue ep = show.getEpisode(int(dbData['season']), int(dbData['episode'])) with ep.lock: if ep.season == 0: sickrage.srCore.srLogger.info( "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season" ) ep.status = SKIPPED else: sickrage.srCore.srLogger.info( "New episode %s airs today, setting to default episode status for this show: %s" % (ep.prettyName(), statusStrings[ep.show.default_ep_status])) ep.status = ep.show.default_ep_status ep.saveToDB() else: sickrage.srCore.srLogger.info("No new released episodes found ...") # queue episode for daily search sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem()) self.amActive = False
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.srCore.srConfig.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.srCore.srConfig.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickrage.srCore.srConfig.NZB_METHOD == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.srCore.srConfig.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.srCore.srLogger.error( "Unknown NZB action specified in config: " + sickrage.srCore.srConfig.NZB_METHOD) elif result.resultType == "torrent": if sickrage.srCore.srConfig.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if all([not result.content, not result.url.startswith('magnet:')]): result.content = sickrage.srCore.srWebSession.get(result.url).content if any([result.content, result.url.startswith('magnet:')]): # add public trackers to magnet url for non-private torrent providers if not result.provider.private and result.url.startswith('magnet:'): result.url += '&tr='.join( [x.strip() for x in sickrage.srCore.srConfig.TORRENT_TRACKERS.split(',') if x.strip()]) client = getClientIstance(sickrage.srCore.srConfig.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: sickrage.srCore.srLogger.warning("Torrent file content is empty") else: sickrage.srCore.srLogger.error("Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.logSnatch(result) sickrage.srCore.srNotifications.message('Episode snatched', result.name) History.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_q = curEpObj.saveToDB(False) if sql_q: sql_l.append(sql_q) if curEpObj.status not in Quality.DOWNLOADED: try: srNotifiers.notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.srCore.srLogger.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.srCore.notifiersDict.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickrage.srCore.srConfig.USE_TRAKT and sickrage.srCore.srConfig.TRAKT_SYNC_WATCHLIST: sickrage.srCore.srLogger.debug( "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str( result.show.name) + " to Traktv Watchlist") if data: sickrage.srCore.notifiersDict.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if len(sql_l) > 0: main_db.MainDB().mass_upsert(sql_l) del sql_l # cleanup return True
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.app.config.allow_high_priority: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER # get result content result.content = result.provider.get_content(result.url) dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.app.config.nzb_method == "blackhole": dlResult = result.provider.download_result(result) elif sickrage.app.config.nzb_method == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.app.config.nzb_method == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.app.log.error("Unknown NZB action specified in config: " + sickrage.app.config.nzb_method) elif result.resultType in ("torrent", "torznab"): # add public trackers to torrent result if not result.provider.private: result = result.provider.add_trackers(result) if sickrage.app.config.torrent_method == "blackhole": dlResult = result.provider.download_result(result) else: if any([result.content, result.url.startswith('magnet:')]): client = getClientIstance(sickrage.app.config.torrent_method)() dlResult = client.send_torrent(result) else: sickrage.app.log.warning("Torrent file content is empty") else: sickrage.app.log.error( "Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False FailedHistory.logSnatch(result) sickrage.app.alerts.message(_('Episode snatched'), result.name) History.logSnatch(result) # don't notify when we re-download an episode trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus( SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus( endStatus, result.quality) # save episode to DB curEpObj.save_to_db() if curEpObj.status not in Quality.DOWNLOADED: try: Notifiers.mass_notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.app.log.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.app.notifier_providers[ 'trakt'].trakt_episode_data_generate(trakt_data) if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist: sickrage.app.log.debug("Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist") if data: sickrage.app.notifier_providers['trakt'].update_watchlist( result.show, data_episode=data, update="add") return True
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7): result.priority = 1 if re.search(r"(^|[\. _-])(proper|repack)([\. _-]|$)", result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith("magnet") or result.url.endswith("torrent"): result.resultType = "torrent" # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickrage.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickrage.NZB_METHOD == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.LOGGER.error("Unknown NZB action specified in config: " + sickrage.NZB_METHOD) dlResult = False # TORRENTs can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickrage.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith("magnet"): result.content = result.provider.getURL(result.url, needBytes=True) if result.content or result.url.startswith("magnet"): client = getClientIstance(sickrage.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: sickrage.LOGGER.warning("Torrent file content is empty") dlResult = False else: sickrage.LOGGER.error("Unknown result type, unable to download it (%r)" % result.resultType) dlResult = False if not dlResult: return False if sickrage.USE_FAILED_DOWNLOADS: FailedHistory.logSnatch(result) notifications.message("Episode snatched", result.name) History.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: try: notify_snatch(curEpObj._format_pattern("%SN - %Sx%0E - %EN - %QN") + " from " + result.provider.name) except: sickrage.LOGGER.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.NOTIFIERS.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickrage.USE_TRAKT and sickrage.TRAKT_SYNC_WATCHLIST: sickrage.LOGGER.debug( "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist" ) if data: sickrage.NOTIFIERS.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if len(sql_l) > 0: main_db.MainDB().mass_action(sql_l) return True