mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2024-11-14 17:40:24 -08:00
f05b09f349
Updates rarfile to 3.1 Updates stevedore to 3.5.0 Updates appdirs to 1.4.4 Updates click to 8.1.3 Updates decorator to 5.1.1 Updates dogpile.cache to 1.1.8 Updates pbr to 5.11.0 Updates pysrt to 1.1.2 Updates pytz to 2022.6 Adds importlib-metadata version 3.1.1 Adds typing-extensions version 4.1.1 Adds zipp version 3.11.0
197 lines
6.1 KiB
Python
197 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
import logging
|
|
|
|
from bs4 import BeautifulSoup, FeatureNotFound
|
|
from six.moves.xmlrpc_client import SafeTransport
|
|
|
|
from .. import __short_version__
|
|
from ..video import Episode, Movie
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TimeoutSafeTransport(SafeTransport):
|
|
"""Timeout support for ``xmlrpc.client.SafeTransport``."""
|
|
def __init__(self, timeout, *args, **kwargs):
|
|
SafeTransport.__init__(self, *args, **kwargs)
|
|
self.timeout = timeout
|
|
|
|
def make_connection(self, host):
|
|
c = SafeTransport.make_connection(self, host)
|
|
c.timeout = self.timeout
|
|
|
|
return c
|
|
|
|
|
|
class ParserBeautifulSoup(BeautifulSoup):
|
|
"""A ``bs4.BeautifulSoup`` that picks the first parser available in `parsers`.
|
|
|
|
:param markup: markup for the ``bs4.BeautifulSoup``.
|
|
:param list parsers: parser names, in order of preference.
|
|
|
|
"""
|
|
def __init__(self, markup, parsers, **kwargs):
|
|
# reject features
|
|
if set(parsers).intersection({'fast', 'permissive', 'strict', 'xml', 'html', 'html5'}):
|
|
raise ValueError('Features not allowed, only parser names')
|
|
|
|
# reject some kwargs
|
|
if 'features' in kwargs:
|
|
raise ValueError('Cannot use features kwarg')
|
|
if 'builder' in kwargs:
|
|
raise ValueError('Cannot use builder kwarg')
|
|
|
|
# pick the first parser available
|
|
for parser in parsers:
|
|
try:
|
|
super(ParserBeautifulSoup, self).__init__(markup, parser, **kwargs)
|
|
return
|
|
except FeatureNotFound:
|
|
pass
|
|
|
|
raise FeatureNotFound
|
|
|
|
|
|
class Provider(object):
|
|
"""Base class for providers.
|
|
|
|
If any configuration is possible for the provider, like credentials, it must take place during instantiation.
|
|
|
|
:raise: :class:`~subliminal.exceptions.ConfigurationError` if there is a configuration error
|
|
|
|
"""
|
|
#: Supported set of :class:`~babelfish.language.Language`
|
|
languages = set()
|
|
|
|
#: Supported video types
|
|
video_types = (Episode, Movie)
|
|
|
|
#: Required hash, if any
|
|
required_hash = None
|
|
|
|
#: Subtitle class to use
|
|
subtitle_class = None
|
|
|
|
#: User Agent to use
|
|
user_agent = 'Subliminal/%s' % __short_version__
|
|
|
|
def __enter__(self):
|
|
self.initialize()
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.terminate()
|
|
|
|
def initialize(self):
|
|
"""Initialize the provider.
|
|
|
|
Must be called when starting to work with the provider. This is the place for network initialization
|
|
or login operations.
|
|
|
|
.. note::
|
|
This is called automatically when entering the `with` statement
|
|
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def terminate(self):
|
|
"""Terminate the provider.
|
|
|
|
Must be called when done with the provider. This is the place for network shutdown or logout operations.
|
|
|
|
.. note::
|
|
This is called automatically when exiting the `with` statement
|
|
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def check(cls, video):
|
|
"""Check if the `video` can be processed.
|
|
|
|
The `video` is considered invalid if not an instance of :attr:`video_types` or if the :attr:`required_hash` is
|
|
not present in :attr:`~subliminal.video.Video.hashes` attribute of the `video`.
|
|
|
|
:param video: the video to check.
|
|
:type video: :class:`~subliminal.video.Video`
|
|
:return: `True` if the `video` is valid, `False` otherwise.
|
|
:rtype: bool
|
|
|
|
"""
|
|
if not cls.check_types(video):
|
|
return False
|
|
if cls.required_hash is not None and cls.required_hash not in video.hashes:
|
|
return False
|
|
|
|
return True
|
|
|
|
@classmethod
|
|
def check_types(cls, video):
|
|
"""Check if the `video` type is supported by the provider.
|
|
|
|
The `video` is considered invalid if not an instance of :attr:`video_types`.
|
|
|
|
:param video: the video to check.
|
|
:type video: :class:`~subliminal.video.Video`
|
|
:return: `True` if the `video` is valid, `False` otherwise.
|
|
:rtype: bool
|
|
|
|
"""
|
|
return isinstance(video, cls.video_types)
|
|
|
|
@classmethod
|
|
def check_languages(cls, languages):
|
|
"""Check if the `languages` are supported by the provider.
|
|
|
|
A subset of the supported languages is returned.
|
|
|
|
:param languages: the languages to check.
|
|
:type languages: set of :class:`~babelfish.language.Language`
|
|
:return: subset of the supported languages.
|
|
:rtype: set of :class:`~babelfish.language.Language`
|
|
|
|
"""
|
|
return cls.languages & languages
|
|
|
|
def query(self, *args, **kwargs):
|
|
"""Query the provider for subtitles.
|
|
|
|
Arguments should match as much as possible the actual parameters for querying the provider
|
|
|
|
:return: found subtitles.
|
|
:rtype: list of :class:`~subliminal.subtitle.Subtitle`
|
|
:raise: :class:`~subliminal.exceptions.ProviderError`
|
|
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def list_subtitles(self, video, languages):
|
|
"""List subtitles for the `video` with the given `languages`.
|
|
|
|
This will call the :meth:`query` method internally. The parameters passed to the :meth:`query` method may
|
|
vary depending on the amount of information available in the `video`.
|
|
|
|
:param video: video to list subtitles for.
|
|
:type video: :class:`~subliminal.video.Video`
|
|
:param languages: languages to search for.
|
|
:type languages: set of :class:`~babelfish.language.Language`
|
|
:return: found subtitles.
|
|
:rtype: list of :class:`~subliminal.subtitle.Subtitle`
|
|
:raise: :class:`~subliminal.exceptions.ProviderError`
|
|
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def download_subtitle(self, subtitle):
|
|
"""Download `subtitle`'s :attr:`~subliminal.subtitle.Subtitle.content`.
|
|
|
|
:param subtitle: subtitle to download.
|
|
:type subtitle: :class:`~subliminal.subtitle.Subtitle`
|
|
:raise: :class:`~subliminal.exceptions.ProviderError`
|
|
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def __repr__(self):
|
|
return '<%s [%r]>' % (self.__class__.__name__, self.video_types)
|