Add base path support for arrs (#96)

This commit is contained in:
Flaminel
2025-03-20 00:08:51 +02:00
committed by GitHub
parent 4bc1c33e81
commit a1354f231a
4 changed files with 96 additions and 44 deletions
+17 -9
View File
@@ -43,9 +43,11 @@ public abstract class ArrClient : IArrClient
public virtual async Task<QueueListResponse> GetQueueItemsAsync(ArrInstance arrInstance, int page) public virtual async Task<QueueListResponse> 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); SetApiKey(request, arrInstance.ApiKey);
using HttpResponseMessage response = await _httpClient.SendAsync(request); using HttpResponseMessage response = await _httpClient.SendAsync(request);
@@ -56,7 +58,7 @@ public abstract class ArrClient : IArrClient
} }
catch catch
{ {
_logger.LogError("queue list failed | {uri}", uri); _logger.LogError("queue list failed | {uri}", uriBuilder.Uri);
throw; throw;
} }
@@ -65,7 +67,7 @@ public abstract class ArrClient : IArrClient
if (queueResponse is null) 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; return queueResponse;
@@ -114,11 +116,13 @@ public abstract class ArrClient : IArrClient
public virtual async Task DeleteQueueItemAsync(ArrInstance arrInstance, QueueRecord record, bool removeFromClient) 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 try
{ {
using HttpRequestMessage request = new(HttpMethod.Delete, uri); using HttpRequestMessage request = new(HttpMethod.Delete, uriBuilder.Uri);
SetApiKey(request, arrInstance.ApiKey); SetApiKey(request, arrInstance.ApiKey);
HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request); HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request);
@@ -134,7 +138,7 @@ public abstract class ArrClient : IArrClient
} }
catch catch
{ {
_logger.LogError("queue delete failed | {uri} | {title}", uri, record.Title); _logger.LogError("queue delete failed | {uri} | {title}", uriBuilder.Uri, record.Title);
throw; throw;
} }
} }
@@ -152,9 +156,13 @@ public abstract class ArrClient : IArrClient
return true; 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) protected virtual void SetApiKey(HttpRequestMessage request, string apiKey)
{ {
@@ -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<SearchItem>? items) public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? 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)) 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( request.Content = new StringContent(
JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
Encoding.UTF8, Encoding.UTF8,
@@ -132,8 +145,11 @@ public class LidarrClient : ArrClient, ILidarrClient
private async Task<List<Album>?> GetAlbumsAsync(ArrInstance arrInstance, List<long> albumIds) private async Task<List<Album>?> GetAlbumsAsync(ArrInstance arrInstance, List<long> albumIds)
{ {
Uri uri = new(arrInstance.Url, $"api/v1/album?{string.Join('&', albumIds.Select(x => $"albumIds={x}"))}"); UriBuilder uriBuilder = new(arrInstance.Url);
using HttpRequestMessage request = new(HttpMethod.Get, uri); 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); SetApiKey(request, arrInstance.ApiKey);
using var response = await _httpClient.SendAsync(request); using var response = await _httpClient.SendAsync(request);
@@ -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"; return $"page={page}&pageSize=200&includeUnknownMovieItems=true&includeMovie=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<SearchItem>? items) public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
@@ -50,14 +59,16 @@ public class RadarrClient : ArrClient, IRadarrClient
List<long> ids = items.Select(item => item.Id).ToList(); List<long> 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() RadarrCommand command = new()
{ {
Name = "MoviesSearch", Name = "MoviesSearch",
MovieIds = ids, MovieIds = ids,
}; };
using HttpRequestMessage request = new(HttpMethod.Post, uri); using HttpRequestMessage request = new(HttpMethod.Post, uriBuilder.Uri);
request.Content = new StringContent( request.Content = new StringContent(
JsonConvert.SerializeObject(command), JsonConvert.SerializeObject(command),
Encoding.UTF8, Encoding.UTF8,
@@ -135,8 +146,10 @@ public class RadarrClient : ArrClient, IRadarrClient
private async Task<Movie?> GetMovie(ArrInstance arrInstance, long movieId) private async Task<Movie?> GetMovie(ArrInstance arrInstance, long movieId)
{ {
Uri uri = new(arrInstance.Url, $"api/v3/movie/{movieId}"); UriBuilder uriBuilder = new(arrInstance.Url);
using HttpRequestMessage request = new(HttpMethod.Get, uri); uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/movie/{movieId}";
using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri);
SetApiKey(request, arrInstance.ApiKey); SetApiKey(request, arrInstance.ApiKey);
using HttpResponseMessage response = await _httpClient.SendAsync(request); using HttpResponseMessage response = await _httpClient.SendAsync(request);
@@ -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<SearchItem>? items) public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
@@ -49,11 +58,12 @@ public class SonarrClient : ArrClient, ISonarrClient
return; 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<SonarrSearchItem>().ToHashSet())) foreach (SonarrCommand command in GetSearchCommands(items.Cast<SonarrSearchItem>().ToHashSet()))
{ {
using HttpRequestMessage request = new(HttpMethod.Post, uri); using HttpRequestMessage request = new(HttpMethod.Post, uriBuilder.Uri);
request.Content = new StringContent( request.Content = new StringContent(
JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), JsonConvert.SerializeObject(command, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
Encoding.UTF8, Encoding.UTF8,
@@ -199,8 +209,11 @@ public class SonarrClient : ArrClient, ISonarrClient
private async Task<List<Episode>?> GetEpisodesAsync(ArrInstance arrInstance, List<long> episodeIds) private async Task<List<Episode>?> GetEpisodesAsync(ArrInstance arrInstance, List<long> episodeIds)
{ {
Uri uri = new(arrInstance.Url, $"api/v3/episode?{string.Join('&', episodeIds.Select(x => $"episodeIds={x}"))}"); UriBuilder uriBuilder = new(arrInstance.Url);
using HttpRequestMessage request = new(HttpMethod.Get, uri); 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); SetApiKey(request, arrInstance.ApiKey);
using HttpResponseMessage response = await _httpClient.SendAsync(request); using HttpResponseMessage response = await _httpClient.SendAsync(request);
@@ -212,8 +225,10 @@ public class SonarrClient : ArrClient, ISonarrClient
private async Task<Series?> GetSeriesAsync(ArrInstance arrInstance, long seriesId) private async Task<Series?> GetSeriesAsync(ArrInstance arrInstance, long seriesId)
{ {
Uri uri = new(arrInstance.Url, $"api/v3/series/{seriesId}"); UriBuilder uriBuilder = new(arrInstance.Url);
using HttpRequestMessage request = new(HttpMethod.Get, uri); uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/v3/series/{seriesId}";
using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri);
SetApiKey(request, arrInstance.ApiKey); SetApiKey(request, arrInstance.ApiKey);
using HttpResponseMessage response = await _httpClient.SendAsync(request); using HttpResponseMessage response = await _httpClient.SendAsync(request);