Updated logic for getting released work information (take 60 day period max limit into consideration).
This commit is contained in:
@@ -4,11 +4,8 @@ namespace JSMR.Application.Scanning.Contracts;
|
|||||||
|
|
||||||
public class DLSiteWork
|
public class DLSiteWork
|
||||||
{
|
{
|
||||||
//public DLSiteWorkType Type { get; set; }
|
|
||||||
//public DLSiteWorkCategory Category { get; set; }
|
|
||||||
public required string ProductName { get; set; }
|
public required string ProductName { get; set; }
|
||||||
public required string ProductId { get; set; }
|
public required string ProductId { get; set; }
|
||||||
//public DateOnly? AnnouncedDate { get; set; }
|
|
||||||
public DateOnly? ExpectedDate { get; set; }
|
public DateOnly? ExpectedDate { get; set; }
|
||||||
public DateOnly? SalesDate { get; set; }
|
public DateOnly? SalesDate { get; set; }
|
||||||
public int Downloads { get; set; }
|
public int Downloads { get; set; }
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace JSMR.Infrastructure.Scanning;
|
|||||||
|
|
||||||
public class ReleasedWorksProvider(IDLSiteClient dlsiteClient) : IReleasedWorksProvider
|
public class ReleasedWorksProvider(IDLSiteClient dlsiteClient) : IReleasedWorksProvider
|
||||||
{
|
{
|
||||||
|
private const int MaxPeriodDays = 60;
|
||||||
|
|
||||||
public async Task<ReleasedWorksCollection> GetReleasedWorksAsync(VoiceWorkScanResult scanResult, CancellationToken cancellationToken)
|
public async Task<ReleasedWorksCollection> GetReleasedWorksAsync(VoiceWorkScanResult scanResult, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
DateOnly[] salesDates =
|
DateOnly[] salesDates =
|
||||||
@@ -20,20 +22,72 @@ public class ReleasedWorksProvider(IDLSiteClient dlsiteClient) : IReleasedWorksP
|
|||||||
if (salesDates.Length == 0)
|
if (salesDates.Length == 0)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
|
HashSet<string> productIds = [.. scanResult.Works.Select(x => x.ProductId)];
|
||||||
|
|
||||||
DateOnly minDate = salesDates.Min();
|
DateOnly minDate = salesDates.Min();
|
||||||
DateOnly maxDate = salesDates.Max();
|
DateOnly maxDate = salesDates.Max();
|
||||||
|
|
||||||
DateOnly requestDate = minDate.AddDays(-1);
|
ReleasedWorksCollection collection = [];
|
||||||
DateOnly requestEndDate = maxDate.AddDays(1);
|
|
||||||
|
|
||||||
int period = (requestEndDate.DayNumber - requestDate.DayNumber) + 1;
|
DateOnly chunkStart = minDate;
|
||||||
|
|
||||||
ReleasedWorksRequest releasedWorksRequest = new(
|
while (chunkStart <= maxDate)
|
||||||
|
{
|
||||||
|
int endDayNumber = Math.Min(chunkStart.DayNumber + MaxPeriodDays - 1, maxDate.DayNumber);
|
||||||
|
DateOnly chunkEnd = DateOnly.FromDayNumber(endDayNumber);
|
||||||
|
|
||||||
|
int period = chunkEnd.DayNumber - chunkStart.DayNumber + 1;
|
||||||
|
|
||||||
|
ReleasedWorksRequest request = new(
|
||||||
Locale: Locale.English,
|
Locale: Locale.English,
|
||||||
Date: requestEndDate,
|
Date: chunkEnd,
|
||||||
Period: period
|
Period: period);
|
||||||
);
|
|
||||||
|
|
||||||
return await dlsiteClient.GetReleasedWorksAsync(releasedWorksRequest, cancellationToken);
|
ReleasedWorksCollection chunk = await dlsiteClient.GetReleasedWorksAsync(request, cancellationToken);
|
||||||
|
|
||||||
|
foreach (string productId in chunk.Keys)
|
||||||
|
{
|
||||||
|
if (productIds.Contains(productId) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (collection.ContainsKey(productId))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
collection.Add(productId, chunk[productId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunkStart = chunkEnd.AddDays(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public async Task<ReleasedWorksCollection> GetReleasedWorksAsync(VoiceWorkScanResult scanResult, CancellationToken cancellationToken)
|
||||||
|
//{
|
||||||
|
// DateOnly[] salesDates =
|
||||||
|
// [
|
||||||
|
// .. scanResult.Works
|
||||||
|
// .Where(x => x.SalesDate.HasValue)
|
||||||
|
// .Select(x => x.SalesDate!.Value)
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// if (salesDates.Length == 0)
|
||||||
|
// return [];
|
||||||
|
|
||||||
|
// DateOnly minDate = salesDates.Min();
|
||||||
|
// DateOnly maxDate = salesDates.Max();
|
||||||
|
|
||||||
|
// DateOnly requestDate = minDate.AddDays(-1);
|
||||||
|
// DateOnly requestEndDate = maxDate.AddDays(1);
|
||||||
|
|
||||||
|
// int period = (requestEndDate.DayNumber - requestDate.DayNumber) + 1;
|
||||||
|
|
||||||
|
// ReleasedWorksRequest releasedWorksRequest = new(
|
||||||
|
// Locale: Locale.English,
|
||||||
|
// Date: requestEndDate,
|
||||||
|
// Period: period
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return await dlsiteClient.GetReleasedWorksAsync(releasedWorksRequest, cancellationToken);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
288
JSMR.Tests/Unit/ReleasedWorksProviderTests.cs
Normal file
288
JSMR.Tests/Unit/ReleasedWorksProviderTests.cs
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
using JSMR.Application.Enums;
|
||||||
|
using JSMR.Application.Integrations.DLSite.Models.ReleasedWorks;
|
||||||
|
using JSMR.Application.Integrations.DLSite.Ports;
|
||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
|
using JSMR.Infrastructure.Scanning;
|
||||||
|
using NSubstitute;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace JSMR.Tests.Unit;
|
||||||
|
|
||||||
|
public class ReleasedWorksProviderTests
|
||||||
|
{
|
||||||
|
private readonly IDLSiteClient _dlsiteClient = Substitute.For<IDLSiteClient>();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetReleasedWorksAsync_WhenNoSalesDates_ReturnsEmptyAndDoesNotCallClient()
|
||||||
|
{
|
||||||
|
VoiceWorkScanResult scanResult = new(
|
||||||
|
Works:
|
||||||
|
[
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
SalesDate = null,
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
EndOfResults: false
|
||||||
|
);
|
||||||
|
|
||||||
|
ReleasedWorksProvider provider = new(_dlsiteClient);
|
||||||
|
|
||||||
|
ReleasedWorksCollection result = await provider.GetReleasedWorksAsync(scanResult, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
result.ShouldBeEmpty();
|
||||||
|
|
||||||
|
await _dlsiteClient.DidNotReceiveWithAnyArgs().GetReleasedWorksAsync(default!, TestContext.Current.CancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetReleasedWorksAsync_WhenRangeIsUnder60Days_CallsClientOnce()
|
||||||
|
{
|
||||||
|
VoiceWorkScanResult scanResult = new(
|
||||||
|
Works:
|
||||||
|
[
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
SalesDate = new DateOnly(2024, 1, 10),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
},
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ002",
|
||||||
|
SalesDate = new DateOnly(2024, 1, 20),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
EndOfResults: false
|
||||||
|
);
|
||||||
|
|
||||||
|
ReleasedWorksCollection apiResult = new()
|
||||||
|
{
|
||||||
|
["RJ001"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
Title = "English title 1",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "English title 1",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
},
|
||||||
|
["RJ002"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ002",
|
||||||
|
Title = "English title 2",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "English title 2",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_dlsiteClient
|
||||||
|
.GetReleasedWorksAsync(Arg.Any<ReleasedWorksRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(apiResult);
|
||||||
|
|
||||||
|
ReleasedWorksProvider provider = new(_dlsiteClient);
|
||||||
|
|
||||||
|
ReleasedWorksCollection result =
|
||||||
|
await provider.GetReleasedWorksAsync(scanResult, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
result.Keys.ShouldBe(["RJ001", "RJ002"], ignoreOrder: true);
|
||||||
|
|
||||||
|
await _dlsiteClient.Received(1).GetReleasedWorksAsync(
|
||||||
|
Arg.Is<ReleasedWorksRequest>(x =>
|
||||||
|
x.Locale == Locale.English &&
|
||||||
|
x.Date == new DateOnly(2024, 1, 20) &&
|
||||||
|
x.Period == 11),
|
||||||
|
Arg.Any<CancellationToken>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetReleasedWorksAsync_WhenRangeExceeds60Days_SplitsIntoMultipleRequests()
|
||||||
|
{
|
||||||
|
VoiceWorkScanResult scanResult = new(
|
||||||
|
Works:
|
||||||
|
[
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
SalesDate = new DateOnly(2024, 1, 1),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
},
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ002",
|
||||||
|
SalesDate = new DateOnly(2024, 3, 5),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
EndOfResults: false
|
||||||
|
);
|
||||||
|
|
||||||
|
_dlsiteClient
|
||||||
|
.GetReleasedWorksAsync(Arg.Any<ReleasedWorksRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns([]);
|
||||||
|
|
||||||
|
ReleasedWorksProvider provider = new(_dlsiteClient);
|
||||||
|
|
||||||
|
await provider.GetReleasedWorksAsync(scanResult, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
await _dlsiteClient.Received(1).GetReleasedWorksAsync(
|
||||||
|
Arg.Is<ReleasedWorksRequest>(x =>
|
||||||
|
x.Date == new DateOnly(2024, 2, 29) &&
|
||||||
|
x.Period == 60),
|
||||||
|
Arg.Any<CancellationToken>());
|
||||||
|
|
||||||
|
await _dlsiteClient.Received(1).GetReleasedWorksAsync(
|
||||||
|
Arg.Is<ReleasedWorksRequest>(x =>
|
||||||
|
x.Date == new DateOnly(2024, 3, 5) &&
|
||||||
|
x.Period == 5),
|
||||||
|
Arg.Any<CancellationToken>());
|
||||||
|
|
||||||
|
await _dlsiteClient.Received(2).GetReleasedWorksAsync(
|
||||||
|
Arg.Any<ReleasedWorksRequest>(),
|
||||||
|
Arg.Any<CancellationToken>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetReleasedWorksAsync_FiltersOutProductsNotInScanResult()
|
||||||
|
{
|
||||||
|
VoiceWorkScanResult scanResult = new(
|
||||||
|
Works:
|
||||||
|
[
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
SalesDate = new DateOnly(2024, 1, 10),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
EndOfResults: false
|
||||||
|
);
|
||||||
|
|
||||||
|
ReleasedWorksCollection apiResult = new()
|
||||||
|
{
|
||||||
|
["RJ001"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
Title = "Keep me",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "Keep me",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
},
|
||||||
|
["RJ999"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ999",
|
||||||
|
Title = "Ignore me",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "Ignore me",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
_dlsiteClient
|
||||||
|
.GetReleasedWorksAsync(Arg.Any<ReleasedWorksRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(apiResult);
|
||||||
|
|
||||||
|
ReleasedWorksProvider provider = new(_dlsiteClient);
|
||||||
|
|
||||||
|
ReleasedWorksCollection result =
|
||||||
|
await provider.GetReleasedWorksAsync(scanResult, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
result.Keys.ShouldBe(["RJ001"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetReleasedWorksAsync_WhenSameProductReturnedTwice_KeepsFirstResult()
|
||||||
|
{
|
||||||
|
VoiceWorkScanResult scanResult = new(
|
||||||
|
Works:
|
||||||
|
[
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
SalesDate = new DateOnly(2024, 1, 1),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
},
|
||||||
|
new DLSiteWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ002",
|
||||||
|
SalesDate = new DateOnly(2024, 3, 5),
|
||||||
|
ProductName = "",
|
||||||
|
MakerId = "",
|
||||||
|
Maker = "",
|
||||||
|
ImageUrl = "",
|
||||||
|
SmallImageUrl = ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
EndOfResults: false
|
||||||
|
);
|
||||||
|
|
||||||
|
_dlsiteClient
|
||||||
|
.GetReleasedWorksAsync(
|
||||||
|
Arg.Is<ReleasedWorksRequest>(x => x.Period == 60),
|
||||||
|
Arg.Any<CancellationToken>())
|
||||||
|
.Returns(new ReleasedWorksCollection
|
||||||
|
{
|
||||||
|
["RJ001"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
Title = "First",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "First",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_dlsiteClient
|
||||||
|
.GetReleasedWorksAsync(
|
||||||
|
Arg.Is<ReleasedWorksRequest>(x => x.Period == 5),
|
||||||
|
Arg.Any<CancellationToken>())
|
||||||
|
.Returns(new ReleasedWorksCollection
|
||||||
|
{
|
||||||
|
["RJ001"] = new ReleasedWork
|
||||||
|
{
|
||||||
|
ProductId = "RJ001",
|
||||||
|
Title = "Second",
|
||||||
|
Description = "Description",
|
||||||
|
MaskedTitle = "Second",
|
||||||
|
MaskedDescription = "Description",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ReleasedWorksProvider provider = new(_dlsiteClient);
|
||||||
|
|
||||||
|
ReleasedWorksCollection result = await provider.GetReleasedWorksAsync(scanResult, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
result["RJ001"].Title.ShouldBe("First");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user