From a1354f231a409dc66b81eb7521d5940169eee787 Mon Sep 17 00:00:00 2001 From: Flaminel Date: Thu, 20 Mar 2025 00:08:51 +0200 Subject: [PATCH] Add base path support for arrs (#96) --- .../Infrastructure/Verticals/Arr/ArrClient.cs | 26 ++++++++---- .../Verticals/Arr/LidarrClient.cs | 38 ++++++++++++----- .../Verticals/Arr/RadarrClient.cs | 35 +++++++++++----- .../Verticals/Arr/SonarrClient.cs | 41 +++++++++++++------ 4 files changed, 96 insertions(+), 44 deletions(-) diff --git a/code/Infrastructure/Verticals/Arr/ArrClient.cs b/code/Infrastructure/Verticals/Arr/ArrClient.cs index 2af6d02..d5d87ce 100644 --- a/code/Infrastructure/Verticals/Arr/ArrClient.cs +++ b/code/Infrastructure/Verticals/Arr/ArrClient.cs @@ -43,9 +43,11 @@ public abstract class ArrClient : IArrClient public virtual async Task GetQueueItemsAsync(ArrInstance arrInstance, int page) { - Uri uri = new(arrInstance.Url, GetQueueUrlPath(page)); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/{GetQueueUrlPath().TrimStart('/')}"; + uriBuilder.Query = GetQueueUrlQuery(page); - using HttpRequestMessage request = new(HttpMethod.Get, uri); + using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); using HttpResponseMessage response = await _httpClient.SendAsync(request); @@ -56,7 +58,7 @@ public abstract class ArrClient : IArrClient } catch { - _logger.LogError("queue list failed | {uri}", uri); + _logger.LogError("queue list failed | {uri}", uriBuilder.Uri); throw; } @@ -65,7 +67,7 @@ public abstract class ArrClient : IArrClient if (queueResponse is null) { - throw new Exception($"unrecognized queue list response | {uri} | {responseBody}"); + throw new Exception($"unrecognized queue list response | {uriBuilder.Uri} | {responseBody}"); } return queueResponse; @@ -114,11 +116,13 @@ public abstract class ArrClient : IArrClient public virtual async Task DeleteQueueItemAsync(ArrInstance arrInstance, QueueRecord record, bool removeFromClient) { - Uri uri = new(arrInstance.Url, GetQueueDeleteUrlPath(record.Id, removeFromClient)); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/{GetQueueDeleteUrlPath(record.Id).TrimStart('/')}"; + uriBuilder.Query = GetQueueDeleteUrlQuery(removeFromClient); try { - using HttpRequestMessage request = new(HttpMethod.Delete, uri); + using HttpRequestMessage request = new(HttpMethod.Delete, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync(SendRequestAsync, request); @@ -134,7 +138,7 @@ public abstract class ArrClient : IArrClient } catch { - _logger.LogError("queue delete failed | {uri} | {title}", uri, record.Title); + _logger.LogError("queue delete failed | {uri} | {title}", uriBuilder.Uri, record.Title); throw; } } @@ -152,9 +156,13 @@ public abstract class ArrClient : IArrClient return true; } - protected abstract string GetQueueUrlPath(int page); + protected abstract string GetQueueUrlPath(); - protected abstract string GetQueueDeleteUrlPath(long recordId, bool removeFromClient); + protected abstract string GetQueueUrlQuery(int page); + + protected abstract string GetQueueDeleteUrlPath(long recordId); + + protected abstract string GetQueueDeleteUrlQuery(bool removeFromClient); protected virtual void SetApiKey(HttpRequestMessage request, string apiKey) { diff --git a/code/Infrastructure/Verticals/Arr/LidarrClient.cs b/code/Infrastructure/Verticals/Arr/LidarrClient.cs index 08ee3f7..730615c 100644 --- a/code/Infrastructure/Verticals/Arr/LidarrClient.cs +++ b/code/Infrastructure/Verticals/Arr/LidarrClient.cs @@ -27,29 +27,42 @@ public class LidarrClient : ArrClient, ILidarrClient { } - protected override string GetQueueUrlPath(int page) + protected override string GetQueueUrlPath() { - return $"/api/v1/queue?page={page}&pageSize=200&includeUnknownArtistItems=true&includeArtist=true&includeAlbum=true"; + return "/api/v1/queue"; } - protected override string GetQueueDeleteUrlPath(long recordId, bool removeFromClient) + protected override string GetQueueUrlQuery(int page) { - string path = $"/api/v1/queue/{recordId}?blocklist=true&skipRedownload=true&changeCategory=false"; + return $"page={page}&pageSize=200&includeUnknownArtistItems=true&includeArtist=true&includeAlbum=true"; + } - path += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + protected override string GetQueueDeleteUrlPath(long recordId) + { + return $"/api/v1/queue/{recordId}"; + } - return path; + protected override string GetQueueDeleteUrlQuery(bool removeFromClient) + { + string query = "blocklist=true&skipRedownload=true&changeCategory=false"; + query += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + + return query; } public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet? items) { - if (items?.Count is null or 0) return; + if (items?.Count is null or 0) + { + return; + } - Uri uri = new(arrInstance.Url, "/api/v1/command"); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v1/command"; foreach (var command in GetSearchCommands(items)) { - using HttpRequestMessage request = new(HttpMethod.Post, uri); + using HttpRequestMessage request = new(HttpMethod.Post, uriBuilder.Uri); request.Content = new StringContent( JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, @@ -132,8 +145,11 @@ public class LidarrClient : ArrClient, ILidarrClient private async Task?> GetAlbumsAsync(ArrInstance arrInstance, List albumIds) { - Uri uri = new(arrInstance.Url, $"api/v1/album?{string.Join('&', albumIds.Select(x => $"albumIds={x}"))}"); - using HttpRequestMessage request = new(HttpMethod.Get, uri); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v1/album"; + uriBuilder.Query = string.Join('&', albumIds.Select(x => $"albumIds={x}")); + + using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); using var response = await _httpClient.SendAsync(request); diff --git a/code/Infrastructure/Verticals/Arr/RadarrClient.cs b/code/Infrastructure/Verticals/Arr/RadarrClient.cs index 86add32..7b9e696 100644 --- a/code/Infrastructure/Verticals/Arr/RadarrClient.cs +++ b/code/Infrastructure/Verticals/Arr/RadarrClient.cs @@ -27,18 +27,27 @@ public class RadarrClient : ArrClient, IRadarrClient { } - protected override string GetQueueUrlPath(int page) + protected override string GetQueueUrlPath() { - return $"/api/v3/queue?page={page}&pageSize=200&includeUnknownMovieItems=true&includeMovie=true"; + return "/api/v3/queue"; } - protected override string GetQueueDeleteUrlPath(long recordId, bool removeFromClient) + protected override string GetQueueUrlQuery(int page) { - string path = $"/api/v3/queue/{recordId}?blocklist=true&skipRedownload=true&changeCategory=false"; - - path += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + return $"page={page}&pageSize=200&includeUnknownMovieItems=true&includeMovie=true"; + } - return path; + protected override string GetQueueDeleteUrlPath(long recordId) + { + return $"/api/v3/queue/{recordId}"; + } + + protected override string GetQueueDeleteUrlQuery(bool removeFromClient) + { + string query = "blocklist=true&skipRedownload=true&changeCategory=false"; + query += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + + return query; } public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet? items) @@ -50,14 +59,16 @@ public class RadarrClient : ArrClient, IRadarrClient List ids = items.Select(item => item.Id).ToList(); - Uri uri = new(arrInstance.Url, "/api/v3/command"); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/command"; + RadarrCommand command = new() { Name = "MoviesSearch", MovieIds = ids, }; - using HttpRequestMessage request = new(HttpMethod.Post, uri); + using HttpRequestMessage request = new(HttpMethod.Post, uriBuilder.Uri); request.Content = new StringContent( JsonConvert.SerializeObject(command), Encoding.UTF8, @@ -135,8 +146,10 @@ public class RadarrClient : ArrClient, IRadarrClient private async Task GetMovie(ArrInstance arrInstance, long movieId) { - Uri uri = new(arrInstance.Url, $"api/v3/movie/{movieId}"); - using HttpRequestMessage request = new(HttpMethod.Get, uri); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/movie/{movieId}"; + + using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); using HttpResponseMessage response = await _httpClient.SendAsync(request); diff --git a/code/Infrastructure/Verticals/Arr/SonarrClient.cs b/code/Infrastructure/Verticals/Arr/SonarrClient.cs index bfba28a..2f5aa44 100644 --- a/code/Infrastructure/Verticals/Arr/SonarrClient.cs +++ b/code/Infrastructure/Verticals/Arr/SonarrClient.cs @@ -28,18 +28,27 @@ public class SonarrClient : ArrClient, ISonarrClient { } - protected override string GetQueueUrlPath(int page) + protected override string GetQueueUrlPath() { - return $"/api/v3/queue?page={page}&pageSize=200&includeUnknownSeriesItems=true&includeSeries=true&includeEpisode=true"; + return "/api/v3/queue"; } - - protected override string GetQueueDeleteUrlPath(long recordId, bool removeFromClient) + + protected override string GetQueueUrlQuery(int page) { - string path = $"/api/v3/queue/{recordId}?blocklist=true&skipRedownload=true&changeCategory=false"; + return $"page={page}&pageSize=200&includeUnknownSeriesItems=true&includeSeries=true&includeEpisode=true"; + } - path += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + protected override string GetQueueDeleteUrlPath(long recordId) + { + return $"/api/v3/queue/{recordId}"; + } - return path; + protected override string GetQueueDeleteUrlQuery(bool removeFromClient) + { + string query = "blocklist=true&skipRedownload=true&changeCategory=false"; + query += removeFromClient ? "&removeFromClient=true" : "&removeFromClient=false"; + + return query; } public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet? items) @@ -49,11 +58,12 @@ public class SonarrClient : ArrClient, ISonarrClient return; } - Uri uri = new(arrInstance.Url, "/api/v3/command"); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/command"; foreach (SonarrCommand command in GetSearchCommands(items.Cast().ToHashSet())) { - using HttpRequestMessage request = new(HttpMethod.Post, uri); + using HttpRequestMessage request = new(HttpMethod.Post, uriBuilder.Uri); request.Content = new StringContent( JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, @@ -199,8 +209,11 @@ public class SonarrClient : ArrClient, ISonarrClient private async Task?> GetEpisodesAsync(ArrInstance arrInstance, List episodeIds) { - Uri uri = new(arrInstance.Url, $"api/v3/episode?{string.Join('&', episodeIds.Select(x => $"episodeIds={x}"))}"); - using HttpRequestMessage request = new(HttpMethod.Get, uri); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/episode"; + uriBuilder.Query = string.Join('&', episodeIds.Select(x => $"episodeIds={x}")); + + using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); using HttpResponseMessage response = await _httpClient.SendAsync(request); @@ -212,8 +225,10 @@ public class SonarrClient : ArrClient, ISonarrClient private async Task GetSeriesAsync(ArrInstance arrInstance, long seriesId) { - Uri uri = new(arrInstance.Url, $"api/v3/series/{seriesId}"); - using HttpRequestMessage request = new(HttpMethod.Get, uri); + UriBuilder uriBuilder = new(arrInstance.Url); + uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/series/{seriesId}"; + + using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri); SetApiKey(request, arrInstance.ApiKey); using HttpResponseMessage response = await _httpClient.SendAsync(request);