Recuperation des metadonnees d'un livre a partir de son ISBN, cote serveur uniquement (aucune interface, aucune persistance). Cascade : BnF en ISBN-13, puis BnF en ISBN-10 converti, puis OpenLibrary. La conversion 13 -> 10 est indispensable et non optionnelle : la BnF indexe l'ISBN tel qu'imprime, les ouvrages d'avant 2007 ne portent qu'un ISBN-10 et sont introuvables par l'EAN-13 que lit le scanner. Toutes les notices trouvees sont remontees (jusqu'a 5) : un meme ISBN peut correspondre a plusieurs reeditions, le choix revient a l'utilisateur. Le double appel /isbn puis /authors d'OpenLibrary est bien fait, avec repli sur l'oeuvre quand l'edition ne porte aucun auteur : c'est le bug de BookLogr (titre rempli, auteur vide) qu'il ne faut pas reproduire. La couverture vient toujours d'OpenLibrary, avec ?default=false pour obtenir un 404 plutot qu'une image placeholder. 87 tests xUnit, sur fixtures enregistrees : aucune dependance au reseau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
87 lines
3.1 KiB
C#
87 lines
3.1 KiB
C#
using MaBibli.Shared.Dtos;
|
|
using MaBibli.Shared.Isbn;
|
|
|
|
namespace MaBibli.Api.Services.Isbn;
|
|
|
|
public interface IIsbnLookupService
|
|
{
|
|
/// <summary>
|
|
/// Cherche toutes les notices correspondant à un ISBN.
|
|
/// </summary>
|
|
/// <returns><c>null</c> si l'ISBN fourni n'est pas un ISBN valide.</returns>
|
|
Task<ResultatLookupIsbn?> RechercherAsync(string isbnBrut, CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cascade de lookup ISBN : <b>BnF d'abord, OpenLibrary ensuite</b>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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
|
|
/// <b>aucune</b> des deux formes d'ISBN.
|
|
/// </remarks>
|
|
public sealed class IsbnLookupService(
|
|
IBnfClient bnf,
|
|
IOpenLibraryClient openLibrary,
|
|
ILogger<IsbnLookupService> logger) : IIsbnLookupService
|
|
{
|
|
public async Task<ResultatLookupIsbn?> 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<string>();
|
|
|
|
// 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<string> avertissements, string? message)
|
|
{
|
|
if (!string.IsNullOrEmpty(message))
|
|
{
|
|
avertissements.Add(message);
|
|
}
|
|
}
|
|
}
|