From 6eeaa46bbf3d3fdc46f6cca39c25284c9459cf12 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Tue, 20 Jul 2021 08:05:30 -0400 Subject: [PATCH 01/42] Fixed wanted list ordering. #1475 --- bazarr/api.py | 3 ++- bazarr/database.py | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bazarr/api.py b/bazarr/api.py index aea8198aa..e4d622234 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -1696,6 +1696,7 @@ class EpisodesWanted(Resource): TableShows.seriesType)\ .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\ .where(wanted_condition)\ + .order_by(TableEpisodes.rowid.desc())\ .limit(length)\ .offset(start)\ .dicts() @@ -1749,7 +1750,7 @@ class MoviesWanted(Resource): TableMovies.tags, TableMovies.monitored)\ .where(wanted_condition)\ - .order_by(TableMovies.radarrId.desc())\ + .order_by(TableMovies.rowid.desc())\ .limit(length)\ .offset(start)\ .dicts() diff --git a/bazarr/database.py b/bazarr/database.py index 8662010ce..9924f8d72 100644 --- a/bazarr/database.py +++ b/bazarr/database.py @@ -8,6 +8,7 @@ from peewee import * from playhouse.sqliteq import SqliteQueueDatabase from playhouse.shortcuts import model_to_dict from playhouse.migrate import * +from playhouse.sqlite_ext import RowIDField from helper import path_mappings from config import settings, get_array_from @@ -69,6 +70,7 @@ class TableBlacklistMovie(BaseModel): class TableEpisodes(BaseModel): + rowid = RowIDField() audio_codec = TextField(null=True) audio_language = TextField(null=True) episode = IntegerField() @@ -140,6 +142,7 @@ class TableLanguagesProfiles(BaseModel): class TableMovies(BaseModel): + rowid = RowIDField() alternativeTitles = TextField(null=True) audio_codec = TextField(null=True) audio_language = TextField(null=True) @@ -163,7 +166,7 @@ class TableMovies(BaseModel): subtitles = TextField(null=True) tags = TextField(null=True) title = TextField() - tmdbId = TextField(primary_key=True) + tmdbId = TextField(unique=True) video_codec = TextField(null=True) year = TextField(null=True) From 5f6b201a71be4002e517f052ede9215f9a81d748 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 22 Jul 2021 07:20:56 -0400 Subject: [PATCH 02/42] Fixed greeksubs provider. #1477 --- libs/subliminal_patch/providers/greeksubs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/subliminal_patch/providers/greeksubs.py b/libs/subliminal_patch/providers/greeksubs.py index ddd7f9d80..bec0749c6 100644 --- a/libs/subliminal_patch/providers/greeksubs.py +++ b/libs/subliminal_patch/providers/greeksubs.py @@ -75,12 +75,12 @@ class GreekSubsProvider(Provider): r = self.session.get(search_link, timeout=30) # 404 is returned if the imdb_id was not found - if r.status_code != 404: - r.raise_for_status() + if r.status_code == 404: + logger.debug('IMDB id {} not found on greeksubs'.format(imdb_id)) + return subtitles if r.status_code != 200: - logger.debug('No subtitles found') - return subtitles + r.raise_for_status() soup_page = ParserBeautifulSoup(r.content.decode('utf-8', 'ignore'), ['html.parser']) From d5b898064d7188d5bc47bcb3a73405a38133d5d6 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 22 Jul 2021 07:37:55 -0400 Subject: [PATCH 03/42] Fixed incomplete SQL queries. #1479 --- bazarr/api.py | 2 +- bazarr/get_episodes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bazarr/api.py b/bazarr/api.py index e4d622234..1f8494c6c 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -1516,7 +1516,7 @@ class MoviesHistory(Resource): if int(upgradable_movie['score']) < 120: upgradable_movies_not_perfect.append(upgradable_movie) - query_conditions = [(TableMovies is not None)] + query_conditions = [(TableMovies.title is not None)] if radarrid: query_conditions.append((TableMovies.radarrId == radarrid)) query_condition = reduce(operator.and_, query_conditions) diff --git a/bazarr/get_episodes.py b/bazarr/get_episodes.py index 4c1332882..55d436f46 100644 --- a/bazarr/get_episodes.py +++ b/bazarr/get_episodes.py @@ -292,7 +292,7 @@ def episodeParser(episode): if 'name' in item: audio_language.append(item['name']) else: - audio_language = TableShows.get(TableShows == episode['seriesId']).audio_language + audio_language = TableShows.get(TableShows.sonarrSeriesId == episode['seriesId']).audio_language if 'mediaInfo' in episode['episodeFile']: if 'videoCodec' in episode['episodeFile']['mediaInfo']: From e2f6223252534a2b0b28d13198065337a536a960 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jul 2021 20:23:59 +0800 Subject: [PATCH 04/42] no log: Bump socket.io-client from 4.0.1 to 4.1.3 in /frontend (#1468) Bumps [socket.io-client](https://github.com/socketio/socket.io-client) from 4.0.1 to 4.1.3. - [Release notes](https://github.com/socketio/socket.io-client/releases) - [Changelog](https://github.com/socketio/socket.io-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io-client/compare/4.0.1...4.1.3) --- updated-dependencies: - dependency-name: socket.io-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 39c1a34cb..39fbb1b64 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7071,9 +7071,9 @@ } }, "node_modules/engine.io-client": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.0.1.tgz", - "integrity": "sha512-CQtGN3YwfvbxVwpPugcsHe5rHT4KgT49CEcQppNtu9N7WxbPN0MAG27lGaem7bvtCFtGNLSL+GEqXsFSz36jTg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz", + "integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==", "dependencies": { "base64-arraybuffer": "0.1.4", "component-emitter": "~1.3.0", @@ -18223,15 +18223,15 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/socket.io-client": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.0.1.tgz", - "integrity": "sha512-6AkaEG5zrVuSVW294cH1chioag9i1OqnCYjKwTc3EBGXbnyb98Lw7yMa40ifLjFj3y6fsFKsd0llbUZUCRf3Qw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz", + "integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==", "dependencies": { "@types/component-emitter": "^1.2.10", "backo2": "~1.0.2", "component-emitter": "~1.3.0", "debug": "~4.3.1", - "engine.io-client": "~5.0.0", + "engine.io-client": "~5.1.2", "parseuri": "0.0.6", "socket.io-parser": "~4.0.4" }, @@ -27764,9 +27764,9 @@ } }, "engine.io-client": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.0.1.tgz", - "integrity": "sha512-CQtGN3YwfvbxVwpPugcsHe5rHT4KgT49CEcQppNtu9N7WxbPN0MAG27lGaem7bvtCFtGNLSL+GEqXsFSz36jTg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz", + "integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==", "requires": { "base64-arraybuffer": "0.1.4", "component-emitter": "~1.3.0", @@ -36477,15 +36477,15 @@ } }, "socket.io-client": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.0.1.tgz", - "integrity": "sha512-6AkaEG5zrVuSVW294cH1chioag9i1OqnCYjKwTc3EBGXbnyb98Lw7yMa40ifLjFj3y6fsFKsd0llbUZUCRf3Qw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz", + "integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==", "requires": { "@types/component-emitter": "^1.2.10", "backo2": "~1.0.2", "component-emitter": "~1.3.0", "debug": "~4.3.1", - "engine.io-client": "~5.0.0", + "engine.io-client": "~5.1.2", "parseuri": "0.0.6", "socket.io-parser": "~4.0.4" } From bb1c30a921126b78df4cef1de55078ce25f31d6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jul 2021 20:32:43 +0800 Subject: [PATCH 05/42] no log: Bump @types/react-redux from 7.1.16 to 7.1.18 in /frontend (#1480) Bumps [@types/react-redux](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-redux) from 7.1.16 to 7.1.18. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-redux) --- updated-dependencies: - dependency-name: "@types/react-redux" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 39fbb1b64..ef43b1768 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2985,9 +2985,9 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", - "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", + "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -24427,9 +24427,9 @@ } }, "@types/react-redux": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", - "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", + "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", From ed30f76c57dd4b6ac511edf430ebe358ef24ccee Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Thu, 22 Jul 2021 21:13:07 +0800 Subject: [PATCH 06/42] Fix wanted pages are not updated properly after changing language profile --- bazarr/api.py | 10 ++++++++++ frontend/src/@redux/hooks/index.ts | 26 -------------------------- frontend/src/@socketio/reducer.ts | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/bazarr/api.py b/bazarr/api.py index 1f8494c6c..5143ec859 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -716,6 +716,15 @@ class Series(Resource): list_missing_subtitles(no=seriesId, send_event=False) event_stream(type='series', payload=seriesId) + + episode_id_list = TableEpisodes\ + .select(TableEpisodes.sonarrEpisodeId)\ + .where(TableEpisodes.sonarrSeriesId == seriesId)\ + .dicts() + + for item in episode_id_list: + event_stream(type='episode-wanted', payload=item['sonarrEpisodeId']) + event_stream(type='badges') return '', 204 @@ -963,6 +972,7 @@ class Movies(Resource): list_missing_subtitles_movies(no=radarrId, send_event=False) event_stream(type='movie', payload=radarrId) + event_stream(type='movie-wanted', payload=radarrId) event_stream(type='badges') return '', 204 diff --git a/frontend/src/@redux/hooks/index.ts b/frontend/src/@redux/hooks/index.ts index 364871a4f..ac15d5b21 100644 --- a/frontend/src/@redux/hooks/index.ts +++ b/frontend/src/@redux/hooks/index.ts @@ -5,13 +5,11 @@ import { episodeDeleteItems, episodeUpdateBy, episodeUpdateById, - movieDeleteWantedItems, movieUpdateBlacklist, movieUpdateHistoryList, movieUpdateList, movieUpdateWantedList, providerUpdateList, - seriesDeleteWantedItems, seriesUpdateBlacklist, seriesUpdateHistoryList, seriesUpdateList, @@ -324,18 +322,6 @@ export function useWantedSeries() { const update = useReduxAction(seriesUpdateWantedList); const items = useReduxStore((d) => d.series.wantedEpisodesList); - const updateAction = useWrapToOptionalId(update); - const deleteAction = useReduxAction(seriesDeleteWantedItems); - const reducer = useMemo( - () => ({ - key: "episode-wanted", - update: updateAction, - delete: deleteAction, - }), - [updateAction, deleteAction] - ); - useSocketIOReducer(reducer); - return stateBuilder(items, update); } @@ -343,18 +329,6 @@ export function useWantedMovies() { const update = useReduxAction(movieUpdateWantedList); const items = useReduxStore((d) => d.movie.wantedMovieList); - const updateAction = useWrapToOptionalId(update); - const deleteAction = useReduxAction(movieDeleteWantedItems); - const reducer = useMemo( - () => ({ - key: "movie-wanted", - update: updateAction, - delete: deleteAction, - }), - [updateAction, deleteAction] - ); - useSocketIOReducer(reducer); - return stateBuilder(items, update); } diff --git a/frontend/src/@socketio/reducer.ts b/frontend/src/@socketio/reducer.ts index 4b39a5eb2..5ea5fba94 100644 --- a/frontend/src/@socketio/reducer.ts +++ b/frontend/src/@socketio/reducer.ts @@ -3,9 +3,13 @@ import { badgeUpdateAll, bootstrap, movieDeleteItems, + movieDeleteWantedItems, movieUpdateList, + movieUpdateWantedList, seriesDeleteItems, + seriesDeleteWantedItems, seriesUpdateList, + seriesUpdateWantedList, siteAddNotifications, siteAddProgress, siteInitializationFailed, @@ -91,6 +95,24 @@ export function createDefaultReducer(): SocketIO.Reducer[] { update: bindToReduxStore(movieUpdateList), delete: bindToReduxStore(movieDeleteItems), }, + { + key: "episode-wanted", + update: (ids: number[] | undefined) => { + if (ids) { + reduxStore.dispatch(seriesUpdateWantedList(ids) as any); + } + }, + delete: bindToReduxStore(seriesDeleteWantedItems), + }, + { + key: "movie-wanted", + update: (ids: number[] | undefined) => { + if (ids) { + reduxStore.dispatch(movieUpdateWantedList(ids) as any); + } + }, + delete: bindToReduxStore(movieDeleteWantedItems), + }, { key: "settings", any: bindToReduxStore(systemUpdateSettings), From 117da38fe6c98b627ac2edd5bf0b7beab6336bc4 Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Fri, 23 Jul 2021 00:01:31 +0800 Subject: [PATCH 07/42] no log: Add source map files back to release asset --- .github/scripts/create_asset.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/create_asset.sh b/.github/scripts/create_asset.sh index 304a7fe15..d699043b6 100755 --- a/.github/scripts/create_asset.sh +++ b/.github/scripts/create_asset.sh @@ -23,6 +23,6 @@ done cp VERSION $to_dist pushd __builds__/bazarr -zip -r ../bazarr.zip . -x '*.map' -b $(mktemp -d) +zip -r ../bazarr.zip . -b $(mktemp -d) popd rm -rf $to_dist \ No newline at end of file From 5e3ce8c8c3e9402d98b6ccdc1b5de5c70e2759ad Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 22 Jul 2021 14:09:39 -0400 Subject: [PATCH 08/42] Improved how Bazarr deals with Sonarr SignalR feed issues that are raising exceptions. --- bazarr/main.py | 6 ++++-- bazarr/signalr_client.py | 42 ++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/bazarr/main.py b/bazarr/main.py index 71632d97e..e29164f9d 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -204,10 +204,12 @@ def proxy(protocol, url): return dict(status=False, error=result.raise_for_status()) +greenlets = [] if settings.general.getboolean('use_sonarr'): - Greenlet.spawn(sonarr_signalr_client.start) + greenlets.append(Greenlet.spawn(sonarr_signalr_client.start)) if settings.general.getboolean('use_radarr'): - Greenlet.spawn(radarr_signalr_client.start) + greenlets.append(Greenlet.spawn(radarr_signalr_client.start)) +gevent.joinall(greenlets) if __name__ == "__main__": diff --git a/bazarr/signalr_client.py b/bazarr/signalr_client.py index 941d8bd9f..583a7942f 100644 --- a/bazarr/signalr_client.py +++ b/bazarr/signalr_client.py @@ -33,26 +33,30 @@ class SonarrSignalrClient: self.connection = None def start(self): - if get_sonarr_version().startswith('2.'): + sonarr_version = get_sonarr_version() + if sonarr_version.startswith('2.'): logging.warning('BAZARR can only sync from Sonarr v3 SignalR feed to get real-time update. You should ' - 'consider upgrading.') - return - - logging.info('BAZARR trying to connect to Sonarr SignalR feed...') - self.configure() - while not self.connection.started: - try: - self.connection.start() - except ConnectionError: - gevent.sleep(5) - except json.decoder.JSONDecodeError: - logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is a known issue when Sonarr " - "doesn't have write permission to it's /config/xdg directory.") - self.stop() - logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.') - if not args.dev: - scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1) - scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1) + 'consider upgrading your version({}).'.format(sonarr_version)) + raise gevent.GreenletExit + else: + logging.info('BAZARR trying to connect to Sonarr SignalR feed...') + self.configure() + while not self.connection.started: + try: + self.connection.start() + except ConnectionError: + gevent.sleep(5) + except json.decoder.JSONDecodeError: + logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is a known issue when " + "Sonarr have issue accessing it's /config/xdg directory. You should delete that " + "directory and restart Sonarr.") + raise gevent.GreenletExit + else: + logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.') + finally: + if not args.dev: + scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1) + scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1) def stop(self, log=True): try: From e2b4912067932dc505fead42ad837c1f1fa03cd1 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Fri, 23 Jul 2021 07:40:46 -0400 Subject: [PATCH 09/42] Fixed gevent import in main.py --- bazarr/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bazarr/main.py b/bazarr/main.py index e29164f9d..c9fcd7560 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -2,7 +2,7 @@ # Gevent monkey patch if gevent available. If not, it will be installed on during the init process. try: - from gevent import monkey, Greenlet + from gevent import monkey, Greenlet, joinall except ImportError: pass else: @@ -209,7 +209,7 @@ if settings.general.getboolean('use_sonarr'): greenlets.append(Greenlet.spawn(sonarr_signalr_client.start)) if settings.general.getboolean('use_radarr'): greenlets.append(Greenlet.spawn(radarr_signalr_client.start)) -gevent.joinall(greenlets) +joinall(greenlets) if __name__ == "__main__": From e3f358bc4f830bec819c87bd545619596a63de0a Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Fri, 23 Jul 2021 07:56:25 -0400 Subject: [PATCH 10/42] no log: typo --- bazarr/get_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/get_series.py b/bazarr/get_series.py index 6dbe76292..cedb0d163 100644 --- a/bazarr/get_series.py +++ b/bazarr/get_series.py @@ -137,7 +137,7 @@ def update_series(send_event=True): def update_one_series(series_id, action): - logging.debug('BAZARR syncing this specific series from RSonarr: {}'.format(series_id)) + logging.debug('BAZARR syncing this specific series from Sonarr: {}'.format(series_id)) # Check if there's a row in database for this series ID try: From 96b8b5ccce9c45c44daf2c3a11ddb41506f369a3 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 25 Jul 2021 09:11:10 -0400 Subject: [PATCH 11/42] Improved Sonarr versions prior to 3.x detection. --- bazarr/filesystem.py | 2 +- bazarr/get_episodes.py | 12 ++++++------ bazarr/get_rootfolder.py | 2 +- bazarr/get_series.py | 11 ++++++----- bazarr/main.py | 2 +- bazarr/signalr_client.py | 2 +- bazarr/utils.py | 6 ++++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/bazarr/filesystem.py b/bazarr/filesystem.py index 47e09c8cb..1c439afc0 100644 --- a/bazarr/filesystem.py +++ b/bazarr/filesystem.py @@ -49,7 +49,7 @@ def browse_sonarr_filesystem(path='#'): sonarr_version = get_sonarr_version() if path == '#': path = '' - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url_sonarr_api_filesystem = url_sonarr() + "/api/filesystem?path=" + path + \ "&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \ settings.sonarr.apikey diff --git a/bazarr/get_episodes.py b/bazarr/get_episodes.py index 55d436f46..d5328f346 100644 --- a/bazarr/get_episodes.py +++ b/bazarr/get_episodes.py @@ -63,7 +63,7 @@ def sync_episodes(series_id=None, send_event=True): continue else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results - if sonarr_version.startswith('3'): + if not sonarr_version.startswith(('0.', '2.')): episodeFiles = get_episodesFiles_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr, series_id=seriesId['sonarrSeriesId']) for episode in episodes: @@ -187,7 +187,7 @@ def sync_one_episode(episode_id): else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results - if sonarr_version.startswith('3'): + if not sonarr_version.startswith(('0.', '2.')): episodeFile = get_episodesFiles_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr, episode_file_id=existing_episode['episode_file_id']) if episode_data['hasFile']: @@ -339,10 +339,10 @@ def episodeParser(episode): def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version): if series_id: url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format( - '' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr) + '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', series_id, apikey_sonarr) else: url_sonarr_api_series = url + "/api/{0}series?apikey={1}".format( - '' if sonarr_version.startswith('2') else 'v3/', apikey_sonarr) + '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', apikey_sonarr) try: r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers) r.raise_for_status() @@ -375,10 +375,10 @@ def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version): def get_episodes_from_sonarr_api(url, apikey_sonarr, sonarr_version, series_id=None, episode_id=None): if series_id: url_sonarr_api_episode = url + "/api/{0}episode?seriesId={1}&apikey={2}".format( - '' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr) + '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', series_id, apikey_sonarr) elif episode_id: url_sonarr_api_episode = url + "/api/{0}episode/{1}?apikey={2}".format( - '' if sonarr_version.startswith('2') else 'v3/', episode_id, apikey_sonarr) + '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', episode_id, apikey_sonarr) else: return diff --git a/bazarr/get_rootfolder.py b/bazarr/get_rootfolder.py index e8529e954..7027c900f 100644 --- a/bazarr/get_rootfolder.py +++ b/bazarr/get_rootfolder.py @@ -18,7 +18,7 @@ def get_sonarr_rootfolder(): sonarr_version = get_sonarr_version() # Get root folder data from Sonarr - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url_sonarr_api_rootfolder = url_sonarr() + "/api/rootfolder?apikey=" + apikey_sonarr else: url_sonarr_api_rootfolder = url_sonarr() + "/api/v3/rootfolder?apikey=" + apikey_sonarr diff --git a/bazarr/get_series.py b/bazarr/get_series.py index cedb0d163..45c68d6ee 100644 --- a/bazarr/get_series.py +++ b/bazarr/get_series.py @@ -212,7 +212,7 @@ def get_profile_list(): profiles_list = [] # Get profiles data from Sonarr - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url_sonarr_api_series = url_sonarr() + "/api/profile?apikey=" + apikey_sonarr else: url_sonarr_api_series = url_sonarr() + "/api/v3/languageprofile?apikey=" + apikey_sonarr @@ -230,7 +230,7 @@ def get_profile_list(): return None # Parsing data returned from Sonarr - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): for profile in profiles_json.json(): profiles_list.append([profile['id'], profile['language'].capitalize()]) else: @@ -250,10 +250,11 @@ def profile_id_to_language(id_, profiles): def get_tags(): apikey_sonarr = settings.sonarr.apikey + sonarr_version = get_sonarr_version() tagsDict = [] # Get tags data from Sonarr - if get_sonarr_version().startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url_sonarr_api_series = url_sonarr() + "/api/tag?apikey=" + apikey_sonarr else: url_sonarr_api_series = url_sonarr() + "/api/v3/tag?apikey=" + apikey_sonarr @@ -290,7 +291,7 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, alternate_titles = str([item['title'] for item in show['alternateTitles']]) audio_language = [] - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles) else: audio_language = profile_id_to_language(show['languageProfileId'], audio_profiles) @@ -334,7 +335,7 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_version, sonarr_series_id=None): url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format( - '' if sonarr_version.startswith('2') else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr) + '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr) try: r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers) r.raise_for_status() diff --git a/bazarr/main.py b/bazarr/main.py index c9fcd7560..77772e79e 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -132,7 +132,7 @@ def series_images(url): apikey = settings.sonarr.apikey baseUrl = settings.sonarr.base_url sonarr_version = get_sonarr_version() - if sonarr_version.startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url_image = (url_sonarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' + apikey).replace('poster-250', 'poster-500') else: diff --git a/bazarr/signalr_client.py b/bazarr/signalr_client.py index 583a7942f..ba7d8b4e2 100644 --- a/bazarr/signalr_client.py +++ b/bazarr/signalr_client.py @@ -34,7 +34,7 @@ class SonarrSignalrClient: def start(self): sonarr_version = get_sonarr_version() - if sonarr_version.startswith('2.'): + if sonarr_version.startswith(('0.', '2.')): logging.warning('BAZARR can only sync from Sonarr v3 SignalR feed to get real-time update. You should ' 'consider upgrading your version({}).'.format(sonarr_version)) raise gevent.GreenletExit diff --git a/bazarr/utils.py b/bazarr/utils.py index 88e55ed84..4ccd3bacb 100644 --- a/bazarr/utils.py +++ b/bazarr/utils.py @@ -255,9 +255,10 @@ def get_sonarr_version(): def get_sonarr_platform(): sonarr_platform = '' + sonarr_version = get_sonarr_version() if settings.general.getboolean('use_sonarr'): try: - if get_sonarr_version().startswith('2'): + if sonarr_version.startswith(('0.', '2.')): sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey else: sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey @@ -272,8 +273,9 @@ def get_sonarr_platform(): def notify_sonarr(sonarr_series_id): + sonarr_version = get_sonarr_version() try: - if get_sonarr_version().startswith('2'): + if sonarr_version.startswith(('0.', '2.')): url = url_sonarr() + "/api/command?apikey=" + settings.sonarr.apikey else: url = url_sonarr() + "/api/v3/command?apikey=" + settings.sonarr.apikey From aca99415b8f4bcc5b2b43dc338e41b6f4ed96bd9 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Mon, 26 Jul 2021 20:14:39 -0400 Subject: [PATCH 12/42] Added chmod execution (if required) after manually triggered tools execution. #1478 --- bazarr/api.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bazarr/api.py b/bazarr/api.py index 5143ec859..ee78227ab 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -1,5 +1,7 @@ # coding=utf-8 +import sys +import os import ast from datetime import timedelta from dateutil import rrule @@ -1977,6 +1979,12 @@ class Subtitles(Resource): else: subtitles_apply_mods(language, subtitles_path, [action]) + # apply chmod if required + chmod = int(settings.general.chmod, 8) if not sys.platform.startswith( + 'win') and settings.general.getboolean('chmod_enabled') else None + if chmod: + os.chmod(subtitles_path, chmod) + return '', 204 From d1f86a3cbf569155ef1a86b5968c393e08b4ecc8 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Mon, 26 Jul 2021 22:38:42 -0400 Subject: [PATCH 13/42] Added virtualenv detection to better deal with requirements installation. --- bazarr/init.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/bazarr/init.py b/bazarr/init.py index 2ecc1902e..f7241149a 100644 --- a/bazarr/init.py +++ b/bazarr/init.py @@ -42,6 +42,13 @@ if not os.path.exists(os.path.join(args.config_dir, 'cache')): configure_logging(settings.general.getboolean('debug') or args.debug) import logging + +def is_virtualenv(): + # return True if Bazarr have been start from within a virtualenv or venv + base_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix + return base_prefix != sys.prefix + + # deploy requirements.txt if not args.no_update: try: @@ -57,10 +64,13 @@ if not args.no_update: else: logging.info('BAZARR installing requirements...') try: - subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--user', '-qq', - '--disable-pip-version-check', '--no-color', '-r', - os.path.join(os.path.dirname(__file__), '..', 'requirements.txt')], - stderr=subprocess.STDOUT) + pip_command = [sys.executable, '-m', 'pip', 'install', '-qq', '--disable-pip-version-check', + '--no-color', '-r', os.path.join(os.path.dirname(os.path.dirname(__file__)), + 'requirements.txt')] + if not is_virtualenv(): + # --user only make sense if not running under venv + pip_command.insert(4, '--user') + subprocess.check_output(pip_command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: logging.exception('BAZARR requirements.txt installation result: {}'.format(e.stdout)) os._exit(1) From b912ca4e41cfa7b91620100b14611fb9f8f58747 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jul 2021 22:47:51 +0800 Subject: [PATCH 14/42] Update React to version 17 Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). These dependencies needed to be updated together. Updates `react` from 16.14.0 to 17.0.2 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v17.0.2/packages/react) Updates `react-dom` from 16.14.0 to 17.0.2 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v17.0.2/packages/react-dom) --- updated-dependencies: - dependency-name: react dependency-type: direct:production update-type: version-update:semver-major - dependency-name: react-dom dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 54 ++++++++++++++++++-------------------- frontend/package.json | 4 +-- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ef43b1768..7b54090f1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -33,9 +33,9 @@ "http-proxy-middleware": "^0.19", "lodash": "^4", "rc-slider": "^9.7", - "react": "^16", + "react": "^17", "react-bootstrap": "^1", - "react-dom": "^16", + "react-dom": "^17", "react-helmet": "^6.1", "react-redux": "^7.2", "react-router-dom": "^5.2", @@ -15776,13 +15776,12 @@ } }, "node_modules/react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" }, "engines": { "node": ">=0.10.0" @@ -16037,17 +16036,16 @@ } }, "node_modules/react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" }, "peerDependencies": { - "react": "^16.14.0" + "react": "17.0.2" } }, "node_modules/react-error-overlay": { @@ -17711,9 +17709,9 @@ } }, "node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -34534,13 +34532,12 @@ } }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" } }, "react-app-polyfill": { @@ -34742,14 +34739,13 @@ } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" } }, "react-error-overlay": { @@ -36048,9 +36044,9 @@ } }, "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" diff --git a/frontend/package.json b/frontend/package.json index 1b23a3647..680c2fa26 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,9 +37,9 @@ "http-proxy-middleware": "^0.19", "lodash": "^4", "rc-slider": "^9.7", - "react": "^16", + "react": "^17", "react-bootstrap": "^1", - "react-dom": "^16", + "react-dom": "^17", "react-helmet": "^6.1", "react-redux": "^7.2", "react-router-dom": "^5.2", From dffb417413919cce61c19eddebc28f4884623e4e Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Tue, 27 Jul 2021 22:52:27 +0800 Subject: [PATCH 15/42] no log: Rename fetched to dirty in OrderIdState --- frontend/src/@redux/utils/index.ts | 2 +- frontend/src/@redux/utils/mapper.ts | 8 ++++---- frontend/src/@types/basic.d.ts | 2 +- frontend/src/components/tables/AsyncPageTable.tsx | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/@redux/utils/index.ts b/frontend/src/@redux/utils/index.ts index 61340a902..e0e063f0d 100644 --- a/frontend/src/@redux/utils/index.ts +++ b/frontend/src/@redux/utils/index.ts @@ -4,7 +4,7 @@ export function defaultAOS(): AsyncOrderState { data: { items: [], order: [], - fetched: false, + dirty: false, }, }; } diff --git a/frontend/src/@redux/utils/mapper.ts b/frontend/src/@redux/utils/mapper.ts index 32c25b8aa..772caa39a 100644 --- a/frontend/src/@redux/utils/mapper.ts +++ b/frontend/src/@redux/utils/mapper.ts @@ -36,7 +36,7 @@ export function updateOrderIdState( return { data: { ...state.data, - fetched: true, + dirty: true, }, updating: true, }; @@ -44,7 +44,7 @@ export function updateOrderIdState( return { data: { ...state.data, - fetched: true, + dirty: true, }, updating: false, error: action.payload.item as Error, @@ -107,7 +107,7 @@ export function updateOrderIdState( return { updating: false, data: { - fetched: true, + dirty: true, items: newItems, order: newOrder, }, @@ -131,7 +131,7 @@ export function deleteOrderListItemBy( return { ...state, data: { - fetched: true, + dirty: true, items: newItems, order: newOrder, }, diff --git a/frontend/src/@types/basic.d.ts b/frontend/src/@types/basic.d.ts index c0fe42c3c..11ae9c5de 100644 --- a/frontend/src/@types/basic.d.ts +++ b/frontend/src/@types/basic.d.ts @@ -14,7 +14,7 @@ type StorageType = string | null; interface OrderIdState { items: IdState; order: (number | null)[]; - fetched: boolean; + dirty: boolean; } interface AsyncState { diff --git a/frontend/src/components/tables/AsyncPageTable.tsx b/frontend/src/components/tables/AsyncPageTable.tsx index ddd9469c3..54bb969c9 100644 --- a/frontend/src/components/tables/AsyncPageTable.tsx +++ b/frontend/src/components/tables/AsyncPageTable.tsx @@ -21,7 +21,7 @@ export default function AsyncPageTable(props: Props) { const { updating, - data: { order, items, fetched }, + data: { order, items, dirty }, } = aos; const allPlugins: PluginHook[] = [useDefaultSettings]; @@ -85,12 +85,12 @@ export default function AsyncPageTable(props: Props) { }, [pageIndex]); useEffect(() => { - const needInit = visibleItemIds.length === 0 && fetched === false; + const needFetch = visibleItemIds.length === 0 && dirty === false; const needRefresh = !visibleItemIds.every(isNonNullable); - if (needInit || needRefresh) { + if (needFetch || needRefresh) { loader(pageStart, pageSize); } - }, [visibleItemIds, pageStart, pageSize, loader, fetched]); + }, [visibleItemIds, pageStart, pageSize, loader, dirty]); const showLoading = useMemo( () => From 90db37e04e7f8a21b78d6b7fa8d6fa684ba36fe8 Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Tue, 27 Jul 2021 23:03:42 +0800 Subject: [PATCH 16/42] Make wanted tabs update on demand --- frontend/src/@redux/actions/movie.ts | 6 +++++ frontend/src/@redux/actions/series.ts | 6 +++++ frontend/src/@redux/constants/index.ts | 2 ++ frontend/src/@redux/hooks/index.ts | 26 +++++++++++++++++++ frontend/src/@redux/reducers/movie.ts | 8 ++++++ frontend/src/@redux/reducers/series.ts | 8 ++++++ frontend/src/@redux/utils/index.ts | 2 +- frontend/src/@redux/utils/mapper.ts | 20 +++++++++++--- frontend/src/@socketio/reducer.ts | 20 +++----------- .../src/components/tables/AsyncPageTable.tsx | 2 +- 10 files changed, 78 insertions(+), 22 deletions(-) diff --git a/frontend/src/@redux/actions/movie.ts b/frontend/src/@redux/actions/movie.ts index b76752cdc..ce3797143 100644 --- a/frontend/src/@redux/actions/movie.ts +++ b/frontend/src/@redux/actions/movie.ts @@ -1,8 +1,10 @@ +import { createAction } from "redux-actions"; import { createDeleteAction } from "../../@socketio/reducer"; import { MoviesApi } from "../../apis"; import { MOVIES_DELETE_ITEMS, MOVIES_DELETE_WANTED_ITEMS, + MOVIES_MARK_WANTED_LIST_DIRTY, MOVIES_UPDATE_BLACKLIST, MOVIES_UPDATE_HISTORY_LIST, MOVIES_UPDATE_LIST, @@ -26,6 +28,10 @@ export const movieDeleteWantedItems = createDeleteAction( MOVIES_DELETE_WANTED_ITEMS ); +export const movieMarkWantedListDirty = createAction( + MOVIES_MARK_WANTED_LIST_DIRTY +); + export const movieUpdateWantedByRange = createAsyncAction( MOVIES_UPDATE_WANTED_LIST, (start: number, length: number) => MoviesApi.wanted(start, length) diff --git a/frontend/src/@redux/actions/series.ts b/frontend/src/@redux/actions/series.ts index c53277469..9b7caef74 100644 --- a/frontend/src/@redux/actions/series.ts +++ b/frontend/src/@redux/actions/series.ts @@ -1,9 +1,11 @@ +import { createAction } from "redux-actions"; import { createDeleteAction } from "../../@socketio/reducer"; import { EpisodesApi, SeriesApi } from "../../apis"; import { SERIES_DELETE_EPISODES, SERIES_DELETE_ITEMS, SERIES_DELETE_WANTED_ITEMS, + SERIES_MARK_WANTED_LIST_DIRTY, SERIES_UPDATE_BLACKLIST, SERIES_UPDATE_EPISODE_LIST, SERIES_UPDATE_HISTORY_LIST, @@ -21,6 +23,10 @@ export const seriesDeleteWantedItems = createDeleteAction( SERIES_DELETE_WANTED_ITEMS ); +export const seriesMarkWantedListDirty = createAction( + SERIES_MARK_WANTED_LIST_DIRTY +); + export const seriesUpdateWantedByRange = createAsyncAction( SERIES_UPDATE_WANTED_LIST, (start: number, length: number) => EpisodesApi.wanted(start, length) diff --git a/frontend/src/@redux/constants/index.ts b/frontend/src/@redux/constants/index.ts index a76476b1b..b675297a5 100644 --- a/frontend/src/@redux/constants/index.ts +++ b/frontend/src/@redux/constants/index.ts @@ -15,6 +15,7 @@ export const SYSTEM_UPDATE_PROVIDERS = "SYSTEM_UPDATE_PROVIDERS"; // Series action export const SERIES_UPDATE_WANTED_LIST = "UPDATE_SERIES_WANTED_LIST"; export const SERIES_DELETE_WANTED_ITEMS = "SERIES_DELETE_WANTED_ITEMS"; +export const SERIES_MARK_WANTED_LIST_DIRTY = "SERIES_MARK_WANTED_LIST_DIRTY"; export const SERIES_UPDATE_EPISODE_LIST = "UPDATE_SERIES_EPISODE_LIST"; export const SERIES_DELETE_EPISODES = "SERIES_DELETE_EPISODES"; export const SERIES_UPDATE_HISTORY_LIST = "UPDATE_SERIES_HISTORY_LIST"; @@ -25,6 +26,7 @@ export const SERIES_UPDATE_BLACKLIST = "UPDATE_SERIES_BLACKLIST"; // Movie action export const MOVIES_UPDATE_LIST = "UPDATE_MOVIE_LIST"; export const MOVIES_DELETE_ITEMS = "MOVIES_DELETE_ITEMS"; +export const MOVIES_MARK_WANTED_LIST_DIRTY = "MOVIES_MARK_WANTED_LIST_DIRTY"; export const MOVIES_UPDATE_WANTED_LIST = "UPDATE_MOVIE_WANTED_LIST"; export const MOVIES_DELETE_WANTED_ITEMS = "MOVIES_DELETE_WANTED_ITEMS"; export const MOVIES_UPDATE_HISTORY_LIST = "UPDATE_MOVIE_HISTORY_LIST"; diff --git a/frontend/src/@redux/hooks/index.ts b/frontend/src/@redux/hooks/index.ts index ac15d5b21..364871a4f 100644 --- a/frontend/src/@redux/hooks/index.ts +++ b/frontend/src/@redux/hooks/index.ts @@ -5,11 +5,13 @@ import { episodeDeleteItems, episodeUpdateBy, episodeUpdateById, + movieDeleteWantedItems, movieUpdateBlacklist, movieUpdateHistoryList, movieUpdateList, movieUpdateWantedList, providerUpdateList, + seriesDeleteWantedItems, seriesUpdateBlacklist, seriesUpdateHistoryList, seriesUpdateList, @@ -322,6 +324,18 @@ export function useWantedSeries() { const update = useReduxAction(seriesUpdateWantedList); const items = useReduxStore((d) => d.series.wantedEpisodesList); + const updateAction = useWrapToOptionalId(update); + const deleteAction = useReduxAction(seriesDeleteWantedItems); + const reducer = useMemo( + () => ({ + key: "episode-wanted", + update: updateAction, + delete: deleteAction, + }), + [updateAction, deleteAction] + ); + useSocketIOReducer(reducer); + return stateBuilder(items, update); } @@ -329,6 +343,18 @@ export function useWantedMovies() { const update = useReduxAction(movieUpdateWantedList); const items = useReduxStore((d) => d.movie.wantedMovieList); + const updateAction = useWrapToOptionalId(update); + const deleteAction = useReduxAction(movieDeleteWantedItems); + const reducer = useMemo( + () => ({ + key: "movie-wanted", + update: updateAction, + delete: deleteAction, + }), + [updateAction, deleteAction] + ); + useSocketIOReducer(reducer); + return stateBuilder(items, update); } diff --git a/frontend/src/@redux/reducers/movie.ts b/frontend/src/@redux/reducers/movie.ts index 2b7fe8df1..40c0a947f 100644 --- a/frontend/src/@redux/reducers/movie.ts +++ b/frontend/src/@redux/reducers/movie.ts @@ -2,6 +2,7 @@ import { Action, handleActions } from "redux-actions"; import { MOVIES_DELETE_ITEMS, MOVIES_DELETE_WANTED_ITEMS, + MOVIES_MARK_WANTED_LIST_DIRTY, MOVIES_UPDATE_BLACKLIST, MOVIES_UPDATE_HISTORY_LIST, MOVIES_UPDATE_LIST, @@ -11,6 +12,7 @@ import { AsyncAction } from "../types"; import { defaultAOS } from "../utils"; import { deleteOrderListItemBy, + markOrderListDirty, updateAsyncState, updateOrderIdState, } from "../utils/mapper"; @@ -36,6 +38,12 @@ const reducer = handleActions( wantedMovieList: deleteOrderListItemBy(action, state.wantedMovieList), }; }, + [MOVIES_MARK_WANTED_LIST_DIRTY]: (state, action) => { + return { + ...state, + wantedMovieList: markOrderListDirty(state.wantedMovieList), + }; + }, [MOVIES_UPDATE_HISTORY_LIST]: ( state, action: AsyncAction diff --git a/frontend/src/@redux/reducers/series.ts b/frontend/src/@redux/reducers/series.ts index 23ae4ecd6..8f72928ae 100644 --- a/frontend/src/@redux/reducers/series.ts +++ b/frontend/src/@redux/reducers/series.ts @@ -3,6 +3,7 @@ import { SERIES_DELETE_EPISODES, SERIES_DELETE_ITEMS, SERIES_DELETE_WANTED_ITEMS, + SERIES_MARK_WANTED_LIST_DIRTY, SERIES_UPDATE_BLACKLIST, SERIES_UPDATE_EPISODE_LIST, SERIES_UPDATE_HISTORY_LIST, @@ -14,6 +15,7 @@ import { defaultAOS } from "../utils"; import { deleteAsyncListItemBy, deleteOrderListItemBy, + markOrderListDirty, updateAsyncList, updateAsyncState, updateOrderIdState, @@ -43,6 +45,12 @@ const reducer = handleActions( ), }; }, + [SERIES_MARK_WANTED_LIST_DIRTY]: (state, action) => { + return { + ...state, + wantedEpisodesList: markOrderListDirty(state.wantedEpisodesList), + }; + }, [SERIES_UPDATE_EPISODE_LIST]: ( state, action: AsyncAction diff --git a/frontend/src/@redux/utils/index.ts b/frontend/src/@redux/utils/index.ts index e0e063f0d..c269932da 100644 --- a/frontend/src/@redux/utils/index.ts +++ b/frontend/src/@redux/utils/index.ts @@ -4,7 +4,7 @@ export function defaultAOS(): AsyncOrderState { data: { items: [], order: [], - dirty: false, + dirty: true, }, }; } diff --git a/frontend/src/@redux/utils/mapper.ts b/frontend/src/@redux/utils/mapper.ts index 772caa39a..1236b2af9 100644 --- a/frontend/src/@redux/utils/mapper.ts +++ b/frontend/src/@redux/utils/mapper.ts @@ -36,7 +36,7 @@ export function updateOrderIdState( return { data: { ...state.data, - dirty: true, + dirty: false, }, updating: true, }; @@ -44,7 +44,7 @@ export function updateOrderIdState( return { data: { ...state.data, - dirty: true, + dirty: false, }, updating: false, error: action.payload.item as Error, @@ -107,7 +107,7 @@ export function updateOrderIdState( return { updating: false, data: { - dirty: true, + dirty: false, items: newItems, order: newOrder, }, @@ -131,13 +131,25 @@ export function deleteOrderListItemBy( return { ...state, data: { - dirty: true, + dirty: false, items: newItems, order: newOrder, }, }; } +export function markOrderListDirty( + state: AsyncOrderState +): AsyncOrderState { + return { + ...state, + data: { + ...state.data, + dirty: true, + }, + }; +} + export function deleteAsyncListItemBy( action: Action, state: AsyncState, diff --git a/frontend/src/@socketio/reducer.ts b/frontend/src/@socketio/reducer.ts index 5ea5fba94..4585592c3 100644 --- a/frontend/src/@socketio/reducer.ts +++ b/frontend/src/@socketio/reducer.ts @@ -3,13 +3,11 @@ import { badgeUpdateAll, bootstrap, movieDeleteItems, - movieDeleteWantedItems, + movieMarkWantedListDirty, movieUpdateList, - movieUpdateWantedList, seriesDeleteItems, - seriesDeleteWantedItems, + seriesMarkWantedListDirty, seriesUpdateList, - seriesUpdateWantedList, siteAddNotifications, siteAddProgress, siteInitializationFailed, @@ -97,21 +95,11 @@ export function createDefaultReducer(): SocketIO.Reducer[] { }, { key: "episode-wanted", - update: (ids: number[] | undefined) => { - if (ids) { - reduxStore.dispatch(seriesUpdateWantedList(ids) as any); - } - }, - delete: bindToReduxStore(seriesDeleteWantedItems), + any: bindToReduxStore(seriesMarkWantedListDirty), }, { key: "movie-wanted", - update: (ids: number[] | undefined) => { - if (ids) { - reduxStore.dispatch(movieUpdateWantedList(ids) as any); - } - }, - delete: bindToReduxStore(movieDeleteWantedItems), + any: bindToReduxStore(movieMarkWantedListDirty), }, { key: "settings", diff --git a/frontend/src/components/tables/AsyncPageTable.tsx b/frontend/src/components/tables/AsyncPageTable.tsx index 54bb969c9..2af0809dc 100644 --- a/frontend/src/components/tables/AsyncPageTable.tsx +++ b/frontend/src/components/tables/AsyncPageTable.tsx @@ -85,7 +85,7 @@ export default function AsyncPageTable(props: Props) { }, [pageIndex]); useEffect(() => { - const needFetch = visibleItemIds.length === 0 && dirty === false; + const needFetch = visibleItemIds.length === 0 || dirty === true; const needRefresh = !visibleItemIds.every(isNonNullable); if (needFetch || needRefresh) { loader(pageStart, pageSize); From 3ad916f71b744febfa6f51e236a9e275698efff8 Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Wed, 28 Jul 2021 22:36:17 +0800 Subject: [PATCH 17/42] Revert "Make wanted tabs update on demand" This reverts commit 90db37e04e7f8a21b78d6b7fa8d6fa684ba36fe8. --- frontend/src/@redux/actions/movie.ts | 6 ----- frontend/src/@redux/actions/series.ts | 6 ----- frontend/src/@redux/constants/index.ts | 2 -- frontend/src/@redux/hooks/index.ts | 26 ------------------- frontend/src/@redux/reducers/movie.ts | 8 ------ frontend/src/@redux/reducers/series.ts | 8 ------ frontend/src/@redux/utils/index.ts | 2 +- frontend/src/@redux/utils/mapper.ts | 20 +++----------- frontend/src/@socketio/reducer.ts | 20 +++++++++++--- .../src/components/tables/AsyncPageTable.tsx | 2 +- 10 files changed, 22 insertions(+), 78 deletions(-) diff --git a/frontend/src/@redux/actions/movie.ts b/frontend/src/@redux/actions/movie.ts index ce3797143..b76752cdc 100644 --- a/frontend/src/@redux/actions/movie.ts +++ b/frontend/src/@redux/actions/movie.ts @@ -1,10 +1,8 @@ -import { createAction } from "redux-actions"; import { createDeleteAction } from "../../@socketio/reducer"; import { MoviesApi } from "../../apis"; import { MOVIES_DELETE_ITEMS, MOVIES_DELETE_WANTED_ITEMS, - MOVIES_MARK_WANTED_LIST_DIRTY, MOVIES_UPDATE_BLACKLIST, MOVIES_UPDATE_HISTORY_LIST, MOVIES_UPDATE_LIST, @@ -28,10 +26,6 @@ export const movieDeleteWantedItems = createDeleteAction( MOVIES_DELETE_WANTED_ITEMS ); -export const movieMarkWantedListDirty = createAction( - MOVIES_MARK_WANTED_LIST_DIRTY -); - export const movieUpdateWantedByRange = createAsyncAction( MOVIES_UPDATE_WANTED_LIST, (start: number, length: number) => MoviesApi.wanted(start, length) diff --git a/frontend/src/@redux/actions/series.ts b/frontend/src/@redux/actions/series.ts index 9b7caef74..c53277469 100644 --- a/frontend/src/@redux/actions/series.ts +++ b/frontend/src/@redux/actions/series.ts @@ -1,11 +1,9 @@ -import { createAction } from "redux-actions"; import { createDeleteAction } from "../../@socketio/reducer"; import { EpisodesApi, SeriesApi } from "../../apis"; import { SERIES_DELETE_EPISODES, SERIES_DELETE_ITEMS, SERIES_DELETE_WANTED_ITEMS, - SERIES_MARK_WANTED_LIST_DIRTY, SERIES_UPDATE_BLACKLIST, SERIES_UPDATE_EPISODE_LIST, SERIES_UPDATE_HISTORY_LIST, @@ -23,10 +21,6 @@ export const seriesDeleteWantedItems = createDeleteAction( SERIES_DELETE_WANTED_ITEMS ); -export const seriesMarkWantedListDirty = createAction( - SERIES_MARK_WANTED_LIST_DIRTY -); - export const seriesUpdateWantedByRange = createAsyncAction( SERIES_UPDATE_WANTED_LIST, (start: number, length: number) => EpisodesApi.wanted(start, length) diff --git a/frontend/src/@redux/constants/index.ts b/frontend/src/@redux/constants/index.ts index b675297a5..a76476b1b 100644 --- a/frontend/src/@redux/constants/index.ts +++ b/frontend/src/@redux/constants/index.ts @@ -15,7 +15,6 @@ export const SYSTEM_UPDATE_PROVIDERS = "SYSTEM_UPDATE_PROVIDERS"; // Series action export const SERIES_UPDATE_WANTED_LIST = "UPDATE_SERIES_WANTED_LIST"; export const SERIES_DELETE_WANTED_ITEMS = "SERIES_DELETE_WANTED_ITEMS"; -export const SERIES_MARK_WANTED_LIST_DIRTY = "SERIES_MARK_WANTED_LIST_DIRTY"; export const SERIES_UPDATE_EPISODE_LIST = "UPDATE_SERIES_EPISODE_LIST"; export const SERIES_DELETE_EPISODES = "SERIES_DELETE_EPISODES"; export const SERIES_UPDATE_HISTORY_LIST = "UPDATE_SERIES_HISTORY_LIST"; @@ -26,7 +25,6 @@ export const SERIES_UPDATE_BLACKLIST = "UPDATE_SERIES_BLACKLIST"; // Movie action export const MOVIES_UPDATE_LIST = "UPDATE_MOVIE_LIST"; export const MOVIES_DELETE_ITEMS = "MOVIES_DELETE_ITEMS"; -export const MOVIES_MARK_WANTED_LIST_DIRTY = "MOVIES_MARK_WANTED_LIST_DIRTY"; export const MOVIES_UPDATE_WANTED_LIST = "UPDATE_MOVIE_WANTED_LIST"; export const MOVIES_DELETE_WANTED_ITEMS = "MOVIES_DELETE_WANTED_ITEMS"; export const MOVIES_UPDATE_HISTORY_LIST = "UPDATE_MOVIE_HISTORY_LIST"; diff --git a/frontend/src/@redux/hooks/index.ts b/frontend/src/@redux/hooks/index.ts index 364871a4f..ac15d5b21 100644 --- a/frontend/src/@redux/hooks/index.ts +++ b/frontend/src/@redux/hooks/index.ts @@ -5,13 +5,11 @@ import { episodeDeleteItems, episodeUpdateBy, episodeUpdateById, - movieDeleteWantedItems, movieUpdateBlacklist, movieUpdateHistoryList, movieUpdateList, movieUpdateWantedList, providerUpdateList, - seriesDeleteWantedItems, seriesUpdateBlacklist, seriesUpdateHistoryList, seriesUpdateList, @@ -324,18 +322,6 @@ export function useWantedSeries() { const update = useReduxAction(seriesUpdateWantedList); const items = useReduxStore((d) => d.series.wantedEpisodesList); - const updateAction = useWrapToOptionalId(update); - const deleteAction = useReduxAction(seriesDeleteWantedItems); - const reducer = useMemo( - () => ({ - key: "episode-wanted", - update: updateAction, - delete: deleteAction, - }), - [updateAction, deleteAction] - ); - useSocketIOReducer(reducer); - return stateBuilder(items, update); } @@ -343,18 +329,6 @@ export function useWantedMovies() { const update = useReduxAction(movieUpdateWantedList); const items = useReduxStore((d) => d.movie.wantedMovieList); - const updateAction = useWrapToOptionalId(update); - const deleteAction = useReduxAction(movieDeleteWantedItems); - const reducer = useMemo( - () => ({ - key: "movie-wanted", - update: updateAction, - delete: deleteAction, - }), - [updateAction, deleteAction] - ); - useSocketIOReducer(reducer); - return stateBuilder(items, update); } diff --git a/frontend/src/@redux/reducers/movie.ts b/frontend/src/@redux/reducers/movie.ts index 40c0a947f..2b7fe8df1 100644 --- a/frontend/src/@redux/reducers/movie.ts +++ b/frontend/src/@redux/reducers/movie.ts @@ -2,7 +2,6 @@ import { Action, handleActions } from "redux-actions"; import { MOVIES_DELETE_ITEMS, MOVIES_DELETE_WANTED_ITEMS, - MOVIES_MARK_WANTED_LIST_DIRTY, MOVIES_UPDATE_BLACKLIST, MOVIES_UPDATE_HISTORY_LIST, MOVIES_UPDATE_LIST, @@ -12,7 +11,6 @@ import { AsyncAction } from "../types"; import { defaultAOS } from "../utils"; import { deleteOrderListItemBy, - markOrderListDirty, updateAsyncState, updateOrderIdState, } from "../utils/mapper"; @@ -38,12 +36,6 @@ const reducer = handleActions( wantedMovieList: deleteOrderListItemBy(action, state.wantedMovieList), }; }, - [MOVIES_MARK_WANTED_LIST_DIRTY]: (state, action) => { - return { - ...state, - wantedMovieList: markOrderListDirty(state.wantedMovieList), - }; - }, [MOVIES_UPDATE_HISTORY_LIST]: ( state, action: AsyncAction diff --git a/frontend/src/@redux/reducers/series.ts b/frontend/src/@redux/reducers/series.ts index 8f72928ae..23ae4ecd6 100644 --- a/frontend/src/@redux/reducers/series.ts +++ b/frontend/src/@redux/reducers/series.ts @@ -3,7 +3,6 @@ import { SERIES_DELETE_EPISODES, SERIES_DELETE_ITEMS, SERIES_DELETE_WANTED_ITEMS, - SERIES_MARK_WANTED_LIST_DIRTY, SERIES_UPDATE_BLACKLIST, SERIES_UPDATE_EPISODE_LIST, SERIES_UPDATE_HISTORY_LIST, @@ -15,7 +14,6 @@ import { defaultAOS } from "../utils"; import { deleteAsyncListItemBy, deleteOrderListItemBy, - markOrderListDirty, updateAsyncList, updateAsyncState, updateOrderIdState, @@ -45,12 +43,6 @@ const reducer = handleActions( ), }; }, - [SERIES_MARK_WANTED_LIST_DIRTY]: (state, action) => { - return { - ...state, - wantedEpisodesList: markOrderListDirty(state.wantedEpisodesList), - }; - }, [SERIES_UPDATE_EPISODE_LIST]: ( state, action: AsyncAction diff --git a/frontend/src/@redux/utils/index.ts b/frontend/src/@redux/utils/index.ts index c269932da..e0e063f0d 100644 --- a/frontend/src/@redux/utils/index.ts +++ b/frontend/src/@redux/utils/index.ts @@ -4,7 +4,7 @@ export function defaultAOS(): AsyncOrderState { data: { items: [], order: [], - dirty: true, + dirty: false, }, }; } diff --git a/frontend/src/@redux/utils/mapper.ts b/frontend/src/@redux/utils/mapper.ts index 1236b2af9..772caa39a 100644 --- a/frontend/src/@redux/utils/mapper.ts +++ b/frontend/src/@redux/utils/mapper.ts @@ -36,7 +36,7 @@ export function updateOrderIdState( return { data: { ...state.data, - dirty: false, + dirty: true, }, updating: true, }; @@ -44,7 +44,7 @@ export function updateOrderIdState( return { data: { ...state.data, - dirty: false, + dirty: true, }, updating: false, error: action.payload.item as Error, @@ -107,7 +107,7 @@ export function updateOrderIdState( return { updating: false, data: { - dirty: false, + dirty: true, items: newItems, order: newOrder, }, @@ -131,25 +131,13 @@ export function deleteOrderListItemBy( return { ...state, data: { - dirty: false, + dirty: true, items: newItems, order: newOrder, }, }; } -export function markOrderListDirty( - state: AsyncOrderState -): AsyncOrderState { - return { - ...state, - data: { - ...state.data, - dirty: true, - }, - }; -} - export function deleteAsyncListItemBy( action: Action, state: AsyncState, diff --git a/frontend/src/@socketio/reducer.ts b/frontend/src/@socketio/reducer.ts index 4585592c3..5ea5fba94 100644 --- a/frontend/src/@socketio/reducer.ts +++ b/frontend/src/@socketio/reducer.ts @@ -3,11 +3,13 @@ import { badgeUpdateAll, bootstrap, movieDeleteItems, - movieMarkWantedListDirty, + movieDeleteWantedItems, movieUpdateList, + movieUpdateWantedList, seriesDeleteItems, - seriesMarkWantedListDirty, + seriesDeleteWantedItems, seriesUpdateList, + seriesUpdateWantedList, siteAddNotifications, siteAddProgress, siteInitializationFailed, @@ -95,11 +97,21 @@ export function createDefaultReducer(): SocketIO.Reducer[] { }, { key: "episode-wanted", - any: bindToReduxStore(seriesMarkWantedListDirty), + update: (ids: number[] | undefined) => { + if (ids) { + reduxStore.dispatch(seriesUpdateWantedList(ids) as any); + } + }, + delete: bindToReduxStore(seriesDeleteWantedItems), }, { key: "movie-wanted", - any: bindToReduxStore(movieMarkWantedListDirty), + update: (ids: number[] | undefined) => { + if (ids) { + reduxStore.dispatch(movieUpdateWantedList(ids) as any); + } + }, + delete: bindToReduxStore(movieDeleteWantedItems), }, { key: "settings", diff --git a/frontend/src/components/tables/AsyncPageTable.tsx b/frontend/src/components/tables/AsyncPageTable.tsx index 2af0809dc..54bb969c9 100644 --- a/frontend/src/components/tables/AsyncPageTable.tsx +++ b/frontend/src/components/tables/AsyncPageTable.tsx @@ -85,7 +85,7 @@ export default function AsyncPageTable(props: Props) { }, [pageIndex]); useEffect(() => { - const needFetch = visibleItemIds.length === 0 || dirty === true; + const needFetch = visibleItemIds.length === 0 && dirty === false; const needRefresh = !visibleItemIds.every(isNonNullable); if (needFetch || needRefresh) { loader(pageStart, pageSize); From d77d6875323718cc9a835e9b55e695ae326959a6 Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Wed, 28 Jul 2021 22:43:58 +0800 Subject: [PATCH 18/42] no log: Remove @types/react-redux --- frontend/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 680c2fa26..f1cb8d833 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,6 @@ "@types/react": "^16", "@types/react-dom": "^16", "@types/react-helmet": "^6.1", - "@types/react-redux": "^7", "@types/react-router-dom": "^5", "@types/react-select": "^4.0.3", "@types/react-table": "^7", From 1d20bbb4b9d83a583d4950c94829733d8d0a4267 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 28 Jul 2021 16:03:29 -0400 Subject: [PATCH 19/42] Fixed settings saving not completing properly when the SignalR client didn't start properly. #1474 --- bazarr/config.py | 10 ++++++++-- frontend/package-lock.json | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bazarr/config.py b/bazarr/config.py index e076ea3b8..910497cf5 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -442,11 +442,17 @@ def save_settings(settings_items): if sonarr_changed: from signalr_client import sonarr_signalr_client - sonarr_signalr_client.restart() + try: + sonarr_signalr_client.restart() + except: + pass if radarr_changed: from signalr_client import radarr_signalr_client - radarr_signalr_client.restart() + try: + radarr_signalr_client.restart() + except: + pass if update_path_map: from helper import path_mappings diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7b54090f1..fab73197e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -21,7 +21,6 @@ "@types/react": "^16", "@types/react-dom": "^16", "@types/react-helmet": "^6.1", - "@types/react-redux": "^7", "@types/react-router-dom": "^5", "@types/react-select": "^4.0.3", "@types/react-table": "^7", From 33a600a714474495a58fdf038d7a636c0e339c44 Mon Sep 17 00:00:00 2001 From: dtcabrerizo <31369951+dtcabrerizo@users.noreply.github.com> Date: Fri, 30 Jul 2021 08:34:57 -0300 Subject: [PATCH 20/42] Added settings to download only featured subtitles for LegendasTV --- .github/scripts/build_test.sh | 15 ++++++ .github/workflows/test_bazarr_execution.yml | 49 +++++++++++++++++++ bazarr/config.py | 3 +- bazarr/get_providers.py | 3 ++ frontend/package.json | 2 +- frontend/src/@types/settings.d.ts | 4 +- frontend/src/Settings/Providers/list.ts | 4 ++ libs/subliminal_patch/providers/legendastv.py | 8 ++- 8 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 .github/scripts/build_test.sh create mode 100644 .github/workflows/test_bazarr_execution.yml diff --git a/.github/scripts/build_test.sh b/.github/scripts/build_test.sh new file mode 100644 index 000000000..4e9287fb1 --- /dev/null +++ b/.github/scripts/build_test.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +python3 "${ROOT_DIRECTORY}"/bazarr.py & +PID=$! + +sleep 30 + +if kill -s 0 $PID +then + echo "Bazarr is still running. We'll kill it..." + kill $PID + exit 0 +else + exit 1 +fi \ No newline at end of file diff --git a/.github/workflows/test_bazarr_execution.yml b/.github/workflows/test_bazarr_execution.yml new file mode 100644 index 000000000..43aedb859 --- /dev/null +++ b/.github/workflows/test_bazarr_execution.yml @@ -0,0 +1,49 @@ +name: test_bazarr_execution +on: workflow_dispatch + +jobs: + Test: + runs-on: ubuntu-latest + env: + ROOT_DIRECTORY: . + SCRIPTS_DIRECTORY: .github/scripts + FETCH_DEPTH: 15 # Should be enough + steps: + - name: Validate branch + if: ${{ github.ref != 'refs/heads/development' }} + run: | + echo This action can only be run on development branch, not ${{ github.ref }} + exit 1 + + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: ${{ env.FETCH_DEPTH }} + ref: development + + - name: Setup NodeJS + uses: actions/setup-node@v2 + with: + node-version: "15.x" + + - name: Install UI Dependencies + run: npm install + working-directory: ${{ env.UI_DIRECTORY }} + + - name: Build UI + run: npm run build + working-directory: ${{ env.UI_DIRECTORY }} + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install -r '${{ env.ROOT_DIRECTORY }}/requirements.txt' + + - name: Test Bazarr execution + run: | + bash '${{ env.SCRIPTS_DIRECTORY }}/build_test.sh' diff --git a/bazarr/config.py b/bazarr/config.py index 910497cf5..249204b40 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -139,7 +139,8 @@ defaults = { }, 'legendastv': { 'username': '', - 'password': '' + 'password': '', + 'featured_only': 'False' }, 'xsubs': { 'username': '', diff --git a/bazarr/get_providers.py b/bazarr/get_providers.py index e0fd0293b..497ce4526 100644 --- a/bazarr/get_providers.py +++ b/bazarr/get_providers.py @@ -164,6 +164,9 @@ def get_providers_auth(): 'legendastv' : { 'username': settings.legendastv.username, 'password': settings.legendastv.password, + 'featured_only': settings.legendastv.getboolean( + 'featured_only' + ), }, 'xsubs' : { 'username': settings.xsubs.username, diff --git a/frontend/package.json b/frontend/package.json index f1cb8d833..4cfa61e23 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "bazarr", - "version": "1", + "version": "1.0.0", "description": "Bazarr is a companion application to Sonarr and Radarr. It manages and downloads subtitles based on your requirements. You define your preferences by TV show or movie and Bazarr takes care of everything for you.", "repository": { "type": "git", diff --git a/frontend/src/@types/settings.d.ts b/frontend/src/@types/settings.d.ts index bc93bd607..6a6e326d7 100644 --- a/frontend/src/@types/settings.d.ts +++ b/frontend/src/@types/settings.d.ts @@ -181,7 +181,9 @@ namespace Settings { skip_wrong_fps: boolean; } - interface Legendastv extends BaseProvider {} + interface Legendastv extends BaseProvider { + featured_only: boolean; + } interface XSubs extends BaseProvider {} diff --git a/frontend/src/Settings/Providers/list.ts b/frontend/src/Settings/Providers/list.ts index 2d3357687..29d359741 100644 --- a/frontend/src/Settings/Providers/list.ts +++ b/frontend/src/Settings/Providers/list.ts @@ -77,6 +77,10 @@ export const ProviderList: Readonly = [ defaultKey: { username: "", password: "", + featured_only: false, + }, + keyNameOverride: { + featured_only: "Only Download Featured", }, }, { key: "napiprojekt", description: "Polish Subtitles Provider" }, diff --git a/libs/subliminal_patch/providers/legendastv.py b/libs/subliminal_patch/providers/legendastv.py index 97a76a4b1..43db667a7 100644 --- a/libs/subliminal_patch/providers/legendastv.py +++ b/libs/subliminal_patch/providers/legendastv.py @@ -70,7 +70,7 @@ class LegendasTVProvider(_LegendasTVProvider): languages = {Language(*l) for l in language_converters['legendastv'].to_legendastv.keys()} subtitle_class = LegendasTVSubtitle - def __init__(self, username=None, password=None): + def __init__(self, username=None, password=None, featured_only=False): # Provider needs UNRAR installed. If not available raise ConfigurationError try: @@ -85,6 +85,7 @@ class LegendasTVProvider(_LegendasTVProvider): self.password = password self.logged_in = False self.session = None + self.featured_only = featured_only @staticmethod def is_valid_title(title, title_id, sanitized_title, season, year, imdb_id): @@ -209,6 +210,11 @@ class LegendasTVProvider(_LegendasTVProvider): # iterate over title's archives for a in archives: + # Check if featured + if self.featured_only and a.featured == False: + logger.info('Subtitle is not featured, skipping') + continue + # compute an expiration time based on the archive timestamp expiration_time = (datetime.utcnow().replace(tzinfo=pytz.utc) - a.timestamp).total_seconds() From 9803a1f75616bb9b72f16d4290715ab391a0cc3f Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 31 Jul 2021 06:16:14 +0000 Subject: [PATCH 21/42] Release 0.9.7-beta.7 --- .github/scripts/build_test.sh | 0 frontend/package-lock.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 .github/scripts/build_test.sh diff --git a/.github/scripts/build_test.sh b/.github/scripts/build_test.sh old mode 100644 new mode 100755 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fab73197e..51c9181d6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "bazarr", - "version": "1", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bazarr", - "version": "1", + "version": "1.0.0", "license": "GPL-3", "dependencies": { "@fontsource/roboto": "^4.2.2", From 360e0cfea19a2d1a285ec42dbbd733fde55ddaf6 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 1 Aug 2021 10:36:45 -0400 Subject: [PATCH 22/42] Fixed root folders check health functions to use the proper path separator. --- bazarr/get_rootfolder.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/bazarr/get_rootfolder.py b/bazarr/get_rootfolder.py index 7027c900f..c7d7770ec 100644 --- a/bazarr/get_rootfolder.py +++ b/bazarr/get_rootfolder.py @@ -63,8 +63,11 @@ def check_sonarr_rootfolder(): rootfolder = TableShowsRootfolder.select(TableShowsRootfolder.id, TableShowsRootfolder.path).dicts() for item in rootfolder: root_path = item['path'] - if not root_path.endswith(os.path.sep): - root_path += os.path.sep + if not root_path.endswith(('/', '\\')): + if root_path.startswith('/'): + root_path += '/' + else: + root_path += '\\' if not os.path.isdir(path_mappings.path_replace(root_path)): TableShowsRootfolder.update({TableShowsRootfolder.accessible: 0, TableShowsRootfolder.error: 'This Sonarr root directory does not seems to ' @@ -134,8 +137,11 @@ def check_radarr_rootfolder(): rootfolder = TableMoviesRootfolder.select(TableMoviesRootfolder.id, TableMoviesRootfolder.path).dicts() for item in rootfolder: root_path = item['path'] - if not root_path.endswith(os.path.sep): - root_path += os.path.sep + if not root_path.endswith(('/', '\\')): + if root_path.startswith('/'): + root_path += '/' + else: + root_path += '\\' if not os.path.isdir(path_mappings.path_replace_movie(root_path)): TableMoviesRootfolder.update({TableMoviesRootfolder.accessible: 0, TableMoviesRootfolder.error: 'This Radarr root directory does not seems to ' From 9372c0b821c25030359a94ca4d05269195634886 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 1 Aug 2021 20:31:36 -0400 Subject: [PATCH 23/42] Fixed subtitles sync issues when sync debug is enable. --- bazarr/subsyncer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bazarr/subsyncer.py b/bazarr/subsyncer.py index daeff09e2..4a523c18d 100644 --- a/bazarr/subsyncer.py +++ b/bazarr/subsyncer.py @@ -58,6 +58,8 @@ class SubSyncer: logging.exception('BAZARR an exception occurs during the synchronization process for this subtitles: ' '{0}'.format(self.srtin)) else: + if settings.subsync.getboolean('debug'): + return result if os.path.isfile(self.srtout): if not settings.subsync.getboolean('debug'): os.remove(self.srtin) From 638d0a8c6857eb302c75d066ebcdf9353e745c11 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Tue, 3 Aug 2021 15:55:55 -0400 Subject: [PATCH 24/42] Added a leftover cleanup function to be run after an upgrade. --- bazarr/check_update.py | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index 699342842..b3c7fbd87 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -1,6 +1,8 @@ # coding=utf-8 import os +import shutil +import re import logging import json import requests @@ -151,6 +153,14 @@ def apply_update(): logging.exception('BAZARR unable to unzip release') else: is_updated = True + try: + logging.debug('BAZARR successfully unzipped new release and will now try to delete the leftover ' + 'files.') + update_cleaner(zipfile=bazarr_zip, bazarr_dir=bazarr_dir, config_dir=args.config_dir) + except: + logging.exception('BAZARR unable to cleanup leftover files after upgrade.') + else: + logging.debug('BAZARR successfully deleted leftover files.') finally: logging.debug('BAZARR now deleting release archive') os.remove(bazarr_zip) @@ -161,3 +171,50 @@ def apply_update(): logging.debug('BAZARR new release have been installed, now we restart') from server import webserver webserver.restart() + + +def update_cleaner(zipfile, bazarr_dir, config_dir): + with ZipFile(zipfile, 'r') as archive: + file_in_zip = archive.namelist() + + dir_to_ignore = ['^.' + os.path.sep, + '^bin' + os.path.sep, + '^venv' + os.path.sep, + os.path.sep + '__pycache__' + os.path.sep + '$'] + if os.path.abspath(bazarr_dir) in os.path.abspath(config_dir): + dir_to_ignore.append('^' + os.path.relpath(config_dir, bazarr_dir) + os.path.sep) + dir_to_ignore_regex = re.compile('(?:% s)' % '|'.join(dir_to_ignore)) + extension_to_ignore = ['.pyc'] + + file_on_disk = [] + folder_list = [] + for foldername, subfolders, filenames in os.walk(bazarr_dir): + relative_foldername = os.path.relpath(foldername, bazarr_dir) + os.path.sep + + if not dir_to_ignore_regex.findall(relative_foldername): + if relative_foldername not in folder_list: + folder_list.append(relative_foldername) + + for file in filenames: + if os.path.splitext(file)[1] in extension_to_ignore: + continue + elif foldername == bazarr_dir: + file_on_disk.append(file) + else: + current_dir = relative_foldername + filepath = os.path.join(current_dir, file) + if not dir_to_ignore_regex.findall(filepath): + file_on_disk.append(filepath) + file_on_disk += folder_list + + file_to_remove = list(set(file_on_disk) - set(file_in_zip)) + + for file in file_to_remove: + filepath = os.path.join(bazarr_dir, file) + try: + if os.path.isdir(filepath): + shutil.rmtree(filepath, ignore_errors=True) + else: + os.remove(filepath) + except: + pass From bf037f1573ad7f991d5b4d949726b7d5b4ec305c Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Tue, 3 Aug 2021 16:32:53 -0400 Subject: [PATCH 25/42] Added plex webhooks endpoint to API to search for subtitles on media.play and media.resume events. --- bazarr/api.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/bazarr/api.py b/bazarr/api.py index ee78227ab..4d9ec796b 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -17,6 +17,8 @@ import hashlib import apprise import gc from peewee import fn, Value +import requests +from bs4 import BeautifulSoup as bso from get_args import args from config import settings, base_url, save_settings, get_settings @@ -2064,6 +2066,68 @@ class BrowseRadarrFS(Resource): return jsonify(data) +class WebHooksPlex(Resource): + @authenticate + def post(self): + json_webhook = request.form.get('payload') + parsed_json_webhook = json.loads(json_webhook) + + event = parsed_json_webhook['event'] + if event not in ['media.play', 'media.resume']: + return '', 204 + + media_type = parsed_json_webhook['Metadata']['type'] + + if media_type == 'episode': + season = parsed_json_webhook['Metadata']['parentIndex'] + episode = parsed_json_webhook['Metadata']['index'] + else: + season = episode = None + + ids = [] + for item in parsed_json_webhook['Metadata']['Guid']: + splitted_id = item['id'].split('://') + if len(splitted_id) == 2: + ids.append({splitted_id[0]: splitted_id[1]}) + if not ids: + return '', 404 + + if media_type == 'episode': + try: + episode_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0] + r = requests.get('https://imdb.com/title/{}'.format(episode_imdb_id), + headers={"User-Agent": os.environ["SZ_USER_AGENT"]}) + soup = bso(r.content, "html.parser") + series_imdb_id = soup.find('a', {'class': re.compile(r'SeriesParentLink__ParentTextLink')})['href'].split('/')[2] + except: + return '', 404 + else: + sonarrEpisodeId = TableEpisodes.select(TableEpisodes.sonarrEpisodeId) \ + .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId)) \ + .where(TableShows.imdbId == series_imdb_id, + TableEpisodes.season == season, + TableEpisodes.episode == episode) \ + .dicts() \ + .get() + + if sonarrEpisodeId: + episode_download_subtitles(no=sonarrEpisodeId['sonarrEpisodeId']) + else: + try: + movie_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0] + except: + return '', 404 + else: + radarrId = TableMovies.select(TableMovies.radarrId)\ + .where(TableMovies.imdbId == movie_imdb_id)\ + .dicts()\ + .get() + if radarrId: + movies_download_subtitles(no=radarrId['radarrId']) + + return '', 200 + + api.add_resource(Badges, '/badges') api.add_resource(Providers, '/providers') @@ -2105,3 +2169,5 @@ api.add_resource(HistoryStats, '/history/stats') api.add_resource(BrowseBazarrFS, '/files') api.add_resource(BrowseSonarrFS, '/files/sonarr') api.add_resource(BrowseRadarrFS, '/files/radarr') + +api.add_resource(WebHooksPlex, '/webhooks/plex') From 842dbf08275b6c6218d29ca1cedb90a5eaca9443 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 4 Aug 2021 15:29:37 -0400 Subject: [PATCH 26/42] Improved how Bazarr get Sonarr/Radarr version to use caching and reduce the number of calls made to their respective API. --- bazarr/analytics.py | 6 +- bazarr/api.py | 6 +- bazarr/filesystem.py | 8 +- bazarr/get_episodes.py | 28 +++---- bazarr/get_movies.py | 50 ++++++------- bazarr/get_rootfolder.py | 8 +- bazarr/get_series.py | 42 +++++------ bazarr/main.py | 8 +- bazarr/signalr_client.py | 7 +- bazarr/utils.py | 153 +++++++++++++++++++++------------------ 10 files changed, 153 insertions(+), 163 deletions(-) diff --git a/bazarr/analytics.py b/bazarr/analytics.py index 59947f1ec..b8df668b7 100644 --- a/bazarr/analytics.py +++ b/bazarr/analytics.py @@ -12,10 +12,10 @@ from pyga.entities import CustomVariable from get_args import args from config import settings -from utils import get_sonarr_version, get_radarr_version +from utils import get_sonarr_info, get_radarr_info -sonarr_version = get_sonarr_version() -radarr_version = get_radarr_version() +sonarr_version = get_sonarr_info.version() +radarr_version = get_radarr_info.version() def track_event(category=None, action=None, label=None): diff --git a/bazarr/api.py b/bazarr/api.py index 4d9ec796b..04df0b11b 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -39,7 +39,7 @@ from notifier import send_notifications, send_notifications_movie from list_subtitles import store_subtitles, store_subtitles_movie, series_scan_subtitles, movies_scan_subtitles, \ list_missing_subtitles, list_missing_subtitles_movies from utils import history_log, history_log_movie, blacklist_log, blacklist_delete, blacklist_delete_all, \ - blacklist_log_movie, blacklist_delete_movie, blacklist_delete_all_movie, get_sonarr_version, get_radarr_version, \ + blacklist_log_movie, blacklist_delete_movie, blacklist_delete_all_movie, get_sonarr_info, get_radarr_info, \ delete_subtitles, subtitles_apply_mods, translate_subtitles_file, check_credentials, get_health_issues from get_providers import get_providers, get_providers_auth, list_throttled_providers, reset_throttled_providers, \ get_throttled_providers, set_throttled_providers @@ -600,8 +600,8 @@ class SystemStatus(Resource): def get(self): system_status = {} system_status.update({'bazarr_version': os.environ["BAZARR_VERSION"]}) - system_status.update({'sonarr_version': get_sonarr_version()}) - system_status.update({'radarr_version': get_radarr_version()}) + system_status.update({'sonarr_version': get_sonarr_info.version()}) + system_status.update({'radarr_version': get_radarr_info.version()}) system_status.update({'operating_system': platform.platform()}) system_status.update({'python_version': platform.python_version()}) system_status.update({'bazarr_directory': os.path.dirname(os.path.dirname(__file__))}) diff --git a/bazarr/filesystem.py b/bazarr/filesystem.py index 1c439afc0..db6ccc782 100644 --- a/bazarr/filesystem.py +++ b/bazarr/filesystem.py @@ -6,7 +6,7 @@ import logging import string from config import settings, url_sonarr, url_radarr -from utils import get_sonarr_version, get_radarr_version +from utils import get_sonarr_info, get_radarr_info headers = {"User-Agent": os.environ["SZ_USER_AGENT"]} @@ -46,10 +46,9 @@ def browse_bazarr_filesystem(path='#'): def browse_sonarr_filesystem(path='#'): - sonarr_version = get_sonarr_version() if path == '#': path = '' - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url_sonarr_api_filesystem = url_sonarr() + "/api/filesystem?path=" + path + \ "&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \ settings.sonarr.apikey @@ -77,11 +76,10 @@ def browse_sonarr_filesystem(path='#'): def browse_radarr_filesystem(path='#'): - radarr_version = get_radarr_version() if path == '#': path = '' - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): url_radarr_api_filesystem = url_radarr() + "/api/filesystem?path=" + path + \ "&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \ settings.radarr.apikey diff --git a/bazarr/get_episodes.py b/bazarr/get_episodes.py index d5328f346..f26c2f545 100644 --- a/bazarr/get_episodes.py +++ b/bazarr/get_episodes.py @@ -12,7 +12,7 @@ from helper import path_mappings from list_subtitles import store_subtitles, series_full_scan_subtitles from get_subtitle import episode_download_subtitles from event_handler import event_stream, show_progress, hide_progress -from utils import get_sonarr_version +from utils import get_sonarr_info headers = {"User-Agent": os.environ["SZ_USER_AGENT"]} @@ -25,7 +25,6 @@ def update_all_episodes(): def sync_episodes(series_id=None, send_event=True): logging.debug('BAZARR Starting episodes sync from Sonarr.') apikey_sonarr = settings.sonarr.apikey - sonarr_version = get_sonarr_version() # Get current episodes id in DB current_episodes_db = TableEpisodes.select(TableEpisodes.sonarrEpisodeId, @@ -42,8 +41,7 @@ def sync_episodes(series_id=None, send_event=True): altered_episodes = [] # Get sonarrId for each series from database - seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr, - sonarr_version=sonarr_version) + seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr,) series_count = len(seriesIdList) for i, seriesId in enumerate(seriesIdList, 1): @@ -57,13 +55,12 @@ def sync_episodes(series_id=None, send_event=True): # Get episodes data for a series from Sonarr episodes = get_episodes_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr, - series_id=seriesId['sonarrSeriesId'], - sonarr_version=sonarr_version) + series_id=seriesId['sonarrSeriesId']) if not episodes: continue else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results - if not sonarr_version.startswith(('0.', '2.')): + if not get_sonarr_info.is_legacy(): episodeFiles = get_episodesFiles_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr, series_id=seriesId['sonarrSeriesId']) for episode in episodes: @@ -166,7 +163,6 @@ def sync_one_episode(episode_id): logging.debug('BAZARR syncing this specific episode from Sonarr: {}'.format(episode_id)) url = url_sonarr() apikey_sonarr = settings.sonarr.apikey - sonarr_version = get_sonarr_version() # Check if there's a row in database for this episode ID try: @@ -181,13 +177,13 @@ def sync_one_episode(episode_id): # Get episode data from sonarr api episode = None episode_data = get_episodes_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr, - episode_id=episode_id, sonarr_version=sonarr_version) + episode_id=episode_id) if not episode_data: return else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results - if not sonarr_version.startswith(('0.', '2.')): + if not get_sonarr_info.is_legacy(): episodeFile = get_episodesFiles_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr, episode_file_id=existing_episode['episode_file_id']) if episode_data['hasFile']: @@ -336,13 +332,13 @@ def episodeParser(episode): 'file_size': episode['episodeFile']['size']} -def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version): +def get_series_from_sonarr_api(series_id, url, apikey_sonarr): if series_id: url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format( - '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', series_id, apikey_sonarr) + '' if get_sonarr_info.is_legacy() else 'v3/', series_id, apikey_sonarr) else: url_sonarr_api_series = url + "/api/{0}series?apikey={1}".format( - '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', apikey_sonarr) + '' if get_sonarr_info.is_legacy() else 'v3/', apikey_sonarr) try: r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers) r.raise_for_status() @@ -372,13 +368,13 @@ def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version): return series_list -def get_episodes_from_sonarr_api(url, apikey_sonarr, sonarr_version, series_id=None, episode_id=None): +def get_episodes_from_sonarr_api(url, apikey_sonarr, series_id=None, episode_id=None): if series_id: url_sonarr_api_episode = url + "/api/{0}episode?seriesId={1}&apikey={2}".format( - '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', series_id, apikey_sonarr) + '' if get_sonarr_info.is_legacy() else 'v3/', series_id, apikey_sonarr) elif episode_id: url_sonarr_api_episode = url + "/api/{0}episode/{1}?apikey={2}".format( - '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', episode_id, apikey_sonarr) + '' if get_sonarr_info.is_legacy() else 'v3/', episode_id, apikey_sonarr) else: return diff --git a/bazarr/get_movies.py b/bazarr/get_movies.py index 1aeeb5c54..322a948a5 100644 --- a/bazarr/get_movies.py +++ b/bazarr/get_movies.py @@ -10,7 +10,7 @@ from peewee import DoesNotExist from config import settings, url_radarr from helper import path_mappings -from utils import get_radarr_version +from utils import get_radarr_info from list_subtitles import store_subtitles_movie, movies_full_scan_subtitles from get_rootfolder import check_radarr_rootfolder @@ -31,7 +31,6 @@ def update_movies(send_event=True): logging.debug('BAZARR Starting movie sync from Radarr.') apikey_radarr = settings.radarr.apikey - radarr_version = get_radarr_version() movie_default_enabled = settings.general.getboolean('movie_default_enabled') if movie_default_enabled is True: @@ -45,11 +44,10 @@ def update_movies(send_event=True): pass else: audio_profiles = get_profile_list() - tagsDict = get_tags(radarr_version=radarr_version) + tagsDict = get_tags() # Get movies data from radarr - movies = get_movies_from_radarr_api(radarr_version=radarr_version, url=url_radarr(), - apikey_radarr=apikey_radarr) + movies = get_movies_from_radarr_api(url=url_radarr(), apikey_radarr=apikey_radarr) if not movies: return else: @@ -82,13 +80,11 @@ def update_movies(send_event=True): if str(movie['tmdbId']) in current_movies_db_list: movies_to_update.append(movieParser(movie, action='update', - radarr_version=radarr_version, tags_dict=tagsDict, movie_default_profile=movie_default_profile, audio_profiles=audio_profiles)) else: movies_to_add.append(movieParser(movie, action='insert', - radarr_version=radarr_version, tags_dict=tagsDict, movie_default_profile=movie_default_profile, audio_profiles=audio_profiles)) @@ -190,7 +186,6 @@ def update_one_movie(movie_id, action): existing_movie['path']))) return - radarr_version = get_radarr_version() movie_default_enabled = settings.general.getboolean('movie_default_enabled') if movie_default_enabled is True: @@ -201,24 +196,22 @@ def update_one_movie(movie_id, action): movie_default_profile = None audio_profiles = get_profile_list() - tagsDict = get_tags(radarr_version=radarr_version) + tagsDict = get_tags() try: # Get movie data from radarr api movie = None - movie_data = get_movies_from_radarr_api(radarr_version=radarr_version, url=url_radarr(), - apikey_radarr=settings.radarr.apikey, radarr_id=movie_id) + movie_data = get_movies_from_radarr_api(url=url_radarr(), apikey_radarr=settings.radarr.apikey, + radarr_id=movie_id) if not movie_data: return else: if action == 'updated' and existing_movie: - movie = movieParser(movie_data, action='update', radarr_version=radarr_version, - tags_dict=tagsDict, movie_default_profile=movie_default_profile, - audio_profiles=audio_profiles) + movie = movieParser(movie_data, action='update', tags_dict=tagsDict, + movie_default_profile=movie_default_profile, audio_profiles=audio_profiles) elif action == 'updated' and not existing_movie: - movie = movieParser(movie_data, action='insert', radarr_version=radarr_version, - tags_dict=tagsDict, movie_default_profile=movie_default_profile, - audio_profiles=audio_profiles) + movie = movieParser(movie_data, action='insert', tags_dict=tagsDict, + movie_default_profile=movie_default_profile, audio_profiles=audio_profiles) except Exception: logging.debug('BAZARR cannot get movie returned by SignalR feed from Radarr API.') return @@ -262,10 +255,9 @@ def update_one_movie(movie_id, action): def get_profile_list(): apikey_radarr = settings.radarr.apikey - radarr_version = get_radarr_version() profiles_list = [] # Get profiles data from radarr - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): url_radarr_api_movies = url_radarr() + "/api/profile?apikey=" + apikey_radarr else: url_radarr_api_movies = url_radarr() + "/api/v3/qualityprofile?apikey=" + apikey_radarr @@ -280,7 +272,7 @@ def get_profile_list(): logging.exception("BAZARR Error trying to get profiles from Radarr.") else: # Parsing data returned from radarr - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): for profile in profiles_json.json(): profiles_list.append([profile['id'], profile['language'].capitalize()]) else: @@ -346,12 +338,12 @@ def RadarrFormatVideoCodec(videoFormat, videoCodecID, videoCodecLibrary): return videoFormat -def get_tags(radarr_version): +def get_tags(): apikey_radarr = settings.radarr.apikey tagsDict = [] # Get tags data from Radarr - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): url_radarr_api_series = url_radarr() + "/api/tag?apikey=" + apikey_radarr else: url_radarr_api_series = url_radarr() + "/api/v3/tag?apikey=" + apikey_radarr @@ -371,7 +363,7 @@ def get_tags(radarr_version): return tagsDict.json() -def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, audio_profiles): +def movieParser(movie, action, tags_dict, movie_default_profile, audio_profiles): if 'movieFile' in movie: # Detect file separator if movie['path'][0] == "/": @@ -399,7 +391,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, sceneName = None alternativeTitles = None - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): if 'alternativeTitles' in movie: alternativeTitles = str([item['title'] for item in movie['alternativeTitles']]) else: @@ -422,7 +414,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, if 'mediaInfo' in movie['movieFile']: videoFormat = videoCodecID = videoProfile = videoCodecLibrary = None - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): if 'videoFormat' in movie['movieFile']['mediaInfo']: videoFormat = \ movie['movieFile']['mediaInfo']['videoFormat'] else: @@ -437,7 +429,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, videoCodec = RadarrFormatVideoCodec(videoFormat, videoCodecID, videoCodecLibrary) audioFormat = audioCodecID = audioProfile = audioAdditionalFeatures = None - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): if 'audioFormat' in movie['movieFile']['mediaInfo']: audioFormat = \ movie['movieFile']['mediaInfo']['audioFormat'] else: @@ -456,7 +448,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, audioCodec = None audio_language = [] - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): if 'mediaInfo' in movie['movieFile']: if 'audioLanguages' in movie['movieFile']['mediaInfo']: audio_languages_list = movie['movieFile']['mediaInfo']['audioLanguages'].split('/') @@ -522,8 +514,8 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, 'file_size': movie['movieFile']['size']} -def get_movies_from_radarr_api(radarr_version, url, apikey_radarr, radarr_id=None): - if radarr_version.startswith('0'): +def get_movies_from_radarr_api(url, apikey_radarr, radarr_id=None): + if get_radarr_info.is_legacy(): url_radarr_api_movies = url + "/api/movie" + ("/{}".format(radarr_id) if radarr_id else "") + "?apikey=" + \ apikey_radarr else: diff --git a/bazarr/get_rootfolder.py b/bazarr/get_rootfolder.py index c7d7770ec..fb33e0d85 100644 --- a/bazarr/get_rootfolder.py +++ b/bazarr/get_rootfolder.py @@ -7,7 +7,7 @@ import logging from config import settings, url_sonarr, url_radarr from helper import path_mappings from database import TableShowsRootfolder, TableMoviesRootfolder, TableShows, TableMovies -from utils import get_sonarr_version, get_radarr_version +from utils import get_sonarr_info, get_radarr_info headers = {"User-Agent": os.environ["SZ_USER_AGENT"]} @@ -15,10 +15,9 @@ headers = {"User-Agent": os.environ["SZ_USER_AGENT"]} def get_sonarr_rootfolder(): apikey_sonarr = settings.sonarr.apikey sonarr_rootfolder = [] - sonarr_version = get_sonarr_version() # Get root folder data from Sonarr - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url_sonarr_api_rootfolder = url_sonarr() + "/api/rootfolder?apikey=" + apikey_sonarr else: url_sonarr_api_rootfolder = url_sonarr() + "/api/v3/rootfolder?apikey=" + apikey_sonarr @@ -90,10 +89,9 @@ def check_sonarr_rootfolder(): def get_radarr_rootfolder(): apikey_radarr = settings.radarr.apikey radarr_rootfolder = [] - radarr_version = get_radarr_version() # Get root folder data from Radarr - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): url_radarr_api_rootfolder = url_radarr() + "/api/rootfolder?apikey=" + apikey_radarr else: url_radarr_api_rootfolder = url_radarr() + "/api/v3/rootfolder?apikey=" + apikey_radarr diff --git a/bazarr/get_series.py b/bazarr/get_series.py index 45c68d6ee..0f3165dfa 100644 --- a/bazarr/get_series.py +++ b/bazarr/get_series.py @@ -11,7 +11,7 @@ from list_subtitles import list_missing_subtitles from get_rootfolder import check_sonarr_rootfolder from database import TableShows, TableEpisodes from get_episodes import sync_episodes -from utils import get_sonarr_version +from utils import get_sonarr_info from helper import path_mappings from event_handler import event_stream, show_progress, hide_progress @@ -24,7 +24,6 @@ def update_series(send_event=True): if apikey_sonarr is None: return - sonarr_version = get_sonarr_version() serie_default_enabled = settings.general.getboolean('serie_default_enabled') if serie_default_enabled is True: @@ -38,8 +37,7 @@ def update_series(send_event=True): tagsDict = get_tags() # Get shows data from Sonarr - series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr, - sonarr_version=sonarr_version) + series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr) if not series: return else: @@ -65,12 +63,12 @@ def update_series(send_event=True): current_shows_sonarr.append(show['id']) if show['id'] in current_shows_db_list: - series_to_update.append(seriesParser(show, action='update', sonarr_version=sonarr_version, - tags_dict=tagsDict, serie_default_profile=serie_default_profile, + series_to_update.append(seriesParser(show, action='update', tags_dict=tagsDict, + serie_default_profile=serie_default_profile, audio_profiles=audio_profiles)) else: - series_to_add.append(seriesParser(show, action='insert', sonarr_version=sonarr_version, - tags_dict=tagsDict, serie_default_profile=serie_default_profile, + series_to_add.append(seriesParser(show, action='insert', tags_dict=tagsDict, + serie_default_profile=serie_default_profile, audio_profiles=audio_profiles)) if send_event: @@ -155,7 +153,6 @@ def update_one_series(series_id, action): event_stream(type='series', action='delete', payload=int(series_id)) return - sonarr_version = get_sonarr_version() serie_default_enabled = settings.general.getboolean('serie_default_enabled') if serie_default_enabled is True: @@ -173,18 +170,19 @@ def update_one_series(series_id, action): series = None series_data = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=settings.sonarr.apikey, - sonarr_series_id=int(series_id), sonarr_version=get_sonarr_version()) + sonarr_series_id=int(series_id), + sonarr_version=get_sonarr_info.version()) if not series_data: return else: if action == 'updated' and existing_series: - series = seriesParser(series_data, action='update', sonarr_version=sonarr_version, - tags_dict=tagsDict, serie_default_profile=serie_default_profile, + series = seriesParser(series_data, action='update', tags_dict=tagsDict, + serie_default_profile=serie_default_profile, audio_profiles=audio_profiles) elif action == 'updated' and not existing_series: - series = seriesParser(series_data, action='insert', sonarr_version=sonarr_version, - tags_dict=tagsDict, serie_default_profile=serie_default_profile, + series = seriesParser(series_data, action='insert', tags_dict=tagsDict, + serie_default_profile=serie_default_profile, audio_profiles=audio_profiles) except Exception: logging.debug('BAZARR cannot parse series returned by SignalR feed.') @@ -208,11 +206,10 @@ def update_one_series(series_id, action): def get_profile_list(): apikey_sonarr = settings.sonarr.apikey - sonarr_version = get_sonarr_version() profiles_list = [] # Get profiles data from Sonarr - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url_sonarr_api_series = url_sonarr() + "/api/profile?apikey=" + apikey_sonarr else: url_sonarr_api_series = url_sonarr() + "/api/v3/languageprofile?apikey=" + apikey_sonarr @@ -230,7 +227,7 @@ def get_profile_list(): return None # Parsing data returned from Sonarr - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): for profile in profiles_json.json(): profiles_list.append([profile['id'], profile['language'].capitalize()]) else: @@ -250,11 +247,10 @@ def profile_id_to_language(id_, profiles): def get_tags(): apikey_sonarr = settings.sonarr.apikey - sonarr_version = get_sonarr_version() tagsDict = [] # Get tags data from Sonarr - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url_sonarr_api_series = url_sonarr() + "/api/tag?apikey=" + apikey_sonarr else: url_sonarr_api_series = url_sonarr() + "/api/v3/tag?apikey=" + apikey_sonarr @@ -274,7 +270,7 @@ def get_tags(): return tagsDict.json() -def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, audio_profiles): +def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles): overview = show['overview'] if 'overview' in show else '' poster = '' fanart = '' @@ -291,7 +287,7 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, alternate_titles = str([item['title'] for item in show['alternateTitles']]) audio_language = [] - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles) else: audio_language = profile_id_to_language(show['languageProfileId'], audio_profiles) @@ -333,9 +329,9 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, 'profileId': serie_default_profile} -def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_version, sonarr_series_id=None): +def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_series_id=None): url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format( - '' if sonarr_version.startswith(('0.', '2.')) else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr) + '' if get_sonarr_info.is_legacy() else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr) try: r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers) r.raise_for_status() diff --git a/bazarr/main.py b/bazarr/main.py index 77772e79e..c579c4979 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -43,7 +43,7 @@ from signalr_client import sonarr_signalr_client, radarr_signalr_client from check_update import apply_update, check_if_new_update, check_releases from server import app, webserver from functools import wraps -from utils import check_credentials, get_sonarr_version, get_radarr_version +from utils import check_credentials, get_sonarr_info, get_radarr_info # Install downloaded update if bazarr_version != '': @@ -131,8 +131,7 @@ def series_images(url): url = url.strip("/") apikey = settings.sonarr.apikey baseUrl = settings.sonarr.base_url - sonarr_version = get_sonarr_version() - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url_image = (url_sonarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' + apikey).replace('poster-250', 'poster-500') else: @@ -151,8 +150,7 @@ def series_images(url): def movies_images(url): apikey = settings.radarr.apikey baseUrl = settings.radarr.base_url - radarr_version = get_radarr_version() - if radarr_version.startswith('0'): + if get_radarr_info.is_legacy(): url_image = url_radarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' + apikey else: url_image = url_radarr() + '/api/v3/' + url.lstrip(baseUrl) + '?apikey=' + apikey diff --git a/bazarr/signalr_client.py b/bazarr/signalr_client.py index ba7d8b4e2..a5dc8df8f 100644 --- a/bazarr/signalr_client.py +++ b/bazarr/signalr_client.py @@ -15,7 +15,7 @@ from get_episodes import sync_episodes, sync_one_episode from get_series import update_series, update_one_series from get_movies import update_movies, update_one_movie from scheduler import scheduler -from utils import get_sonarr_version +from utils import get_sonarr_info from get_args import args @@ -33,10 +33,9 @@ class SonarrSignalrClient: self.connection = None def start(self): - sonarr_version = get_sonarr_version() - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): logging.warning('BAZARR can only sync from Sonarr v3 SignalR feed to get real-time update. You should ' - 'consider upgrading your version({}).'.format(sonarr_version)) + 'consider upgrading your version({}).'.format(get_sonarr_info.version())) raise gevent.GreenletExit else: logging.info('BAZARR trying to connect to Sonarr SignalR feed...') diff --git a/bazarr/utils.py b/bazarr/utils.py index 4ccd3bacb..98f6ec4b6 100644 --- a/bazarr/utils.py +++ b/bazarr/utils.py @@ -236,46 +236,52 @@ def cache_maintenance(): remove_expired(fn, pack_cache_validity) -def get_sonarr_version(): - sonarr_version = '' - if settings.general.getboolean('use_sonarr'): - try: - sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey - sonarr_json = requests.get(sv, timeout=60, verify=False, headers=headers).json() - if 'version' in sonarr_json: - sonarr_version = sonarr_json['version'] - else: - sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey - sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version'] - except Exception: - logging.debug('BAZARR cannot get Sonarr version') - sonarr_version = 'unknown' - return sonarr_version - - -def get_sonarr_platform(): - sonarr_platform = '' - sonarr_version = get_sonarr_version() - if settings.general.getboolean('use_sonarr'): - try: - if sonarr_version.startswith(('0.', '2.')): +class GetSonarrInfo: + @staticmethod + def version(): + """ + Call system/status API endpoint and get the Sonarr version + @return: str + """ + sonarr_version = region.get("sonarr_version", expiration_time=datetime.timedelta(seconds=60).total_seconds()) + if sonarr_version: + region.set("sonarr_version", sonarr_version) + return sonarr_version + else: + sonarr_version = '' + if settings.general.getboolean('use_sonarr'): + try: sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey - else: - sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey - response = requests.get(sv, timeout=60, verify=False, headers=headers).json() - if response['isLinux'] or response['isOsx']: - sonarr_platform = 'posix' - elif response['isWindows']: - sonarr_platform = 'nt' - except Exception: - logging.debug('BAZARR cannot get Sonarr platform') - return sonarr_platform + sonarr_json = requests.get(sv, timeout=60, verify=False, headers=headers).json() + if 'version' in sonarr_json: + sonarr_version = sonarr_json['version'] + else: + sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey + sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version'] + except Exception: + logging.debug('BAZARR cannot get Sonarr version') + sonarr_version = 'unknown' + region.set("sonarr_version", sonarr_version) + return sonarr_version + + def is_legacy(self): + """ + Call self.version() and parse the result to determine if it's a legacy version of Sonarr API + @return: bool + """ + sonarr_version = self.version() + if sonarr_version.startswith(('0.', '2.')): + return True + else: + return False + + +get_sonarr_info = GetSonarrInfo() def notify_sonarr(sonarr_series_id): - sonarr_version = get_sonarr_version() try: - if sonarr_version.startswith(('0.', '2.')): + if get_sonarr_info.is_legacy(): url = url_sonarr() + "/api/command?apikey=" + settings.sonarr.apikey else: url = url_sonarr() + "/api/v3/command?apikey=" + settings.sonarr.apikey @@ -285,47 +291,54 @@ def notify_sonarr(sonarr_series_id): } requests.post(url, json=data, timeout=60, verify=False, headers=headers) except Exception as e: - logging.debug('BAZARR notify Sonarr') + logging.exception('BAZARR cannot notify Sonarr') -def get_radarr_version(): - radarr_version = '' - if settings.general.getboolean('use_radarr'): - try: - rv = url_radarr() + "/api/system/status?apikey=" + settings.radarr.apikey - radarr_json = requests.get(rv, timeout=60, verify=False, headers=headers).json() - if 'version' in radarr_json: - radarr_version = radarr_json['version'] - else: - rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey - radarr_version = requests.get(rv, timeout=60, verify=False, headers=headers).json()['version'] - except Exception as e: - logging.debug('BAZARR cannot get Radarr version') - radarr_version = 'unknown' - return radarr_version - - -def get_radarr_platform(): - radarr_platform = '' - if settings.general.getboolean('use_radarr'): - try: - if get_radarr_version().startswith('0'): +class GetRadarrInfo: + @staticmethod + def version(): + """ + Call system/status API endpoint and get the Radarr version + @return: str + """ + radarr_version = region.get("radarr_version", expiration_time=datetime.timedelta(seconds=60).total_seconds()) + if radarr_version: + return radarr_version + else: + radarr_version = '' + if settings.general.getboolean('use_radarr'): + try: rv = url_radarr() + "/api/system/status?apikey=" + settings.radarr.apikey - else: - rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey - response = requests.get(rv, timeout=60, verify=False, headers=headers).json() - if response['isLinux'] or response['isOsx']: - radarr_platform = 'posix' - elif response['isWindows']: - radarr_platform = 'nt' - except Exception: - logging.debug('BAZARR cannot get Radarr platform') - return radarr_platform + radarr_json = requests.get(rv, timeout=60, verify=False, headers=headers).json() + if 'version' in radarr_json: + radarr_version = radarr_json['version'] + else: + rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey + radarr_version = requests.get(rv, timeout=60, verify=False, headers=headers).json()['version'] + except Exception as e: + logging.debug('BAZARR cannot get Radarr version') + radarr_version = 'unknown' + region.set("radarr_version", radarr_version) + return radarr_version + + def is_legacy(self): + """ + Call self.version() and parse the result to determine if it's a legacy version of Radarr + @return: bool + """ + radarr_version = self.version() + if radarr_version.startswith('0.'): + return True + else: + return False + + +get_radarr_info = GetRadarrInfo() def notify_radarr(radarr_id): try: - if get_radarr_version().startswith('0'): + if get_radarr_info.is_legacy(): url = url_radarr() + "/api/command?apikey=" + settings.radarr.apikey else: url = url_radarr() + "/api/v3/command?apikey=" + settings.radarr.apikey @@ -335,7 +348,7 @@ def notify_radarr(radarr_id): } requests.post(url, json=data, timeout=60, verify=False, headers=headers) except Exception as e: - logging.debug('BAZARR notify Radarr') + logging.exception('BAZARR cannot notify Radarr') def delete_subtitles(media_type, language, forced, hi, media_path, subtitles_path, sonarr_series_id=None, From 91c53ba475eacb66f3c5673ff3122b7cf5c238da Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 5 Aug 2021 15:55:31 -0400 Subject: [PATCH 27/42] Added search progress modal when searching for an episode subtitles triggered by Plex webhook. --- bazarr/api.py | 2 +- bazarr/get_subtitle.py | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/bazarr/api.py b/bazarr/api.py index 04df0b11b..94b7f2a5d 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -2111,7 +2111,7 @@ class WebHooksPlex(Resource): .get() if sonarrEpisodeId: - episode_download_subtitles(no=sonarrEpisodeId['sonarrEpisodeId']) + episode_download_subtitles(no=sonarrEpisodeId['sonarrEpisodeId'], send_progress=True) else: try: movie_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0] diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py index 13011b4b1..07363606d 100644 --- a/bazarr/get_subtitle.py +++ b/bazarr/get_subtitle.py @@ -806,7 +806,7 @@ def series_download_subtitles(no): hide_progress(id='series_search_progress_{}'.format(no)) -def episode_download_subtitles(no): +def episode_download_subtitles(no, send_progress=False): conditions = [(TableEpisodes.sonarrEpisodeId == no)] conditions += get_exclusion_clause('series') episodes_details = TableEpisodes.select(TableEpisodes.path, @@ -818,7 +818,10 @@ def episode_download_subtitles(no): TableShows.title, TableShows.sonarrSeriesId, TableEpisodes.audio_language, - TableShows.seriesType)\ + TableShows.seriesType, + TableEpisodes.title.alias('episodeTitle'), + TableEpisodes.season, + TableEpisodes.episode)\ .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\ .where(reduce(operator.and_, conditions))\ .dicts() @@ -831,6 +834,15 @@ def episode_download_subtitles(no): for episode in episodes_details: if providers_list: + if send_progress: + show_progress(id='episode_search_progress_{}'.format(no), + header='Searching missing subtitles...', + name='{0} - S{1:02d}E{2:02d} - {3}'.format(episode['title'], + episode['season'], + episode['episode'], + episode['episodeTitle']), + value=1, + count=1) for language in ast.literal_eval(episode['missing_subtitles']): # confirm if language is still missing or if cutoff have been reached confirmed_missing_subs = TableEpisodes.select(TableEpisodes.missing_subtitles) \ @@ -875,6 +887,8 @@ def episode_download_subtitles(no): history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path, language_code, provider, score, subs_id, subs_path) send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message) + if send_progress: + hide_progress(id='episode_search_progress_{}'.format(no)) else: logging.info("BAZARR All providers are throttled") break From dd80fec9d4a6d5a5af1e7d41bbcebb07c43ae35c Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Fri, 6 Aug 2021 10:29:58 -0400 Subject: [PATCH 28/42] Fixed issue with upgrade cleanup routine when installed with Windows Installer. --- bazarr/check_update.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index b3c7fbd87..ca8ff3d85 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -180,10 +180,13 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): dir_to_ignore = ['^.' + os.path.sep, '^bin' + os.path.sep, '^venv' + os.path.sep, + '^WinPython' + os.path.sep, os.path.sep + '__pycache__' + os.path.sep + '$'] if os.path.abspath(bazarr_dir) in os.path.abspath(config_dir): dir_to_ignore.append('^' + os.path.relpath(config_dir, bazarr_dir) + os.path.sep) dir_to_ignore_regex = re.compile('(?:% s)' % '|'.join(dir_to_ignore)) + + file_to_ignore = ['nssm.exe', '7za.exe'] extension_to_ignore = ['.pyc'] file_on_disk = [] @@ -196,7 +199,9 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): folder_list.append(relative_foldername) for file in filenames: - if os.path.splitext(file)[1] in extension_to_ignore: + if file in file_to_ignore: + continue + elif os.path.splitext(file)[1] in extension_to_ignore: continue elif foldername == bazarr_dir: file_on_disk.append(file) From 2cea2d22bfb0e050e95ba3c50dba9631210886d0 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Fri, 6 Aug 2021 22:11:24 -0400 Subject: [PATCH 29/42] Fixed issue when trying to remove non-empty directory when cleaning leftover files after upgrade. --- bazarr/check_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index ca8ff3d85..0c45f0208 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -218,7 +218,7 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): filepath = os.path.join(bazarr_dir, file) try: if os.path.isdir(filepath): - shutil.rmtree(filepath, ignore_errors=True) + rmtree(filepath, ignore_errors=True) else: os.remove(filepath) except: From 275aa24f58d061362e9ff8b0f6d14c0983bce844 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sat, 7 Aug 2021 18:57:34 -0400 Subject: [PATCH 30/42] Fixed issue with upgrade leftover cleanup on Windows. --- bazarr/check_update.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index 0c45f0208..49fee7eea 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -176,12 +176,17 @@ def apply_update(): def update_cleaner(zipfile, bazarr_dir, config_dir): with ZipFile(zipfile, 'r') as archive: file_in_zip = archive.namelist() + if os.path.sep == '\\': + for i, item in enumerate(file_in_zip): + file_in_zip[i] = item.replace('/', '\\') - dir_to_ignore = ['^.' + os.path.sep, - '^bin' + os.path.sep, - '^venv' + os.path.sep, - '^WinPython' + os.path.sep, - os.path.sep + '__pycache__' + os.path.sep + '$'] + separator = os.path.sep * 2 if os.path.sep == '\\' else os.path.sep + + dir_to_ignore = ['^.' + separator, + '^bin' + separator, + '^venv' + separator, + '^WinPython' + separator, + separator + '__pycache__' + separator + '$'] if os.path.abspath(bazarr_dir) in os.path.abspath(config_dir): dir_to_ignore.append('^' + os.path.relpath(config_dir, bazarr_dir) + os.path.sep) dir_to_ignore_regex = re.compile('(?:% s)' % '|'.join(dir_to_ignore)) From 28e28fbd5c7c89fead99b1ff055b66f597d6a88b Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sat, 7 Aug 2021 18:59:29 -0400 Subject: [PATCH 31/42] Removed media.resume from Plex webhook to prevent over usage in specific scenarios. --- bazarr/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/api.py b/bazarr/api.py index 94b7f2a5d..5e56f61f7 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -2073,7 +2073,7 @@ class WebHooksPlex(Resource): parsed_json_webhook = json.loads(json_webhook) event = parsed_json_webhook['event'] - if event not in ['media.play', 'media.resume']: + if event not in ['media.play']: return '', 204 media_type = parsed_json_webhook['Metadata']['type'] From a5852e605251c4c90076269fbea9669be3abb22c Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 8 Aug 2021 23:06:01 -0400 Subject: [PATCH 32/42] Added some debug logging to the upgrade leftover cleaner. --- bazarr/check_update.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index 49fee7eea..bdad84fe6 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -176,11 +176,17 @@ def apply_update(): def update_cleaner(zipfile, bazarr_dir, config_dir): with ZipFile(zipfile, 'r') as archive: file_in_zip = archive.namelist() + logging.debug('BAZARR zip file contain {} directories and files'.format(len(file_in_zip))) + separator = os.path.sep if os.path.sep == '\\': + logging.debug('BAZARR upgrade leftover cleaner is running on Windows. We\'ll fix the zip file separator ' + 'accordingly.') for i, item in enumerate(file_in_zip): file_in_zip[i] = item.replace('/', '\\') - - separator = os.path.sep * 2 if os.path.sep == '\\' else os.path.sep + separator += os.path.sep + else: + logging.debug('BAZARR upgrade leftover cleaner is running on something else than Windows. The zip file ' + 'separator are fine.') dir_to_ignore = ['^.' + separator, '^bin' + separator, @@ -190,9 +196,14 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): if os.path.abspath(bazarr_dir) in os.path.abspath(config_dir): dir_to_ignore.append('^' + os.path.relpath(config_dir, bazarr_dir) + os.path.sep) dir_to_ignore_regex = re.compile('(?:% s)' % '|'.join(dir_to_ignore)) + logging.debug('BAZARR upgrade leftover cleaner will ignore directories matching this regex: ' + '{}'.format(dir_to_ignore_regex)) file_to_ignore = ['nssm.exe', '7za.exe'] + logging.debug('BAZARR upgrade leftover cleaner will ignore those files: {}'.format(', '.join(file_to_ignore))) extension_to_ignore = ['.pyc'] + logging.debug('BAZARR upgrade leftover cleaner will ignore files with those extensions: ' + '{}'.format(', '.join(extension_to_ignore))) file_on_disk = [] folder_list = [] @@ -215,9 +226,14 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): filepath = os.path.join(current_dir, file) if not dir_to_ignore_regex.findall(filepath): file_on_disk.append(filepath) + logging.debug('BAZARR directory contain {} files'.format(len(file_on_disk))) + logging.debug('BAZARR directory contain {} directories'.format(len(folder_list))) file_on_disk += folder_list + logging.debug('BAZARR directory contain {} directories and files'.format(len(file_on_disk))) file_to_remove = list(set(file_on_disk) - set(file_in_zip)) + logging.debug('BAZARR will delete {} directories and files'.format(len(file_to_remove))) + logging.debug('BAZARR will delete this: {}'.format(', '.join(file_to_remove))) for file in file_to_remove: filepath = os.path.join(bazarr_dir, file) @@ -226,5 +242,5 @@ def update_cleaner(zipfile, bazarr_dir, config_dir): rmtree(filepath, ignore_errors=True) else: os.remove(filepath) - except: - pass + except Exception as e: + logging.debug('BAZARR upgrade leftover cleaner cannot delete {}'.format(filepath)) From 144db064cda4502fbe100307c458e0b233980585 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Sun, 8 Aug 2021 23:06:46 -0400 Subject: [PATCH 33/42] Removed unused variables in check_releases function. --- bazarr/check_update.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bazarr/check_update.py b/bazarr/check_update.py index bdad84fe6..8cfc841ee 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -21,13 +21,13 @@ def check_releases(): logging.debug('BAZARR getting releases from Github: {}'.format(url_releases)) r = requests.get(url_releases, allow_redirects=True) r.raise_for_status() - except requests.exceptions.HTTPError as errh: + except requests.exceptions.HTTPError: logging.exception("Error trying to get releases from Github. Http error.") - except requests.exceptions.ConnectionError as errc: + except requests.exceptions.ConnectionError: logging.exception("Error trying to get releases from Github. Connection Error.") - except requests.exceptions.Timeout as errt: + except requests.exceptions.Timeout: logging.exception("Error trying to get releases from Github. Timeout Error.") - except requests.exceptions.RequestException as err: + except requests.exceptions.RequestException: logging.exception("Error trying to get releases from Github.") else: for release in r.json(): From aa6dcbd7328fe8c08119e67debaee96fb6d810c9 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Mon, 9 Aug 2021 09:14:56 -0400 Subject: [PATCH 34/42] Removed the --no-color argument to pip command when installing requirements as it's not supported by older version of pip. --- bazarr/init.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bazarr/init.py b/bazarr/init.py index f7241149a..93014edf3 100644 --- a/bazarr/init.py +++ b/bazarr/init.py @@ -65,8 +65,7 @@ if not args.no_update: logging.info('BAZARR installing requirements...') try: pip_command = [sys.executable, '-m', 'pip', 'install', '-qq', '--disable-pip-version-check', - '--no-color', '-r', os.path.join(os.path.dirname(os.path.dirname(__file__)), - 'requirements.txt')] + '-r', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'requirements.txt')] if not is_virtualenv(): # --user only make sense if not running under venv pip_command.insert(4, '--user') From f2d4ac8266c48d69c76ccbdfb558e2f831b243aa Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Mon, 9 Aug 2021 16:15:38 -0400 Subject: [PATCH 35/42] Changed the warning when Sonarr SignalR return malformed JSON because of a permissions issue on its config directory. --- bazarr/signalr_client.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bazarr/signalr_client.py b/bazarr/signalr_client.py index a5dc8df8f..9968bacfb 100644 --- a/bazarr/signalr_client.py +++ b/bazarr/signalr_client.py @@ -46,9 +46,11 @@ class SonarrSignalrClient: except ConnectionError: gevent.sleep(5) except json.decoder.JSONDecodeError: - logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is a known issue when " - "Sonarr have issue accessing it's /config/xdg directory. You should delete that " - "directory and restart Sonarr.") + logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is caused by a permissions " + "issue when Sonarr try to access its /config/.config directory. You should fix " + "permissions on that directory and restart Sonarr. Also, if you're a Docker image " + "user, you should make sure you properly defined PUID/PGID environment variables. " + "Otherwise, please contact Sonarr support.") raise gevent.GreenletExit else: logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.') From 9c9e7de158555c3523600ebd4162e6059353e563 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Aug 2021 12:31:24 +0800 Subject: [PATCH 36/42] no log: Bump @types/react-dom from 16.9.12 to 17.0.9 in /frontend (#1500) Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 16.9.12 to 17.0.9. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom) --- updated-dependencies: - dependency-name: "@types/react-dom" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 18 +++++++++--------- frontend/package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 51c9181d6..f5c7cbb10 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,7 +19,7 @@ "@types/lodash": "^4", "@types/node": "^15", "@types/react": "^16", - "@types/react-dom": "^16", + "@types/react-dom": "^17", "@types/react-helmet": "^6.1", "@types/react-router-dom": "^5", "@types/react-select": "^4.0.3", @@ -2968,11 +2968,11 @@ } }, "node_modules/@types/react-dom": { - "version": "16.9.12", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.12.tgz", - "integrity": "sha512-i7NPZZpPte3jtVOoW+eLB7G/jsX5OM6GqQnH+lC0nq0rqwlK0x8WcMEvYDgFWqWhWMlTltTimzdMax6wYfZssA==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", "dependencies": { - "@types/react": "^16" + "@types/react": "*" } }, "node_modules/@types/react-helmet": { @@ -24408,11 +24408,11 @@ } }, "@types/react-dom": { - "version": "16.9.12", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.12.tgz", - "integrity": "sha512-i7NPZZpPte3jtVOoW+eLB7G/jsX5OM6GqQnH+lC0nq0rqwlK0x8WcMEvYDgFWqWhWMlTltTimzdMax6wYfZssA==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", "requires": { - "@types/react": "^16" + "@types/react": "*" } }, "@types/react-helmet": { diff --git a/frontend/package.json b/frontend/package.json index 4cfa61e23..11cda9df8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,7 +23,7 @@ "@types/lodash": "^4", "@types/node": "^15", "@types/react": "^16", - "@types/react-dom": "^16", + "@types/react-dom": "^17", "@types/react-helmet": "^6.1", "@types/react-router-dom": "^5", "@types/react-select": "^4.0.3", From 83764bb07b152edb8009bbcd70b6809da8cfcd20 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Tue, 10 Aug 2021 09:53:47 -0400 Subject: [PATCH 37/42] Added some logging to Sonarr/Radarr get_version. --- bazarr/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bazarr/utils.py b/bazarr/utils.py index 98f6ec4b6..0a66b5a0c 100644 --- a/bazarr/utils.py +++ b/bazarr/utils.py @@ -261,6 +261,7 @@ class GetSonarrInfo: except Exception: logging.debug('BAZARR cannot get Sonarr version') sonarr_version = 'unknown' + logging.debug('BAZARR got this Sonarr version from its API: {}'.format(sonarr_version)) region.set("sonarr_version", sonarr_version) return sonarr_version @@ -303,6 +304,7 @@ class GetRadarrInfo: """ radarr_version = region.get("radarr_version", expiration_time=datetime.timedelta(seconds=60).total_seconds()) if radarr_version: + region.set("radarr_version", radarr_version) return radarr_version else: radarr_version = '' @@ -318,6 +320,7 @@ class GetRadarrInfo: except Exception as e: logging.debug('BAZARR cannot get Radarr version') radarr_version = 'unknown' + logging.debug('BAZARR got this Radarr version from its API: {}'.format(radarr_version)) region.set("radarr_version", radarr_version) return radarr_version From c2059584db9ae3a3c19c3fcfe205f7d72b9e4fcf Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 11 Aug 2021 09:37:50 -0400 Subject: [PATCH 38/42] Fixed empty strings being saved as 'None' in config.ini. --- bazarr/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/config.py b/bazarr/config.py index 249204b40..04183895c 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -318,7 +318,7 @@ def save_settings(settings_items): # Make sure that text based form values aren't pass as list if isinstance(value, list) and len(value) == 1 and settings_keys[-1] not in array_keys: value = value[0] - if value in empty_values: + if value in empty_values and value is not '': value = None # Make sure empty language list are stored correctly From c05db9f8c5731351304ec01aec9d7ad3ce3cebf8 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 11 Aug 2021 09:38:39 -0400 Subject: [PATCH 39/42] Added a validation of existing credentials for opensubtitles.com provider. --- libs/subliminal_patch/providers/opensubtitlescom.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/subliminal_patch/providers/opensubtitlescom.py b/libs/subliminal_patch/providers/opensubtitlescom.py index fd4bb6684..7d04a6026 100644 --- a/libs/subliminal_patch/providers/opensubtitlescom.py +++ b/libs/subliminal_patch/providers/opensubtitlescom.py @@ -124,6 +124,9 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider): languages.update(set(Language.rebuild(l, forced=True) for l in languages)) 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') + if not api_key: raise ConfigurationError('Api_key must be specified') From 0e763b79d52cd71d43bd65fe1f14abed0bd585a7 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 11 Aug 2021 09:39:59 -0400 Subject: [PATCH 40/42] no log: quick fix --- bazarr/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/config.py b/bazarr/config.py index 04183895c..1b2a3c655 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -318,7 +318,7 @@ def save_settings(settings_items): # Make sure that text based form values aren't pass as list if isinstance(value, list) and len(value) == 1 and settings_keys[-1] not in array_keys: value = value[0] - if value in empty_values and value is not '': + if value in empty_values and value != '': value = None # Make sure empty language list are stored correctly From d23d36d81c065a16af601040d68092a84f3ba9b8 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Wed, 11 Aug 2021 15:35:39 -0400 Subject: [PATCH 41/42] Modified Bazarr user-agent to report real version --- bazarr/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazarr/init.py b/bazarr/init.py index 93014edf3..928c44f3d 100644 --- a/bazarr/init.py +++ b/bazarr/init.py @@ -16,7 +16,7 @@ import subliminal import datetime # set subliminal_patch user agent -os.environ["SZ_USER_AGENT"] = "Bazarr/1" +os.environ["SZ_USER_AGENT"] = "Bazarr/{}".format(os.environ["BAZARR_VERSION"]) # set anti-captcha provider and key configure_captcha_func() From 9b05a3a63ae950a225d5d720aa648156375a1df7 Mon Sep 17 00:00:00 2001 From: Marian Moravcik Date: Thu, 12 Aug 2021 20:26:12 +0200 Subject: [PATCH 42/42] Fix broken url for titulky.com provider --- libs/subliminal_patch/providers/titulky.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/subliminal_patch/providers/titulky.py b/libs/subliminal_patch/providers/titulky.py index 66d6f8c7f..0639a042f 100644 --- a/libs/subliminal_patch/providers/titulky.py +++ b/libs/subliminal_patch/providers/titulky.py @@ -152,12 +152,12 @@ class TitulkyProvider(Provider): """Titulky Provider.""" languages = {Language(l) for l in ['ces', 'slk']} - server_url = 'https://premium.titulky.com' + server_url = 'https://oldpremium.titulky.com' sign_out_url = '?Logoff=true' search_url_series = '?Fulltext={}' search_url_movies = '?Searching=AdvancedResult&ARelease={}' - dn_url = 'https://premium.titulky.com' - download_url = 'https://premium.titulky.com/idown.php?titulky=' + dn_url = 'https://oldpremium.titulky.com' + download_url = 'https://oldpremium.titulky.com/idown.php?titulky=' UserAgent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'