From e477ecafcce268d7de112f33711fc02a089a4206 Mon Sep 17 00:00:00 2001 From: Jagandeep Brar Date: Sun, 18 Sep 2022 21:31:58 -0400 Subject: [PATCH] fix(sonarr): support Sonarr v4 API changes --- lib/api/sonarr/controllers/series.dart | 4 ++-- .../sonarr/controllers/series/add_series.dart | 4 ++-- .../controllers/series/delete_series.dart | 5 ++--- lib/modules/sonarr/core/api_controller.dart | 2 +- .../core/extensions/sonarr_event_type.dart | 18 ++++++++++-------- .../sonarr/core/extensions/sonarr_series.dart | 7 +++++-- lib/modules/sonarr/core/state.dart | 18 +++++++++++++++++- .../routes/add_series_details/route.dart | 3 ++- .../sonarr/routes/edit_series/route.dart | 3 ++- .../sonarr/routes/edit_series/state.dart | 7 ++++--- .../widgets/tile_language_profile.dart | 3 ++- .../routes/queue/widgets/queue_tile.dart | 19 +++++++++++-------- .../routes/releases/widgets/release_tile.dart | 15 +++++++++------ .../sheets/episode_details.dart | 4 +++- 14 files changed, 72 insertions(+), 40 deletions(-) diff --git a/lib/api/sonarr/controllers/series.dart b/lib/api/sonarr/controllers/series.dart index 4b0ce567..b27f6791 100644 --- a/lib/api/sonarr/controllers/series.dart +++ b/lib/api/sonarr/controllers/series.dart @@ -17,10 +17,10 @@ class SonarrControllerSeries { required SonarrSeriesType seriesType, required bool seasonFolder, required SonarrQualityProfile qualityProfile, - required SonarrLanguageProfile languageProfile, required SonarrRootFolder rootFolder, required SonarrSeriesMonitorType monitorType, List tags = const [], + SonarrLanguageProfile? languageProfile, bool searchForMissingEpisodes = false, bool searchForCutoffUnmetEpisodes = false, bool includeSeasonImages = false, @@ -42,7 +42,7 @@ class SonarrControllerSeries { /// Handler for [series/{id}](https://github.com/Sonarr/Sonarr/wiki/Series#deleteid). /// /// Delete the series with the given series ID. - Future delete({ + Future delete({ required int seriesId, bool deleteFiles = false, bool addImportListExclusion = false, diff --git a/lib/api/sonarr/controllers/series/add_series.dart b/lib/api/sonarr/controllers/series/add_series.dart index 12c6d949..b75c648a 100644 --- a/lib/api/sonarr/controllers/series/add_series.dart +++ b/lib/api/sonarr/controllers/series/add_series.dart @@ -6,9 +6,9 @@ Future _commandAddSeries( required SonarrSeriesType seriesType, required bool seasonFolder, required SonarrQualityProfile qualityProfile, - required SonarrLanguageProfile languageProfile, required SonarrRootFolder rootFolder, required SonarrSeriesMonitorType monitorType, + SonarrLanguageProfile? languageProfile, List tags = const [], bool searchForMissingEpisodes = false, bool searchForCutoffUnmetEpisodes = false, @@ -17,7 +17,7 @@ Future _commandAddSeries( _payload.addAll({ 'monitored': true, 'qualityProfileId': qualityProfile.id, - 'languageProfileId': languageProfile.id, + if (languageProfile != null) 'languageProfileId': languageProfile.id, 'seasonFolder': seasonFolder, 'seriesType': seriesType.value, 'tags': tags.map((tag) => tag.id).toList(), diff --git a/lib/api/sonarr/controllers/series/delete_series.dart b/lib/api/sonarr/controllers/series/delete_series.dart index 761aad21..f5535bc1 100644 --- a/lib/api/sonarr/controllers/series/delete_series.dart +++ b/lib/api/sonarr/controllers/series/delete_series.dart @@ -1,14 +1,13 @@ part of sonarr_commands; -Future _commandDeleteSeries( +Future _commandDeleteSeries( Dio client, { required int seriesId, bool deleteFiles = false, bool addImportListExclusion = false, }) async { - Response response = await client.delete('series/$seriesId', queryParameters: { + await client.delete('series/$seriesId', queryParameters: { 'deleteFiles': deleteFiles, 'addImportListExclusion': addImportListExclusion, }); - return SonarrSeries.fromJson(response.data); } diff --git a/lib/modules/sonarr/core/api_controller.dart b/lib/modules/sonarr/core/api_controller.dart index 32396348..8233b11d 100644 --- a/lib/modules/sonarr/core/api_controller.dart +++ b/lib/modules/sonarr/core/api_controller.dart @@ -621,10 +621,10 @@ class SonarrAPIController { required SonarrSeriesType seriesType, required bool seasonFolder, required SonarrQualityProfile qualityProfile, - required SonarrLanguageProfile languageProfile, required SonarrRootFolder rootFolder, required SonarrSeriesMonitorType monitorType, required List tags, + SonarrLanguageProfile? languageProfile, bool showSnackbar = true, }) async { if (context.read().enabled) { diff --git a/lib/modules/sonarr/core/extensions/sonarr_event_type.dart b/lib/modules/sonarr/core/extensions/sonarr_event_type.dart index a7ab5ecb..35bfc0b6 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_event_type.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_event_type.dart @@ -139,10 +139,11 @@ extension SonarrEventTypeLunaExtension on SonarrEventType { title: 'sonarr.Quality'.tr(), body: history.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, ), - LunaTableContent( - title: 'sonarr.Languages'.tr(), - body: history.language?.name ?? LunaUI.TEXT_EMDASH, - ), + if (history.language != null) + LunaTableContent( + title: 'sonarr.Languages'.tr(), + body: history.language?.name ?? LunaUI.TEXT_EMDASH, + ), LunaTableContent( title: 'sonarr.Client'.tr(), body: history.data!['downloadClient'] ?? LunaUI.TEXT_EMDASH, @@ -242,10 +243,11 @@ extension SonarrEventTypeLunaExtension on SonarrEventType { title: 'sonarr.Quality'.tr(), body: history.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, ), - LunaTableContent( - title: 'sonarr.Languages'.tr(), - body: history.language?.name ?? LunaUI.TEXT_EMDASH, - ), + if (history.language != null) + LunaTableContent( + title: 'sonarr.Languages'.tr(), + body: history.language?.name ?? LunaUI.TEXT_EMDASH, + ), LunaTableContent( title: 'sonarr.Indexer'.tr(), body: history.data!['indexer'], diff --git a/lib/modules/sonarr/core/extensions/sonarr_series.dart b/lib/modules/sonarr/core/extensions/sonarr_series.dart index 27e7a3e4..2a2082bf 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_series.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_series.dart @@ -142,10 +142,13 @@ extension SonarrSeriesExtension on SonarrSeries { series.seasonFolder = edits.useSeasonFolders; series.path = edits.seriesPath; series.qualityProfileId = edits.qualityProfile?.id ?? this.qualityProfileId; - series.languageProfileId = - edits.languageProfile.id ?? this.languageProfileId; series.seriesType = edits.seriesType ?? this.seriesType; series.tags = edits.tags?.map((t) => t.id!).toList() ?? []; + if (edits.languageProfile != null) { + series.languageProfileId = + edits.languageProfile!.id ?? this.languageProfileId; + } + return series; } } diff --git a/lib/modules/sonarr/core/state.dart b/lib/modules/sonarr/core/state.dart index 6d9aa6b5..7c69a628 100644 --- a/lib/modules/sonarr/core/state.dart +++ b/lib/modules/sonarr/core/state.dart @@ -221,8 +221,24 @@ class SonarrState extends LunaModuleState { notifyListeners(); } + Future> _fetchLanguageProfiles() async { + try { + final profiles = await _api!.profile.getLanguageProfiles(); + return profiles; + } catch (error, stack) { + LunaLogger().error( + 'Failed to fetch language profiles, assuming v4', + error, + stack, + ); + return const []; + } + } + void fetchLanguageProfiles() { - if (_api != null) _languageProfiles = _api!.profile.getLanguageProfiles(); + if (_api != null) { + _languageProfiles = _fetchLanguageProfiles(); + } notifyListeners(); } diff --git a/lib/modules/sonarr/routes/add_series_details/route.dart b/lib/modules/sonarr/routes/add_series_details/route.dart index 828a7e79..e39d0cca 100644 --- a/lib/modules/sonarr/routes/add_series_details/route.dart +++ b/lib/modules/sonarr/routes/add_series_details/route.dart @@ -124,7 +124,8 @@ class _State extends State const SonarrSeriesAddDetailsRootFolderTile(), const SonarrSeriesAddDetailsMonitorTile(), const SonarrSeriesAddDetailsQualityProfileTile(), - const SonarrSeriesAddDetailsLanguageProfileTile(), + if (languageProfiles.isNotEmpty) + const SonarrSeriesAddDetailsLanguageProfileTile(), const SonarrSeriesAddDetailsSeriesTypeTile(), const SonarrSeriesAddDetailsUseSeasonFoldersTile(), const SonarrSeriesAddDetailsTagsTile(), diff --git a/lib/modules/sonarr/routes/edit_series/route.dart b/lib/modules/sonarr/routes/edit_series/route.dart index f58f90ec..0cf0d7e8 100644 --- a/lib/modules/sonarr/routes/edit_series/route.dart +++ b/lib/modules/sonarr/routes/edit_series/route.dart @@ -121,7 +121,8 @@ class _State extends State const SonarrSeriesEditMonitoredTile(), const SonarrSeriesEditSeasonFoldersTile(), SonarrSeriesEditQualityProfileTile(profiles: qualityProfiles), - SonarrSeriesEditLanguageProfileTile(profiles: languageProfiles), + if (languageProfiles.isNotEmpty) + SonarrSeriesEditLanguageProfileTile(profiles: languageProfiles), const SonarrSeriesEditSeriesTypeTile(), const SonarrSeriesEditSeriesPathTile(), const SonarrSeriesEditTagsTile(), diff --git a/lib/modules/sonarr/routes/edit_series/state.dart b/lib/modules/sonarr/routes/edit_series/state.dart index 9ad3e6c0..dab78068 100644 --- a/lib/modules/sonarr/routes/edit_series/state.dart +++ b/lib/modules/sonarr/routes/edit_series/state.dart @@ -80,14 +80,15 @@ class SonarrSeriesEditState extends ChangeNotifier { ); } - late SonarrLanguageProfile _languageProfile; - SonarrLanguageProfile get languageProfile => _languageProfile; - set languageProfile(SonarrLanguageProfile languageProfile) { + SonarrLanguageProfile? _languageProfile; + SonarrLanguageProfile? get languageProfile => _languageProfile; + set languageProfile(SonarrLanguageProfile? languageProfile) { _languageProfile = languageProfile; notifyListeners(); } void initializeLanguageProfile(List languageProfiles) { + if (languageProfiles.isEmpty) return; _languageProfile = languageProfiles.firstWhere( (p) => p.id == series!.languageProfileId, ); diff --git a/lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart index 081b0564..2ab1856c 100644 --- a/lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart +++ b/lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart @@ -16,7 +16,8 @@ class SonarrSeriesEditLanguageProfileTile extends StatelessWidget { title: 'sonarr.LanguageProfile'.tr(), body: [ TextSpan( - text: context.watch().languageProfile.name, + text: context.watch().languageProfile?.name ?? + LunaUI.TEXT_EMDASH, ), ], trailing: const LunaIconButton.arrow(), diff --git a/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart b/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart index ad6e8772..2576ce43 100644 --- a/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart +++ b/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart @@ -92,10 +92,12 @@ class _State extends State { text: widget.queueRecord.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, ), TextSpan(text: LunaUI.TEXT_BULLET.pad()), - TextSpan( - text: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, - ), - TextSpan(text: LunaUI.TEXT_BULLET.pad()), + if (widget.queueRecord.language != null) + TextSpan( + text: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, + ), + if (widget.queueRecord.language != null) + TextSpan(text: LunaUI.TEXT_BULLET.pad()), TextSpan( text: widget.queueRecord.lunaTimeLeft(), ), @@ -162,10 +164,11 @@ class _State extends State { title: 'sonarr.Quality'.tr(), body: widget.queueRecord.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, ), - LunaTableContent( - title: 'sonarr.Language'.tr(), - body: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, - ), + if (widget.queueRecord.language != null) + LunaTableContent( + title: 'sonarr.Language'.tr(), + body: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, + ), LunaTableContent( title: 'sonarr.Client'.tr(), body: widget.queueRecord.downloadClient ?? LunaUI.TEXT_EMDASH, diff --git a/lib/modules/sonarr/routes/releases/widgets/release_tile.dart b/lib/modules/sonarr/routes/releases/widgets/release_tile.dart index 0edea8a6..531877da 100644 --- a/lib/modules/sonarr/routes/releases/widgets/release_tile.dart +++ b/lib/modules/sonarr/routes/releases/widgets/release_tile.dart @@ -80,8 +80,10 @@ class _State extends State { if (_preferredWordScore != null) TextSpan(text: LunaUI.TEXT_BULLET.pad()), TextSpan(text: widget.release.lunaQuality), - TextSpan(text: LunaUI.TEXT_BULLET.pad()), - TextSpan(text: widget.release.lunaLanguage), + if (widget.release.language != null) + TextSpan(text: LunaUI.TEXT_BULLET.pad()), + if (widget.release.language != null) + TextSpan(text: widget.release.lunaLanguage), TextSpan(text: LunaUI.TEXT_BULLET.pad()), TextSpan(text: widget.release.lunaSize), ], @@ -118,10 +120,11 @@ class _State extends State { title: 'sonarr.Size'.tr(), body: widget.release.lunaSize, ), - LunaTableContent( - title: 'sonarr.Language'.tr(), - body: widget.release.lunaLanguage, - ), + if (widget.release.language != null) + LunaTableContent( + title: 'sonarr.Language'.tr(), + body: widget.release.lunaLanguage, + ), LunaTableContent( title: 'sonarr.Quality'.tr(), body: widget.release.lunaQuality, diff --git a/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart b/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart index fb324eb1..761685f1 100644 --- a/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart +++ b/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart @@ -47,7 +47,9 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { : LunaColours.accent, text: episodeFile!.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, ), - if (episode!.hasFile! && episodeFile != null) + if (episode!.hasFile! && + episodeFile != null && + episodeFile!.languageCutoffNotMet != null) LunaHighlightedNode( backgroundColor: episodeFile!.languageCutoffNotMet! ? LunaColours.orange