From 0ce95b58c022b46017e0bce8296da9dfd63de046 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Mon, 21 Jun 2021 21:59:54 -0500 Subject: [PATCH] fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add initial Blazor Server project --- src/.editorconfig | 2 +- .../Pages/Radarr/QualityProfilesPage.razor | 64 ++++++++++++++----- .../QualityProfileApiPersistenceStepTest.cs | 22 ++++--- .../Api/IQualityProfileService.cs | 6 +- .../Api/Models/QualityProfileData.cs | 31 +++++++++ .../Radarr/CustomFormat/Api/Models/foo.cs | 22 ------- .../CustomFormat/Api/QualityProfileService.cs | 14 ++-- .../QualityProfileApiPersistenceStep.cs | 28 ++++---- src/TrashLib/Radarr/RadarrAutofacModule.cs | 36 +++++------ 9 files changed, 134 insertions(+), 91 deletions(-) create mode 100644 src/TrashLib/Radarr/CustomFormat/Api/Models/QualityProfileData.cs delete mode 100644 src/TrashLib/Radarr/CustomFormat/Api/Models/foo.cs diff --git a/src/.editorconfig b/src/.editorconfig index 644954f0..c82719e2 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -1039,7 +1039,7 @@ resharper_place_event_attribute_on_same_line = false resharper_place_expr_accessor_on_single_line = true resharper_place_expr_method_on_single_line = true resharper_place_expr_property_on_single_line = true -resharper_place_field_attribute_on_same_line = true +resharper_place_field_attribute_on_same_line = false resharper_place_linq_into_on_new_line = true resharper_place_method_attribute_on_same_line = false resharper_place_namespace_definitions_on_same_line = false diff --git a/src/Recyclarr/Pages/Radarr/QualityProfilesPage.razor b/src/Recyclarr/Pages/Radarr/QualityProfilesPage.razor index 49bde7d3..ec3ba8e6 100644 --- a/src/Recyclarr/Pages/Radarr/QualityProfilesPage.razor +++ b/src/Recyclarr/Pages/Radarr/QualityProfilesPage.razor @@ -1,11 +1,12 @@ @page "/radarr/quality-profiles" @using TrashLib.Radarr.CustomFormat.Api +@using TrashLib.Radarr.CustomFormat.Api.Models @using TrashLib.Radarr.Config @using TrashLib.Config @using Recyclarr.Components -@using Newtonsoft.Json.Linq @using Flurl.Http -@using Newtonsoft.Json +@using TrashLib.Cache +@using TrashLib.Radarr.CustomFormat
@@ -49,11 +50,11 @@ return; } - + @foreach (var profile in _profiles) { - - @((string) profile["name"]) + + @profile.Name } @@ -76,13 +77,19 @@ @if (SelectedProfile != null) { - @foreach (var formatItem in SelectedProfile["formatItems"].Children()) + @foreach (var formatItem in SelectedProfile.FormatItems) { + @formatItem.Name + + + - - - @((int)formatItem["score"]) + @formatItem.Score } } @@ -108,6 +115,26 @@ await base.OnInitializedAsync(); } + class ProfileSelectionPageManager + { + private readonly Func _cachePersisterFactory; + private readonly Func _customFormatServiceFactory; + + public ProfileSelectionPageManager( + Func cachePersisterFactory, + Func customFormatServiceFactory) + { + _cachePersisterFactory = cachePersisterFactory; + _customFormatServiceFactory = customFormatServiceFactory; + } + + async Task RequestCustomFormatsAndUpdateCache(RadarrConfiguration config) + { + var cfService = _customFormatServiceFactory(config.BuildUrl()); + var customFormats = await cfService.GetCustomFormats(); + } + } + private async Task OnSelectedInstanceChanged(RadarrConfiguration? activeConfig) { try @@ -119,7 +146,14 @@ if (activeConfig != null) { - _profiles.AddRange(await ProfileServiceFactory(activeConfig.BuildUrl()).GetQualityProfiles()); + // todo: + // - Build the cache (for TrashID -> CfId mapping) + // - Need to pair guide score with current profile score + // - Exclude FormatItems that represent Custom Formats not selected by the user + // + var qualityProfiles = await ProfileServiceFactory(activeConfig.BuildUrl()).GetQualityProfiles(); + qualityProfiles.Where(_activeConfig.CustomFormats) + _profiles.AddRange(); } SelectedProfile = _profiles.FirstOrDefault(); @@ -134,7 +168,7 @@ private RadarrConfiguration? _activeConfig; private ServerSelector? _serverSelector; - private readonly List _profiles = new(); + private readonly List _profiles = new(); private Exception? _exception; private bool _loading; @@ -143,11 +177,7 @@ await OnSelectedInstanceChanged(_activeConfig); } - private JObject? SelectedProfile - { - get => _profiles.FirstOrDefault(p => (int) p["id"] == _selectedProfileId); - set => _selectedProfileId = (int?) value?["id"]; - } + private QualityProfileData? SelectedProfile { get; set; } - private int? _selectedProfileId; + // private int? _selectedProfileId; } diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs b/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs index 11df5eb6..70df6937 100644 --- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs +++ b/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using FluentAssertions; -using FluentAssertions.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NSubstitute; @@ -8,6 +7,7 @@ using NUnit.Framework; using TestLibrary.NSubstitute; using Trash.TestLibrary; using TrashLib.Radarr.CustomFormat.Api; +using TrashLib.Radarr.CustomFormat.Api.Models; using TrashLib.Radarr.CustomFormat.Models; using TrashLib.Radarr.CustomFormat.Models.Cache; using TrashLib.Radarr.CustomFormat.Processors.PersistenceSteps; @@ -43,7 +43,8 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps }]"; var api = Substitute.For(); - api.GetQualityProfiles().Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); + api.GetQualityProfiles() + .Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); var cfScores = new Dictionary { @@ -59,7 +60,7 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps var processor = new QualityProfileApiPersistenceStep(); processor.Process(api, cfScores); - api.DidNotReceive().UpdateQualityProfile(Arg.Any(), Arg.Any()); + api.DidNotReceive().UpdateQualityProfile(Arg.Any(), Arg.Any()); } [Test] @@ -68,7 +69,8 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps const string radarrQualityProfileData = @"[{'name': 'profile1'}]"; var api = Substitute.For(); - api.GetQualityProfiles().Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); + api.GetQualityProfiles() + .Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); var cfScores = new Dictionary { @@ -107,7 +109,8 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps }]"; var api = Substitute.For(); - api.GetQualityProfiles().Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); + api.GetQualityProfiles() + .Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); var cfScores = new Dictionary { @@ -134,7 +137,7 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps }); api.Received().UpdateQualityProfile( - Verify.That(j => j["formatItems"].Children().Should().HaveCount(3)), + Verify.That(j => j.FormatItems.Should().HaveCount(3)), Arg.Any()); } @@ -183,7 +186,8 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps }]"; var api = Substitute.For(); - api.GetQualityProfiles().Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); + api.GetQualityProfiles() + .Returns(JsonConvert.DeserializeObject>(radarrQualityProfileData)); var cfScores = new Dictionary { @@ -251,8 +255,8 @@ namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps 'id': 1 }"); - api.Received() - .UpdateQualityProfile(Verify.That(a => a.Should().BeEquivalentTo(expectedProfileJson)), 1); + api.Received().UpdateQualityProfile( + Verify.That(a => a.Should().BeEquivalentTo(expectedProfileJson)), 1); processor.InvalidProfileNames.Should().BeEmpty(); processor.UpdatedScores.Should() .ContainKey("profile1").WhichValue.Should() diff --git a/src/TrashLib/Radarr/CustomFormat/Api/IQualityProfileService.cs b/src/TrashLib/Radarr/CustomFormat/Api/IQualityProfileService.cs index f1ba6442..55dc2766 100644 --- a/src/TrashLib/Radarr/CustomFormat/Api/IQualityProfileService.cs +++ b/src/TrashLib/Radarr/CustomFormat/Api/IQualityProfileService.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using TrashLib.Radarr.CustomFormat.Api.Models; namespace TrashLib.Radarr.CustomFormat.Api { public interface IQualityProfileService { - Task> GetQualityProfiles(); - Task UpdateQualityProfile(JObject profileJson, int id); + Task> GetQualityProfiles(); + Task UpdateQualityProfile(QualityProfileData profile, int profileId); } } diff --git a/src/TrashLib/Radarr/CustomFormat/Api/Models/QualityProfileData.cs b/src/TrashLib/Radarr/CustomFormat/Api/Models/QualityProfileData.cs new file mode 100644 index 00000000..f26e815c --- /dev/null +++ b/src/TrashLib/Radarr/CustomFormat/Api/Models/QualityProfileData.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +// ReSharper disable CollectionNeverUpdated.Global + +namespace TrashLib.Radarr.CustomFormat.Api.Models +{ + public class QualityProfileData + { + [UsedImplicitly] + [JsonExtensionData] + private JObject? _extraJson; + + public int Id { get; [UsedImplicitly] set; } + public string Name { get; [UsedImplicitly] set; } = ""; + public List FormatItems { get; [UsedImplicitly] set; } = new(); + + public class FormatItemData + { + [UsedImplicitly] + [JsonExtensionData] + private JObject? _extraJson; + + public int Format { get; [UsedImplicitly] set; } + public string Name { get; [UsedImplicitly] set; } = ""; + public int Score { get; [UsedImplicitly] set; } + } + } +} diff --git a/src/TrashLib/Radarr/CustomFormat/Api/Models/foo.cs b/src/TrashLib/Radarr/CustomFormat/Api/Models/foo.cs deleted file mode 100644 index 0965954d..00000000 --- a/src/TrashLib/Radarr/CustomFormat/Api/Models/foo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace TrashLib.Radarr.CustomFormat.Api.Models -{ - public class QualityProfileData - { - [JsonExtensionData] private IDictionary _extraJson; - - public int Id { get; set; } - public string Name { get; set; } - public List FormatItems { get; set; } - - public class FormatItemData - { - // public int Format { get; set; } - public string Name { get; set; } - public int Score { get; set; } - } - } -} diff --git a/src/TrashLib/Radarr/CustomFormat/Api/QualityProfileService.cs b/src/TrashLib/Radarr/CustomFormat/Api/QualityProfileService.cs index d768a0c6..081c76e9 100644 --- a/src/TrashLib/Radarr/CustomFormat/Api/QualityProfileService.cs +++ b/src/TrashLib/Radarr/CustomFormat/Api/QualityProfileService.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Flurl; using Flurl.Http; -using Newtonsoft.Json.Linq; +using TrashLib.Radarr.CustomFormat.Api.Models; namespace TrashLib.Radarr.CustomFormat.Api { @@ -15,19 +15,19 @@ namespace TrashLib.Radarr.CustomFormat.Api _baseUrl = baseUrl; } - public async Task> GetQualityProfiles() + public async Task> GetQualityProfiles() { return await _baseUrl .AppendPathSegment("qualityprofile") - .GetJsonAsync>(); + .GetJsonAsync>(); } - public async Task UpdateQualityProfile(JObject profileJson, int id) + public async Task UpdateQualityProfile(QualityProfileData profile, int profileId) { return await _baseUrl - .AppendPathSegment($"qualityprofile/{id}") - .PutJsonAsync(profileJson) - .ReceiveJson(); + .AppendPathSegment($"qualityprofile/{profileId}") + .PutJsonAsync(profile) + .ReceiveJson(); } } } diff --git a/src/TrashLib/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs b/src/TrashLib/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs index 983dcdba..94785729 100644 --- a/src/TrashLib/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs +++ b/src/TrashLib/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Common.Extensions; -using Newtonsoft.Json.Linq; using TrashLib.Radarr.CustomFormat.Api; +using TrashLib.Radarr.CustomFormat.Api.Models; using TrashLib.Radarr.CustomFormat.Models; namespace TrashLib.Radarr.CustomFormat.Processors.PersistenceSteps @@ -28,21 +28,23 @@ namespace TrashLib.Radarr.CustomFormat.Processors.PersistenceSteps // do not match profiles in Radarr. var profileScores = cfScores.GroupJoin(radarrProfiles, s => s.Key, - p => (string) p["name"], - (s, p) => (s.Key, s.Value, p.SelectMany(pi => pi["formatItems"].Children()).ToList()), + p => p.Name, + (s, p) => (s.Key, s.Value, p.First()), StringComparer.InvariantCultureIgnoreCase); - foreach (var (profileName, scoreMap, formatItems) in profileScores) + foreach (var (profileName, scoreMap, profileData) in profileScores) { + // `SelectMany` is only needed here because we used GroupJoin() above the loop. + var formatItems = profileData.FormatItems; if (formatItems.Count == 0) { _invalidProfileNames.Add(profileName); continue; } - foreach (var json in formatItems) + foreach (var formatItem in formatItems) { - var map = FindScoreEntry(json, scoreMap); + var map = FindScoreEntry(formatItem, scoreMap); int? scoreToUse = null; FormatScoreUpdateReason? reason = null; @@ -58,33 +60,31 @@ namespace TrashLib.Radarr.CustomFormat.Processors.PersistenceSteps reason = FormatScoreUpdateReason.Reset; } - if (scoreToUse == null || reason == null || (int) json["score"] == scoreToUse) + if (scoreToUse == null || reason == null || formatItem.Score == scoreToUse) { continue; } - json["score"] = scoreToUse.Value; + formatItem.Score = scoreToUse.Value; _updatedScores.GetOrCreate(profileName) - .Add(new UpdatedFormatScore((string) json["name"], scoreToUse.Value, reason.Value)); + .Add(new UpdatedFormatScore(formatItem.Name, scoreToUse.Value, reason.Value)); } if (!_updatedScores.TryGetValue(profileName, out var updatedScores) || updatedScores.Count == 0) { // No scores to update, so don't bother with the API call - continue; } - var jsonRoot = (JObject) formatItems.First().Root; - await api.UpdateQualityProfile(jsonRoot, (int) jsonRoot["id"]); + await api.UpdateQualityProfile(profileData, profileData.Id); } } - private static FormatMappingEntry? FindScoreEntry(JObject formatItem, + private static FormatMappingEntry? FindScoreEntry(QualityProfileData.FormatItemData formatItem, QualityProfileCustomFormatScoreMapping scoreMap) { return scoreMap.Mapping.FirstOrDefault( m => m.CustomFormat.CacheEntry != null && - (int) formatItem["format"] == m.CustomFormat.CacheEntry.CustomFormatId); + formatItem.Format == m.CustomFormat.CacheEntry.CustomFormatId); } } } diff --git a/src/TrashLib/Radarr/RadarrAutofacModule.cs b/src/TrashLib/Radarr/RadarrAutofacModule.cs index d42321da..05549672 100644 --- a/src/TrashLib/Radarr/RadarrAutofacModule.cs +++ b/src/TrashLib/Radarr/RadarrAutofacModule.cs @@ -17,24 +17,24 @@ namespace TrashLib.Radarr { public class RadarrAutofacModule : Module { - class CachePersisterFactory - { - private readonly Func _guidBuilderFactory; - private readonly Func _persisterFactory; - - public CachePersisterFactory( - Func guidBuilderFactory, - Func persisterFactory) - { - _guidBuilderFactory = guidBuilderFactory; - _persisterFactory = persisterFactory; - } - - public ICachePersister Create(IServiceConfiguration config) - { - return _persisterFactory(_guidBuilderFactory(config)); - } - } + // class CachePersisterFactory + // { + // private readonly Func _guidBuilderFactory; + // private readonly Func _persisterFactory; + // + // public CachePersisterFactory( + // Func guidBuilderFactory, + // Func persisterFactory) + // { + // _guidBuilderFactory = guidBuilderFactory; + // _persisterFactory = persisterFactory; + // } + // + // public ICachePersister Create(IServiceConfiguration config) + // { + // return _persisterFactory(_guidBuilderFactory(config)); + // } + // } protected override void Load(ContainerBuilder builder) {