mirror of https://github.com/morpheus65535/bazarr
Implemented some utility functions to subliminal_patch providers to list supported languages and video types.
This commit is contained in:
parent
f8282efeb6
commit
b53f8ad80a
|
@ -21,6 +21,7 @@ from bs4 import UnicodeDammit
|
|||
from babelfish import LanguageReverseError
|
||||
from guessit.jsonutils import GuessitEncoder
|
||||
from subliminal import ProviderError, refiner_manager
|
||||
from concurrent.futures import as_completed
|
||||
|
||||
from .extensions import provider_registry
|
||||
from subliminal.exceptions import ServiceUnavailable, DownloadLimitExceeded
|
||||
|
@ -427,6 +428,58 @@ class SZProviderPool(ProviderPool):
|
|||
|
||||
return downloaded_subtitles
|
||||
|
||||
def list_supported_languages(self):
|
||||
"""List supported languages.
|
||||
|
||||
:return: languages supported by the providers.
|
||||
:rtype: list of dicts
|
||||
|
||||
"""
|
||||
languages = []
|
||||
|
||||
for name in self.providers:
|
||||
# list supported languages for a single provider
|
||||
try:
|
||||
provider_languages = self[name].languages
|
||||
except AttributeError:
|
||||
logger.exception(f"{name} provider doesn't have a languages attribute")
|
||||
continue
|
||||
|
||||
if provider_languages is None:
|
||||
logger.info(f"Skipping provider {name} because it doesn't support any languages.")
|
||||
continue
|
||||
|
||||
# add the languages for this provider
|
||||
languages.append({'provider': name, 'languages': provider_languages})
|
||||
|
||||
return languages
|
||||
|
||||
def list_supported_video_types(self):
|
||||
"""List supported video types.
|
||||
|
||||
:return: video types supported by the providers.
|
||||
:rtype: tuple of video types
|
||||
|
||||
"""
|
||||
video_types = []
|
||||
|
||||
for name in self.providers:
|
||||
# list supported video types for a single provider
|
||||
try:
|
||||
provider_video_type = self[name].video_types
|
||||
except AttributeError:
|
||||
logger.exception(f"{name} provider doesn't have a video_types method")
|
||||
continue
|
||||
|
||||
if provider_video_type is None:
|
||||
logger.info(f"Skipping provider {name} because it doesn't support any video type.")
|
||||
continue
|
||||
|
||||
# add the video types for this provider
|
||||
video_types.append({'provider': name, 'video_types': provider_video_type})
|
||||
|
||||
return video_types
|
||||
|
||||
|
||||
class SZAsyncProviderPool(SZProviderPool):
|
||||
"""Subclass of :class:`ProviderPool` with asynchronous support for :meth:`~ProviderPool.list_subtitles`.
|
||||
|
@ -474,6 +527,65 @@ class SZAsyncProviderPool(SZProviderPool):
|
|||
|
||||
return subtitles
|
||||
|
||||
def list_supported_languages(self):
|
||||
"""List supported languages asynchronously.
|
||||
|
||||
:return: languages supported by the providers.
|
||||
:rtype: list of dicts
|
||||
|
||||
"""
|
||||
languages = []
|
||||
|
||||
def get_providers_languages(provider_name):
|
||||
provider_languages = None
|
||||
try:
|
||||
provider_languages = {'provider': provider_name, 'languages': self[provider_name].languages}
|
||||
except AttributeError:
|
||||
logger.exception(f"{provider_name} provider doesn't have a languages attribute")
|
||||
|
||||
return provider_languages
|
||||
|
||||
with ThreadPoolExecutor(self.max_workers) as executor:
|
||||
for future in as_completed([executor.submit(get_providers_languages, x) for x in self.providers]):
|
||||
provider_languages = future.result()
|
||||
if provider_languages is None:
|
||||
continue
|
||||
|
||||
# add the languages for this provider
|
||||
languages.append(provider_languages)
|
||||
|
||||
return languages
|
||||
|
||||
def list_supported_video_types(self):
|
||||
"""List supported video types asynchronously.
|
||||
|
||||
:return: video types supported by the providers.
|
||||
:rtype: tuple of video types
|
||||
|
||||
"""
|
||||
video_types = []
|
||||
|
||||
def get_providers_video_types(provider_name):
|
||||
provider_video_types = None
|
||||
try:
|
||||
provider_video_types = {'provider': provider_name,
|
||||
'video_types': self[provider_name].video_types}
|
||||
except AttributeError:
|
||||
logger.exception(f"{provider_name} provider doesn't have a video_types attribute")
|
||||
|
||||
return provider_video_types
|
||||
|
||||
with ThreadPoolExecutor(self.max_workers) as executor:
|
||||
for future in as_completed([executor.submit(get_providers_video_types, x) for x in self.providers]):
|
||||
provider_video_types = future.result()
|
||||
if provider_video_types is None:
|
||||
continue
|
||||
|
||||
# add the languages for this provider
|
||||
video_types.append(provider_video_types)
|
||||
|
||||
return video_types
|
||||
|
||||
|
||||
if is_windows_special_path:
|
||||
SZAsyncProviderPool = SZProviderPool
|
||||
|
@ -758,6 +870,16 @@ def list_all_subtitles(videos, languages, **kwargs):
|
|||
return listed_subtitles
|
||||
|
||||
|
||||
def list_supported_languages(pool_class, **kwargs):
|
||||
with pool_class(**kwargs) as pool:
|
||||
return pool.list_supported_languages()
|
||||
|
||||
|
||||
def list_supported_video_types(pool_class, **kwargs):
|
||||
with pool_class(**kwargs) as pool:
|
||||
return pool.list_supported_video_types()
|
||||
|
||||
|
||||
def download_subtitles(subtitles, pool_class=ProviderPool, **kwargs):
|
||||
"""Download :attr:`~subliminal.subtitle.Subtitle.content` of `subtitles`.
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ class AssrtSubtitle(Subtitle):
|
|||
class AssrtProvider(Provider):
|
||||
"""Assrt Provider."""
|
||||
languages = {Language(*l) for l in supported_languages}
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def __init__(self, token=None):
|
||||
if not token:
|
||||
|
|
|
@ -72,6 +72,7 @@ class BSPlayerProvider(Provider):
|
|||
'ara', 'bul', 'ces', 'dan', 'deu', 'ell', 'eng', 'fin', 'fra', 'hun', 'ita', 'jpn', 'kor', 'nld', 'pol', 'por',
|
||||
'ron', 'rus', 'spa', 'swe', 'tur', 'ukr', 'zho'
|
||||
]}
|
||||
video_types = (Episode, Movie)
|
||||
SEARCH_THROTTLE = 8
|
||||
hash_verifiable = True
|
||||
# fmt: on
|
||||
|
|
|
@ -54,6 +54,7 @@ class GreekSubsSubtitle(Subtitle):
|
|||
class GreekSubsProvider(Provider):
|
||||
"""GreekSubs Provider."""
|
||||
languages = {Language('ell')}
|
||||
video_types = (Episode, Movie)
|
||||
server_url = 'https://greeksubs.net/'
|
||||
subtitle_class = GreekSubsSubtitle
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ class GreekSubtitlesSubtitle(Subtitle):
|
|||
class GreekSubtitlesProvider(Provider):
|
||||
"""GreekSubtitles Provider."""
|
||||
languages = {Language(l) for l in ['ell', 'eng']}
|
||||
video_types = (Episode, Movie)
|
||||
server_url = 'http://gr.greek-subtitles.com/'
|
||||
search_url = 'search.php?name={}'
|
||||
download_url = 'http://www.greeksubtitles.info/getp.php?id={:d}'
|
||||
|
|
|
@ -110,6 +110,7 @@ class KtuvitProvider(Provider):
|
|||
"""Ktuvit Provider."""
|
||||
|
||||
languages = {Language(l) for l in ["heb"]}
|
||||
video_types = (Episode, Movie)
|
||||
server_url = "https://www.ktuvit.me/"
|
||||
sign_in_url = "Services/MembershipService.svc/Login"
|
||||
search_url = "Services/ContentProvider.svc/SearchPage_search"
|
||||
|
|
|
@ -121,6 +121,7 @@ class LegendasdivxSubtitle(Subtitle):
|
|||
class LegendasdivxProvider(Provider):
|
||||
"""Legendasdivx Provider."""
|
||||
languages = {Language('por', 'BR')} | {Language('por')}
|
||||
video_types = (Episode, Movie)
|
||||
SEARCH_THROTTLE = 8
|
||||
site = 'https://www.legendasdivx.pt'
|
||||
headers = {
|
||||
|
|
|
@ -68,6 +68,7 @@ class LegendasTVSubtitle(_LegendasTVSubtitle):
|
|||
|
||||
class LegendasTVProvider(_LegendasTVProvider):
|
||||
languages = {Language(*l) for l in language_converters['legendastv'].to_legendastv.keys()}
|
||||
video_types = (Episode, Movie)
|
||||
subtitle_class = LegendasTVSubtitle
|
||||
|
||||
def __init__(self, username=None, password=None, featured_only=False):
|
||||
|
|
|
@ -5,6 +5,7 @@ import logging
|
|||
from subliminal.providers.napiprojekt import NapiProjektProvider as _NapiProjektProvider, \
|
||||
NapiProjektSubtitle as _NapiProjektSubtitle, get_subhash
|
||||
from subzero.language import Language
|
||||
from subliminal.video import Episode, Movie
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -21,6 +22,7 @@ class NapiProjektSubtitle(_NapiProjektSubtitle):
|
|||
|
||||
class NapiProjektProvider(_NapiProjektProvider):
|
||||
languages = {Language.fromalpha2(l) for l in ['pl']}
|
||||
video_types = (Episode, Movie)
|
||||
subtitle_class = NapiProjektSubtitle
|
||||
|
||||
def query(self, language, hash):
|
||||
|
|
|
@ -12,6 +12,7 @@ from subliminal import __short_version__
|
|||
from subliminal.exceptions import AuthenticationError, ConfigurationError
|
||||
from subliminal.subtitle import fix_line_ending
|
||||
from subzero.language import Language
|
||||
from subliminal.video import Episode, Movie
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -47,6 +48,7 @@ class Napisy24Subtitle(Subtitle):
|
|||
class Napisy24Provider(Provider):
|
||||
'''Napisy24 Provider.'''
|
||||
languages = {Language(l) for l in ['pol']}
|
||||
video_types = (Episode, Movie)
|
||||
required_hash = 'napisy24'
|
||||
api_url = 'http://napisy24.pl/run/CheckSubAgent.php'
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ class NekurProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
"""Nekur Provider."""
|
||||
subtitle_class = NekurSubtitle
|
||||
languages = {Language('lva', 'LV')} | {Language.fromalpha2(l) for l in ['lv']}
|
||||
video_types = (Movie,)
|
||||
server_url = 'http://subtitri.nekur.net/'
|
||||
search_url = server_url + 'modules/Subtitles.php'
|
||||
|
||||
|
|
|
@ -140,6 +140,8 @@ class OpenSubtitlesProvider(ProviderRetryMixin, _OpenSubtitlesProvider):
|
|||
languages.update(set(Language.rebuild(l, forced=True) for l in languages))
|
||||
languages.update(set(Language.rebuild(l, hi=True) for l in languages))
|
||||
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def __init__(self, username=None, password=None, use_tag_search=False, only_foreign=False, also_foreign=False,
|
||||
skip_wrong_fps=True, is_vip=False, use_ssl=True, timeout=15):
|
||||
if any((username, password)) and not all((username, password)):
|
||||
|
|
|
@ -126,6 +126,8 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider):
|
|||
languages = {Language.fromopensubtitles(lang) for lang in language_converters['szopensubtitles'].codes}
|
||||
languages.update(set(Language.rebuild(lang, forced=True) for lang in languages))
|
||||
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def __init__(self, username=None, password=None, use_hash=True, api_key=None):
|
||||
if not all((username, password)):
|
||||
raise ConfigurationError('Username and password must be specified')
|
||||
|
|
|
@ -27,8 +27,7 @@ except ImportError:
|
|||
except ImportError:
|
||||
import xml.etree.ElementTree as etree
|
||||
from babelfish import language_converters
|
||||
from subliminal import Episode
|
||||
from subliminal import Movie
|
||||
from subliminal.video import Episode, Movie
|
||||
from subliminal.providers.podnapisi import PodnapisiProvider as _PodnapisiProvider, \
|
||||
PodnapisiSubtitle as _PodnapisiSubtitle
|
||||
from subliminal_patch.utils import sanitize, fix_inconsistent_naming as _fix_inconsistent_naming
|
||||
|
@ -130,6 +129,8 @@ class PodnapisiProvider(_PodnapisiProvider, ProviderSubtitleArchiveMixin):
|
|||
languages.update(set(Language.rebuild(l, forced=True) for l in languages))
|
||||
languages.update(set(Language.rebuild(l, hi=True) for l in languages))
|
||||
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
server_url = 'https://podnapisi.net/subtitles/'
|
||||
only_foreign = False
|
||||
also_foreign = False
|
||||
|
|
|
@ -65,6 +65,7 @@ class RegieLiveProvider(Provider):
|
|||
"""RegieLive Provider."""
|
||||
languages = {Language(l) for l in ['ron']}
|
||||
language = list(languages)[0]
|
||||
video_types = (Episode, Movie)
|
||||
SEARCH_THROTTLE = 8
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from __future__ import absolute_import
|
||||
from subliminal.providers.shooter import ShooterProvider as _ShooterProvider, ShooterSubtitle as _ShooterSubtitle
|
||||
from subliminal.video import Episode, Movie
|
||||
|
||||
|
||||
class ShooterSubtitle(_ShooterSubtitle):
|
||||
|
@ -13,4 +14,4 @@ class ShooterSubtitle(_ShooterSubtitle):
|
|||
|
||||
class ShooterProvider(_ShooterProvider):
|
||||
subtitle_class = ShooterSubtitle
|
||||
|
||||
video_types = (Episode, Movie)
|
||||
|
|
|
@ -102,6 +102,7 @@ class SoustitreseuProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
"""Sous-Titres.eu Provider."""
|
||||
subtitle_class = SoustitreseuSubtitle
|
||||
languages = {Language(l) for l in ['fra', 'eng']}
|
||||
video_types = (Episode, Movie)
|
||||
server_url = 'https://www.sous-titres.eu/'
|
||||
search_url = server_url + 'search.html'
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ class SubdivxSubtitlesProvider(Provider):
|
|||
provider_name = "subdivx"
|
||||
hash_verifiable = False
|
||||
languages = {Language("spa", "MX")} | {Language.fromalpha2("es")}
|
||||
video_types = (Episode, Movie)
|
||||
subtitle_class = SubdivxSubtitle
|
||||
|
||||
server_url = "https://www.subdivx.com/"
|
||||
|
|
|
@ -21,6 +21,7 @@ from babelfish import language_converters
|
|||
from guessit import guessit
|
||||
from dogpile.cache.api import NO_VALUE
|
||||
from subliminal import Episode, ProviderError
|
||||
from subliminal.video import Episode, Movie
|
||||
from subliminal.exceptions import ConfigurationError, ServiceUnavailable
|
||||
from subliminal.utils import sanitize_release_group
|
||||
from subliminal.cache import region
|
||||
|
@ -124,7 +125,7 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
languages = supported_languages
|
||||
languages.update(set(Language.rebuild(l, forced=True) for l in languages))
|
||||
languages.update(set(Language.rebuild(l, hi=True) for l in languages))
|
||||
|
||||
video_types = (Episode, Movie)
|
||||
session = None
|
||||
skip_wrong_fps = False
|
||||
hearing_impaired_verifiable = True
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from guessit import guessit
|
||||
from subliminal.video import Episode
|
||||
from subliminal.video import Episode, Movie
|
||||
from subliminal.providers.subscenter import SubsCenterProvider as _SubsCenterProvider, \
|
||||
SubsCenterSubtitle as _SubsCenterSubtitle
|
||||
from subzero.language import Language
|
||||
|
@ -37,7 +37,7 @@ class SubsCenterSubtitle(_SubsCenterSubtitle):
|
|||
|
||||
class SubsCenterProvider(_SubsCenterProvider):
|
||||
languages = {Language.fromalpha2(l) for l in ['he']}
|
||||
video_types = (Episode, Movie)
|
||||
subtitle_class = SubsCenterSubtitle
|
||||
hearing_impaired_verifiable = True
|
||||
server_url = 'http://www.subscenter.info/he/'
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ class SubsSabBzProvider(Provider):
|
|||
languages = {Language(l) for l in [
|
||||
'bul', 'eng'
|
||||
]}
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def initialize(self):
|
||||
self.session = Session()
|
||||
|
|
|
@ -120,6 +120,7 @@ class SubsUnacsProvider(Provider):
|
|||
languages = {Language(l) for l in [
|
||||
'bul', 'eng'
|
||||
]}
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def initialize(self):
|
||||
self.session = Session()
|
||||
|
|
|
@ -124,6 +124,7 @@ class SubtitrarinoiProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
subtitle_class = SubtitrarinoiSubtitle
|
||||
languages = {Language(lang) for lang in ['ron']}
|
||||
languages.update(set(Language.rebuild(lang, forced=True) for lang in languages))
|
||||
video_types = (Episode, Movie)
|
||||
server_url = 'https://www.subtitrari-noi.ro/'
|
||||
api_url = server_url + 'paginare_filme.php'
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ class SubtitriIdProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
"""subtitri.id.lv Provider."""
|
||||
subtitle_class = SubtitriIdSubtitle
|
||||
languages = {Language('lva', 'LV')} | {Language.fromalpha2(l) for l in ['lv']}
|
||||
video_types = (Movie,)
|
||||
server_url = 'http://subtitri.id.lv'
|
||||
search_url = server_url + '/search/'
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ class TitloviSubtitle(Subtitle):
|
|||
class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
|
||||
subtitle_class = TitloviSubtitle
|
||||
languages = {Language.fromtitlovi(l) for l in language_converters['titlovi'].codes} | {Language.fromietf('sr-Latn')}
|
||||
video_types = (Episode, Movie)
|
||||
api_url = 'https://kodi.titlovi.com/api/subtitles'
|
||||
api_gettoken_url = api_url + '/gettoken'
|
||||
api_search_url = api_url + '/search'
|
||||
|
|
|
@ -125,6 +125,7 @@ class TitrariProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
subtitle_class = TitrariSubtitle
|
||||
languages = {Language(lang) for lang in ['ron', 'eng']}
|
||||
languages.update(set(Language.rebuild(lang, forced=True) for lang in languages))
|
||||
video_types = (Episode, Movie)
|
||||
api_url = 'https://www.titrari.ro/'
|
||||
query_advanced_search = 'cautarepreaavansata'
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ class TitulkyProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
"""Titulky.com provider"""
|
||||
|
||||
languages = {Language(l) for l in ['ces', 'slk']}
|
||||
video_types = (Episode, Movie)
|
||||
hash_verifiable = False
|
||||
hearing_impaired_verifiable = False
|
||||
|
||||
|
@ -203,7 +204,7 @@ class TitulkyProvider(Provider, ProviderSubtitleArchiveMixin):
|
|||
def terminate(self):
|
||||
self.logout()
|
||||
self.session.close()
|
||||
|
||||
|
||||
def login(self):
|
||||
logger.info("Titulky.com: Logging in")
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ from subliminal.cache import SHOW_EXPIRATION_TIME, region, EPISODE_EXPIRATION_TI
|
|||
from subliminal.providers.tvsubtitles import TVsubtitlesProvider as _TVsubtitlesProvider, \
|
||||
TVsubtitlesSubtitle as _TVsubtitlesSubtitle, link_re, episode_id_re
|
||||
from subliminal.utils import sanitize
|
||||
from subliminal.video import Episode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -26,6 +27,7 @@ class TVsubtitlesProvider(_TVsubtitlesProvider):
|
|||
'ara', 'bul', 'ces', 'dan', 'deu', 'ell', 'eng', 'fin', 'fra', 'hun', 'ita', 'jpn', 'kor', 'nld', 'pol', 'por',
|
||||
'ron', 'rus', 'spa', 'swe', 'tur', 'ukr', 'zho'
|
||||
]}
|
||||
video_types = (Episode,)
|
||||
subtitle_class = TVsubtitlesSubtitle
|
||||
|
||||
@region.cache_on_arguments(expiration_time=SHOW_EXPIRATION_TIME)
|
||||
|
|
|
@ -79,6 +79,7 @@ class WizdomSubtitle(Subtitle):
|
|||
class WizdomProvider(Provider):
|
||||
"""Wizdom Provider."""
|
||||
languages = {Language(l) for l in ['heb']}
|
||||
video_types = (Episode, Movie)
|
||||
server_url = 'wizdom.xyz'
|
||||
|
||||
_tmdb_api_key = 'a51ee051bcd762543373903de296e0a3'
|
||||
|
|
|
@ -102,6 +102,7 @@ class YavkaNetProvider(Provider):
|
|||
languages = {Language(l) for l in [
|
||||
'bul', 'eng', 'rus', 'spa', 'ita'
|
||||
]}
|
||||
video_types = (Episode, Movie)
|
||||
|
||||
def initialize(self):
|
||||
self.session = Session()
|
||||
|
|
|
@ -84,6 +84,7 @@ class ZimukuProvider(Provider):
|
|||
"""Zimuku Provider."""
|
||||
|
||||
languages = {Language(*l) for l in supported_languages}
|
||||
video_types = (Episode, Movie)
|
||||
logger.info(str(supported_languages))
|
||||
|
||||
server_url = "http://zimuku.org"
|
||||
|
|
Loading…
Reference in New Issue