using MaBibli.Shared.Dtos; using MaBibli.Shared.Isbn; namespace MaBibli.Api.Services.Isbn; public interface IIsbnLookupService { /// /// Cherche toutes les notices correspondant à un ISBN. /// /// null si l'ISBN fourni n'est pas un ISBN valide. Task RechercherAsync(string isbnBrut, CancellationToken ct = default); } /// /// Cascade de lookup ISBN : BnF d'abord, OpenLibrary ensuite. /// /// /// L'ordre est dicté par CLAUDE.md : la collection est majoritairement francophone et le dépôt /// légal français donne à la BnF la meilleure couverture possible sur ce fonds, là où OpenLibrary /// est lacunaire. OpenLibrary n'est interrogée que si la BnF ne renvoie rien sous /// aucune des deux formes d'ISBN. /// public sealed class IsbnLookupService( IBnfClient bnf, IOpenLibraryClient openLibrary, ILogger logger) : IIsbnLookupService { public async Task RechercherAsync(string isbnBrut, CancellationToken ct = default) { var isbn = IsbnUtils.Normaliser(isbnBrut); if (!IsbnUtils.EstValide(isbn)) { return null; } // La couverture ne vient jamais de la BnF : son Dublin Core n'en fournit aucune. // On construit l'URL OpenLibrary quelle que soit la source des métadonnées. var couverture = IsbnUtils.UrlCouverture(isbn!); IsbnUtils.TryConvertirEnIsbn10(isbn, out var isbn10); var avertissements = new List(); // 1. BnF avec l'ISBN tel que scanné. var (candidats, avertissement) = await bnf.RechercherAsync(isbn!, couverture, ct); Ajouter(avertissements, avertissement); // 2. BnF avec l'ISBN-10 converti. Indispensable : la BnF indexe l'ISBN tel qu'imprimé, // et les ouvrages d'avant 2007 ne portent qu'un ISBN-10. if (candidats.Count == 0 && isbn10 is not null) { var (candidats10, avertissement10) = await bnf.RechercherAsync(isbn10, couverture, ct); Ajouter(avertissements, avertissement10); candidats = candidats10; } // 3. OpenLibrary en second rideau, seulement si la BnF n'a rien donné du tout. if (candidats.Count == 0) { var (candidatsOl, avertissementOl) = await openLibrary.RechercherAsync(isbn!, couverture, ct); Ajouter(avertissements, avertissementOl); candidats = candidatsOl; } logger.LogInformation( "Lookup ISBN {Isbn} : {Nombre} candidat(s), {Avertissements} avertissement(s)", isbn, candidats.Count, avertissements.Count); return new ResultatLookupIsbn { IsbnDemande = isbn!, Isbn10 = isbn10, Candidats = candidats, Avertissements = avertissements, }; } private static void Ajouter(List avertissements, string? message) { if (!string.IsNullOrEmpty(message)) { avertissements.Add(message); } } }