from __future__ import unicode_literals, division, absolute_import import os import re import logging from flexget import plugin from flexget.event import event from flexget.config_schema import one_or_more from flexget.plugin import get_plugin_by_name from flexget.utils.tools import TimedDict log = logging.getLogger('my_exists_movie') class FilterExistsMovie(object): """ Reject existing movies. Example:: exists_movie: /storage/movies/ """ schema = { 'anyOf': [ one_or_more({'type': 'string', 'format': 'path'}), { 'type': 'object', 'properties': { 'path': one_or_more({'type': 'string', 'format': 'path'}), 'allow_different_qualities': {'enum': ['better', True, False], 'default': False}, 'type': {'enum': ['files', 'dirs'], 'default': 'files'} }, 'required': ['path'], 'additionalProperties': False } ] } def __init__(self): self.cache = TimedDict(cache_time='1 hour') def prepare_config(self, config): # if config is not a dict, assign value to 'path' key if not isinstance(config, dict): config = {'path': config} # if only a single path is passed turn it into a 1 element list if isinstance(config['path'], basestring): config['path'] = [config['path']] return config @plugin.priority(-1) def on_task_filter(self, task, config): # if not task.accepted: # log.debug('nothing accepted, aborting') # return config = self.prepare_config(config) imdb_lookup = plugin.get_plugin_by_name('imdb_lookup').instance incompatible_files = 0 incompatible_entries = 0 count_entries = 0 count_files = 0 # list of imdb ids gathered from paths / cache qualities = {} for folder in config['path']: folder = os.path.expanduser(folder) # see if this path has already been scanned if folder in self.cache: log.verbose('Using cached scan for %s ...' % folder) qualities.update(self.cache[folder]) continue path_ids = {} if not os.path.isdir(folder): log.critical('Path %s does not exist' % folder) continue log.verbose('Scanning path %s ...' % folder) # Help debugging by removing a lot of noise #logging.getLogger('movieparser').setLevel(logging.WARNING) #logging.getLogger('imdb_lookup').setLevel(logging.WARNING) # scan through for root, dirs, files in os.walk(folder): for item in eval(config['type']): log.debug("item: %s" % item) pattern = re.compile(".*\.(avi|mkv|mp4|mpg|webm)") if not re.search(pattern, item): continue count_files += 1 movie = get_plugin_by_name('parsing').instance.parse_movie(item) try: imdb_id = imdb_lookup.imdb_id_lookup(movie_title=movie.name, raw_title=item, session=task.session) if imdb_id in path_ids: log.trace('duplicate %s' % item) continue if imdb_id is not None: log.trace('adding: %s' % imdb_id) path_ids[imdb_id] = movie.quality except plugin.PluginError as e: log.trace('%s lookup failed (%s)' % (item, e.value)) incompatible_files += 1 # store to cache and extend to found list self.cache[folder] = path_ids qualities.update(path_ids) log.debug('qualities: %s' % qualities) log.debug('-- Start filtering entries ----------------------------------') # do actual filtering for entry in task.accepted: count_entries += 1 if not entry.get('imdb_id', eval_lazy=False): try: imdb_lookup.lookup(entry) except plugin.PluginError as e: log.trace('entry %s imdb failed (%s)' % (entry['title'], e.value)) incompatible_entries += 1 continue entry.trace("msg") # actual filtering if entry['imdb_id'] in qualities: if config.get('allow_different_qualities') == 'better': if entry['quality'] > qualities[entry['imdb_id']]: log.trace('better quality') continue elif config.get('allow_different_qualities'): if entry['quality'] != qualities[entry['imdb_id']]: log.trace('wrong quality') continue entry.reject('movie exists') if incompatible_files or incompatible_entries: log.verbose('There were some incompatible items. %s of %s entries ' 'and %s of %s directories could not be verified.' % (incompatible_entries, count_entries, incompatible_files, count_dirs)) log.debug('-- Finished filtering entries -------------------------------') @event('plugin.register') def register_plugin(): plugin.register(FilterExistsMovie, 'my_exists_movie', groups=['exists'], api_ver=2)