Source code for flexget.components.trakt.next_trakt_episodes

import re

from loguru import logger
from requests import RequestException

from flexget import plugin
from flexget.entry import Entry
from flexget.event import event

from . import db

logger = logger.bind(name='next_trakt_episodes')


[docs] class NextTraktEpisodes: """Create an entry for the latest or the next item in your watched or collected episodes in your trakt account. Syntax: next_trakt_episodes: account: <value> username: <value> position: <last|next> context: <collect|collected|watch|watched> list: <value> `account` option is required if the profile is private. `username` will default to account owner if `account` is specified. """ schema = { 'type': 'object', 'properties': { 'username': {'type': 'string'}, 'account': {'type': 'string'}, 'position': {'type': 'string', 'enum': ['last', 'next'], 'default': 'next'}, 'context': { 'type': 'string', 'enum': ['watched', 'collected', 'aired'], 'default': 'watched', }, 'list': {'type': 'string'}, 'strip_dates': {'type': 'boolean', 'default': False}, }, 'required': ['list'], 'anyOf': [{'required': ['username']}, {'required': ['account']}], 'error_anyOf': 'At least one of `username` or `account` options are needed.', 'additionalProperties': False, }
[docs] def on_task_input(self, task, config): if config.get('account') and not config.get('username'): config['username'] = 'me' session = db.get_session(account=config.get('account')) listed_series = {} args = ('users', config['username']) if config['list'] in ['collection', 'watchlist', 'watched']: args += (config['list'], 'shows') else: args += ('lists', db.make_list_slug(config['list']), 'items') try: data = session.get(db.get_api_url(args)).json() except RequestException as e: raise plugin.PluginError('Unable to get trakt list `{}`: {}'.format(config['list'], e)) if not data: logger.warning('The list "{}" is empty.', config['list']) return None for item in data: if item.get('show'): if not item['show']['title']: # Seems we can get entries with a blank show title sometimes logger.warning('Found trakt list show without series name.') continue ids = item['show']['ids'] trakt_id = ids['trakt'] listed_series[trakt_id] = { 'series_name': '{} ({})'.format(item['show']['title'], item['show']['year']), 'trakt_id': trakt_id, 'trakt_series_name': item['show']['title'], 'trakt_series_year': item['show']['year'], 'trakt_list': config.get('list'), } for id_name, id_value in ids.items(): entry_field_name = ( 'trakt_slug' if id_name == 'slug' else id_name ) # rename slug to trakt_slug listed_series[trakt_id][entry_field_name] = id_value context = 'collection' if config['context'] == 'collected' else config['context'] entries = [] for trakt_id, fields in listed_series.items(): if context == 'aired': url = db.get_api_url('shows', trakt_id, '{}_episode'.format(config['position'])) else: url = db.get_api_url('shows', trakt_id, 'progress', context) try: response = session.get(url) if response.status_code == 204: logger.debug('No {} episode for {}', config['position'], fields['series_name']) continue data = response.json() except RequestException as e: raise plugin.PluginError( f'An error has occurred looking up: Trakt_id: {trakt_id} Error: {e}' ) if context == 'aired': season_number = data['season'] episode_number = data['number'] elif config['position'] == 'next' and data.get('next_episode'): # If the next episode is already in the trakt database, we'll get it here season_number = data['next_episode']['season'] episode_number = data['next_episode']['number'] else: # If we need last ep, or next_episode was not provided, search for last ep for season in reversed(data['seasons']): # Find the first season with collected/watched episodes if not season['completed']: continue season_number = season['number'] # Pick the highest collected/watched episode episode_number = max( item['number'] for item in season['episodes'] if item['completed'] ) # If we are in next episode mode, we have to increment this number if config['position'] == 'next': if season['completed'] >= season['aired']: # TODO: next_episode doesn't count unaired episodes right now, this will skip to next # season too early when there are episodes left to air this season. season_number += 1 episode_number = 1 break else: if config['position'] != 'next': # There were no watched/collected episodes, nothing to emit in 'last' mode continue season_number = episode_number = 1 if season_number and episode_number: if config.get('strip_dates'): # remove year from end of series_name if present fields['series_name'] = re.sub(r'\s+\(\d{4}\)$', '', fields['series_name']) entry = self.make_entry(fields, season_number, episode_number) entries.append(entry) return entries
[docs] @staticmethod def make_entry(fields, season, episode): entry = Entry() entry.update(fields) entry['series_season'] = season entry['series_episode'] = episode entry['series_id_type'] = 'ep' entry['series_id'] = f'S{season:02d}E{episode:02d}' entry['title'] = entry['series_name'] + ' ' + entry['series_id'] entry['url'] = 'https://trakt.tv/shows/{}/seasons/{}/episodes/{}'.format( fields['trakt_id'], season, episode, ) return entry
[docs] @event('plugin.register') def register_plugin(): plugin.register(NextTraktEpisodes, 'next_trakt_episodes', api_ver=2)