2
from flexget.plugin import register_plugin, priority, get_plugin_by_name, PluginError
3
from flexget.utils.log import log_once
5
log = logging.getLogger('thetvdb')
8
class FilterTvdb(object):
10
This plugin allows filtering based on thetvdb series rating,
11
episode rating, status, genres, runtime, content-rating,
12
languages, directors, writers, network, guest stars, episode
17
series_status (Continuing or Ended)
18
series_runtime (show runtime in minutes)
23
series_language (en, fr, etc.)
24
episode info: (if episode is found)
33
Note: All parameters are optional. Some are mutually exclusive.
35
min_series_rating: <num>
36
min_episode_rating: <num>
37
min_episode_air_year: <num>
38
max_episode_air_year: <num>
39
min_episode_runtime: <num>
40
max_episode_runtime: <num>
42
# reject if genre contains any of these
43
reject_content_rating:
45
# accept only this content rating
46
accept_content_rating:
49
# accept only these networks
52
# reject if this network
56
# reject if genre contains any of these
61
# reject if status contains any of these
65
# reject if language contain any of these
68
# accept only this language
72
# Actors below take into account series actors, and guest stars
73
# accept episode with any of these actors
77
# reject episode if it has any of these actors
82
# accept all episodes by these writers
85
# reject episodes by these writers
89
# accept all episodes by these directors
92
# reject movies by these directors
98
"""Validate given configuration"""
99
from flexget import validator
100
thetvdb = validator.factory('dict')
101
thetvdb.accept('number', key='min_series_rating')
102
thetvdb.accept('number', key='min_episode_rating')
103
thetvdb.accept('integer', key='min_episode_air_year')
104
thetvdb.accept('integer', key='max_episode_air_year')
105
thetvdb.accept('number', key='min_episode_runtime')
106
thetvdb.accept('number', key='max_episode_runtime')
107
thetvdb.accept('list', key='reject_content_rating').accept('text')
108
thetvdb.accept('list', key='accept_content_rating').accept('text')
109
thetvdb.accept('list', key='accept_network').accept('text')
110
thetvdb.accept('list', key='reject_network').accept('text')
111
thetvdb.accept('list', key='reject_genres').accept('text')
112
thetvdb.accept('list', key='reject_status').accept('text')
113
thetvdb.accept('list', key='reject_languages').accept('text')
114
thetvdb.accept('list', key='accept_languages').accept('text')
115
thetvdb.accept('list', key='accept_actors').accept('text')
116
thetvdb.accept('list', key='reject_actors').accept('text')
117
thetvdb.accept('list', key='accept_writers').accept('text')
118
thetvdb.accept('list', key='reject_writers').accept('text')
119
thetvdb.accept('list', key='accept_directors').accept('text')
120
thetvdb.accept('list', key='reject_directors').accept('text')
123
def is_in_set(self, config, configkey, entryitem,):
125
this takes the config object, config key (to a list), and entry
126
item so it can return True if the object matches,
127
(be that a subset of the list, or if the entry item is contained
128
within the config object list) or false if it does not.
130
# will want to port this over to filter_imdb as well, for code
131
# clarity in that module.
132
if configkey in config:
133
configlist = config[configkey]
134
if isinstance(entryitem, list):
135
for item in entryitem:
136
if item in configlist:
139
if entryitem in configlist:
144
def on_feed_filter(self, feed):
145
config = feed.config['thetvdb']
147
lookup = get_plugin_by_name('thetvdb_lookup').instance.lookup
150
for entry in feed.entries:
155
except PluginError, e:
156
log.error('Skipping %s because of an error: %s' % (entry['title'], e.value))
159
# Check defined conditions
161
if 'min_series_rating' in config:
162
if entry['series_rating'] < config['min_series_rating']:
163
reasons.append('series_rating (%s < %s)' % (entry['series_rating'], config['min_series_rating']))
164
if 'min_episode_rating' in config:
165
if entry['ep_rating'] < config['min_episode_rating']:
166
reasons.append('ep_rating (%s < %s)' % (entry['ep_rating'], config['min_episode_rating']))
167
if 'min_episode_air_year' in config:
168
if entry['ep_air_date'].strftime("%Y") < config['min_episode_air_year']:
169
reasons.append('ep_air_date (%s < %s)' % (entry['ep_air_date'].strftime("%Y"), config['min_episode_air_year']))
170
if 'max_episode_air_year' in config:
171
if entry['ep_air_date'].strftime("%Y") > config['max_episode_air_year']:
172
reasons.append('ep_air_date (%s < %s)' % (entry['ep_air_date'].strftime("%Y"), config['max_episode_air_year']))
174
if self.is_in_set(config, 'reject_content_rating', entry['series_content_rating']):
175
reasons.append('reject_content_rating')
177
if not self.is_in_set(config, 'accept_content_rating', entry['series_content_rating']):
178
reasons.append('accept_content_rating')
180
if self.is_in_set(config, 'reject_network', entry['series_network']):
181
reasons.append('reject_network')
183
if not self.is_in_set(config, 'accept_network', entry['series_network']):
184
reasons.append('accept_network')
186
if self.is_in_set(config, 'reject_genres', entry['series_genres']):
187
reasons.append('reject_genres')
189
if self.is_in_set(config, 'reject_status', entry['series_status']):
190
reasons.append('reject_status')
192
if self.is_in_set(config, 'reject_languages', entry['series_language']):
193
reasons.append('reject_languages')
195
if not self.is_in_set(config, 'accept_languages', entry['series_language']):
196
reasons.append('accept_languages')
198
# Accept if actors contains an accepted actor, but don't reject otherwise
199
if self.is_in_set(config, 'accept_actors', entry['series_actors'] + entry['ep_guest_stars']):
202
if self.is_in_set(config, 'reject_actors', entry['series_actors'] + entry['ep_guest_stars']):
203
reasons.append('reject_genres')
205
# Accept if writer is an accepted writer, but don't reject otherwise
206
if self.is_in_set(config, 'accept_writers', entry['ep_writer']):
209
if self.is_in_set(config, 'reject_writers', entry['ep_writer']):
210
reasons.append('reject_writers')
212
# Accept if director is an accepted director, but don't reject otherwise
213
if self.is_in_set(config, 'accept_directors', entry['ep_director']):
216
if self.is_in_set(config, 'reject_directors', entry['ep_director']):
217
reasons.append('reject_directors')
219
if reasons and not force_accept:
220
msg = 'Skipping %s because of rule(s) %s' % \
221
(entry.get('series_name_thetvdb', None) or entry['title'], ', '.join(reasons))
222
if feed.manager.options.debug:
227
log.debug('Accepting %s' % (entry))
230
register_plugin(FilterTvdb, 'thetvdb')