def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): """Decides whether we should look for next ep/season based on whether we found/accepted any episodes.""" with Session() as session: series = session.query(Series).filter(Series.name == entry['series_name']).first() latest = get_latest_release(series) db_release = (session.query(Release).join(Release.episode).join(Episode.series). filter(Series.name == entry['series_name']). filter(Episode.season == entry['series_season']). filter(Episode.number == entry['series_episode']).first()) if entry.accepted: log.debug('%s %s was accepted, rerunning to look for next ep.' % (entry['series_name'], entry['series_id'])) self.rerun_entries.append(self.search_entry(series, entry['series_season'], entry['series_episode'] + 1, task)) task.rerun() elif db_release: # There are know releases of this episode, but none were accepted return elif latest and identified_by == 'ep' and ( entry['series_season'] == latest.season and entry['series_episode'] == latest.number + 1): # We searched for next predicted episode of this season unsuccessfully, try the next season self.rerun_entries.append(self.search_entry(series, latest.season + 1, 1, task)) log.debug('%s %s not found, rerunning to look for next season' % (entry['series_name'], entry['series_id'])) task.rerun()
def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): with closing(Session()) as session: series = session.query(Series).filter( Series.name == entry['series_name']).first() latest = get_latest_release(series) episode = (session.query(Episode).join(Episode.series).filter( Series.name == entry['series_name']).filter( Episode.season == entry['series_season']).filter( Episode.number == entry['series_episode']).first()) if entry.accepted or (episode and len(episode.releases) > 0): self.try_next_season.pop(entry['series_name'], None) task.rerun() elif latest and latest.season == entry['series_season']: if identified_by != 'ep': # Do not try next season if this is not an 'ep' show return if entry['series_name'] not in self.try_next_season: self.try_next_season[entry['series_name']] = True task.rerun() else: # Don't try a second time self.try_next_season[entry['series_name']] = False
def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): """Decides whether we should look for next ep/season based on whether we found/accepted any episodes.""" with Session() as session: series = session.query(Series).filter(Series.name == entry['series_name']).first() latest = get_latest_release(series) db_release = (session.query(EpisodeRelease).join(EpisodeRelease.episode).join(Episode.series). filter(Series.name == entry['series_name']). filter(Episode.season == entry['series_season']). filter(Episode.number == entry['series_episode']).first()) if entry.accepted: log.debug('%s %s was accepted, rerunning to look for next ep.' % (entry['series_name'], entry['series_id'])) self.rerun_entries.append(self.search_entry(series, entry['series_season'], entry['series_episode'] + 1, task)) # Increase rerun limit by one if we have matches, this way # we keep searching as long as matches are found! # TODO: this should ideally be in discover so it would be more generic task.max_reruns += 1 task.rerun(plugin='next_series_episodes', reason='Look for next episode') elif db_release: # There are know releases of this episode, but none were accepted return elif latest and identified_by == 'ep' and ( entry['series_season'] == latest.season and entry['series_episode'] == latest.number + 1): # We searched for next predicted episode of this season unsuccessfully, try the next season self.rerun_entries.append(self.search_entry(series, latest.season + 1, 1, task)) log.debug('%s %s not found, rerunning to look for next season' % (entry['series_name'], entry['series_id'])) task.rerun(plugin='next_series_episodes', reason='Look for next season')
def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): """Decides whether we should look for next ep/season based on whether we found/accepted any episodes.""" with Session() as session: series = session.query(Series).filter(Series.name == entry['series_name']).first() latest = get_latest_release(series) db_release = (session.query(Release).join(Release.episode).join(Episode.series). filter(Series.name == entry['series_name']). filter(Episode.season == entry['series_season']). filter(Episode.number == entry['series_episode']).first()) if entry.accepted: log.debug('%s %s was accepted, rerunning to look for next ep.' % (entry['series_name'], entry['series_id'])) self.rerun_entries.append(self.search_entry(series, entry['series_season'], entry['series_episode'] + 1, task)) # Increase rerun limit by one if we have matches, this way # we keep searching as long as matches are found! # TODO: this should ideally be in discover so it would be more generic task.max_reruns += 1 task.rerun(plugin='next_series_episodes', reason='Look for next episode') elif db_release: # There are know releases of this episode, but none were accepted return elif latest and identified_by == 'ep' and ( entry['series_season'] == latest.season and entry['series_episode'] == latest.number + 1): # We searched for next predicted episode of this season unsuccessfully, try the next season self.rerun_entries.append(self.search_entry(series, latest.season + 1, 1, task)) log.debug('%s %s not found, rerunning to look for next season' % (entry['series_name'], entry['series_id'])) task.rerun(plugin='next_series_episodes', reason='Look for next season')
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ formatting = ' %-30s %-10s %-10s %-20s' console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) session = Session() try: query = (session.query(Series).outerjoin(Series.episodes).outerjoin(Episode.releases). outerjoin(Series.in_tasks).group_by(Series.id)) if options.configured == 'configured': query = query.having(func.count(SeriesTask.id) >= 1) elif options.configured == 'unconfigured': query = query.having(func.count(SeriesTask.id) < 1) if options.premieres: query = (query.having(func.max(Episode.season) <= 1).having(func.max(Episode.number) <= 2). having(func.count(SeriesTask.id) < 1)).filter(Release.downloaded == True) if options.new: query = query.having(func.max(Episode.first_seen) > datetime.now() - timedelta(days=options.new)) if options.stale: query = query.having(func.max(Episode.first_seen) < datetime.now() - timedelta(days=options.stale)) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console(' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) console('-' * 79) console(' > = new episode ') console(' Use `flexget series show NAME` to get detailed information') finally: session.close()
def series_details(show, begin=False, latest=False): series_dict = { 'id': show.id, 'name': show.name, 'alternate_names': [n.alt_name for n in show.alternate_names], 'in_tasks': [_show.name for _show in show.in_tasks] } if begin: series_dict['begin_episode'] = show.begin.to_dict() if show.begin else None if latest: latest_ep = series.get_latest_release(show) series_dict['latest_episode'] = latest_ep.to_dict() if latest_ep else None if latest_ep: series_dict['latest_episode']['latest_release'] = latest_ep.latest_release.to_dict() return series_dict
def series_details(show, begin=False, latest=False): series_dict = { "id": show.id, "name": show.name, "alternate_names": [n.alt_name for n in show.alternate_names], "in_tasks": [_show.name for _show in show.in_tasks], } if begin: series_dict["begin_episode"] = show.begin.to_dict() if show.begin else None if latest: latest_ep = series.get_latest_release(show) series_dict["latest_episode"] = latest_ep.to_dict() if latest_ep else None if latest_ep: series_dict["latest_episode"]["latest_release"] = latest_ep.latest_release.to_dict() return series_dict
def get_series_details(show): latest_ep = series.get_latest_release(show) begin_ep = show.begin if begin_ep: begin_ep_id = begin_ep.id begin_ep_identifier = begin_ep.identifier else: begin_ep_id = begin_ep_identifier = None begin = { 'episode_id': begin_ep_id, 'episode_identifier': begin_ep_identifier } if latest_ep: latest_ep_id = latest_ep.id latest_ep_identifier = latest_ep.identifier latest_ep_age = latest_ep.age new_eps_after_latest_ep = series.new_eps_after(latest_ep) release = get_release_details( sorted(latest_ep.downloaded_releases, key=lambda release: release.first_seen if release.downloaded else None, reverse=True)[0]) else: latest_ep_id = latest_ep_identifier = latest_ep_age = new_eps_after_latest_ep = release = None latest = { 'episode_id': latest_ep_id, 'episode_identifier': latest_ep_identifier, 'episode_age': latest_ep_age, 'number_of_episodes_behind': new_eps_after_latest_ep, 'last_downloaded_release': release } show_item = { 'show_id': show.id, 'show_name': show.name, 'alternate_names': [n.alt_name for n in show.alternate_names], 'begin_episode': begin, 'latest_downloaded_episode': latest, 'in_tasks': [_show.name for _show in show.in_tasks] } return show_item
def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): series = task.session.query(Series).filter(Series.name == entry['series_name']).first() latest = get_latest_release(series) episode = (task.session.query(Episode).join(Episode.series). filter(Series.name == entry['series_name']). filter(Episode.season == entry['series_season']). filter(Episode.number == entry['series_episode']). first()) if entry.accepted or (episode and len(episode.releases) > 0): self.try_next_season.pop(entry['series_name'], None) task.rerun() elif latest and latest.season == entry['series_season']: if identified_by != 'ep': # Do not try next season if this is not an 'ep' show return if entry['series_name'] not in self.try_next_season: self.try_next_season[entry['series_name']] = True task.rerun() else: # Don't try a second time self.try_next_season[entry['series_name']] = False
def on_search_complete(self, entry, task=None, identified_by=None, **kwargs): """Decides whether we should look for next ep/season based on whether we found/accepted any episodes.""" with Session() as session: series = session.query(Series).filter( Series.name == entry['series_name']).first() latest = get_latest_release(series) db_release = (session.query(Release).join(Release.episode).join( Episode.series).filter( Series.name == entry['series_name']).filter( Episode.season == entry['series_season']).filter( Episode.number == entry['series_episode']).first()) if entry.accepted: log.debug( '%s %s was accepted, rerunning to look for next ep.' % (entry['series_name'], entry['series_id'])) self.rerun_entries.append( self.search_entry(series, entry['series_season'], entry['series_episode'] + 1, task)) task.rerun() elif db_release: # There are know releases of this episode, but none were accepted return elif latest and identified_by == 'ep' and ( entry['series_season'] == latest.season and entry['series_episode'] == latest.number + 1): # We searched for next predicted episode of this season unsuccessfully, try the next season self.rerun_entries.append( self.search_entry(series, latest.season + 1, 1, task)) log.debug( '%s %s not found, rerunning to look for next season' % (entry['series_name'], entry['series_id'])) task.rerun()
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] threshold = config.get('threshold') entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter(SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug('Found SeriesTask item without series specified. Cleaning up.') session.delete(seriestask) continue if series.identified_by not in ['ep']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 # Don't look for seasons older than begin ep if series.begin and series.begin.season and series.begin.season > 1: low_season = max(series.begin.season - 1, 0) new_season = None check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: if latest_season.season <= low_season: latest_season = new_season = low_season + 1 elif latest_season.season in series.completed_seasons: latest_season = new_season = latest_season.season + 1 else: latest_season = latest_season.season else: latest_season = low_season + 1 if (latest_season - low_season > MAX_SEASON_DIFF_WITHOUT_BEGIN and not series.begin) or ( series.begin and latest_season - series.begin.season > MAX_SEASON_DIFF_WITH_BEGIN): if series.begin: log.error('Series `%s` has a begin episode set (`%s`), but the season currently being processed' ' (%s) is %s seasons later than it. To prevent emitting incorrect seasons, this ' 'series will not emit unless the begin episode is adjusted to a season that is less ' 'than %s seasons from season %s.', series.name, series.begin.identifier, latest_season, (latest_season - series.begin.season), MAX_SEASON_DIFF_WITH_BEGIN, latest_season) else: log.error('Series `%s` does not have a begin episode set and continuing this task would result ' 'in more than %s seasons being emitted. To prevent emitting incorrect seasons, this ' 'series will not emit unless the begin episode is set in your series config or by ' 'using the CLI subcommand `series begin "%s" <SxxExx>`.', series.name, MAX_SEASON_DIFF_WITHOUT_BEGIN, series.name) continue for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue if threshold is not None and series.episodes_for_season(season) > threshold: log.debug('season %s has met threshold of threshold of %s, skipping', season, threshold) continue log.trace('Evaluating season %s for series `%s`', season, series.name) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and season == series.begin.season and (not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season while lookup_season in series.completed_seasons: lookup_season += 1 entries.append(self.search_entry(series, lookup_season, task)) elif latest: entries.append(self.search_entry(series, latest.season, task)) # First iteration of a new season with no show begin and show has downloads elif new_season and season == new_season: entries.append(self.search_entry(series, season, task)) else: if config.get('from_start') or config.get('backfill'): entries.append(self.search_entry(series, season, task)) else: log.verbose('Series `%s` has no history. Set the begin option in your config, ' 'or use the CLI subcommand `series begin "%s" <SxxExx>` ' 'to set the first episode to emit', series.name, series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): log.debug('backfill is not enabled; skipping older seasons') break for reason, series in impossible.items(): log.verbose('Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter(SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug('Found SeriesTask item without series specified. Cleaning up.') session.delete(seriestask) continue if series.identified_by not in ['ep', 'sequence']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 if series.identified_by == 'ep' else -1 # Don't look for seasons older than begin ep if series.begin and series.begin.season and series.begin.season > 1: # begin-1 or the range() loop will never get to the begin season low_season = max(series.begin.season - 1, 0) new_season = None check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: if latest_season.season <= low_season: latest_season = new_season = low_season + 1 elif latest_season.season in series.completed_seasons: latest_season = new_season = latest_season.season + 1 else: latest_season = latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue log.trace('Evaluating episodes for series %s, season %d', series.name, season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and season == series.begin.season and (not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season ep_number = series.begin.number while lookup_season in series.completed_seasons: lookup_season += 1 # If season number was bumped, start looking for ep 1 ep_number = 1 entries.append(self.search_entry(series, lookup_season, ep_number, task)) elif latest and not config.get('backfill'): entries.append(self.search_entry(series, latest.season, latest.number + 1, task)) elif latest: start_at_ep = 1 episodes_this_season = (session.query(Episode). filter(Episode.series_id == series.id). filter(Episode.season == season)) if series.identified_by == 'sequence': # Don't look for missing too far back with sequence shows start_at_ep = max(latest.number - 10, 1) episodes_this_season = episodes_this_season.filter(Episode.number >= start_at_ep) latest_ep_this_season = episodes_this_season.order_by(desc(Episode.number)).first() if latest_ep_this_season: downloaded_this_season = (episodes_this_season.join(Episode.releases). filter(EpisodeRelease.downloaded == True).all()) # Calculate the episodes we still need to get from this season if series.begin and series.begin.season == season: start_at_ep = max(start_at_ep, series.begin.number) eps_to_get = list(range(start_at_ep, latest_ep_this_season.number + 1)) for ep in downloaded_this_season: try: eps_to_get.remove(ep.number) except ValueError: pass entries.extend(self.search_entry(series, season, x, task, rerun=False) for x in eps_to_get) # If we have already downloaded the latest known episode, try the next episode if latest_ep_this_season.releases: entries.append( self.search_entry(series, season, latest_ep_this_season.number + 1, task)) else: # No episode means that latest is a season pack, emit episode 1 entries.append(self.search_entry(series, season, 1, task)) # First iteration of a new season with no show begin and show has downloads elif new_season and season == new_season: entries.append(self.search_entry(series, season, 1, task)) else: if config.get('from_start') or config.get('backfill'): entries.append(self.search_entry(series, season, 1, task)) else: log.verbose('Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit', series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): log.debug('backfill is not enabled; skipping older seasons') break for reason, series in impossible.items(): log.verbose('Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter(SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug('Found SeriesTask item without series specified. Cleaning up.') session.delete(seriestask) continue if series.identified_by not in ['ep']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: latest_season = latest_season.season + 1 if latest_season.season in series.completed_seasons \ else latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue log.trace('Adding episodes for series %s season %d', series.name, season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and (not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season while lookup_season in series.completed_seasons: lookup_season += 1 entries.append(self.search_entry(series, lookup_season, task)) elif latest: entries.append(self.search_entry(series, latest.season, task)) else: if config.get('from_start') or config.get('backfill'): entries.append(self.search_entry(series, season, 1, task)) else: log.verbose('Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit', series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): break # Don't look for seasons older than begin ep if series.begin and series.begin.season >= season: break for reason, series in impossible.items(): log.verbose('Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ porcelain = options.table_type == 'porcelain' with Session() as session: kwargs = { 'configured': options.configured, 'premieres': options.premieres, 'session': session, 'sort_by': options.sort_by, 'descending': options.order } if options.new: kwargs['status'] = 'new' kwargs['days'] = options.new elif options.stale: kwargs['status'] = 'stale' kwargs['days'] = options.stale if options.sort_by == 'name': kwargs['sort_by'] = 'show_name' else: kwargs['sort_by'] = 'last_download_date' query = get_series_summary(**kwargs) header = ['Name', 'Latest', 'Age', 'Downloaded', 'Identified By'] for index, value in enumerate(header): if value.lower() == options.sort_by: header[index] = colorize(SORT_COLUMN_COLOR, value) table_data = [header] for series in query: name_column = series.name behind = (0, ) latest_release = '-' age_col = '-' episode_id = '-' latest = get_latest_release(series) identifier_type = series.identified_by if identifier_type == 'auto': identifier_type = colorize('yellow', 'auto') if latest: behind = new_entities_after(latest) latest_release = get_latest_status(latest) # colorize age age_col = latest.age if latest.age_timedelta is not None: if latest.age_timedelta < timedelta(days=1): age_col = colorize(NEW_EP_COLOR, latest.age) elif latest.age_timedelta < timedelta(days=3): age_col = colorize(FRESH_EP_COLOR, latest.age) elif latest.age_timedelta > timedelta(days=400): age_col = colorize(OLD_EP_COLOR, latest.age) episode_id = latest.identifier if not porcelain: if behind[0] > 0: name_column += colorize( BEHIND_EP_COLOR, ' {} {} behind'.format(behind[0], behind[1])) table_data.append([ name_column, episode_id, age_col, latest_release, identifier_type ]) try: table = TerminalTable(options.table_type, table_data, wrap_columns=[3], drop_columns=[4, 3, 2]) console(table.output) except TerminalTableError as e: console('ERROR: %s' % str(e)) return if not porcelain: if not query.count(): console('Use `flexget series list all` to view all known series.') else: console( 'Use `flexget series show NAME` to get detailed information.')
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ formatting = ' %-30s %-10s %-10s %-20s' console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) session = Session() try: query = (session.query(Series).outerjoin(Series.episodes).outerjoin( Episode.releases).outerjoin(Series.in_tasks).group_by(Series.id)) if options.configured == 'configured': query = query.having(func.count(SeriesTask.id) >= 1) elif options.configured == 'unconfigured': query = query.having(func.count(SeriesTask.id) < 1) if options.premieres: query = (query.having(func.max(Episode.season) <= 1).having( func.max(Episode.number) <= 2).having( func.count(SeriesTask.id) < 1)).filter( Release.downloaded == True) if options.new: query = query.having( func.max(Episode.first_seen) > datetime.now() - timedelta(days=options.new)) if options.stale: query = query.having( func.max(Episode.first_seen) < datetime.now() - timedelta(days=options.stale)) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console( ' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) console('-' * 79) console(' > = new episode ') console(' Use `flexget series show NAME` to get detailed information') finally: session.close()
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ porcelain = options.table_type == 'porcelain' with Session() as session: kwargs = {'configured': options.configured, 'premieres': options.premieres, 'session': session, 'sort_by': options.sort_by, 'descending': options.order} if options.new: kwargs['status'] = 'new' kwargs['days'] = options.new elif options.stale: kwargs['status'] = 'stale' kwargs['days'] = options.stale if options.sort_by == 'name': kwargs['sort_by'] = 'show_name' else: kwargs['sort_by'] = 'last_download_date' query = get_series_summary(**kwargs) header = ['Name', 'Latest', 'Age', 'Downloaded', 'Identified By'] for index, value in enumerate(header): if value.lower() == options.sort_by: header[index] = colorize(SORT_COLUMN_COLOR, value) footer = 'Use `flexget series show NAME` to get detailed information' table_data = [header] for series in query: name_column = series.name new_ep = False behind = 0 latest_release = '-' age_col = '-' episode_id = '-' latest = get_latest_release(series) identifier_type = series.identified_by if identifier_type == 'auto': identifier_type = colorize('yellow', 'auto') if latest: behind = new_eps_after(latest) latest_release = get_latest_status(latest) # colorize age age_col = latest.age if latest.age_timedelta is not None: if latest.age_timedelta < timedelta(days=1): age_col = colorize(NEW_EP_COLOR, latest.age) elif latest.age_timedelta < timedelta(days=3): age_col = colorize(FRESH_EP_COLOR, latest.age) elif latest.age_timedelta > timedelta(days=400): age_col = colorize(OLD_EP_COLOR, latest.age) episode_id = latest.identifier if not porcelain: if behind > 0: name_column += colorize(BEHIND_EP_COLOR, ' {} behind'.format(behind)) table_data.append([name_column, episode_id, age_col, latest_release, identifier_type]) table = TerminalTable(options.table_type, table_data, wrap_columns=[3], drop_columns=[4, 3, 2]) try: console(table.output) except TerminalTableError as e: console('ERROR: %s' % str(e)) return if not porcelain: console(footer)
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if not task.is_rerun: self.try_next_season = {} entries = [] for seriestask in task.session.query(SeriesTask).filter(SeriesTask.name == task.name).all(): series = seriestask.series if not series: # TODO: How can this happen? log.debug("Found SeriesTask item without series specified. Cleaning up.") task.session.delete(seriestask) continue if series.identified_by not in ["ep", "sequence"]: log.verbose( "Can only emit ep or sequence based series. `%s` is identified_by %s" % (series.name, series.identified_by or "auto") ) continue low_season = 0 if series.identified_by == "ep" else -1 latest_season = get_latest_release(series) if latest_season: latest_season = latest_season.season else: latest_season = low_season + 1 if self.try_next_season.get(series.name): entries.append(self.search_entry(series, latest_season + 1, 1, task)) else: for season in xrange(latest_season, low_season, -1): log.debug("Adding episodes for %d" % latest_season) check_downloaded = not config.get("backfill") latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and (not latest or latest < series.begin): entries.append(self.search_entry(series, series.begin.season, series.begin.number, task)) elif latest: start_at_ep = 1 episodes_this_season = ( task.session.query(Episode) .filter(Episode.series_id == series.id) .filter(Episode.season == season) ) if series.identified_by == "sequence": # Don't look for missing too far back with sequence shows start_at_ep = max(latest.number - 10, 1) episodes_this_season = episodes_this_season.filter(Episode.number >= start_at_ep) latest_ep_this_season = episodes_this_season.order_by(desc(Episode.number)).first() downloaded_this_season = ( episodes_this_season.join(Episode.releases).filter(Release.downloaded == True).all() ) # Calculate the episodes we still need to get from this season if series.begin and series.begin.season == season: start_at_ep = max(start_at_ep, series.begin.number) eps_to_get = range(start_at_ep, latest_ep_this_season.number + 1) for ep in downloaded_this_season: try: eps_to_get.remove(ep.number) except ValueError: pass entries.extend(self.search_entry(series, season, x, task, rerun=False) for x in eps_to_get) # If we have already downloaded the latest known episode, try the next episode if latest_ep_this_season.releases: entries.append(self.search_entry(series, season, latest_ep_this_season.number + 1, task)) else: if config.get("from_start") or config.get("backfill"): entries.append(self.search_entry(series, season, 1, task)) else: log.verbose( "Series `%s` has no history. Set begin option, or use CLI `series begin` " "subcommand to set first episode to emit" % series.name ) continue if not config.get("backfill"): break return entries
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter( SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug( 'Found SeriesTask item without series specified. Cleaning up.' ) session.delete(seriestask) continue if series.identified_by not in ['ep']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 # Don't look for seasons older than begin ep if series.begin and series.begin.season and series.begin.season > 1: low_season = max(series.begin.season - 1, 0) new_season = None check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: if latest_season.season <= low_season: latest_season = new_season = low_season + 1 elif latest_season.season in series.completed_seasons: latest_season = new_season = latest_season.season + 1 else: latest_season = latest_season.season else: latest_season = low_season + 1 if (latest_season - low_season > MAX_SEASON_DIFF_WITHOUT_BEGIN and not series.begin) or ( series.begin and latest_season - series.begin.season > MAX_SEASON_DIFF_WITH_BEGIN): if series.begin: log.error( 'Series `%s` has a begin episode set (`%s`), but the season currently being processed ' '(%s) is %s seasons later than it. To prevent emitting incorrect seasons, this ' 'series will not emit unless the begin episode is adjusted to a season that is less ' 'than %s seasons from season %s.', series.name, series.begin.identifier, latest_season, (latest_season - series.begin.season), MAX_SEASON_DIFF_WITH_BEGIN, latest_season) else: log.error( 'Series `%s` does not have a begin episode set and continuing this task would result ' 'in more than %s seasons being emitted. To prevent emitting incorrect seasons, this ' 'series will not emit unless the begin episode is set in your series config or by ' 'using the CLI subcommand `series begin "%s" <SxxExx>`.', series.name, MAX_SEASON_DIFF_WITHOUT_BEGIN, series.name) continue for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue log.trace('Evaluating season %s for series `%s`', season, series.name) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and season == series.begin.season and ( not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season while lookup_season in series.completed_seasons: lookup_season += 1 entries.append( self.search_entry(series, lookup_season, task)) elif latest: entries.append( self.search_entry(series, latest.season, task)) # First iteration of a new season with no show begin and show has downloads elif new_season and season == new_season: entries.append(self.search_entry(series, season, task)) else: if config.get('from_start') or config.get('backfill'): entries.append( self.search_entry(series, season, task)) else: log.verbose( 'Series `%s` has no history. Set the begin option in your config, ' 'or use the CLI subcommand `series begin "%s" <SxxExx>` ' 'to set the first episode to emit', series.name, series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): log.debug( 'backfill is not enabled; skipping older seasons') break for reason, series in impossible.items(): log.verbose( 'Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ with Session() as session: kwargs = {'configured': options.configured, 'premieres': options.premieres, 'session': session} if options.new: kwargs['status'] = 'new' kwargs['days'] = options.new elif options.stale: kwargs['status'] = 'stale' kwargs['days'] = options.stale query = get_series_summary(**kwargs) if options.porcelain: formatting = '%-30s %s %-10s %s %-10s %s %-20s' console(formatting % ('Name', '|', 'Latest', '|', 'Age', '|', 'Downloaded')) else: formatting = ' %-30s %-10s %-10s %-20s' console('-' * 79) console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): if options.porcelain: pass else: new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind if options.porcelain: console(formatting % (series_name, '|', episode_id, '|', age, '|', status)) else: console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console(' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) if options.porcelain: pass else: console('-' * 79) console(' > = new episode ') console(' Use `flexget series show NAME` to get detailed information')
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ porcelain = options.table_type == 'porcelain' configured = options.configured or os.environ.get(ENV_LIST_CONFIGURED, 'configured') premieres = True if (os.environ.get(ENV_LIST_PREMIERES) == 'yes' or options.premieres) else False sort_by = options.sort_by or os.environ.get(ENV_LIST_SORTBY_FIELD, 'name') if options.order is not None: descending = True if options.order == 'desc' else False else: descending = True if os.environ.get(ENV_LIST_SORTBY_ORDER) == 'desc' else False with Session() as session: kwargs = {'configured': configured, 'premieres': premieres, 'session': session, 'sort_by': sort_by, 'descending': descending} if sort_by == 'name': kwargs['sort_by'] = 'show_name' else: kwargs['sort_by'] = 'last_download_date' query = get_series_summary(**kwargs) header = ['Name', 'Begin', 'Last Encountered', 'Age', 'Downloaded', 'Identified By'] for index, value in enumerate(header): if value.lower() == options.sort_by: header[index] = colorize(SORT_COLUMN_COLOR, value) table_data = [header] for series in query: name_column = series.name behind = (0,) begin = series.begin.identifier if series.begin else '-' latest_release = '-' age_col = '-' episode_id = '-' latest = get_latest_release(series) identifier_type = series.identified_by if identifier_type == 'auto': identifier_type = colorize('yellow', 'auto') if latest: behind = new_entities_after(latest) latest_release = get_latest_status(latest) # colorize age age_col = latest.age if latest.age_timedelta is not None: if latest.age_timedelta < timedelta(days=1): age_col = colorize(NEW_EP_COLOR, latest.age) elif latest.age_timedelta < timedelta(days=3): age_col = colorize(FRESH_EP_COLOR, latest.age) elif latest.age_timedelta > timedelta(days=400): age_col = colorize(OLD_EP_COLOR, latest.age) episode_id = latest.identifier if not porcelain: if behind[0] > 0: name_column += colorize(BEHIND_EP_COLOR, ' {} {} behind'.format(behind[0], behind[1])) table_data.append([name_column, begin, episode_id, age_col, latest_release, identifier_type]) try: table = TerminalTable(options.table_type, table_data, wrap_columns=[3], drop_columns=[4, 3, 2]) console(table.output) except TerminalTableError as e: console('ERROR: %s' % str(e)) return if not porcelain: if not query.count(): console('Use `flexget series list all` to view all known series.') else: console('Use `flexget series show NAME` to get detailed information.')
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter( SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug( 'Found SeriesTask item without series specified. Cleaning up.' ) session.delete(seriestask) continue if series.identified_by not in ['ep']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: latest_season = latest_season.season + 1 if latest_season.season in series.completed_seasons \ else latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue log.trace('Adding episodes for series %s season %d', series.name, season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and (not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season while lookup_season in series.completed_seasons: lookup_season += 1 entries.append( self.search_entry(series, lookup_season, task)) elif latest: entries.append( self.search_entry(series, latest.season, task)) else: if config.get('from_start') or config.get('backfill'): entries.append( self.search_entry(series, season, 1, task)) else: log.verbose( 'Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit', series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): break # Don't look for seasons older than begin ep if series.begin and series.begin.season >= season: break for reason, series in impossible.items(): log.verbose( 'Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ with Session() as session: kwargs = { 'configured': options.configured, 'premieres': options.premieres, 'session': session } if options.new: kwargs['status'] = 'new' kwargs['days'] = options.new elif options.stale: kwargs['status'] = 'stale' kwargs['days'] = options.stale query = get_series_summary(**kwargs) if options.porcelain: formatting = '%-30s %s %-10s %s %-10s %s %-20s' console(formatting % ('Name', '|', 'Latest', '|', 'Age', '|', 'Downloaded')) else: formatting = ' %-30s %-10s %-10s %-20s' console('-' * 79) console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): if options.porcelain: pass else: new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind if options.porcelain: console(formatting % (series_name, '|', episode_id, '|', age, '|', status)) else: console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console( ' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) if options.porcelain: pass else: console('-' * 79) console(' > = new episode ') console( ' Use `flexget series show NAME` to get detailed information')
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] with Session() as session: for seriestask in session.query(SeriesTask).filter(SeriesTask.name == task.name).all(): series = seriestask.series if not series: # TODO: How can this happen? log.debug('Found SeriesTask item without series specified. Cleaning up.') session.delete(seriestask) continue if series.identified_by not in ['ep', 'sequence']: log.verbose('Can only emit ep or sequence based series. ' '`%s` is identified_by %s' % (series.name, series.identified_by or 'auto')) continue low_season = 0 if series.identified_by == 'ep' else -1 check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: latest_season = latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): log.debug('Adding episodes for season %d' % season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and (not latest or latest < series.begin): entries.append(self.search_entry(series, series.begin.season, series.begin.number, task)) elif latest and not config.get('backfill'): entries.append(self.search_entry(series, latest.season, latest.number + 1, task)) elif latest: start_at_ep = 1 episodes_this_season = (session.query(Episode). filter(Episode.series_id == series.id). filter(Episode.season == season)) if series.identified_by == 'sequence': # Don't look for missing too far back with sequence shows start_at_ep = max(latest.number - 10, 1) episodes_this_season = episodes_this_season.filter(Episode.number >= start_at_ep) latest_ep_this_season = episodes_this_season.order_by(desc(Episode.number)).first() downloaded_this_season = (episodes_this_season.join(Episode.releases). filter(Release.downloaded == True).all()) # Calculate the episodes we still need to get from this season if series.begin and series.begin.season == season: start_at_ep = max(start_at_ep, series.begin.number) eps_to_get = list(range(start_at_ep, latest_ep_this_season.number + 1)) for ep in downloaded_this_season: try: eps_to_get.remove(ep.number) except ValueError: pass entries.extend(self.search_entry(series, season, x, task, rerun=False) for x in eps_to_get) # If we have already downloaded the latest known episode, try the next episode if latest_ep_this_season.releases: entries.append(self.search_entry(series, season, latest_ep_this_season.number + 1, task)) else: if config.get('from_start') or config.get('backfill'): entries.append(self.search_entry(series, season, 1, task)) else: log.verbose('Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit' % series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): break # Don't look for seasons older than begin ep if series.begin and series.begin.season >= season: break return entries
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] impossible = {} with Session() as session: for seriestask in session.query(SeriesTask).filter( SeriesTask.name == task.name).all(): series = seriestask.series log.trace('evaluating %s', series.name) if not series: # TODO: How can this happen? log.debug( 'Found SeriesTask item without series specified. Cleaning up.' ) session.delete(seriestask) continue if series.identified_by not in ['ep', 'sequence']: log.trace('unsupported identified_by scheme') reason = series.identified_by or 'auto' impossible.setdefault(reason, []).append(series.name) continue low_season = 0 if series.identified_by == 'ep' else -1 # Don't look for seasons older than begin ep if series.begin and series.begin.season and series.begin.season > 1: # begin-1 or the range() loop will never get to the begin season low_season = max(series.begin.season - 1, 0) new_season = None check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: if latest_season.season <= low_season: latest_season = new_season = low_season + 1 elif latest_season.season in series.completed_seasons: latest_season = new_season = latest_season.season + 1 else: latest_season = latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): if season in series.completed_seasons: log.debug('season %s is marked as completed, skipping', season) continue log.trace('Evaluating episodes for series %s, season %d', series.name, season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and season == series.begin.season and ( not latest or latest < series.begin): # In case series.begin season is already completed, look in next available season lookup_season = series.begin.season ep_number = series.begin.number while lookup_season in series.completed_seasons: lookup_season += 1 # If season number was bumped, start looking for ep 1 ep_number = 1 entries.append( self.search_entry(series, lookup_season, ep_number, task)) elif latest and not config.get('backfill'): entries.append( self.search_entry(series, latest.season, latest.number + 1, task)) elif latest: start_at_ep = 1 episodes_this_season = (session.query(Episode).filter( Episode.series_id == series.id).filter( Episode.season == season)) if series.identified_by == 'sequence': # Don't look for missing too far back with sequence shows start_at_ep = max(latest.number - 10, 1) episodes_this_season = episodes_this_season.filter( Episode.number >= start_at_ep) latest_ep_this_season = episodes_this_season.order_by( desc(Episode.number)).first() if latest_ep_this_season: downloaded_this_season = ( episodes_this_season.join( Episode.releases).filter( EpisodeRelease.downloaded == True).all()) # Calculate the episodes we still need to get from this season if series.begin and series.begin.season == season: start_at_ep = max(start_at_ep, series.begin.number) eps_to_get = list( range(start_at_ep, latest_ep_this_season.number + 1)) for ep in downloaded_this_season: try: eps_to_get.remove(ep.number) except ValueError: pass entries.extend( self.search_entry( series, season, x, task, rerun=False) for x in eps_to_get) # If we have already downloaded the latest known episode, try the next episode if latest_ep_this_season.releases: entries.append( self.search_entry( series, season, latest_ep_this_season.number + 1, task)) else: # No episode means that latest is a season pack, emit episode 1 entries.append( self.search_entry(series, season, 1, task)) # First iteration of a new season with no show begin and show has downloads elif new_season and season == new_season: entries.append( self.search_entry(series, season, 1, task)) else: if config.get('from_start') or config.get('backfill'): entries.append( self.search_entry(series, season, 1, task)) else: log.verbose( 'Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit', series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): log.debug( 'backfill is not enabled; skipping older seasons') break for reason, series in impossible.items(): log.verbose( 'Series `%s` with identified_by value `%s` are not supported. ', ', '.join(sorted(series)), reason) return entries
def on_task_input(self, task, config): if not config: return if isinstance(config, bool): config = {} if task.is_rerun: # Just return calculated next eps on reruns entries = self.rerun_entries self.rerun_entries = [] return entries else: self.rerun_entries = [] entries = [] with Session() as session: for seriestask in session.query(SeriesTask).filter( SeriesTask.name == task.name).all(): series = seriestask.series if not series: # TODO: How can this happen? log.debug( 'Found SeriesTask item without series specified. Cleaning up.' ) session.delete(seriestask) continue if series.identified_by not in ['ep', 'sequence']: log.verbose('Can only emit ep or sequence based series. ' '`%s` is identified_by %s' % (series.name, series.identified_by or 'auto')) continue low_season = 0 if series.identified_by == 'ep' else -1 check_downloaded = not config.get('backfill') latest_season = get_latest_release(series, downloaded=check_downloaded) if latest_season: latest_season = latest_season.season else: latest_season = low_season + 1 for season in range(latest_season, low_season, -1): log.debug('Adding episodes for season %d' % season) latest = get_latest_release(series, season=season, downloaded=check_downloaded) if series.begin and (not latest or latest < series.begin): entries.append( self.search_entry(series, series.begin.season, series.begin.number, task)) elif latest and not config.get('backfill'): entries.append( self.search_entry(series, latest.season, latest.number + 1, task)) elif latest: start_at_ep = 1 episodes_this_season = (session.query(Episode).filter( Episode.series_id == series.id).filter( Episode.season == season)) if series.identified_by == 'sequence': # Don't look for missing too far back with sequence shows start_at_ep = max(latest.number - 10, 1) episodes_this_season = episodes_this_season.filter( Episode.number >= start_at_ep) latest_ep_this_season = episodes_this_season.order_by( desc(Episode.number)).first() downloaded_this_season = (episodes_this_season.join( Episode.releases).filter( Release.downloaded == True).all()) # Calculate the episodes we still need to get from this season if series.begin and series.begin.season == season: start_at_ep = max(start_at_ep, series.begin.number) eps_to_get = list( range(start_at_ep, latest_ep_this_season.number + 1)) for ep in downloaded_this_season: try: eps_to_get.remove(ep.number) except ValueError: pass entries.extend( self.search_entry( series, season, x, task, rerun=False) for x in eps_to_get) # If we have already downloaded the latest known episode, try the next episode if latest_ep_this_season.releases: entries.append( self.search_entry( series, season, latest_ep_this_season.number + 1, task)) else: if config.get('from_start') or config.get('backfill'): entries.append( self.search_entry(series, season, 1, task)) else: log.verbose( 'Series `%s` has no history. Set begin option, ' 'or use CLI `series begin` ' 'subcommand to set first episode to emit' % series.name) break # Skip older seasons if we are not in backfill mode if not config.get('backfill'): break # Don't look for seasons older than begin ep if series.begin and series.begin.season >= season: break return entries