from loguru import logger
from flexget import plugin
from flexget.event import event
from flexget.utils.log import log_once
logger = logger.bind(name='imdb')
[docs]
class FilterImdb:
"""Allow filtering based on IMDB score, votes and genres etc.
Note: All parameters are optional. Some are mutually exclusive.
Configuration::
min_score: <num>
min_votes: <num>
min_meta_score: <num>
min_year: <num>
max_year: <num>
# accept movies with any of these genres
accept_genres:
- genre1
- genre2
# reject if genre contains any of these
reject_genres:
- genre1
- genre2
# reject if language contain any of these
reject_languages:
- language1
# accept only these primary languages
accept_languages:
- language1
# accept movies with any of these actors
accept_actors:
- nm0004695
- nm0004754
# reject movie if it has any of these actors
reject_actors:
- nm0001191
- nm0002071
# accept all movies by these directors
accept_directors:
- nm0000318
# reject movies by these directors
reject_directors:
- nm0093051
# accept all movies by these writers
accept_writers:
- nm0000318
# reject movies by these writers
reject_writers:
- nm0093051
# reject movies/TV shows with any of these ratings
reject_mpaa_ratings:
- PG_13
- R
- X
# accept movies/TV shows with only these ratings
accept_mpaa_ratings:
- PG
- G
- TV_Y
"""
schema = {
'type': 'object',
'properties': {
'min_year': {'type': 'integer'},
'max_year': {'type': 'integer'},
'min_votes': {'type': 'integer'},
'min_meta_score': {'type': 'integer'},
'min_score': {'type': 'number'},
'accept_genres': {'type': 'array', 'items': {'type': 'string'}},
'reject_genres': {'type': 'array', 'items': {'type': 'string'}},
'reject_languages': {'type': 'array', 'items': {'type': 'string'}},
'accept_languages': {'type': 'array', 'items': {'type': 'string'}},
'reject_actors': {'type': 'array', 'items': {'type': 'string'}},
'accept_actors': {'type': 'array', 'items': {'type': 'string'}},
'reject_directors': {'type': 'array', 'items': {'type': 'string'}},
'accept_directors': {'type': 'array', 'items': {'type': 'string'}},
'reject_writers': {'type': 'array', 'items': {'type': 'string'}},
'accept_writers': {'type': 'array', 'items': {'type': 'string'}},
'reject_mpaa_ratings': {'type': 'array', 'items': {'type': 'string'}},
'accept_mpaa_ratings': {'type': 'array', 'items': {'type': 'string'}},
},
'additionalProperties': False,
}
# Run later to avoid unnecessary lookups
[docs]
@plugin.priority(120)
def on_task_filter(self, task, config):
lookup = plugin.get('imdb_lookup', self).lookup
# since the plugin does not reject anything, no sense going through accepted
for entry in task.undecided:
force_accept = False
try:
lookup(entry)
except plugin.PluginError as e:
# logs skip message once through log_once (info) and then only when ran from cmd line (w/o --cron)
log_once(
'Skipping {} because of an error: {}'.format(entry['title'], e.value),
logger=logger,
)
continue
# for key, value in entry.iteritems():
# log.debug('%s = %s (type: %s)' % (key, value, type(value)))
# Check defined conditions, TODO: rewrite into functions?
reasons = []
if 'min_score' in config and entry.get('imdb_score', 0) < config['min_score']:
reasons.append(
'min_score ({} < {})'.format(entry.get('imdb_score'), config['min_score'])
)
if 'min_votes' in config and entry.get('imdb_votes', 0) < config['min_votes']:
reasons.append(
'min_votes ({} < {})'.format(entry.get('imdb_votes'), config['min_votes'])
)
if (
'min_meta_score' in config
and entry.get('imdb_meta_score', 0) < config['min_meta_score']
):
reasons.append(
'min_meta_score ({} < {})'.format(
entry.get('imdb_meta_score'), config['min_meta_score']
)
)
if 'min_year' in config and entry.get('imdb_year', 0) < config['min_year']:
reasons.append(
'min_year ({} < {})'.format(entry.get('imdb_year'), config['min_year'])
)
if 'max_year' in config and entry.get('imdb_year', 0) > config['max_year']:
reasons.append(
'max_year ({} > {})'.format(entry.get('imdb_year'), config['max_year'])
)
if 'accept_genres' in config:
accepted = config['accept_genres']
accept_genre = False
for genre in entry.get('imdb_genres', []):
if genre in accepted:
accept_genre = True
break
if not accept_genre:
reasons.append('accept_genres')
if 'reject_genres' in config:
rejected = config['reject_genres']
for genre in entry.get('imdb_genres', []):
if genre in rejected:
reasons.append('reject_genres')
break
if 'reject_languages' in config:
rejected = config['reject_languages']
for language in entry.get('imdb_languages', []):
if language in rejected:
reasons.append('reject_languages')
break
if 'accept_languages' in config:
accepted = config['accept_languages']
if entry.get('imdb_languages') and entry['imdb_languages'][0] not in accepted:
# Reject if the first (primary) language is not among acceptable languages
reasons.append('accept_languages')
if 'reject_actors' in config:
rejected = config['reject_actors']
for actor_id, actor_name in entry.get('imdb_actors', {}).items():
if actor_id in rejected or actor_name in rejected:
reasons.append(f'reject_actors {actor_name}' or actor_id)
break
# Accept if actors contains an accepted actor, but don't reject otherwise
if 'accept_actors' in config:
accepted = config['accept_actors']
for actor_id, actor_name in entry.get('imdb_actors', {}).items():
if actor_id in accepted or actor_name in accepted:
logger.debug(
'Accepting because of accept_actors {}', actor_name or actor_id
)
force_accept = True
break
if 'reject_directors' in config:
rejected = config['reject_directors']
for director_id, director_name in entry.get('imdb_directors', {}).items():
if director_id in rejected or director_name in rejected:
reasons.append(f'reject_directors {director_name}' or director_id)
break
# Accept if the director is in the accept list, but do not reject if the director is unknown
if 'accept_directors' in config:
accepted = config['accept_directors']
for director_id, director_name in entry.get('imdb_directors', {}).items():
if director_id in accepted or director_name in accepted:
logger.debug(
'Accepting because of accept_directors {}',
director_name or director_id,
)
force_accept = True
break
if 'reject_writers' in config:
rejected = config['reject_writers']
for writer_id, writer_name in entry.get('imdb_writers', {}).items():
if writer_id in rejected or writer_name in rejected:
reasons.append(f'reject_writers {writer_name}' or writer_id)
break
# Accept if the writer is in the accept list, but do not reject if the writer is unknown
if 'accept_writers' in config:
accepted = config['accept_writers']
for writer_id, writer_name in entry.get('imdb_writers', {}).items():
if writer_id in accepted or writer_name in accepted:
logger.debug(
'Accepting because of accept_writers {}', writer_name or writer_id
)
force_accept = True
break
if 'reject_mpaa_ratings' in config:
rejected = config['reject_mpaa_ratings']
if entry.get('imdb_mpaa_rating') in rejected:
reasons.append('reject_mpaa_ratings {}'.format(entry['imdb_mpaa_rating']))
if 'accept_mpaa_ratings' in config:
accepted = config['accept_mpaa_ratings']
if entry.get('imdb_mpaa_rating') not in accepted:
reasons.append('accept_mpaa_ratings {}'.format(entry.get('imdb_mpaa_rating')))
if reasons and not force_accept:
msg = "Didn't accept `{}` because of rule(s) {}".format(
entry.get('imdb_name', None) or entry['title'],
', '.join(reasons),
)
if task.options.debug:
logger.debug(msg)
elif task.options.cron:
log_once(msg, logger)
else:
logger.info(msg)
else:
logger.debug('Accepting {}', entry['title'])
entry.accept()
[docs]
@event('plugin.register')
def register_plugin():
plugin.register(FilterImdb, 'imdb', api_ver=2)