from loguru import logger
from flexget import plugin
from flexget.entry import register_lazy_lookup
from flexget.event import event
from flexget.utils.database import with_session
try:
# NOTE: Importing other plugins is discouraged!
from flexget.components.thetvdb import api_tvdb as plugin_api_tvdb
except ImportError:
raise plugin.DependencyError(issued_by=__name__, missing='api_tvdb')
logger = logger.bind(name='thetvdb_lookup')
[docs]
class PluginThetvdbLookup:
"""Retrieve TheTVDB information for entries.
Use series_name, series_season, series_episode from series plugin.
Example::
thetvdb_lookup: yes
Primarily used for passing thetvdb information to other plugins.
Among these is the IMDB url for the series.
This information is provided (via entry)::
series info:
tvdb_series_name
tvdb_rating
tvdb_status (Continuing or Ended)
tvdb_runtime (show runtime in minutes)
tvdb_first_air_date
tvdb_air_time
tvdb_content_rating
tvdb_genres
tvdb_network
tvdb_overview
tvdb_banner
tvdb_posters
tvdb_airs_day_of_week
tvdb_actors
tvdb_language (en, fr, etc.)
imdb_url (if available)
zap2it_id (if available)
episode info: (if episode is found)
tvdb_ep_name
tvdb_ep_overview
tvdb_ep_directors
tvdb_ep_writers
tvdb_ep_air_date
tvdb_ep_rating
tvdb_ep_guest_stars
tvdb_ep_image
"""
# Series info
series_map = {
'tvdb_series_name': 'name',
'tvdb_rating': 'rating',
'tvdb_status': 'status',
'tvdb_runtime': 'runtime',
'tvdb_first_air_date': 'first_aired',
'tvdb_air_time': 'airs_time',
'tvdb_content_rating': 'content_rating',
'tvdb_genres': lambda series: list(series.genres),
'tvdb_network': 'network',
'tvdb_overview': 'overview',
'tvdb_banner': 'banner',
'tvdb_language': 'language',
'tvdb_airs_day_of_week': 'airs_dayofweek',
'imdb_url': lambda series: (
series.imdb_id and f'http://www.imdb.com/title/{series.imdb_id}'
),
'imdb_id': 'imdb_id',
'zap2it_id': 'zap2it_id',
'tvdb_id': 'id',
'tvdb_url': lambda series: f'http://thetvdb.com/index.php?tab=series&id={series.id!s}',
}
series_actor_map = {'tvdb_actors': 'actors'}
series_poster_map = {'tvdb_posters': 'posters'}
# Episode info
episode_map = {
'tvdb_ep_name': 'name',
'tvdb_ep_air_date': 'first_aired',
'tvdb_ep_rating': 'rating',
'tvdb_ep_image': 'image',
'tvdb_ep_overview': 'overview',
'tvdb_ep_directors': 'director',
'tvdb_absolute_number': 'absolute_number',
'tvdb_season': 'season_number',
'tvdb_episode': 'episode_number',
'tvdb_ep_id': lambda ep: f'S{ep.season_number:02d}E{ep.episode_number:02d}',
}
schema = {
'oneOf': [
{'type': 'boolean'},
{'type': 'object', 'properties': {'language': {'type': 'string', 'default': 'en'}}},
]
}
@with_session
def series_lookup(self, entry, language, field_map, session=None):
try:
series = plugin_api_tvdb.lookup_series(
entry.get('series_name', eval_lazy=False),
tvdb_id=entry.get('tvdb_id', eval_lazy=False),
language=entry.get('language', language),
session=session,
)
entry.update_using_map(field_map, series)
except LookupError as e:
logger.debug(
'Error looking up tvdb series information for {}: {}', entry['title'], e.args[0]
)
return entry
[docs]
@register_lazy_lookup('tvdb_series_lookup')
def lazy_series_lookup(self, entry, language):
return self.series_lookup(entry, language, self.series_map)
[docs]
@register_lazy_lookup('tvdb_series_actor_lookup')
def lazy_series_actor_lookup(self, entry, language):
return self.series_lookup(entry, language, self.series_actor_map)
[docs]
@register_lazy_lookup('tvdb_series_poster_lookup')
def lazy_series_poster_lookup(self, entry, language):
return self.series_lookup(entry, language, self.series_poster_map)
[docs]
@register_lazy_lookup('tvdb_episode_lookup')
def lazy_episode_lookup(self, entry, language):
try:
season_offset = entry.get('thetvdb_lookup_season_offset', 0)
episode_offset = entry.get('thetvdb_lookup_episode_offset', 0)
if not isinstance(season_offset, int):
logger.error('thetvdb_lookup_season_offset must be an integer')
season_offset = 0
if not isinstance(episode_offset, int):
logger.error('thetvdb_lookup_episode_offset must be an integer')
episode_offset = 0
if season_offset != 0 or episode_offset != 0:
logger.debug(
'Using offset for tvdb lookup: season: {}, episode: {}',
season_offset,
episode_offset,
)
lookupargs = {
'name': entry.get('series_name', eval_lazy=False),
'tvdb_id': entry.get('tvdb_id', eval_lazy=False),
'language': entry.get('language', language),
}
if entry['series_id_type'] == 'ep':
lookupargs['season_number'] = entry['series_season'] + season_offset
lookupargs['episode_number'] = entry['series_episode'] + episode_offset
elif entry['series_id_type'] == 'sequence':
lookupargs['absolute_number'] = entry['series_id'] + episode_offset
elif entry['series_id_type'] == 'date':
# TODO: Should thetvdb_lookup_episode_offset be used for date lookups as well?
lookupargs['first_aired'] = entry['series_date']
episode = plugin_api_tvdb.lookup_episode(**lookupargs)
entry.update_using_map(self.episode_map, episode)
except LookupError as e:
logger.debug(
'Error looking up tvdb episode information for {}: {}', entry['title'], e.args[0]
)
# Run after series and metainfo series
@property
def series_identifier(self):
"""Return the plugin main identifier type."""
return 'tvdb_id'
[docs]
@event('plugin.register')
def register_plugin():
plugin.register(
PluginThetvdbLookup, 'thetvdb_lookup', api_ver=2, interfaces=['task', 'series_metainfo']
)