@prose-reader/metadata-fetcher 1.339.0 → 1.340.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,37 +1,38 @@
1
1
  import { normalizeIsbn as e } from "@prose-reader/archive-reader";
2
2
  import { Report as t } from "@prose-reader/shared";
3
+ import { XmlDocument as n } from "xmldoc";
3
4
  //#region src/utils/metadataAuthors.ts
4
- var n = (e) => {
5
+ var r = (e) => {
5
6
  let t = e.contributors ?? [], n = t.filter((e) => e.roles.includes("author")), r = (n.length > 0 ? n : t).map((e) => e.name.trim()).filter((e) => e.length > 0);
6
7
  return [...new Set(r)];
7
- }, r = /^\d{13}$/, i = /^\d{9}[\dX]$/, a = (t) => {
8
+ }, i = /^\d{13}$/, a = /^\d{9}[\dX]$/, o = (t) => {
8
9
  let n = e(t);
9
10
  if (n === void 0) return;
10
- if (r.test(n)) return n;
11
- if (!i.test(n)) return;
12
- let a = `978${n.slice(0, 9)}`, o = 0;
13
- for (let e = 0; e < a.length; e++) {
14
- let t = a.charCodeAt(e) - 48;
11
+ if (i.test(n)) return n;
12
+ if (!a.test(n)) return;
13
+ let r = `978${n.slice(0, 9)}`, o = 0;
14
+ for (let e = 0; e < r.length; e++) {
15
+ let t = r.charCodeAt(e) - 48;
15
16
  o += e % 2 == 0 ? t : t * 3;
16
17
  }
17
- return `${a}${(10 - o % 10) % 10}`;
18
- }, o = /[\u0300-\u036f]/g, s = /[^\p{L}\p{N}]+/gu, c = (e) => e.normalize("NFD").replace(o, "").toLowerCase().replace(s, " ").trim(), l = (e) => {
18
+ return `${r}${(10 - o % 10) % 10}`;
19
+ }, s = /[\u0300-\u036f]/g, c = /[^\p{L}\p{N}]+/gu, l = (e) => e.normalize("NFD").replace(s, "").toLowerCase().replace(c, " ").trim(), u = (e) => {
19
20
  let t = /* @__PURE__ */ new Map();
20
21
  for (let n = 0; n < e.length - 1; n++) {
21
22
  let r = e.slice(n, n + 2);
22
23
  t.set(r, (t.get(r) ?? 0) + 1);
23
24
  }
24
25
  return t;
25
- }, u = (e, t) => {
26
- let n = c(e).replaceAll(" ", ""), r = c(t).replaceAll(" ", "");
26
+ }, d = (e, t) => {
27
+ let n = l(e).replaceAll(" ", ""), r = l(t).replaceAll(" ", "");
27
28
  if (n.length === 0 || r.length === 0) return 0;
28
29
  if (n === r) return 1;
29
30
  if (n.length < 2 || r.length < 2) return 0;
30
- let i = l(n), a = 0;
31
- for (let [e, t] of l(r)) a += Math.min(t, i.get(e) ?? 0);
31
+ let i = u(n), a = 0;
32
+ for (let [e, t] of u(r)) a += Math.min(t, i.get(e) ?? 0);
32
33
  return 2 * a / (n.length - 1 + (r.length - 1));
33
- }, d = /\s*[:;]\s*|\s+[-–—]\s+/, f = (e) => {
34
- let [t = "", ...n] = e.split(d), r = t.trim(), i = n.join(" ").trim();
34
+ }, f = /\s*[:;]\s*|\s+[-–—]\s+/, p = (e) => {
35
+ let [t = "", ...n] = e.split(f), r = t.trim(), i = n.join(" ").trim();
35
36
  return r.length === 0 ? {
36
37
  main: e,
37
38
  hasSubtitle: !1
@@ -39,11 +40,11 @@ var n = (e) => {
39
40
  main: r,
40
41
  hasSubtitle: i.length > 0
41
42
  };
42
- }, p = .9, m = [
43
+ }, m = .9, h = [
43
44
  "volume",
44
45
  "part",
45
46
  "book"
46
- ], h = /\b(volumes?|vols?|parts?|books?)\s+([\p{L}\p{N}]+)\b/gu, g = {
47
+ ], ee = /\b(volumes?|vols?|parts?|books?)\s+([\p{L}\p{N}]+)\b/gu, g = {
47
48
  one: 1,
48
49
  first: 1,
49
50
  two: 2,
@@ -91,7 +92,7 @@ var n = (e) => {
91
92
  if (e.startsWith("book")) return "book";
92
93
  }, x = (e) => {
93
94
  let t = /* @__PURE__ */ new Map();
94
- for (let n of c(e).matchAll(h)) {
95
+ for (let n of l(e).matchAll(ee)) {
95
96
  let e = n[1] === void 0 ? void 0 : b(n[1]), r = n[2] === void 0 ? void 0 : y(n[2]);
96
97
  if (e === void 0 || r === void 0) continue;
97
98
  let i = t.get(e) ?? /* @__PURE__ */ new Set();
@@ -100,116 +101,131 @@ var n = (e) => {
100
101
  return t;
101
102
  }, S = (e, t) => {
102
103
  let n = x(e), r = x(t);
103
- for (let e of m) {
104
+ for (let e of h) {
104
105
  let t = n.get(e), i = r.get(e);
105
106
  if (!(t === void 0 || i === void 0) && [...t].every((e) => !i.has(e))) return !0;
106
107
  }
107
108
  return !1;
108
109
  }, C = (e, t) => {
109
110
  if (S(e, t)) return 0;
110
- let n = u(e, t), r = f(e), i = f(t);
111
- return r.hasSubtitle === i.hasSubtitle ? n : Math.max(n, u(r.main, i.main) * p);
112
- }, w = (e) => c(e).split(" ").filter((e) => e.length > 0).sort().join(" "), T = (e, t) => u(w(e), w(t)), E = {
111
+ let n = d(e, t), r = p(e), i = p(t);
112
+ return r.hasSubtitle === i.hasSubtitle ? n : Math.max(n, d(r.main, i.main) * m);
113
+ }, w = (e) => l(e).split(" ").filter((e) => e.length > 0).sort().join(" "), T = (e, t) => d(w(e), w(t)), E = {
113
114
  isbn: 1,
114
115
  gtin: 1,
115
116
  identifiers: .6,
116
117
  title: .8,
117
118
  contributors: .5,
118
119
  series: .3,
119
- published: .2,
120
- publisher: .15,
120
+ "publication.original.date": .2,
121
+ "publication.original.publisher": .15,
122
+ "publication.edition.date": .2,
123
+ "publication.edition.publisher": .15,
121
124
  languages: .15,
122
125
  numberOfPages: .15
123
- }, D = /* @__PURE__ */ new Set(["isbn", "gtin"]), O = (e) => {
126
+ }, te = /* @__PURE__ */ new Set(["isbn", "gtin"]), D = (e) => {
124
127
  let t = e?.trim();
125
128
  return t !== void 0 && t.length > 0 ? t : void 0;
126
- }, k = (e) => e.value.trim().toLowerCase(), A = (e) => e.scheme === void 0 ? e.value : `${e.scheme}:${e.value}`, j = (e, t) => k(e) === k(t) ? e.scheme === void 0 || t.scheme === void 0 || e.scheme.trim().toLowerCase() === t.scheme.trim().toLowerCase() : !1, M = (e) => e.trim().toLowerCase().split("-")[0] ?? "", N = (e, t) => {
129
+ }, ne = (e, t) => {
130
+ let n = D(e.value)?.toLowerCase();
131
+ return n !== void 0 && n === D(t.value)?.toLowerCase();
132
+ }, O = (e) => D(e.scheme)?.toLowerCase(), re = (e) => e.scheme === void 0 ? e.value : `${e.scheme}:${e.value}`, ie = (e, t) => {
133
+ if (!ne(e, t)) return !1;
134
+ let n = O(e), r = O(t);
135
+ return n === void 0 || r === void 0 || n === r;
136
+ }, ae = (e, t) => {
137
+ if (!ne(e, t)) return !1;
138
+ let n = O(e), r = O(t);
139
+ return n !== void 0 && n === r;
140
+ }, k = (e) => e.trim().toLowerCase().split("-")[0] ?? "", oe = (e, t) => {
127
141
  let n = Math.abs(e - t);
128
142
  return n === 0 ? 1 : n === 1 ? .6 : n <= 3 ? .3 : 0;
129
- }, ee = (e, t) => {
143
+ }, se = (e, t) => {
130
144
  let n = Math.max(e, t);
131
145
  return n <= 0 ? 0 : Math.max(0, 1 - Math.abs(e - t) / n * 2);
132
- }, P = (e, t, n) => e.reduce((e, r) => t.reduce((e, t) => Math.max(e, n(r, t)), e), 0), F = (e, t) => {
133
- let r = [], i = (e, t) => {
134
- t !== void 0 && r.push({
146
+ }, ce = (e, t, n) => e.reduce((e, r) => t.reduce((e, t) => Math.max(e, n(r, t)), e), 0), A = (e, t) => {
147
+ let n = [], i = (e, t) => {
148
+ t !== void 0 && n.push({
135
149
  field: e,
136
150
  weight: E[e],
137
151
  score: Math.min(1, Math.max(0, t.score)),
138
152
  query: t.query,
139
153
  candidate: t.candidate
140
154
  });
141
- }, o = (e, t, n, r = u) => {
142
- let a = O(t), o = O(n);
155
+ }, a = (e, t, n, r = d) => {
156
+ let a = D(t), o = D(n);
143
157
  a === void 0 || o === void 0 || i(e, {
144
158
  score: r(a, o),
145
159
  query: a,
146
160
  candidate: o
147
161
  });
148
- }, s = O(e.isbn), c = O(t.isbn), l = s === void 0 ? void 0 : a(s), d = c === void 0 ? void 0 : a(c);
149
- s !== void 0 && c !== void 0 && l !== void 0 && d !== void 0 && i("isbn", {
150
- score: +(l === d),
162
+ }, s = D(e.isbn), c = D(t.isbn), l = s === void 0 ? void 0 : o(s), u = c === void 0 ? void 0 : o(c);
163
+ s !== void 0 && c !== void 0 && l !== void 0 && u !== void 0 && i("isbn", {
164
+ score: +(l === u),
151
165
  query: s,
152
166
  candidate: c
153
167
  });
154
- let f = O(e.gtin), p = O(t.gtin);
168
+ let f = D(e.gtin), p = D(t.gtin);
155
169
  f !== void 0 && p !== void 0 && i("gtin", {
156
170
  score: +(f === p),
157
171
  query: f,
158
172
  candidate: p
159
173
  });
160
- let m = e.identifiers ?? [], h = t.identifiers ?? [];
174
+ let m = e.identifiers ?? [], h = t.identifiers ?? [], ee = m.some((e) => h.some((t) => ae(e, t)));
161
175
  m.length > 0 && h.length > 0 && i("identifiers", {
162
- score: +!!m.some((e) => h.some((t) => j(e, t))),
163
- query: m.map(A).join(", "),
164
- candidate: h.map(A).join(", ")
165
- }), o("title", e.title, t.title, C), o("publisher", e.publisher, t.publisher), o("series", e.belongsTo?.series?.[0]?.name, t.belongsTo?.series?.[0]?.name);
166
- let g = n(t), _ = n(e);
176
+ score: +!!m.some((e) => h.some((t) => ie(e, t))),
177
+ query: m.map(re).join(", "),
178
+ candidate: h.map(re).join(", ")
179
+ }), a("title", e.title, t.title, C), a("publication.original.publisher", e.publication?.original?.publisher, t.publication?.original?.publisher), a("publication.edition.publisher", e.publication?.edition?.publisher, t.publication?.edition?.publisher), a("series", e.belongsTo?.series?.[0]?.name, t.belongsTo?.series?.[0]?.name);
180
+ let g = r(t), _ = r(e);
167
181
  _.length > 0 && g.length > 0 && i("contributors", {
168
- score: P(_, g, T),
182
+ score: ce(_, g, T),
169
183
  query: _.join(", "),
170
184
  candidate: g.join(", ")
171
185
  });
172
- let v = e.published?.year, y = t.published?.year;
173
- v !== void 0 && y !== void 0 && i("published", {
174
- score: N(v, y),
175
- query: String(v),
176
- candidate: String(y)
177
- });
178
- let b = e.languages ?? [], x = t.languages ?? [];
179
- if (b.length > 0 && x.length > 0) {
180
- let e = new Set(x.map(M));
186
+ let v = (e, t, n) => {
187
+ t === void 0 || n === void 0 || i(e, {
188
+ score: oe(t, n),
189
+ query: String(t),
190
+ candidate: String(n)
191
+ });
192
+ };
193
+ v("publication.original.date", e.publication?.original?.date?.year, t.publication?.original?.date?.year), v("publication.edition.date", e.publication?.edition?.date?.year, t.publication?.edition?.date?.year);
194
+ let y = e.languages ?? [], b = t.languages ?? [];
195
+ if (y.length > 0 && b.length > 0) {
196
+ let e = new Set(b.map(k));
181
197
  i("languages", {
182
- score: +!!b.some((t) => e.has(M(t))),
183
- query: b.join(", "),
184
- candidate: x.join(", ")
198
+ score: +!!y.some((t) => e.has(k(t))),
199
+ query: y.join(", "),
200
+ candidate: b.join(", ")
185
201
  });
186
202
  }
187
203
  e.numberOfPages !== void 0 && t.numberOfPages !== void 0 && i("numberOfPages", {
188
- score: ee(e.numberOfPages, t.numberOfPages),
204
+ score: se(e.numberOfPages, t.numberOfPages),
189
205
  query: String(e.numberOfPages),
190
206
  candidate: String(t.numberOfPages)
191
207
  });
192
- let S = r.filter((e) => D.has(e.field));
193
- if (S.some((e) => e.score === 0)) return {
208
+ let x = n.filter((e) => te.has(e.field));
209
+ if (x.some((e) => e.score === 0)) return {
194
210
  score: 0,
195
- signals: r
211
+ signals: n
196
212
  };
197
- if (S.some((e) => e.score === 1)) return {
213
+ if (ee || x.some((e) => e.score === 1)) return {
198
214
  score: 1,
199
- signals: r
215
+ signals: n
200
216
  };
201
- let w = r.reduce((e, t) => e + t.weight, 0);
202
- return w === 0 ? {
217
+ let S = n.reduce((e, t) => e + t.weight, 0);
218
+ return S === 0 ? {
203
219
  score: 0,
204
- signals: r
220
+ signals: n
205
221
  } : {
206
- score: r.reduce((e, t) => e + t.score * t.weight, 0) / w,
207
- signals: r
222
+ score: n.reduce((e, t) => e + t.score * t.weight, 0) / S,
223
+ signals: n
208
224
  };
209
- }, I = (e) => {
225
+ }, j = (e) => {
210
226
  let t = Object.entries(e).filter(([, e]) => e !== void 0);
211
227
  return Object.fromEntries(t);
212
- }, te = (e) => {
228
+ }, le = (e) => {
213
229
  let t = /* @__PURE__ */ new Map();
214
230
  for (let n of e) {
215
231
  let e = `${n.scheme?.trim().toLowerCase() ?? ""}:${n.value.trim().toLowerCase()}`, r = t.get(e);
@@ -223,27 +239,35 @@ var n = (e) => {
223
239
  });
224
240
  }
225
241
  return [...t.values()];
226
- }, L = (...e) => {
242
+ }, M = (...e) => {
227
243
  let t = e.filter((e) => e !== void 0), n = (e) => {
228
244
  for (let n of t) {
229
245
  let t = n[e];
230
246
  if (t !== void 0) return t;
231
247
  }
232
- }, r = te(t.flatMap((e) => e.identifiers ?? [])), i = I({
248
+ }, r = le(t.flatMap((e) => e.identifiers ?? [])), i = j({
233
249
  series: t.find((e) => e.belongsTo?.series !== void 0)?.belongsTo?.series,
234
250
  collection: t.find((e) => e.belongsTo?.collection !== void 0)?.belongsTo?.collection
251
+ }), a = (e) => {
252
+ let n = j({
253
+ date: t.find((t) => t.publication?.[e]?.date !== void 0)?.publication?.[e]?.date,
254
+ publisher: t.find((t) => t.publication?.[e]?.publisher !== void 0)?.publication?.[e]?.publisher,
255
+ imprint: t.find((t) => t.publication?.[e]?.imprint !== void 0)?.publication?.[e]?.imprint
256
+ });
257
+ return n.date !== void 0 || n.publisher !== void 0 || n.imprint !== void 0 ? n : void 0;
258
+ }, o = j({
259
+ original: a("original"),
260
+ edition: a("edition")
235
261
  });
236
- return I({
262
+ return j({
237
263
  title: n("title"),
238
264
  cover: n("cover"),
239
265
  description: n("description"),
240
- publisher: n("publisher"),
241
- imprint: n("imprint"),
266
+ publication: o.original !== void 0 || o.edition !== void 0 ? o : void 0,
242
267
  rights: n("rights"),
243
268
  languages: n("languages"),
244
269
  subjects: n("subjects"),
245
270
  contributors: n("contributors"),
246
- published: n("published"),
247
271
  readingDirection: n("readingDirection"),
248
272
  renditionLayout: n("renditionLayout"),
249
273
  renditionFlow: n("renditionFlow"),
@@ -258,16 +282,16 @@ var n = (e) => {
258
282
  apple: n("apple"),
259
283
  kobo: n("kobo")
260
284
  });
261
- }, R = class extends Error {
285
+ }, N = class extends Error {
262
286
  status;
263
287
  constructor(e, t) {
264
288
  super(t ?? `Provider responded with status ${e}`), this.name = "MetadataProviderResponseError", this.status = e;
265
289
  }
266
- }, z = (e) => {
290
+ }, ue = (e) => {
267
291
  if (typeof e != "object" || !e || !("status" in e)) return;
268
292
  let { status: t } = e;
269
293
  if (!(typeof t != "number" || !Number.isInteger(t))) return t >= 100 && t <= 599 ? t : void 0;
270
- }, B = t.namespace("@prose-reader/metadata-fetcher", void 0, { color: "#b06642" }), ne = 5, re = .5, ie = 1, ae = ({ candidate: e, providerId: t, score: n, signals: r, accepted: i, includeRaw: a }) => I({
294
+ }, de = t.namespace("@prose-reader/metadata-fetcher", void 0, { color: "#b06642" }), fe = 5, pe = .5, me = 2, he = ({ candidate: e, providerId: t, score: n, signals: r, accepted: i, includeRaw: a }) => j({
271
295
  providerId: t,
272
296
  score: n,
273
297
  signals: r,
@@ -276,8 +300,8 @@ var n = (e) => {
276
300
  id: e.id,
277
301
  url: e.url,
278
302
  raw: a ? e.raw : void 0
279
- }), V = async (e, t) => {
280
- let n = "metadata" in e ? e.metadata : e, r = t.limit ?? ne, i = t.minScore ?? re, a = t.includeRaw === !0, o = await Promise.all(t.providers.map(async (e) => {
303
+ }), ge = async (e, t) => {
304
+ let n = "metadata" in e ? e.metadata : e, r = t.limit ?? fe, i = t.minScore ?? pe, a = t.includeRaw === !0, o = await Promise.all(t.providers.map(async (e) => {
281
305
  try {
282
306
  return {
283
307
  provider: e,
@@ -289,12 +313,12 @@ var n = (e) => {
289
313
  };
290
314
  } catch (n) {
291
315
  if (t.signal?.aborted === !0) throw n;
292
- return B.error(`fetchMetadata: provider "${e.id}" failed`, n), {
316
+ return de.error(`fetchMetadata: provider "${e.id}" failed`, n), {
293
317
  provider: e,
294
318
  candidates: void 0,
295
- failure: I({
319
+ failure: j({
296
320
  id: e.id,
297
- status: z(n)
321
+ status: ue(n)
298
322
  })
299
323
  };
300
324
  }
@@ -302,8 +326,8 @@ var n = (e) => {
302
326
  for (let { provider: e, candidates: t } of o) {
303
327
  if (t === void 0) continue;
304
328
  let o = t.map((t) => {
305
- let { score: r, signals: o } = F(n, t.metadata);
306
- return ae({
329
+ let { score: r, signals: o } = A(n, t.metadata);
330
+ return he({
307
331
  candidate: t,
308
332
  providerId: e.id,
309
333
  score: r,
@@ -312,7 +336,7 @@ var n = (e) => {
312
336
  includeRaw: a
313
337
  });
314
338
  }).sort((e, t) => t.score - e.score).slice(0, r);
315
- c[e.id] !== void 0 && B.warn(`fetchMetadata: several providers share the id "${e.id}"`), c[e.id] = {
339
+ c[e.id] !== void 0 && de.warn(`fetchMetadata: several providers share the id "${e.id}"`), c[e.id] = {
316
340
  provider: {
317
341
  id: e.id,
318
342
  name: e.name
@@ -322,61 +346,36 @@ var n = (e) => {
322
346
  }
323
347
  let u = [...l].sort((e, t) => t.score - e.score);
324
348
  return {
325
- version: ie,
326
- metadata: L(...u.filter((e) => e.accepted).map((e) => e.metadata)),
349
+ version: me,
350
+ metadata: M(...u.filter((e) => e.accepted).map((e) => e.metadata)),
327
351
  matches: u,
328
352
  sources: c,
329
353
  failedProviders: s
330
354
  };
331
- }, H = (e) => typeof e == "object" && !!e && !Array.isArray(e), U = (e, t) => {
332
- let n = e[t];
333
- if (typeof n != "string") return;
334
- let r = n.trim();
335
- return r.length > 0 ? r : void 0;
336
- }, W = (e, t) => {
337
- let n = e[t];
338
- return typeof n == "number" && Number.isFinite(n) ? n : void 0;
339
- }, G = (e, t) => {
340
- let n = e[t];
341
- if (!Array.isArray(n)) return;
342
- let r = n.filter((e) => typeof e == "string").map((e) => e.trim()).filter((e) => e.length > 0);
343
- return r.length > 0 ? r : void 0;
344
- }, K = (e, t) => {
345
- let n = e[t];
346
- return Array.isArray(n) ? n.filter(H) : [];
347
- }, q = (e) => ({
348
- key: U(e, "key"),
349
- title: U(e, "title"),
350
- subtitle: U(e, "subtitle"),
351
- author_name: G(e, "author_name"),
352
- first_publish_year: W(e, "first_publish_year"),
353
- publisher: G(e, "publisher"),
354
- language: G(e, "language"),
355
- subject: G(e, "subject"),
356
- number_of_pages_median: W(e, "number_of_pages_median"),
357
- cover_i: W(e, "cover_i"),
358
- id_project_gutenberg: G(e, "id_project_gutenberg")
359
- }), J = (e) => H(e) ? K(e, "docs").map(q) : [], oe = /* @__PURE__ */ new Set(["gutenberg.org", "www.gutenberg.org"]), se = [
355
+ }, P = "ProjectGutenberg", _e = /* @__PURE__ */ new Set(["gutenberg.org", "www.gutenberg.org"]), ve = [
360
356
  /^\/ebooks\/(\d+)(?:[./]|$)/i,
361
357
  /^\/files\/(\d+)(?:\/|$)/i,
362
358
  /^\/cache\/epub\/(\d+)(?:\/|$)/i,
363
359
  /^\/(\d+)(?:\/|$)/
364
- ], ce = (e) => {
360
+ ], F = (e) => {
361
+ let t = e.trim();
362
+ if (!/^\d+$/.test(t)) return;
363
+ let n = t.replace(/^0+(?=\d)/, "");
364
+ return n === "0" ? void 0 : n;
365
+ }, ye = (e) => {
365
366
  try {
366
367
  let t = new URL(e.trim());
367
- if (t.protocol !== "http:" && t.protocol !== "https:" || !oe.has(t.hostname.toLowerCase())) return;
368
- for (let e of se) {
368
+ if (t.protocol !== "http:" && t.protocol !== "https:" || !_e.has(t.hostname.toLowerCase())) return;
369
+ for (let e of ve) {
369
370
  let n = e.exec(t.pathname)?.[1];
370
- if (n !== void 0) return n;
371
+ if (n !== void 0) return F(n);
371
372
  }
372
373
  } catch {
373
374
  return;
374
375
  }
375
- }, le = (e) => {
376
+ }, I = (e) => {
376
377
  for (let t of e.identifiers ?? []) {
377
- let e = t.scheme?.trim().toLowerCase();
378
- if (e !== void 0 && e !== "url" && e !== "uri") continue;
379
- let n = ce(t.value);
378
+ let e = t.scheme?.trim().toLowerCase(), n = e === "projectgutenberg" ? F(t.value) : e === void 0 || e === "url" || e === "uri" ? ye(t.value) : void 0;
380
379
  if (n !== void 0) return {
381
380
  id: n,
382
381
  identifier: {
@@ -385,7 +384,34 @@ var n = (e) => {
385
384
  }
386
385
  };
387
386
  }
388
- }, ue = {
387
+ }, L = (e) => typeof e == "object" && !!e && !Array.isArray(e), R = (e, t) => {
388
+ let n = e[t];
389
+ if (typeof n != "string") return;
390
+ let r = n.trim();
391
+ return r.length > 0 ? r : void 0;
392
+ }, z = (e, t) => {
393
+ let n = e[t];
394
+ return typeof n == "number" && Number.isFinite(n) ? n : void 0;
395
+ }, B = (e, t) => {
396
+ let n = e[t];
397
+ if (!Array.isArray(n)) return;
398
+ let r = n.filter((e) => typeof e == "string").map((e) => e.trim()).filter((e) => e.length > 0);
399
+ return r.length > 0 ? r : void 0;
400
+ }, be = (e, t) => {
401
+ let n = e[t];
402
+ return Array.isArray(n) ? n.filter(L) : [];
403
+ }, xe = (e) => ({
404
+ key: R(e, "key"),
405
+ title: R(e, "title"),
406
+ subtitle: R(e, "subtitle"),
407
+ author_name: B(e, "author_name"),
408
+ first_publish_year: z(e, "first_publish_year"),
409
+ language: B(e, "language"),
410
+ subject: B(e, "subject"),
411
+ number_of_pages_median: z(e, "number_of_pages_median"),
412
+ cover_i: z(e, "cover_i"),
413
+ id_project_gutenberg: B(e, "id_project_gutenberg")
414
+ }), V = (e) => L(e) ? be(e, "docs").map(xe) : [], Se = {
389
415
  afr: "af",
390
416
  alb: "sq",
391
417
  amh: "am",
@@ -490,28 +516,27 @@ var n = (e) => {
490
516
  wel: "cy",
491
517
  yid: "yi",
492
518
  zho: "zh"
493
- }, de = /* @__PURE__ */ new Set([
519
+ }, Ce = /* @__PURE__ */ new Set([
494
520
  "mul",
495
521
  "und",
496
522
  "zxx",
497
523
  "sgn"
498
- ]), Y = (e) => {
524
+ ]), H = (e) => {
499
525
  let t = e.trim().toLowerCase();
500
- if (t.length !== 0 && !de.has(t)) return ue[t] ?? t;
501
- }, fe = 25, pe = {
526
+ if (t.length !== 0 && !Ce.has(t)) return Se[t] ?? t;
527
+ }, we = 25, Te = {
502
528
  key: "identifiers",
503
529
  title: "title",
504
530
  subtitle: "title",
505
531
  author_name: "contributors",
506
- first_publish_year: "published",
507
- publisher: "publisher",
532
+ first_publish_year: "publication.original.date",
508
533
  language: "languages",
509
534
  subject: "subjects",
510
535
  number_of_pages_median: "numberOfPages",
511
536
  cover_i: "cover",
512
537
  id_project_gutenberg: "identifiers"
513
- }, X = "OpenLibrary", me = "ProjectGutenberg", Z = (e) => e.length > 0 ? e : void 0, Q = (e, t) => {
514
- let n = e.title !== void 0 && e.subtitle !== void 0 ? `${e.title}: ${e.subtitle}` : e.title, r = Z([...new Set((e.language ?? []).map(Y).filter((e) => e !== void 0))]), i = [
538
+ }, U = "OpenLibrary", Ee = "ProjectGutenberg", W = (e) => e.length > 0 ? e : void 0, G = (e, t) => {
539
+ let n = e.title !== void 0 && e.subtitle !== void 0 ? `${e.title}: ${e.subtitle}` : e.title, r = W([...new Set((e.language ?? []).map(H).filter((e) => e !== void 0))]), i = [
515
540
  ...t.isbn === void 0 ? [] : [{
516
541
  value: t.isbn,
517
542
  scheme: "ISBN"
@@ -519,57 +544,55 @@ var n = (e) => {
519
544
  ...t.matchedProjectGutenbergIdentifier === void 0 ? [] : [t.matchedProjectGutenbergIdentifier],
520
545
  ...(e.id_project_gutenberg ?? []).map((e) => ({
521
546
  value: e,
522
- scheme: me
547
+ scheme: Ee
523
548
  })),
524
549
  ...e.key === void 0 ? [] : [{
525
550
  value: e.key,
526
- scheme: X
551
+ scheme: U
527
552
  }]
528
553
  ];
529
- return I({
554
+ return j({
530
555
  title: n,
531
556
  cover: e.cover_i === void 0 ? void 0 : {
532
557
  uri: `${t.coversBaseUrl}/b/id/${e.cover_i}-L.jpg`,
533
558
  mediaType: "image/jpeg",
534
559
  confidence: "derived"
535
560
  },
536
- publisher: e.publisher?.[0],
561
+ publication: e.first_publish_year === void 0 ? void 0 : { original: { date: { year: e.first_publish_year } } },
537
562
  languages: r,
538
- subjects: Z((e.subject ?? []).slice(0, 25)),
539
- contributors: Z((e.author_name ?? []).map((e) => ({
563
+ subjects: W((e.subject ?? []).slice(0, 25)),
564
+ contributors: W((e.author_name ?? []).map((e) => ({
540
565
  name: e,
541
566
  roles: ["author"]
542
567
  }))),
543
- published: e.first_publish_year === void 0 ? void 0 : { year: e.first_publish_year },
544
568
  numberOfPages: e.number_of_pages_median,
545
569
  isbn: t.isbn,
546
- identifiers: Z(i)
570
+ identifiers: W(i)
547
571
  });
548
- }, $ = "openLibrary", he = "https://openlibrary.org", ge = "https://covers.openlibrary.org", _e = [
572
+ }, K = "openLibrary", De = "https://openlibrary.org", Oe = "https://covers.openlibrary.org", ke = [
549
573
  "key",
550
574
  "title",
551
575
  "subtitle",
552
576
  "author_name",
553
577
  "first_publish_year",
554
- "publisher",
555
578
  "language",
556
579
  "subject",
557
580
  "number_of_pages_median",
558
581
  "cover_i",
559
582
  "id_project_gutenberg"
560
- ].join(","), ve = (e) => {
583
+ ].join(","), Ae = (e) => {
561
584
  let t = e.title?.trim();
562
585
  if (t === void 0 || t.length === 0) return;
563
- let r = n(e)[0];
586
+ let n = r(e)[0];
564
587
  return {
565
588
  title: t,
566
- ...r === void 0 ? {} : { author: r }
589
+ ...n === void 0 ? {} : { author: n }
567
590
  };
568
- }, ye = (e = {}) => {
569
- let t = e.baseUrl ?? he, n = e.coversBaseUrl ?? ge, r = async (n, r) => {
591
+ }, je = (e = {}) => {
592
+ let t = e.baseUrl ?? De, n = e.coversBaseUrl ?? Oe, r = async (n, r) => {
570
593
  let i = new URL("/search.json", t);
571
594
  for (let [e, t] of Object.entries(n)) i.searchParams.set(e, t);
572
- i.searchParams.set("fields", _e), i.searchParams.set("limit", String(r.limit));
595
+ i.searchParams.set("fields", ke), i.searchParams.set("limit", String(r.limit));
573
596
  let a = await (e.fetch ?? globalThis.fetch)(i.toString(), {
574
597
  signal: r.signal,
575
598
  headers: {
@@ -577,10 +600,10 @@ var n = (e) => {
577
600
  ...e.userAgent === void 0 ? {} : { "User-Agent": e.userAgent }
578
601
  }
579
602
  });
580
- if (!a.ok) throw new R(a.status, `Open Library search failed with status ${a.status}`);
581
- return J(await a.json());
603
+ if (!a.ok) throw new N(a.status, `Open Library search failed with status ${a.status}`);
604
+ return V(await a.json());
582
605
  }, i = (e, r = {}) => e.map((e) => ({
583
- metadata: Q(e, {
606
+ metadata: G(e, {
584
607
  coversBaseUrl: n,
585
608
  isbn: r.isbn,
586
609
  matchedProjectGutenbergIdentifier: r.confirmedProjectGutenberg?.identifier
@@ -590,10 +613,10 @@ var n = (e) => {
590
613
  raw: e
591
614
  }));
592
615
  return {
593
- id: $,
616
+ id: K,
594
617
  name: "Open Library",
595
618
  search: async (e, t) => {
596
- let n = e.isbn?.trim() || void 0, a = le(e);
619
+ let n = e.isbn?.trim() || void 0, a = I(e);
597
620
  if (n !== void 0) {
598
621
  let e = await r({ isbn: n }, t);
599
622
  if (e.length > 0) return i(e, { isbn: n });
@@ -602,17 +625,204 @@ var n = (e) => {
602
625
  let e = await r({ q: `id_project_gutenberg:${a.id}` }, t);
603
626
  if (e.length > 0) return i(e, { confirmedProjectGutenberg: a });
604
627
  }
605
- let o = ve(e);
628
+ let o = Ae(e);
606
629
  return o === void 0 ? [] : i(await r(o, t));
607
630
  }
608
631
  };
609
- }, be = (e) => [
632
+ }, q = (e) => e.includes(":") ? e.slice(e.lastIndexOf(":") + 1) : e, Me = (e) => e.type === "element", J = (e, t) => e.children.filter((e) => Me(e) && q(e.name).toLowerCase() === t.toLowerCase()), Y = (e, t) => J(e, t)[0], X = (e) => {
633
+ let t = e?.val.trim();
634
+ return t !== void 0 && t.length > 0 ? t : void 0;
635
+ }, Z = (e, t) => {
636
+ for (let [n, r] of Object.entries(e.attr)) {
637
+ if (q(n).toLowerCase() !== t.toLowerCase()) continue;
638
+ let e = r.trim();
639
+ if (e.length > 0) return e;
640
+ }
641
+ }, Ne = (e, t) => J(e, t).flatMap((e) => {
642
+ let t = X(Y(Y(e, "Description") ?? e, "value"));
643
+ return t === void 0 ? [] : [t];
644
+ }), Pe = (e) => {
645
+ let t = Z(e, "about"), n = t === void 0 ? void 0 : /(?:^|\/)ebooks\/(\d+)$/.exec(t)?.[1];
646
+ if (n === void 0) return;
647
+ let r = n.replace(/^0+(?=\d)/, "");
648
+ return r === "0" ? void 0 : r;
649
+ }, Fe = (e) => {
650
+ let t = [];
651
+ for (let n of e.children) {
652
+ if (!Me(n)) continue;
653
+ let e = n.name.toLowerCase() === "dcterms:creator", r = n.name.toLowerCase().startsWith("marcrel:");
654
+ if (!e && !r) continue;
655
+ let i = X(Y(Y(n, "agent") ?? n, "name"));
656
+ i !== void 0 && t.push({
657
+ name: i,
658
+ role: e ? "aut" : q(n.name).toLowerCase()
659
+ });
660
+ }
661
+ return t;
662
+ }, Ie = (e) => J(e, "subject").flatMap((e) => {
663
+ let t = Y(e, "Description"), n = t === void 0 ? void 0 : Z(Y(t, "memberOf") ?? t, "resource"), r = X(t === void 0 ? void 0 : Y(t, "value"));
664
+ return r !== void 0 && n?.endsWith("/LCSH") === !0 ? [r] : [];
665
+ }), Le = (e) => {
666
+ let t = J(e, "hasFormat").flatMap((e) => {
667
+ let t = Y(e, "file");
668
+ if (t === void 0) return [];
669
+ let n = Z(t, "about"), r = J(t, "format").map((e) => X(Y(Y(e, "Description") ?? e, "value"))).find((e) => e?.startsWith("image/") === !0);
670
+ return n === void 0 || r === void 0 || !/\.cover\.(?:medium|small)\.[a-z0-9]+(?:$|[?#])/i.test(n) ? [] : [{
671
+ uri: n,
672
+ mediaType: r
673
+ }];
674
+ });
675
+ return t.find((e) => /\.cover\.medium\./i.test(e.uri)) ?? t[0];
676
+ }, Q = (e) => e.length > 0 ? e : void 0, Re = (e) => {
677
+ let t;
678
+ try {
679
+ t = new n(e);
680
+ } catch (e) {
681
+ let t = e instanceof Error ? e.message : String(e);
682
+ throw Error(`Project Gutenberg RDF is malformed: ${t}`, { cause: e });
683
+ }
684
+ if (q(t.name).toLowerCase() !== "rdf") return;
685
+ let r = Y(t, "ebook");
686
+ if (r === void 0) return;
687
+ let i = Pe(r);
688
+ if (i === void 0) return;
689
+ let a = [...new Set(Ne(r, "language"))], o = [...new Set(Ie(r))], s = [...new Set(Ne(r, "bookshelf"))], c = Fe(r);
690
+ return {
691
+ id: i,
692
+ title: X(Y(r, "title")),
693
+ publisher: X(Y(r, "publisher")),
694
+ issued: X(Y(r, "issued")),
695
+ originalPublication: X(Y(r, "marc260")),
696
+ rights: X(Y(r, "rights")),
697
+ description: X(Y(r, "description")),
698
+ summary: X(Y(r, "marc520")),
699
+ languages: Q(a),
700
+ subjects: Q(o),
701
+ bookshelves: Q(s),
702
+ contributors: Q(c),
703
+ cover: Le(r)
704
+ };
705
+ }, ze = 25, Be = {
706
+ id: "identifiers",
707
+ title: "title",
708
+ publisher: "publication.edition.publisher",
709
+ issued: "publication.edition.date",
710
+ originalPublication: "publication.original",
711
+ rights: "rights",
712
+ description: "description",
713
+ summary: "description",
714
+ languages: "languages",
715
+ subjects: "subjects",
716
+ bookshelves: "subjects",
717
+ contributors: "contributors",
718
+ cover: "cover"
719
+ }, Ve = {
720
+ art: "artist",
721
+ aut: "author",
722
+ clr: "colorist",
723
+ ctb: "contributor",
724
+ edt: "editor",
725
+ ill: "illustrator",
726
+ nrt: "narrator",
727
+ trl: "translator"
728
+ }, He = (e) => {
729
+ let t = /* @__PURE__ */ new Map();
730
+ for (let n of e.contributors ?? []) {
731
+ let e = n.name.trim().toLowerCase(), r = Ve[n.role.trim().toLowerCase()] ?? n.role, i = t.get(e);
732
+ i === void 0 ? t.set(e, {
733
+ name: n.name,
734
+ roles: [r]
735
+ }) : i.roles.includes(r) || i.roles.push(r);
736
+ }
737
+ return t.size > 0 ? [...t.values()] : void 0;
738
+ }, Ue = (e) => {
739
+ if (e === void 0) return;
740
+ let t = /^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?$/.exec(e.trim());
741
+ if (t === null) return;
742
+ let n = Number(t[1]), r = t[2] === void 0 ? void 0 : Number(t[2]), i = t[3] === void 0 ? void 0 : Number(t[3]);
743
+ if (!(!Number.isInteger(n) || n <= 0 || r !== void 0 && (r < 1 || r > 12) || i !== void 0 && (i < 1 || i > 31))) return {
744
+ year: n,
745
+ ...r === void 0 ? {} : { month: r },
746
+ ...i === void 0 ? {} : { day: i }
747
+ };
748
+ }, We = (e, t) => e.split("$").slice(1).flatMap((e) => e[0]?.toLowerCase() === t.toLowerCase() ? [e.slice(1).trim()] : []).filter((e) => e.length > 0), Ge = (e) => {
749
+ if (e === void 0) return;
750
+ let t = We(e, "b"), n = (t.length === 1 ? t[0] : void 0)?.replace(/[\s,;:/]+$/u, "").trim(), r = We(e, "c"), i = [...new Set(r.flatMap((e) => [...e.matchAll(/\d{4}/g)].flatMap((e) => e[0] === void 0 ? [] : [Number(e[0])])))], a = j({
751
+ date: i.length === 1 ? { year: i[0] } : void 0,
752
+ publisher: n !== void 0 && n.length > 0 && !/^\[?s\.n\.?\]?$/i.test(n) ? n : void 0
753
+ });
754
+ return a.date !== void 0 || a.publisher !== void 0 ? a : void 0;
755
+ }, Ke = (e, t) => {
756
+ try {
757
+ let n = new URL(e, t);
758
+ return n.protocol === "http:" || n.protocol === "https:" ? n.toString() : void 0;
759
+ } catch {
760
+ return;
761
+ }
762
+ }, qe = (e) => e.length > 0 ? e : void 0, Je = (e, t) => {
763
+ let n = [t.matchedIdentifier, {
764
+ value: e.id,
765
+ scheme: P
766
+ }].filter((e, t, n) => n.findIndex((t) => t.value.trim().toLowerCase() === e.value.trim().toLowerCase() && t.scheme?.trim().toLowerCase() === e.scheme?.trim().toLowerCase()) === t), r = [.../* @__PURE__ */ new Set([...e.subjects ?? [], ...e.bookshelves ?? []])].slice(0, 25), i = e.cover === void 0 ? void 0 : Ke(e.cover.uri, t.baseUrl), a = i === void 0 ? void 0 : {
767
+ uri: i,
768
+ mediaType: e.cover?.mediaType,
769
+ confidence: "derived"
770
+ }, o = j({
771
+ date: Ue(e.issued),
772
+ publisher: e.publisher
773
+ }), s = j({
774
+ original: Ge(e.originalPublication),
775
+ edition: o.date !== void 0 || o.publisher !== void 0 ? o : void 0
776
+ });
777
+ return j({
778
+ title: e.title,
779
+ publication: s.original !== void 0 || s.edition !== void 0 ? s : void 0,
780
+ description: e.summary ?? e.description,
781
+ rights: e.rights,
782
+ languages: qe([...new Set(e.languages ?? [])]),
783
+ subjects: qe(r),
784
+ contributors: He(e),
785
+ identifiers: n,
786
+ cover: a
787
+ });
788
+ }, $ = "projectGutenberg", Ye = "https://www.gutenberg.org", Xe = (e = {}) => {
789
+ let t = e.baseUrl ?? Ye;
790
+ return {
791
+ id: $,
792
+ name: "Project Gutenberg",
793
+ search: async (n, r) => {
794
+ let i = I(n);
795
+ if (i === void 0) return [];
796
+ let a = new URL(`/cache/epub/${i.id}/pg${i.id}.rdf`, t), o = await (e.fetch ?? globalThis.fetch)(a.toString(), {
797
+ signal: r.signal,
798
+ headers: {
799
+ Accept: "application/rdf+xml, application/xml;q=0.9",
800
+ ...e.userAgent === void 0 ? {} : { "User-Agent": e.userAgent }
801
+ }
802
+ });
803
+ if (o.status === 404) return [];
804
+ if (!o.ok) throw new N(o.status, `Project Gutenberg metadata lookup failed with status ${o.status}`);
805
+ let s = Re(await o.text());
806
+ if (s === void 0 || s.id !== i.id) throw Error(`Project Gutenberg RDF did not contain the requested eBook ${i.id}`);
807
+ let c = new URL(`/ebooks/${i.id}`, t).toString();
808
+ return [{
809
+ id: s.id,
810
+ url: c,
811
+ raw: s,
812
+ metadata: Je(s, {
813
+ baseUrl: t,
814
+ matchedIdentifier: i.identifier
815
+ })
816
+ }];
817
+ }
818
+ };
819
+ }, Ze = (e) => [
610
820
  e.title,
611
821
  e.isbn,
612
822
  e.gtin,
613
823
  e.belongsTo?.series?.[0]?.name
614
- ].some((e) => e !== void 0 && e.trim().length > 0) || (e.identifiers ?? []).length > 0 || n(e).length > 0;
824
+ ].some((e) => e !== void 0 && e.trim().length > 0) || (e.identifiers ?? []).length > 0 || r(e).length > 0;
615
825
  //#endregion
616
- export { E as METADATA_MATCH_WEIGHTS, R as MetadataProviderResponseError, X as OPEN_LIBRARY_IDENTIFIER_SCHEME, fe as OPEN_LIBRARY_MAX_SUBJECTS, $ as OPEN_LIBRARY_PROVIDER_ID, ye as createOpenLibraryProvider, V as fetchMetadata, be as hasSearchTerms, Y as marcLanguageToBcp47, L as mergeResolvedMetadata, n as metadataAuthors, c as normalizeForComparison, pe as openLibraryMetadataHomes, J as parseOpenLibrarySearchResponse, T as personNameSimilarity, Q as resolveOpenLibraryDoc, z as responseErrorStatus, F as scoreMetadataCandidate, u as textSimilarity, C as titleSimilarity, a as toIsbn13 };
826
+ export { E as METADATA_MATCH_WEIGHTS, N as MetadataProviderResponseError, U as OPEN_LIBRARY_IDENTIFIER_SCHEME, we as OPEN_LIBRARY_MAX_SUBJECTS, K as OPEN_LIBRARY_PROVIDER_ID, P as PROJECT_GUTENBERG_IDENTIFIER_SCHEME, ze as PROJECT_GUTENBERG_MAX_SUBJECTS, $ as PROJECT_GUTENBERG_PROVIDER_ID, je as createOpenLibraryProvider, Xe as createProjectGutenbergProvider, ge as fetchMetadata, Ze as hasSearchTerms, H as marcLanguageToBcp47, M as mergeResolvedMetadata, r as metadataAuthors, l as normalizeForComparison, Te as openLibraryMetadataHomes, V as parseOpenLibrarySearchResponse, Re as parseProjectGutenbergRdf, T as personNameSimilarity, I as projectGutenbergLookupFromMetadata, Be as projectGutenbergMetadataHomes, G as resolveOpenLibraryDoc, Je as resolveProjectGutenbergRecord, ue as responseErrorStatus, A as scoreMetadataCandidate, d as textSimilarity, C as titleSimilarity, o as toIsbn13 };
617
827
 
618
828
  //# sourceMappingURL=index.js.map