From 95474b29db452a7dad055af6d89a671ff50ae2d4 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 11 Feb 2024 14:51:30 -0500 Subject: Added support for opensubtitles.com dedicated VIP subdomain that get automatically used according to subscription status. --- bazarr/app/config.py | 2 + .../subliminal_patch/providers/opensubtitlescom.py | 45 +++++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/bazarr/app/config.py b/bazarr/app/config.py index 560069f40..955270640 100644 --- a/bazarr/app/config.py +++ b/bazarr/app/config.py @@ -615,10 +615,12 @@ def save_settings(settings_items): if key != settings.opensubtitlescom.username: reset_providers = True region.delete('oscom_token') + region.delete('oscom_server') elif key == 'settings-opensubtitlescom-password': if key != settings.opensubtitlescom.password: reset_providers = True region.delete('oscom_token') + region.delete('oscom_server') if key == 'settings-subscene-username': if key != settings.subscene.username: diff --git a/libs/subliminal_patch/providers/opensubtitlescom.py b/libs/subliminal_patch/providers/opensubtitlescom.py index e51e5cb12..83f7f0327 100644 --- a/libs/subliminal_patch/providers/opensubtitlescom.py +++ b/libs/subliminal_patch/providers/opensubtitlescom.py @@ -154,7 +154,7 @@ class OpenSubtitlesComSubtitle(Subtitle): class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): """OpenSubtitlesCom Provider""" - server_url = 'https://api.opensubtitles.com/api/v1/' + server_hostname = 'api.opensubtitles.com' languages = {Language.fromopensubtitles(lang) for lang in language_converters['szopensubtitles'].codes} languages.update(set(Language.rebuild(lang, forced=True) for lang in languages)) @@ -193,15 +193,24 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): else: self.token = region.get("oscom_token", expiration_time=TOKEN_EXPIRATION_TIME) + if region.get("oscom_server", expiration_time=TOKEN_EXPIRATION_TIME) is NO_VALUE: + logger.debug("No cached server, we'll try to login again.") + self.login() + else: + self.server_hostname = region.get("oscom_server", expiration_time=TOKEN_EXPIRATION_TIME) + def terminate(self): self.session.close() def ping(self): return self._started and (time.time() - self._started) < TOKEN_EXPIRATION_TIME + def server_url(self): + return f'https://{self.server_hostname}/api/v1/' + def login(self, is_retry=False): r = self.checked( - lambda: self.session.post(self.server_url + 'login', + lambda: self.session.post(self.server_url() + 'login', json={"username": self.username, "password": self.password}, allow_redirects=False, timeout=30), @@ -216,6 +225,20 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): log_request_response(r, non_standard=False) region.set("oscom_token", self.token) + try: + self.server_hostname = r.json()['base_url'] + except (ValueError, JSONDecodeError): + log_request_response(r) + raise ProviderError("Cannot get server from provider login response") + else: + log_request_response(r, non_standard=False) + region.set("oscom_server", self.server_hostname) + finally: + if self.server_hostname.startswith('vip'): + self.session.headers.update({'Authorization': 'Bearer ' + self.token}) + else: + self.session.headers.pop('Authorization', None) + @staticmethod def sanitize_external_ids(external_id): if isinstance(external_id, str): @@ -232,7 +255,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): results = self.retry( lambda: self.checked( - lambda: self.session.get(self.server_url + 'features', params=parameters, timeout=30), + lambda: self.session.get(self.server_url() + 'features', params=parameters, timeout=30), validate_json=True, json_key_name='data' ), @@ -300,7 +323,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): if isinstance(self.video, Episode): res = self.retry( lambda: self.checked( - lambda: self.session.get(self.server_url + 'subtitles', + lambda: self.session.get(self.server_url() + 'subtitles', params=(('ai_translated', 'exclude' if not self.include_ai_translated else 'include'), ('episode_number', self.video.episode), @@ -318,7 +341,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): else: res = self.retry( lambda: self.checked( - lambda: self.session.get(self.server_url + 'subtitles', + lambda: self.session.get(self.server_url() + 'subtitles', params=(('ai_translated', 'exclude' if not self.include_ai_translated else 'include'), ('id', title_id if title_id else None), @@ -410,7 +433,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): 'Authorization': 'Bearer ' + self.token} res = self.retry( lambda: self.checked( - lambda: self.session.post(self.server_url + 'download', + lambda: self.session.post(self.server_url() + 'download', json={'file_id': subtitle.file_id, 'sub_format': 'srt'}, headers=headers, timeout=30), @@ -443,6 +466,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): def reset_token(): logger.debug('Authentication failed: clearing cache and attempting to login.') region.delete("oscom_token") + region.delete("oscom_server") return def checked(self, fn, raise_api_limit=False, validate_json=False, json_key_name=None, validate_content=False, @@ -558,9 +582,12 @@ def log_request_response(response, non_standard=True): if 'Authorization' in redacted_request_headers and isinstance(redacted_request_headers['Authorization'], str): redacted_request_headers['Authorization'] = redacted_request_headers['Authorization'][:-8]+8*'x' - redacted_request_body = json.loads(response.request.body) - if 'password' in redacted_request_body: - redacted_request_body['password'] = 'redacted' + if response.request.body: + redacted_request_body = json.loads(response.request.body) + if 'password' in redacted_request_body: + redacted_request_body['password'] = 'redacted' + else: + redacted_request_body = None redacted_response_body = json.loads(response.text) if 'token' in redacted_response_body and isinstance(redacted_response_body['token'], str): -- cgit v1.2.3