import { Injectable } from "@nestjs/common"; import { XMLParser } from "fast-xml-parser"; import { MetadataLookup, MetadataMatch, MetadataProvider, MetadataProviderConfig } from "../metadata.types.js"; const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_" }); @Injectable() export class BnfProvider implements MetadataProvider { readonly id = "bnf" as const; async lookup(lookup: MetadataLookup, _config: MetadataProviderConfig): Promise { const query = lookup.identifiers.isbn13 ? `bib.isbn all "${lookup.identifiers.isbn13}"` : `bib.title all "${lookup.title.replace(/"/g, " ")}"`; const url = new URL("https://catalogue.bnf.fr/api/SRU"); url.searchParams.set("version", "1.2"); url.searchParams.set("operation", "searchRetrieve"); url.searchParams.set("query", query); url.searchParams.set("maximumRecords", "1"); const response = await fetch(url, { signal: AbortSignal.timeout(5000) }); if (!response.ok) return null; const parsed = parser.parse(await response.text()); const record = parsed?.searchRetrieveResponse?.records?.record?.recordData; if (!record) return null; const text = JSON.stringify(record); return { title: match(text, /"titleInfo"[^}]*"title":"([^"]+)"/), author: match(text, /"namePart":"([^"]+)"/), publisher: match(text, /"publisher":"([^"]+)"/), publishedDate: match(text, /"dateIssued":"([^"]+)"/) }; } } function match(value: string, pattern: RegExp): string | undefined { return value.match(pattern)?.[1]; }