mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-10-28 10:48:49 -04:00
added whisparr v2 release date to episodes
This commit is contained in:
1 parent
b51d8323a6
commit
91dca8cb84
5 files changed
+96
-4
No files matched your search
@@ -14,6 +14,11 @@ public sealed record SearchableEpisode
|
||||
|
||||
public DateTimeOffset? AirDateUtc { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whisparr v2 sends a release date in place of an air date.
|
||||
/// </summary>
|
||||
public DateOnly? ReleaseDate { get; init; }
|
||||
|
||||
public bool HasFile { get; init; }
|
||||
|
||||
public long EpisodeFileId { get; init; }
|
||||
|
||||
@@ -135,8 +135,72 @@ public class WhisparrV2ClientTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region Release date
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_ReleaseDate_BecomesMidnightUtcAirDate()
|
||||
{
|
||||
// Arrange
|
||||
RouteEpisodes("""[{"id":1,"seriesId":10,"seasonNumber":2024,"releaseDate":"2024-05-12"}]""");
|
||||
|
||||
// Act
|
||||
List<SearchableEpisode> episodes = await _client.GetEpisodesAsync(_arrInstance, seriesId: 10);
|
||||
|
||||
// Assert
|
||||
episodes.ShouldHaveSingleItem().AirDateUtc.ShouldBe(new DateTimeOffset(2024, 5, 12, 0, 0, 0, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetMissingEpisodesAsync_ReleaseDate_BecomesMidnightUtcAirDate()
|
||||
{
|
||||
// Arrange
|
||||
RouteEpisodes("""{"page":1,"pageSize":1000,"totalRecords":1,"records":[{"id":1,"seriesId":10,"seasonNumber":2024,"releaseDate":"2024-05-12"}]}""");
|
||||
|
||||
// Act
|
||||
List<SearchableEpisode> episodes = await _client.GetMissingEpisodesAsync(_arrInstance, monitored: true);
|
||||
|
||||
// Assert
|
||||
episodes.ShouldHaveSingleItem().AirDateUtc.ShouldBe(new DateTimeOffset(2024, 5, 12, 0, 0, 0, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCutoffUnmetEpisodesAsync_ReleaseDate_BecomesMidnightUtcAirDate()
|
||||
{
|
||||
// Arrange
|
||||
RouteEpisodes("""{"page":1,"pageSize":1000,"totalRecords":1,"records":[{"id":1,"seriesId":10,"seasonNumber":2024,"releaseDate":"2024-05-12"}]}""");
|
||||
|
||||
// Act
|
||||
List<SearchableEpisode> episodes = await _client.GetCutoffUnmetEpisodesAsync(_arrInstance, monitored: true);
|
||||
|
||||
// Assert
|
||||
episodes.ShouldHaveSingleItem().AirDateUtc.ShouldBe(new DateTimeOffset(2024, 5, 12, 0, 0, 0, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_NoReleaseDate_LeavesAirDateNull()
|
||||
{
|
||||
// Arrange
|
||||
RouteEpisodes("""[{"id":1,"seriesId":10,"seasonNumber":2024}]""");
|
||||
|
||||
// Act
|
||||
List<SearchableEpisode> episodes = await _client.GetEpisodesAsync(_arrInstance, seriesId: 10);
|
||||
|
||||
// Assert
|
||||
episodes.ShouldHaveSingleItem().AirDateUtc.ShouldBeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void RouteEpisodes(string json)
|
||||
{
|
||||
_httpMessageHandler.SetupResponse((_, _) => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json"),
|
||||
}));
|
||||
}
|
||||
|
||||
private void RouteResponses()
|
||||
{
|
||||
_httpMessageHandler.SetupResponse((req, _) =>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
namespace Cleanuparr.Infrastructure.Features.Arr.Interfaces;
|
||||
|
||||
public interface IWhisparrV2Client : IArrClient
|
||||
public interface IWhisparrV2Client : ISonarrClient
|
||||
{
|
||||
}
|
||||
@@ -267,7 +267,7 @@ public class SonarrClient : ArrClient, ISonarrClient
|
||||
return await DeserializeStreamAsync<List<Tag>>(response) ?? [];
|
||||
}
|
||||
|
||||
public async Task<List<SearchableEpisode>> GetEpisodesAsync(ArrInstance arrInstance, long seriesId, CancellationToken cancellationToken = default)
|
||||
public virtual async Task<List<SearchableEpisode>> GetEpisodesAsync(ArrInstance arrInstance, long seriesId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
UriBuilder uriBuilder = new(arrInstance.Url);
|
||||
uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/api/{ApiVersion}/episode";
|
||||
@@ -351,11 +351,11 @@ public class SonarrClient : ArrClient, ISonarrClient
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SearchableEpisode>> GetMissingEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
public virtual 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) =>
|
||||
public virtual 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)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Cleanuparr.Domain.Entities.Arr;
|
||||
using Cleanuparr.Infrastructure.Features.Arr.Interfaces;
|
||||
using Cleanuparr.Infrastructure.Features.ItemStriker;
|
||||
using Cleanuparr.Infrastructure.Interceptors;
|
||||
using Cleanuparr.Persistence.Models.Configuration.Arr;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Cleanuparr.Infrastructure.Features.Arr;
|
||||
@@ -15,4 +17,25 @@ public class WhisparrV2Client : SonarrClient, IWhisparrV2Client
|
||||
) : base(logger, httpClientFactory, striker, dryRunInterceptor)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<List<SearchableEpisode>> GetEpisodesAsync(ArrInstance arrInstance, long seriesId, CancellationToken cancellationToken = default) =>
|
||||
WithAirDates(await base.GetEpisodesAsync(arrInstance, seriesId, cancellationToken));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<List<SearchableEpisode>> GetMissingEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
WithAirDates(await base.GetMissingEpisodesAsync(arrInstance, monitored, cancellationToken));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<List<SearchableEpisode>> GetCutoffUnmetEpisodesAsync(ArrInstance arrInstance, bool monitored, CancellationToken cancellationToken = default) =>
|
||||
WithAirDates(await base.GetCutoffUnmetEpisodesAsync(arrInstance, monitored, cancellationToken));
|
||||
|
||||
private static List<SearchableEpisode> WithAirDates(List<SearchableEpisode> episodes) =>
|
||||
episodes
|
||||
.Select(e => e with
|
||||
{
|
||||
AirDateUtc = e.AirDateUtc
|
||||
?? (e.ReleaseDate is { } releaseDate ? new DateTimeOffset(releaseDate.ToDateTime(TimeOnly.MinValue), TimeSpan.Zero) : null),
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
Reference in new issue
Block a user