diff --git a/README.md b/README.md index a847be2b8..f37589825 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,20 @@ If you need something that is not already part of Bazarr, feel free to create a * Manual search so you can download subtitles on demand * Upgrade subtitles previously downloaded when a better one is found * Ability to delete external subtitles from disk -* Currently support 184 subtitles languages +* Currently support 184 subtitles languages with support for forced/foreign subtitles (depending of providers) * And a beautiful UI based on Sonarr ## Supported subtitles providers: * Addic7ed * Argenteam * Assrt +* BetaSeries * GreekSubtitles * Hosszupuska * LegendasTV * Napiprojekt * Napisy24 +* Nekur * OpenSubtitles * Podnapisi * Subdivx diff --git a/bazarr/config.py b/bazarr/config.py index 0b823f5f0..4817cb65f 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -120,6 +120,9 @@ defaults = { 'subscene': { 'username': '', 'password': '' + }, + 'betaseries': { + 'token': '' } } diff --git a/bazarr/get_providers.py b/bazarr/get_providers.py index 93d3faec0..8a033be49 100644 --- a/bazarr/get_providers.py +++ b/bazarr/get_providers.py @@ -113,7 +113,8 @@ def get_providers_auth(): 'assrt': {'token': settings.assrt.token, }, 'napisy24': {'username': settings.napisy24.username, 'password': settings.napisy24.password, - } + }, + 'betaseries': {'token': settings.betaseries.token} } return providers_auth diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py index 564672db5..08a33c6be 100644 --- a/bazarr/get_subtitle.py +++ b/bazarr/get_subtitle.py @@ -67,8 +67,8 @@ def get_video(path, title, sceneName, use_scenename, use_mediainfo, providers=No video.original_path = original_path refine_from_db(original_path, video) - #if use_mediainfo: - # refine_from_mediainfo(original_path, video) + if use_mediainfo: + refine_from_mediainfo(original_path, video) logging.debug('BAZARR is using those video object properties: %s', vars(video)) return video diff --git a/bazarr/main.py b/bazarr/main.py index f112acf1e..8a03423eb 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -397,6 +397,7 @@ def save_wizard(): settings.napisy24.password = request.forms.get('settings_napisy24_password') settings.subscene.username = request.forms.get('settings_subscene_username') settings.subscene.password = request.forms.get('settings_subscene_password') + settings.betaseries.token = request.forms.get('settings_betaseries_token') settings_subliminal_languages = request.forms.getall('settings_subliminal_languages') c.execute("UPDATE table_settings_languages SET enabled = 0") @@ -1536,7 +1537,8 @@ def save_settings(): settings.napisy24.password = request.forms.get('settings_napisy24_password') settings.subscene.username = request.forms.get('settings_subscene_username') settings.subscene.password = request.forms.get('settings_subscene_password') - + settings.betaseries.token = request.forms.get('settings_betaseries_token') + settings_subliminal_languages = request.forms.getall('settings_subliminal_languages') c.execute("UPDATE table_settings_languages SET enabled = 0") for item in settings_subliminal_languages: diff --git a/bin/Linux/aarch64/MediaInfo/mediainfo b/bin/Linux/aarch64/MediaInfo/mediainfo deleted file mode 100644 index 60308384d..000000000 Binary files a/bin/Linux/aarch64/MediaInfo/mediainfo and /dev/null differ diff --git a/bin/Linux/armv7l/MediaInfo/mediainfo b/bin/Linux/armv7l/MediaInfo/mediainfo deleted file mode 100644 index 2cacc30a2..000000000 Binary files a/bin/Linux/armv7l/MediaInfo/mediainfo and /dev/null differ diff --git a/bin/Linux/i386/MediaInfo/mediainfo b/bin/Linux/i386/MediaInfo/mediainfo deleted file mode 100644 index e72e00188..000000000 Binary files a/bin/Linux/i386/MediaInfo/mediainfo and /dev/null differ diff --git a/bin/Linux/x86_64/MediaInfo/mediainfo b/bin/Linux/x86_64/MediaInfo/mediainfo deleted file mode 100644 index f10405957..000000000 Binary files a/bin/Linux/x86_64/MediaInfo/mediainfo and /dev/null differ diff --git a/libs/subliminal_patch/providers/betaseries.py b/libs/subliminal_patch/providers/betaseries.py new file mode 100644 index 000000000..4452e614b --- /dev/null +++ b/libs/subliminal_patch/providers/betaseries.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +import json +import logging +import os +import re +import io +import rarfile +import zipfile + +from babelfish import language_converters +from guessit import guessit +from requests import Session +from subzero.language import Language + +from subliminal import Movie, Episode, ProviderError, __short_version__ +from subliminal.exceptions import AuthenticationError, ConfigurationError, DownloadLimitExceeded, ProviderError +from subliminal_patch.subtitle import Subtitle, guess_matches +from subliminal.subtitle import fix_line_ending, SUBTITLE_EXTENSIONS +from subliminal_patch.providers import Provider +from subzero.language import Language + +logger = logging.getLogger(__name__) + +server_url = 'https://api.betaseries.com/' + + +class BetaSeriesSubtitle(Subtitle): + provider_name = 'betaseries' + + def __init__(self, subtitle_id, language, video_name, url, matches, source): + super(BetaSeriesSubtitle, self).__init__(language, page_link=url) + self.subtitle_id = subtitle_id + self.video_name = video_name + self.download_url = url + self.matches = matches + self.source = source + + @property + def id(self): + return self.subtitle_id + + @property + def download_link(self): + return self.download_url + + def get_matches(self, video): + matches = self.matches + + if isinstance(video, Episode): + matches |= guess_matches(video, guessit( + self.video_name, {'type': 'episode'}), partial=True) + + return matches + + +class BetaSeriesProvider(Provider): + """BetaSeries Provider""" + languages = {Language(l) for l in ['fra', 'eng']} + video_types = (Episode,) + + def __init__(self, token=None): + if not token: + raise ConfigurationError('Token must be specified') + self.token = token + + def initialize(self): + self.session = Session() + self.session.headers = { + 'User-Agent': os.environ.get("SZ_USER_AGENT", "Sub-Zero/2")} + + def terminate(self): + self.session.close() + + def query(self, languages, video): + # query the server + result = None + matches = set() + if video.tvdb_id: + params = {'key': self.token, + 'thetvdb_id': video.tvdb_id, + 'v': 3.0, + 'subtitles': 1} + logger.debug('Searching subtitles %r', params) + res = self.session.get( + server_url + 'episodes/display', params=params, timeout=10) + res.raise_for_status() + result = res.json() + matches.add('tvdb_id') + elif video.series_tvdb_id: + params = {'key': self.token, + 'thetvdb_id': video.series_tvdb_id, + 'season': video.season, + 'episode': video.episode, + 'subtitles': 1, + 'v': 3.0} + logger.debug('Searching subtitles %r', params) + res = self.session.get( + server_url + 'shows/episodes', params=params, timeout=10) + res.raise_for_status() + result = res.json() + matches.add('series_tvdb_id') + else: + logger.debug( + 'The show has no tvdb_id and series_tvdb_id: the search can\'t be done') + return [] + + if result['errors'] != []: + logger.debug('Status error: %r', result['errors']) + return [] + + # parse the subtitles + subtitles = [] + if 'episode' in result: + subs = result['episode']['subtitles'] + elif 'episodes' in result: + subs = result['episodes'][0]['subtitles'] + else: + return [] + + for sub in subs: + language = _translateLanguageCodeToLanguage(sub['language']) + if language in languages: + # Filter seriessub source because it shut down so the links are all 404 + if str(sub['source']) != 'seriessub': + subtitles.append(BetaSeriesSubtitle( + sub['id'], language, sub['file'], sub['url'], matches, str(sub['source']))) + + return subtitles + + def list_subtitles(self, video, languages): + return self.query(languages, video) + + def download_subtitle(self, subtitle): + logger.info('Downloading subtitle %r', subtitle) + r = self.session.get(subtitle.download_link, timeout=10) + r.raise_for_status() + + archive = _get_archive(r.content) + subtitle_content = _get_subtitle_from_archive( + archive) if archive else r.content + + if subtitle_content: + subtitle.content = fix_line_ending(subtitle_content) + else: + logger.debug('Could not extract subtitle from %r', archive) + + +def _get_archive(content): + # open the archive + archive_stream = io.BytesIO(content) + archive = None + if rarfile.is_rarfile(archive_stream): + logger.debug('Identified rar archive') + archive = rarfile.RarFile(archive_stream) + elif zipfile.is_zipfile(archive_stream): + logger.debug('Identified zip archive') + archive = zipfile.ZipFile(archive_stream) + + return archive + + +def _get_subtitle_from_archive(archive): + for name in archive.namelist(): + # discard hidden files + if os.path.split(name)[-1].startswith('.'): + continue + + # discard non-subtitle files + if not name.lower().endswith(SUBTITLE_EXTENSIONS): + continue + + return archive.read(name) + + return None + + +def _translateLanguageCodeToLanguage(languageCode): + if languageCode.lower() == 'vo': + return Language.fromalpha2('en') + elif languageCode.lower() == 'vf': + return Language.fromalpha2('fr') diff --git a/views/providers.tpl b/views/providers.tpl index 8d6a3fe64..9386b16a8 100644 --- a/views/providers.tpl +++ b/views/providers.tpl @@ -106,6 +106,44 @@ +
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+ +
+
+
+
+
diff --git a/views/settings_subtitles.tpl b/views/settings_subtitles.tpl index f1c48f32d..b0a44c2c5 100644 --- a/views/settings_subtitles.tpl +++ b/views/settings_subtitles.tpl @@ -37,6 +37,13 @@
+