using JSMR.Application.Common.Caching; using JSMR.Application.Integrations.DLSite.Models; using JSMR.Application.Integrations.Ports; using JSMR.Application.Scanning.Contracts; using JSMR.Application.Scanning.Ports; using JSMR.Application.VoiceWorks.Ports; using Microsoft.Extensions.DependencyInjection; namespace JSMR.Application.Scanning; public sealed class ScanVoiceWorksHandler( IServiceProvider serviceProvider, IDLSiteClient dlsiteClient, ISpamCircleCache spamCircleCache, IVoiceWorkWriter writer, IVoiceWorkSearchUpdater searchUpdater) { public async Task HandleAsync(ScanVoiceWorksRequest request, CancellationToken cancellationToken) { IVoiceWorksScanner? scanner = serviceProvider.GetKeyedService(request.Locale); if (scanner is null) return new(); VoiceWorkScanOptions options = new( PageNumber: request.PageNumber, PageSize: request.PageSize, ExcludedMakerIds: await spamCircleCache.GetAsync(cancellationToken), ExcludePartiallyAIGeneratedWorks: true, ExcludeAIGeneratedWorks: true ); IReadOnlyList works = await scanner.ScanPageAsync(options, cancellationToken); if (works.Count == 0) return new(); string[] productIds = [.. works.Where(x => !string.IsNullOrWhiteSpace(x.ProductId)).Select(x => x.ProductId!)]; VoiceWorkDetailCollection voiceWorkDetails = await dlsiteClient.GetVoiceWorkDetailsAsync(productIds, cancellationToken); List ingests = [.. works.Select(work => { voiceWorkDetails.TryGetValue(work.ProductId!, out VoiceWorkDetails? value); return new VoiceWorkIngest(work, value); })]; int[] voiceWorkIds = await writer.UpsertAsync(ingests, cancellationToken); await searchUpdater.UpdateAsync(voiceWorkIds, cancellationToken); return new(); } }