From e3c4def89acc185bdbb67f8dcb7a12531e209df7 Mon Sep 17 00:00:00 2001 From: Vitiko Date: Mon, 12 Jun 2023 19:36:11 -0400 Subject: [PATCH] Subf2m Provider: add user-agent header configuration This change fixes empty queries. --- bazarr/app/config.py | 3 +- bazarr/app/get_providers.py | 3 +- frontend/src/pages/Settings/Providers/list.ts | 6 + libs/subliminal_patch/providers/subf2m.py | 33 ++++- tests/subliminal_patch/test_subf2m.py | 115 ++++++++---------- 5 files changed, 93 insertions(+), 67 deletions(-) diff --git a/bazarr/app/config.py b/bazarr/app/config.py index b3840e0c4..b04ca93c3 100644 --- a/bazarr/app/config.py +++ b/bazarr/app/config.py @@ -169,7 +169,8 @@ defaults = { 'verify_ssl': 'True' }, 'subf2m': { - 'verify_ssl': 'True' + 'verify_ssl': 'True', + 'user_agent': '' }, 'whisperai': { 'endpoint': 'http://127.0.0.1:9000', diff --git a/bazarr/app/get_providers.py b/bazarr/app/get_providers.py index 04593ea15..84a64be4d 100644 --- a/bazarr/app/get_providers.py +++ b/bazarr/app/get_providers.py @@ -294,7 +294,8 @@ def get_providers_auth(): 'f_password': settings.karagarga.f_password, }, 'subf2m': { - 'verify_ssl': settings.subf2m.getboolean('verify_ssl') + 'verify_ssl': settings.subf2m.getboolean('verify_ssl'), + 'user_agent': settings.subf2m.user_agent, }, 'whisperai': { 'endpoint': settings.whisperai.endpoint, diff --git a/frontend/src/pages/Settings/Providers/list.ts b/frontend/src/pages/Settings/Providers/list.ts index c266f5203..a6db25bf9 100644 --- a/frontend/src/pages/Settings/Providers/list.ts +++ b/frontend/src/pages/Settings/Providers/list.ts @@ -329,7 +329,13 @@ export const ProviderList: Readonly = [ name: "Verify SSL", defaultValue: true, }, + { + type: "text", + key: "user_agent", + name: "User-agent header", + }, ], + message: "Make sure to use a unique and credible user agent.", }, { key: "subs4free", diff --git a/libs/subliminal_patch/providers/subf2m.py b/libs/subliminal_patch/providers/subf2m.py index 8a9807fff..7f8cb6bfd 100644 --- a/libs/subliminal_patch/providers/subf2m.py +++ b/libs/subliminal_patch/providers/subf2m.py @@ -115,6 +115,21 @@ _LANGUAGE_MAP = { "turkish": "tur", } +_DEFAULT_HEADERS = { + "authority": "subf2m.co", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "accept-language": "en-US,en;q=0.9", + "referer": "https://subf2m.co", + "sec-ch-ua": '"Chromium";v="111", "Not(A:Brand";v="8"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Unknown"', + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "same-origin", + "sec-fetch-user": "?1", + "upgrade-insecure-requests": "1", +} + class Subf2mProvider(Provider): provider_name = "subf2m" @@ -138,15 +153,25 @@ class Subf2mProvider(Provider): video_types = (Episode, Movie) subtitle_class = Subf2mSubtitle - def __init__(self, verify_ssl=True): + def __init__(self, verify_ssl=True, user_agent=None, session_factory=None): super().__init__() + if not user_agent: + raise ValueError("User-agent config missing") + + self._user_agent = user_agent self._verify_ssl = verify_ssl + self._session_factory = session_factory def initialize(self): - self._session = Session() - self._session.verify = self._verify_ssl + if self._session_factory is not None: + self._session = self._session_factory() + else: + logger.debug("No session factory set. Using default requests.Session.") + self._session = Session() - self._session.headers.update({"user-agent": "Bazarr"}) + self._session.verify = self._verify_ssl + self._session.headers.update(_DEFAULT_HEADERS) + self._session.headers.update({"user-agent": self._user_agent}) def terminate(self): self._session.close() diff --git a/tests/subliminal_patch/test_subf2m.py b/tests/subliminal_patch/test_subf2m.py index 19275d48a..cdf201734 100644 --- a/tests/subliminal_patch/test_subf2m.py +++ b/tests/subliminal_patch/test_subf2m.py @@ -5,6 +5,15 @@ from subliminal_patch.providers.subf2m import Subf2mSubtitle from subzero.language import Language +_U_A = "Mozilla/5.0 (Linux; Android 10; SM-G996U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36" + + +@pytest.fixture +def provider(): + with Subf2mProvider(user_agent=_U_A) as provider: + yield provider + + @pytest.mark.parametrize( "title,year,expected_url", [ @@ -17,14 +26,13 @@ from subzero.language import Language ("Cure", 1997, "/subtitles/cure-kyua"), ], ) -def test_search_movie(movies, title, year, expected_url): +def test_search_movie(provider, movies, title, year, expected_url): movie = list(movies.values())[0] movie.title = title movie.year = year - with Subf2mProvider() as provider: - result = provider._search_movie(movie.title, movie.year) - assert result == expected_url + result = provider._search_movie(movie.title, movie.year) + assert result == expected_url @pytest.mark.parametrize( @@ -42,39 +50,33 @@ def test_search_movie(movies, title, year, expected_url): ), ], ) -def test_search_tv_show_season(series_title, season, year, expected_url): - with Subf2mProvider() as provider: - result = provider._search_tv_show_season(series_title, season, year) - assert result == expected_url +def test_search_tv_show_season(provider, series_title, season, year, expected_url): + result = provider._search_tv_show_season(series_title, season, year) + assert result == expected_url @pytest.mark.parametrize("language", [Language.fromalpha2("en"), Language("por", "BR")]) -def test_find_movie_subtitles(language): +def test_find_movie_subtitles(provider, language): path = "/subtitles/dune-2021" - with Subf2mProvider() as provider: - for sub in provider._find_movie_subtitles(path, language): - assert sub.language == language + for sub in provider._find_movie_subtitles(path, language): + assert sub.language == language @pytest.mark.parametrize("language", [Language.fromalpha2("en"), Language("por", "BR")]) -def test_find_episode_subtitles(language): +def test_find_episode_subtitles(provider, language): path = "/subtitles/breaking-bad-first-season" - with Subf2mProvider() as provider: - for sub in provider._find_episode_subtitles(path, 1, 1, language): - assert sub.language == language + for sub in provider._find_episode_subtitles(path, 1, 1, language): + assert sub.language == language -def test_find_episode_subtitles_from_complete_series_path(): +def test_find_episode_subtitles_from_complete_series_path(provider): path = "/subtitles/courage-the-cowardly-dog" - with Subf2mProvider() as provider: - for sub in provider._find_episode_subtitles( - path, 1, 1, Language.fromalpha2("en") - ): - assert sub.language == Language.fromalpha2("en") + for sub in provider._find_episode_subtitles(path, 1, 1, Language.fromalpha2("en")): + assert sub.language == Language.fromalpha2("en") -def test_list_and_download_subtitles_complete_series_pack(episodes): +def test_list_and_download_subtitles_complete_series_pack(provider, episodes): episode = list(episodes.values())[0] episode.series = "Sam & Max: Freelance Police" @@ -83,14 +85,13 @@ def test_list_and_download_subtitles_complete_series_pack(episodes): episode.season = 1 episode.episode = 21 - with Subf2mProvider() as provider: - subtitles = provider.list_subtitles(episode, {Language.fromalpha2("en")}) - assert subtitles + subtitles = provider.list_subtitles(episode, {Language.fromalpha2("en")}) + assert subtitles - subtitle = subtitles[0] - provider.download_subtitle(subtitle) + subtitle = subtitles[0] + provider.download_subtitle(subtitle) - assert subtitle.is_valid() + assert subtitle.is_valid() @pytest.fixture @@ -136,47 +137,40 @@ def test_subtitle_get_matches_episode(subtitle_episode, episodes): assert "source" not in matches -def test_list_subtitles_movie(movies): - with Subf2mProvider() as provider: - assert provider.list_subtitles(movies["dune"], {Language.fromalpha2("en")}) +def test_list_subtitles_movie(provider, movies): + assert provider.list_subtitles(movies["dune"], {Language.fromalpha2("en")}) -def test_list_subtitles_inexistent_movie(movies): - with Subf2mProvider() as provider: - assert ( - provider.list_subtitles(movies["inexistent"], {Language.fromalpha2("en")}) - == [] - ) +def test_list_subtitles_inexistent_movie(provider, movies): + assert ( + provider.list_subtitles(movies["inexistent"], {Language.fromalpha2("en")}) == [] + ) -def test_list_subtitles_episode(episodes): - with Subf2mProvider() as provider: - assert provider.list_subtitles( - episodes["breaking_bad_s01e01"], {Language.fromalpha2("en")} - ) +def test_list_subtitles_episode(provider, episodes): + assert provider.list_subtitles( + episodes["breaking_bad_s01e01"], {Language.fromalpha2("en")} + ) -def test_list_subtitles_inexistent_episode(episodes): - with Subf2mProvider() as provider: - assert ( - provider.list_subtitles(episodes["inexistent"], {Language.fromalpha2("en")}) - == [] - ) +def test_list_subtitles_inexistent_episode(provider, episodes): + assert ( + provider.list_subtitles(episodes["inexistent"], {Language.fromalpha2("en")}) + == [] + ) -def test_download_subtitle(subtitle): - with Subf2mProvider() as provider: - provider.download_subtitle(subtitle) - assert subtitle.is_valid() +def test_download_subtitle(provider, subtitle): + provider.download_subtitle(subtitle) + assert subtitle.is_valid() -def test_download_subtitle_episode(subtitle_episode): - with Subf2mProvider() as provider: - provider.download_subtitle(subtitle_episode) - assert subtitle_episode.is_valid() +def test_download_subtitle_episode(provider, subtitle_episode): + provider.download_subtitle(subtitle_episode) + assert subtitle_episode.is_valid() -def test_download_subtitle_episode_with_title(): +def test_download_subtitle_episode_with_title(provider): sub = Subf2mSubtitle( Language.fromalpha2("en"), "https://subf2m.co/subtitles/courage-the-cowardly-dog/english/2232402", @@ -185,9 +179,8 @@ def test_download_subtitle_episode_with_title(): ) sub.episode_title = "Feast of the Bullfrogs" - with Subf2mProvider() as provider: - provider.download_subtitle(sub) - assert sub.is_valid() + provider.download_subtitle(sub) + assert sub.is_valid() def test_get_episode_from_release():