@prose-reader/metadata-fetcher 1.338.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,110 +40,192 @@ var n = (e) => {
39
40
  main: r,
40
41
  hasSubtitle: i.length > 0
41
42
  };
42
- }, p = .9, m = (e, t) => {
43
- let n = u(e, t), r = f(e), i = f(t);
44
- return r.hasSubtitle === i.hasSubtitle ? n : Math.max(n, u(r.main, i.main) * p);
45
- }, h = (e) => c(e).split(" ").filter((e) => e.length > 0).sort().join(" "), g = (e, t) => u(h(e), h(t)), _ = {
43
+ }, m = .9, h = [
44
+ "volume",
45
+ "part",
46
+ "book"
47
+ ], ee = /\b(volumes?|vols?|parts?|books?)\s+([\p{L}\p{N}]+)\b/gu, g = {
48
+ one: 1,
49
+ first: 1,
50
+ two: 2,
51
+ second: 2,
52
+ three: 3,
53
+ third: 3,
54
+ four: 4,
55
+ fourth: 4,
56
+ five: 5,
57
+ fifth: 5,
58
+ six: 6,
59
+ sixth: 6,
60
+ seven: 7,
61
+ seventh: 7,
62
+ eight: 8,
63
+ eighth: 8,
64
+ nine: 9,
65
+ ninth: 9,
66
+ ten: 10,
67
+ tenth: 10,
68
+ eleven: 11,
69
+ eleventh: 11,
70
+ twelve: 12,
71
+ twelfth: 12
72
+ }, _ = {
73
+ i: 1,
74
+ v: 5,
75
+ x: 10,
76
+ l: 50,
77
+ c: 100,
78
+ d: 500,
79
+ m: 1e3
80
+ }, v = (e) => {
81
+ if (!/^m{0,3}(cm|cd|d?c{0,3})(xc|xl|l?x{0,3})(ix|iv|v?i{0,3})$/i.test(e)) return;
82
+ let t = 0, n = 0;
83
+ for (let r of [...e.toLowerCase()].reverse()) {
84
+ let e = _[r];
85
+ if (e === void 0) return;
86
+ e < n ? t -= e : (t += e, n = e);
87
+ }
88
+ return t > 0 ? t : void 0;
89
+ }, y = (e) => /^\d+$/.test(e) ? Number.parseInt(e, 10) : g[e] ?? v(e), b = (e) => {
90
+ if (e.startsWith("vol")) return "volume";
91
+ if (e.startsWith("part")) return "part";
92
+ if (e.startsWith("book")) return "book";
93
+ }, x = (e) => {
94
+ let t = /* @__PURE__ */ new Map();
95
+ for (let n of l(e).matchAll(ee)) {
96
+ let e = n[1] === void 0 ? void 0 : b(n[1]), r = n[2] === void 0 ? void 0 : y(n[2]);
97
+ if (e === void 0 || r === void 0) continue;
98
+ let i = t.get(e) ?? /* @__PURE__ */ new Set();
99
+ i.add(r), t.set(e, i);
100
+ }
101
+ return t;
102
+ }, S = (e, t) => {
103
+ let n = x(e), r = x(t);
104
+ for (let e of h) {
105
+ let t = n.get(e), i = r.get(e);
106
+ if (!(t === void 0 || i === void 0) && [...t].every((e) => !i.has(e))) return !0;
107
+ }
108
+ return !1;
109
+ }, C = (e, t) => {
110
+ if (S(e, t)) return 0;
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 = {
46
114
  isbn: 1,
47
115
  gtin: 1,
48
116
  identifiers: .6,
49
117
  title: .8,
50
118
  contributors: .5,
51
119
  series: .3,
52
- published: .2,
53
- publisher: .15,
120
+ "publication.original.date": .2,
121
+ "publication.original.publisher": .15,
122
+ "publication.edition.date": .2,
123
+ "publication.edition.publisher": .15,
54
124
  languages: .15,
55
125
  numberOfPages: .15
56
- }, v = /* @__PURE__ */ new Set(["isbn", "gtin"]), y = (e) => {
126
+ }, te = /* @__PURE__ */ new Set(["isbn", "gtin"]), D = (e) => {
57
127
  let t = e?.trim();
58
128
  return t !== void 0 && t.length > 0 ? t : void 0;
59
- }, b = (e) => e.value.trim().toLowerCase(), x = (e) => e.scheme === void 0 ? e.value : `${e.scheme}:${e.value}`, S = (e, t) => b(e) === b(t) ? e.scheme === void 0 || t.scheme === void 0 || e.scheme.trim().toLowerCase() === t.scheme.trim().toLowerCase() : !1, C = (e) => e.trim().toLowerCase().split("-")[0] ?? "", w = (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) => {
60
141
  let n = Math.abs(e - t);
61
142
  return n === 0 ? 1 : n === 1 ? .6 : n <= 3 ? .3 : 0;
62
- }, T = (e, t) => {
143
+ }, se = (e, t) => {
63
144
  let n = Math.max(e, t);
64
145
  return n <= 0 ? 0 : Math.max(0, 1 - Math.abs(e - t) / n * 2);
65
- }, E = (e, t, n) => e.reduce((e, r) => t.reduce((e, t) => Math.max(e, n(r, t)), e), 0), D = (e, t) => {
66
- let r = [], i = (e, t) => {
67
- 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({
68
149
  field: e,
69
- weight: _[e],
150
+ weight: E[e],
70
151
  score: Math.min(1, Math.max(0, t.score)),
71
152
  query: t.query,
72
153
  candidate: t.candidate
73
154
  });
74
- }, o = (e, t, n, r = u) => {
75
- let a = y(t), o = y(n);
155
+ }, a = (e, t, n, r = d) => {
156
+ let a = D(t), o = D(n);
76
157
  a === void 0 || o === void 0 || i(e, {
77
158
  score: r(a, o),
78
159
  query: a,
79
160
  candidate: o
80
161
  });
81
- }, s = y(e.isbn), c = y(t.isbn), l = s === void 0 ? void 0 : a(s), d = c === void 0 ? void 0 : a(c);
82
- s !== void 0 && c !== void 0 && l !== void 0 && d !== void 0 && i("isbn", {
83
- 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),
84
165
  query: s,
85
166
  candidate: c
86
167
  });
87
- let f = y(e.gtin), p = y(t.gtin);
168
+ let f = D(e.gtin), p = D(t.gtin);
88
169
  f !== void 0 && p !== void 0 && i("gtin", {
89
170
  score: +(f === p),
90
171
  query: f,
91
172
  candidate: p
92
173
  });
93
- let h = e.identifiers ?? [], b = t.identifiers ?? [];
94
- h.length > 0 && b.length > 0 && i("identifiers", {
95
- score: +!!h.some((e) => b.some((t) => S(e, t))),
96
- query: h.map(x).join(", "),
97
- candidate: b.map(x).join(", ")
98
- }), o("title", e.title, t.title, m), o("publisher", e.publisher, t.publisher), o("series", e.belongsTo?.series?.[0]?.name, t.belongsTo?.series?.[0]?.name);
99
- let D = n(t), O = n(e);
100
- O.length > 0 && D.length > 0 && i("contributors", {
101
- score: E(O, D, g),
102
- query: O.join(", "),
103
- candidate: D.join(", ")
174
+ let m = e.identifiers ?? [], h = t.identifiers ?? [], ee = m.some((e) => h.some((t) => ae(e, t)));
175
+ m.length > 0 && h.length > 0 && i("identifiers", {
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);
181
+ _.length > 0 && g.length > 0 && i("contributors", {
182
+ score: ce(_, g, T),
183
+ query: _.join(", "),
184
+ candidate: g.join(", ")
104
185
  });
105
- let k = e.published?.year, A = t.published?.year;
106
- k !== void 0 && A !== void 0 && i("published", {
107
- score: w(k, A),
108
- query: String(k),
109
- candidate: String(A)
110
- });
111
- let j = e.languages ?? [], M = t.languages ?? [];
112
- if (j.length > 0 && M.length > 0) {
113
- let e = new Set(M.map(C));
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));
114
197
  i("languages", {
115
- score: +!!j.some((t) => e.has(C(t))),
116
- query: j.join(", "),
117
- candidate: M.join(", ")
198
+ score: +!!y.some((t) => e.has(k(t))),
199
+ query: y.join(", "),
200
+ candidate: b.join(", ")
118
201
  });
119
202
  }
120
203
  e.numberOfPages !== void 0 && t.numberOfPages !== void 0 && i("numberOfPages", {
121
- score: T(e.numberOfPages, t.numberOfPages),
204
+ score: se(e.numberOfPages, t.numberOfPages),
122
205
  query: String(e.numberOfPages),
123
206
  candidate: String(t.numberOfPages)
124
207
  });
125
- let N = r.filter((e) => v.has(e.field));
126
- if (N.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 {
127
210
  score: 0,
128
- signals: r
211
+ signals: n
129
212
  };
130
- if (N.some((e) => e.score === 1)) return {
213
+ if (ee || x.some((e) => e.score === 1)) return {
131
214
  score: 1,
132
- signals: r
215
+ signals: n
133
216
  };
134
- let P = r.reduce((e, t) => e + t.weight, 0);
135
- return P === 0 ? {
217
+ let S = n.reduce((e, t) => e + t.weight, 0);
218
+ return S === 0 ? {
136
219
  score: 0,
137
- signals: r
220
+ signals: n
138
221
  } : {
139
- score: r.reduce((e, t) => e + t.score * t.weight, 0) / P,
140
- signals: r
222
+ score: n.reduce((e, t) => e + t.score * t.weight, 0) / S,
223
+ signals: n
141
224
  };
142
- }, O = (e) => {
225
+ }, j = (e) => {
143
226
  let t = Object.entries(e).filter(([, e]) => e !== void 0);
144
227
  return Object.fromEntries(t);
145
- }, k = (e) => {
228
+ }, le = (e) => {
146
229
  let t = /* @__PURE__ */ new Map();
147
230
  for (let n of e) {
148
231
  let e = `${n.scheme?.trim().toLowerCase() ?? ""}:${n.value.trim().toLowerCase()}`, r = t.get(e);
@@ -156,27 +239,35 @@ var n = (e) => {
156
239
  });
157
240
  }
158
241
  return [...t.values()];
159
- }, A = (...e) => {
242
+ }, M = (...e) => {
160
243
  let t = e.filter((e) => e !== void 0), n = (e) => {
161
244
  for (let n of t) {
162
245
  let t = n[e];
163
246
  if (t !== void 0) return t;
164
247
  }
165
- }, r = k(t.flatMap((e) => e.identifiers ?? [])), i = O({
248
+ }, r = le(t.flatMap((e) => e.identifiers ?? [])), i = j({
166
249
  series: t.find((e) => e.belongsTo?.series !== void 0)?.belongsTo?.series,
167
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")
168
261
  });
169
- return O({
262
+ return j({
170
263
  title: n("title"),
171
264
  cover: n("cover"),
172
265
  description: n("description"),
173
- publisher: n("publisher"),
174
- imprint: n("imprint"),
266
+ publication: o.original !== void 0 || o.edition !== void 0 ? o : void 0,
175
267
  rights: n("rights"),
176
268
  languages: n("languages"),
177
269
  subjects: n("subjects"),
178
270
  contributors: n("contributors"),
179
- published: n("published"),
180
271
  readingDirection: n("readingDirection"),
181
272
  renditionLayout: n("renditionLayout"),
182
273
  renditionFlow: n("renditionFlow"),
@@ -191,16 +282,16 @@ var n = (e) => {
191
282
  apple: n("apple"),
192
283
  kobo: n("kobo")
193
284
  });
194
- }, j = class extends Error {
285
+ }, N = class extends Error {
195
286
  status;
196
287
  constructor(e, t) {
197
288
  super(t ?? `Provider responded with status ${e}`), this.name = "MetadataProviderResponseError", this.status = e;
198
289
  }
199
- }, M = (e) => {
290
+ }, ue = (e) => {
200
291
  if (typeof e != "object" || !e || !("status" in e)) return;
201
292
  let { status: t } = e;
202
293
  if (!(typeof t != "number" || !Number.isInteger(t))) return t >= 100 && t <= 599 ? t : void 0;
203
- }, N = t.namespace("@prose-reader/metadata-fetcher", void 0, { color: "#b06642" }), P = 5, F = .5, I = 1, L = ({ candidate: e, providerId: t, score: n, signals: r, accepted: i, includeRaw: a }) => O({
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({
204
295
  providerId: t,
205
296
  score: n,
206
297
  signals: r,
@@ -209,8 +300,8 @@ var n = (e) => {
209
300
  id: e.id,
210
301
  url: e.url,
211
302
  raw: a ? e.raw : void 0
212
- }), R = async (e, t) => {
213
- let n = "metadata" in e ? e.metadata : e, r = t.limit ?? P, i = t.minScore ?? F, 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) => {
214
305
  try {
215
306
  return {
216
307
  provider: e,
@@ -222,12 +313,12 @@ var n = (e) => {
222
313
  };
223
314
  } catch (n) {
224
315
  if (t.signal?.aborted === !0) throw n;
225
- return N.error(`fetchMetadata: provider "${e.id}" failed`, n), {
316
+ return de.error(`fetchMetadata: provider "${e.id}" failed`, n), {
226
317
  provider: e,
227
318
  candidates: void 0,
228
- failure: O({
319
+ failure: j({
229
320
  id: e.id,
230
- status: M(n)
321
+ status: ue(n)
231
322
  })
232
323
  };
233
324
  }
@@ -235,8 +326,8 @@ var n = (e) => {
235
326
  for (let { provider: e, candidates: t } of o) {
236
327
  if (t === void 0) continue;
237
328
  let o = t.map((t) => {
238
- let { score: r, signals: o } = D(n, t.metadata);
239
- return L({
329
+ let { score: r, signals: o } = A(n, t.metadata);
330
+ return he({
240
331
  candidate: t,
241
332
  providerId: e.id,
242
333
  score: r,
@@ -245,7 +336,7 @@ var n = (e) => {
245
336
  includeRaw: a
246
337
  });
247
338
  }).sort((e, t) => t.score - e.score).slice(0, r);
248
- c[e.id] !== void 0 && N.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] = {
249
340
  provider: {
250
341
  id: e.id,
251
342
  name: e.name
@@ -255,40 +346,72 @@ var n = (e) => {
255
346
  }
256
347
  let u = [...l].sort((e, t) => t.score - e.score);
257
348
  return {
258
- version: I,
259
- metadata: A(...u.filter((e) => e.accepted).map((e) => e.metadata)),
349
+ version: me,
350
+ metadata: M(...u.filter((e) => e.accepted).map((e) => e.metadata)),
260
351
  matches: u,
261
352
  sources: c,
262
353
  failedProviders: s
263
354
  };
264
- }, z = (e) => typeof e == "object" && !!e && !Array.isArray(e), B = (e, t) => {
355
+ }, P = "ProjectGutenberg", _e = /* @__PURE__ */ new Set(["gutenberg.org", "www.gutenberg.org"]), ve = [
356
+ /^\/ebooks\/(\d+)(?:[./]|$)/i,
357
+ /^\/files\/(\d+)(?:\/|$)/i,
358
+ /^\/cache\/epub\/(\d+)(?:\/|$)/i,
359
+ /^\/(\d+)(?:\/|$)/
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) => {
366
+ try {
367
+ let t = new URL(e.trim());
368
+ if (t.protocol !== "http:" && t.protocol !== "https:" || !_e.has(t.hostname.toLowerCase())) return;
369
+ for (let e of ve) {
370
+ let n = e.exec(t.pathname)?.[1];
371
+ if (n !== void 0) return F(n);
372
+ }
373
+ } catch {
374
+ return;
375
+ }
376
+ }, I = (e) => {
377
+ for (let t of e.identifiers ?? []) {
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;
379
+ if (n !== void 0) return {
380
+ id: n,
381
+ identifier: {
382
+ value: t.value,
383
+ ...t.scheme === void 0 ? {} : { scheme: t.scheme }
384
+ }
385
+ };
386
+ }
387
+ }, L = (e) => typeof e == "object" && !!e && !Array.isArray(e), R = (e, t) => {
265
388
  let n = e[t];
266
389
  if (typeof n != "string") return;
267
390
  let r = n.trim();
268
391
  return r.length > 0 ? r : void 0;
269
- }, V = (e, t) => {
392
+ }, z = (e, t) => {
270
393
  let n = e[t];
271
394
  return typeof n == "number" && Number.isFinite(n) ? n : void 0;
272
- }, H = (e, t) => {
395
+ }, B = (e, t) => {
273
396
  let n = e[t];
274
397
  if (!Array.isArray(n)) return;
275
398
  let r = n.filter((e) => typeof e == "string").map((e) => e.trim()).filter((e) => e.length > 0);
276
399
  return r.length > 0 ? r : void 0;
277
- }, U = (e, t) => {
400
+ }, be = (e, t) => {
278
401
  let n = e[t];
279
- return Array.isArray(n) ? n.filter(z) : [];
280
- }, W = (e) => ({
281
- key: B(e, "key"),
282
- title: B(e, "title"),
283
- subtitle: B(e, "subtitle"),
284
- author_name: H(e, "author_name"),
285
- first_publish_year: V(e, "first_publish_year"),
286
- publisher: H(e, "publisher"),
287
- language: H(e, "language"),
288
- subject: H(e, "subject"),
289
- number_of_pages_median: V(e, "number_of_pages_median"),
290
- cover_i: V(e, "cover_i")
291
- }), G = (e) => z(e) ? U(e, "docs").map(W) : [], K = {
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 = {
292
415
  afr: "af",
293
416
  alb: "sq",
294
417
  amh: "am",
@@ -393,76 +516,83 @@ var n = (e) => {
393
516
  wel: "cy",
394
517
  yid: "yi",
395
518
  zho: "zh"
396
- }, q = /* @__PURE__ */ new Set([
519
+ }, Ce = /* @__PURE__ */ new Set([
397
520
  "mul",
398
521
  "und",
399
522
  "zxx",
400
523
  "sgn"
401
- ]), J = (e) => {
524
+ ]), H = (e) => {
402
525
  let t = e.trim().toLowerCase();
403
- if (t.length !== 0 && !q.has(t)) return K[t] ?? t;
404
- }, Y = 25, ee = {
526
+ if (t.length !== 0 && !Ce.has(t)) return Se[t] ?? t;
527
+ }, we = 25, Te = {
405
528
  key: "identifiers",
406
529
  title: "title",
407
530
  subtitle: "title",
408
531
  author_name: "contributors",
409
- first_publish_year: "published",
410
- publisher: "publisher",
532
+ first_publish_year: "publication.original.date",
411
533
  language: "languages",
412
534
  subject: "subjects",
413
535
  number_of_pages_median: "numberOfPages",
414
- cover_i: "cover"
415
- }, X = "OpenLibrary", Z = (e) => e.length > 0 ? e : void 0, Q = (e, t) => {
416
- let n = e.title !== void 0 && e.subtitle !== void 0 ? `${e.title}: ${e.subtitle}` : e.title, r = Z([...new Set((e.language ?? []).map(J).filter((e) => e !== void 0))]), i = [...t.isbn === void 0 ? [] : [{
417
- value: t.isbn,
418
- scheme: "ISBN"
419
- }], ...e.key === void 0 ? [] : [{
420
- value: e.key,
421
- scheme: X
422
- }]];
423
- return O({
536
+ cover_i: "cover",
537
+ id_project_gutenberg: "identifiers"
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 = [
540
+ ...t.isbn === void 0 ? [] : [{
541
+ value: t.isbn,
542
+ scheme: "ISBN"
543
+ }],
544
+ ...t.matchedProjectGutenbergIdentifier === void 0 ? [] : [t.matchedProjectGutenbergIdentifier],
545
+ ...(e.id_project_gutenberg ?? []).map((e) => ({
546
+ value: e,
547
+ scheme: Ee
548
+ })),
549
+ ...e.key === void 0 ? [] : [{
550
+ value: e.key,
551
+ scheme: U
552
+ }]
553
+ ];
554
+ return j({
424
555
  title: n,
425
556
  cover: e.cover_i === void 0 ? void 0 : {
426
557
  uri: `${t.coversBaseUrl}/b/id/${e.cover_i}-L.jpg`,
427
558
  mediaType: "image/jpeg",
428
559
  confidence: "derived"
429
560
  },
430
- publisher: e.publisher?.[0],
561
+ publication: e.first_publish_year === void 0 ? void 0 : { original: { date: { year: e.first_publish_year } } },
431
562
  languages: r,
432
- subjects: Z((e.subject ?? []).slice(0, 25)),
433
- contributors: Z((e.author_name ?? []).map((e) => ({
563
+ subjects: W((e.subject ?? []).slice(0, 25)),
564
+ contributors: W((e.author_name ?? []).map((e) => ({
434
565
  name: e,
435
566
  roles: ["author"]
436
567
  }))),
437
- published: e.first_publish_year === void 0 ? void 0 : { year: e.first_publish_year },
438
568
  numberOfPages: e.number_of_pages_median,
439
569
  isbn: t.isbn,
440
- identifiers: Z(i)
570
+ identifiers: W(i)
441
571
  });
442
- }, $ = "openLibrary", te = "https://openlibrary.org", ne = "https://covers.openlibrary.org", re = [
572
+ }, K = "openLibrary", De = "https://openlibrary.org", Oe = "https://covers.openlibrary.org", ke = [
443
573
  "key",
444
574
  "title",
445
575
  "subtitle",
446
576
  "author_name",
447
577
  "first_publish_year",
448
- "publisher",
449
578
  "language",
450
579
  "subject",
451
580
  "number_of_pages_median",
452
- "cover_i"
453
- ].join(","), ie = (e) => {
581
+ "cover_i",
582
+ "id_project_gutenberg"
583
+ ].join(","), Ae = (e) => {
454
584
  let t = e.title?.trim();
455
585
  if (t === void 0 || t.length === 0) return;
456
- let r = n(e)[0];
586
+ let n = r(e)[0];
457
587
  return {
458
588
  title: t,
459
- ...r === void 0 ? {} : { author: r }
589
+ ...n === void 0 ? {} : { author: n }
460
590
  };
461
- }, ae = (e = {}) => {
462
- let t = e.baseUrl ?? te, n = e.coversBaseUrl ?? ne, r = async (n, r) => {
591
+ }, je = (e = {}) => {
592
+ let t = e.baseUrl ?? De, n = e.coversBaseUrl ?? Oe, r = async (n, r) => {
463
593
  let i = new URL("/search.json", t);
464
594
  for (let [e, t] of Object.entries(n)) i.searchParams.set(e, t);
465
- i.searchParams.set("fields", re), i.searchParams.set("limit", String(r.limit));
595
+ i.searchParams.set("fields", ke), i.searchParams.set("limit", String(r.limit));
466
596
  let a = await (e.fetch ?? globalThis.fetch)(i.toString(), {
467
597
  signal: r.signal,
468
598
  headers: {
@@ -470,37 +600,229 @@ var n = (e) => {
470
600
  ...e.userAgent === void 0 ? {} : { "User-Agent": e.userAgent }
471
601
  }
472
602
  });
473
- if (!a.ok) throw new j(a.status, `Open Library search failed with status ${a.status}`);
474
- return G(await a.json());
475
- }, i = (e, r) => e.map((e) => ({
476
- metadata: Q(e, {
603
+ if (!a.ok) throw new N(a.status, `Open Library search failed with status ${a.status}`);
604
+ return V(await a.json());
605
+ }, i = (e, r = {}) => e.map((e) => ({
606
+ metadata: G(e, {
477
607
  coversBaseUrl: n,
478
- isbn: r
608
+ isbn: r.isbn,
609
+ matchedProjectGutenbergIdentifier: r.confirmedProjectGutenberg?.identifier
479
610
  }),
480
611
  id: e.key,
481
612
  url: e.key === void 0 ? void 0 : `${t}${e.key}`,
482
613
  raw: e
483
614
  }));
484
615
  return {
485
- id: $,
616
+ id: K,
486
617
  name: "Open Library",
487
618
  search: async (e, t) => {
488
- let n = e.isbn?.trim() || void 0;
619
+ let n = e.isbn?.trim() || void 0, a = I(e);
489
620
  if (n !== void 0) {
490
621
  let e = await r({ isbn: n }, t);
491
- if (e.length > 0) return i(e, n);
622
+ if (e.length > 0) return i(e, { isbn: n });
623
+ }
624
+ if (a !== void 0) {
625
+ let e = await r({ q: `id_project_gutenberg:${a.id}` }, t);
626
+ if (e.length > 0) return i(e, { confirmedProjectGutenberg: a });
492
627
  }
493
- let a = ie(e);
494
- return a === void 0 ? [] : i(await r(a, t), void 0);
628
+ let o = Ae(e);
629
+ return o === void 0 ? [] : i(await r(o, t));
630
+ }
631
+ };
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
+ }];
495
817
  }
496
818
  };
497
- }, oe = (e) => [
819
+ }, Ze = (e) => [
498
820
  e.title,
499
821
  e.isbn,
500
822
  e.gtin,
501
823
  e.belongsTo?.series?.[0]?.name
502
- ].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;
503
825
  //#endregion
504
- export { _ as METADATA_MATCH_WEIGHTS, j as MetadataProviderResponseError, X as OPEN_LIBRARY_IDENTIFIER_SCHEME, Y as OPEN_LIBRARY_MAX_SUBJECTS, $ as OPEN_LIBRARY_PROVIDER_ID, ae as createOpenLibraryProvider, R as fetchMetadata, oe as hasSearchTerms, J as marcLanguageToBcp47, A as mergeResolvedMetadata, n as metadataAuthors, c as normalizeForComparison, ee as openLibraryMetadataHomes, G as parseOpenLibrarySearchResponse, g as personNameSimilarity, Q as resolveOpenLibraryDoc, M as responseErrorStatus, D as scoreMetadataCandidate, u as textSimilarity, m 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 };
505
827
 
506
828
  //# sourceMappingURL=index.js.map