# coding=utf-8 from __future__ import absolute_import import functools import importlib import os import logging import subliminal from subliminal.providers import Provider as _Provider from subliminal.subtitle import Subtitle as _Subtitle from subliminal_patch.extensions import provider_registry from subliminal_patch.http import RetryingSession from subliminal_patch.subtitle import Subtitle, guess_matches from subzero.lib.io import get_viable_encoding import six logger = logging.getLogger(__name__) class Provider(_Provider): hash_verifiable = False hearing_impaired_verifiable = False skip_wrong_fps = True def ping(self): """Check if the provider is alive.""" return True def reinitialize_on_error(exceptions: tuple, attempts=1): """Method decorator for Provider class. It will reinitialize the instance and re-run the method in case of exceptions. :param exceptions: tuple of expected exceptions :param attempts: number of attempts to call the method """ def real_decorator(method): @functools.wraps(method) def wrapper(self, *args, **kwargs): inc = 1 while True: try: return method(self, *args, **kwargs) except exceptions as error: if inc > attempts: raise logger.exception(error) logger.debug("Reinitializing %s instance (%s attempt)", self, inc) self.terminate() self.initialize() inc += 1 return wrapper return real_decorator # register providers # fixme: this is bad for name in os.listdir(os.path.dirname(__file__)): if name in ("__init__.py", "mixins.py", "utils.py") or not name.endswith(".py"): continue module_name = os.path.splitext(name)[0] mod = importlib.import_module("subliminal_patch.providers.%s" % module_name.lower()) for item in dir(mod): cls = getattr(mod, item) if item != "Provider" and item.endswith("Provider") and not item.startswith("_"): is_sz_provider = issubclass(cls, Provider) is_provider = issubclass(cls, _Provider) if not is_provider: continue if not is_sz_provider: # patch provider bases new_bases = [] for base in cls.__bases__: if base == _Provider: base = Provider else: if _Provider in base.__bases__: base.__bases__ = (Provider,) new_bases.append(base) cls.__bases__ = tuple(new_bases) # patch subtitle bases new_bases = [] for base in cls.subtitle_class.__bases__: if base == _Subtitle: base = Subtitle else: if _Subtitle in base.__bases__: base.__bases__ = (Subtitle,) new_bases.append(base) cls.subtitle_class.__bases__ = tuple(new_bases) # inject our requests.Session wrapper for automatic retry mod.Session = RetryingSession mod.guess_matches = guess_matches provider_registry.register(module_name, cls) # try patching the correspondent subliminal provider try: subliminal_mod = importlib.import_module("subliminal.providers.%s" % module_name.lower()) except ImportError: pass else: subliminal_mod.Session = RetryingSession subliminal_mod.guess_matches = guess_matches