mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-10-28 10:48:49 -04:00
added wanted list reads to sonarr and radarr
This commit is contained in:
1 parent
3f29613499
commit
00a1cdeda7
9 files changed
+286
No files matched your search
@@ -36,6 +36,16 @@ public abstract class ArrClient : IArrClient
|
||||
/// </summary>
|
||||
protected const int QueuePageSize = 200;
|
||||
|
||||
/// <summary>
|
||||
/// Page size used when paging through an *arr instance's wanted lists.
|
||||
/// </summary>
|
||||
protected const int WantedPageSize = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Hard cap on pages read from a wanted list, so a stuck pagination loop can't run forever.
|
||||
/// </summary>
|
||||
private const int MaxWantedPages = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Command API path for this app's API version.
|
||||
/// </summary>
|
||||
@@ -308,6 +318,71 @@ public abstract class ArrClient : IArrClient
|
||||
return await DeserializeStreamAsync<List<ArrHistoryRecord>>(response, cancellationToken) ?? [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads every record of a paged wanted list (missing or cutoff) from an arr instance.
|
||||
/// </summary>
|
||||
/// <param name="arrInstance">The arr instance to query.</param>
|
||||
/// <param name="wantedKind">The wanted list to read, "missing" or "cutoff".</param>
|
||||
/// <param name="monitored">Only monitored items when true, only unmonitored items when false.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
protected async Task<List<T>> GetAllWantedAsync<T>(
|
||||
ArrInstance arrInstance,
|
||||
string wantedKind,
|
||||
bool monitored,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
List<T> records = [];
|
||||
int totalRecords = 0;
|
||||
int page = 1;
|
||||
string monitoredValue = monitored ? "true" : "false";
|
||||
|
||||
do
|
||||
{
|
||||
UriBuilder uriBuilder = new(arrInstance.Url);
|
||||
uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/{ApiVersion}/wanted/{wantedKind}";
|
||||
uriBuilder.Query = $"page={page}&pageSize={WantedPageSize}&monitored={monitoredValue}";
|
||||
|
||||
using HttpRequestMessage request = new(HttpMethod.Get, uriBuilder.Uri);
|
||||
SetApiKey(request, arrInstance.ApiKey);
|
||||
|
||||
using HttpResponseMessage response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogError("wanted {Kind} failed | {Uri}", wantedKind, uriBuilder.Uri);
|
||||
throw;
|
||||
}
|
||||
|
||||
ArrPagedResponse<T>? wantedResponse = await DeserializeStreamAsync<ArrPagedResponse<T>>(response, cancellationToken);
|
||||
|
||||
if (wantedResponse is null || wantedResponse.Records.Count is 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (totalRecords is 0)
|
||||
{
|
||||
totalRecords = wantedResponse.TotalRecords;
|
||||
}
|
||||
|
||||
records.AddRange(wantedResponse.Records);
|
||||
|
||||
if (records.Count >= totalRecords)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
page++;
|
||||
} while (page <= MaxWantedPages);
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ManualImportFile? MapCandidate(QueueRecord record, ManualImportCandidate candidate) => null;
|
||||
|
||||
|
||||
@@ -24,4 +24,14 @@ public interface IRadarrClient : IArrClient
|
||||
/// Fetches the ids of movies Radarr grabbed since the given time.
|
||||
/// </summary>
|
||||
Task<HashSet<long>> GetRecentlyGrabbedMovieIdsAsync(ArrInstance arrInstance, DateTimeOffset since, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches every movie Radarr lists as missing, filtered by monitored state.
|
||||
/// </summary>
|
||||
Task<List<SearchableMovie>> GetMissingMoviesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches every movie Radarr lists as a cutoff-unmet upgrade, filtered by monitored state.
|
||||
/// </summary>
|
||||
Task<List<SearchableMovie>> GetCutoffUnmetMoviesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -34,4 +34,14 @@ public interface ISonarrClient : IArrClient
|
||||
/// Fetches the series/season pairs Sonarr grabbed an episode for since the given time.
|
||||
/// </summary>
|
||||
Task<HashSet<(long SeriesId, long SeasonNumber)>> GetRecentlyGrabbedSeasonsAsync(ArrInstance arrInstance, DateTimeOffset since, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches every episode Sonarr lists as missing, filtered by monitored state.
|
||||
/// </summary>
|
||||
Task<List<SearchableEpisode>> GetMissingEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches every episode Sonarr lists as a cutoff-unmet upgrade, filtered by monitored state.
|
||||
/// </summary>
|
||||
Task<List<SearchableEpisode>> GetCutoffUnmetEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -234,6 +234,14 @@ public class RadarrClient : ArrClient, IRadarrClient
|
||||
.ToHashSet();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SearchableMovie>> GetMissingMoviesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
await GetAllWantedAsync<SearchableMovie>(arrInstance, "missing", monitored, cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SearchableMovie>> GetCutoffUnmetMoviesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
await GetAllWantedAsync<SearchableMovie>(arrInstance, "cutoff", monitored, cancellationToken);
|
||||
|
||||
private async Task<Movie?> GetMovie(ArrInstance arrInstance, long movieId)
|
||||
{
|
||||
UriBuilder uriBuilder = new(arrInstance.Url);
|
||||
|
||||
@@ -350,6 +350,14 @@ public class SonarrClient : ArrClient, ISonarrClient
|
||||
.ToHashSet();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SearchableEpisode>> GetMissingEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
await GetAllWantedAsync<SearchableEpisode>(arrInstance, "missing", monitored, cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SearchableEpisode>> GetCutoffUnmetEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
await GetAllWantedAsync<SearchableEpisode>(arrInstance, "cutoff", monitored, cancellationToken);
|
||||
|
||||
private async Task<List<Episode>?> GetEpisodesAsync(ArrInstance arrInstance, List<long> episodeIds)
|
||||
{
|
||||
UriBuilder uriBuilder = new(arrInstance.Url);
|
||||
|
||||
Reference in new issue
Block a user