book-index-ui 0.2.11 → 0.2.13
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.cjs +3 -3
- package/dist/index.d.ts +34 -0
- package/dist/index.js +1466 -1448
- package/dist/storage-entry-QB1IoDUU.cjs +1 -0
- package/dist/{storage-entry-Bfhi3hs7.js → storage-entry-UQLfmeLb.js} +350 -281
- package/dist/storage.cjs +1 -1
- package/dist/storage.d.ts +34 -0
- package/dist/storage.js +1 -1
- package/package.json +1 -1
- package/dist/storage-entry-DEouFxE1.cjs +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
const ct = { official: 0, draft: 1 }, lt = { 0: "official", 1: "draft" }, ht = { book: 0, collection: 2, work: 3, entity: 4 }, ut = { 0: "book", 2: "collection", 3: "work", 4: "entity" }, V = 62n, X = 59n, Q = 19n, Z = 8n, tt = (1n << 40n) - 1n, dt = (1n << 3n) - 1n, ft = (1n << 11n) - 1n, yt = (1n << 8n) - 1n, R = "0123456789abcdefghijklmnopqrstuvwxyz", et = /* @__PURE__ */ new Map();
|
|
2
|
-
for (let
|
|
3
|
-
et.set(R[
|
|
4
|
-
function
|
|
5
|
-
if (
|
|
2
|
+
for (let c = 0; c < R.length; c++)
|
|
3
|
+
et.set(R[c], BigInt(c));
|
|
4
|
+
function D(c) {
|
|
5
|
+
if (c === 0n) return R[0];
|
|
6
6
|
let t = "";
|
|
7
|
-
for (;
|
|
8
|
-
t = R[Number(
|
|
7
|
+
for (; c > 0n; )
|
|
8
|
+
t = R[Number(c % 36n)] + t, c = c / 36n;
|
|
9
9
|
return t;
|
|
10
10
|
}
|
|
11
|
-
function st(
|
|
11
|
+
function st(c) {
|
|
12
12
|
let t = 0n;
|
|
13
|
-
for (const e of
|
|
13
|
+
for (const e of c) {
|
|
14
14
|
const s = et.get(e);
|
|
15
15
|
if (s === void 0)
|
|
16
16
|
throw new Error(`Invalid Base36 character: ${e}`);
|
|
@@ -19,11 +19,11 @@ function st(r) {
|
|
|
19
19
|
return t;
|
|
20
20
|
}
|
|
21
21
|
const H = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", nt = /* @__PURE__ */ new Map();
|
|
22
|
-
for (let
|
|
23
|
-
nt.set(H[
|
|
24
|
-
function gt(
|
|
22
|
+
for (let c = 0; c < H.length; c++)
|
|
23
|
+
nt.set(H[c], BigInt(c));
|
|
24
|
+
function gt(c) {
|
|
25
25
|
let t = 0n;
|
|
26
|
-
for (const e of
|
|
26
|
+
for (const e of c) {
|
|
27
27
|
const s = nt.get(e);
|
|
28
28
|
if (s === void 0)
|
|
29
29
|
throw new Error(`Invalid Base58 character: ${e}`);
|
|
@@ -31,12 +31,12 @@ function gt(r) {
|
|
|
31
31
|
}
|
|
32
32
|
return t;
|
|
33
33
|
}
|
|
34
|
-
function x(
|
|
35
|
-
return /[A-Z]/.test(
|
|
34
|
+
function x(c) {
|
|
35
|
+
return /[A-Z]/.test(c) ? gt(c) : st(c);
|
|
36
36
|
}
|
|
37
|
-
const
|
|
38
|
-
function
|
|
39
|
-
const t = Number(
|
|
37
|
+
const jt = D, Pt = st;
|
|
38
|
+
function $(c) {
|
|
39
|
+
const t = Number(c >> V & 1n), e = Number(c >> X & dt), s = c >> Q & tt, n = Number(c >> Z & ft), i = Number(c & yt);
|
|
40
40
|
return {
|
|
41
41
|
status: lt[t] ?? "draft",
|
|
42
42
|
type: ut[e] ?? "book",
|
|
@@ -45,31 +45,31 @@ function A(r) {
|
|
|
45
45
|
sequence: i
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
function z(
|
|
49
|
-
return BigInt(ct[
|
|
48
|
+
function z(c, t, e, s, n) {
|
|
49
|
+
return BigInt(ct[c]) << V | BigInt(ht[t]) << X | (e & tt) << Q | BigInt(s) << Z | BigInt(n);
|
|
50
50
|
}
|
|
51
|
-
function L(
|
|
52
|
-
return
|
|
51
|
+
function L(c) {
|
|
52
|
+
return $(x(c));
|
|
53
53
|
}
|
|
54
|
-
function
|
|
55
|
-
return L(
|
|
54
|
+
function pt(c) {
|
|
55
|
+
return L(c).type;
|
|
56
56
|
}
|
|
57
|
-
function Tt(
|
|
58
|
-
return L(
|
|
57
|
+
function Tt(c) {
|
|
58
|
+
return L(c).status;
|
|
59
59
|
}
|
|
60
|
-
const N = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" },
|
|
61
|
-
function
|
|
60
|
+
const N = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" }, mt = { Book: "book", Collection: "collection", Work: "work", Entity: "entity" }, T = 16;
|
|
61
|
+
function J(c, t = T) {
|
|
62
62
|
let e = 0;
|
|
63
|
-
for (let s = 0; s <
|
|
64
|
-
e = Math.imul(e, 31) +
|
|
63
|
+
for (let s = 0; s < c.length; s++)
|
|
64
|
+
e = Math.imul(e, 31) + c.charCodeAt(s) >>> 0;
|
|
65
65
|
return e % t;
|
|
66
66
|
}
|
|
67
|
-
function b(...
|
|
68
|
-
const t =
|
|
67
|
+
function b(...c) {
|
|
68
|
+
const t = c.join("/");
|
|
69
69
|
return t.startsWith("//") ? "//" + t.slice(2).replace(/\/+/g, "/") : t.replace(/\/+/g, "/");
|
|
70
70
|
}
|
|
71
|
-
function
|
|
72
|
-
return
|
|
71
|
+
function _t(c) {
|
|
72
|
+
return c.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "") || "Undefined";
|
|
73
73
|
}
|
|
74
74
|
class it {
|
|
75
75
|
constructor(t, e) {
|
|
@@ -79,30 +79,30 @@ class it {
|
|
|
79
79
|
return t === "draft" ? this.draftRoot : this.officialRoot;
|
|
80
80
|
}
|
|
81
81
|
getRootById(t) {
|
|
82
|
-
const e = x(t), s =
|
|
82
|
+
const e = x(t), s = $(e);
|
|
83
83
|
return this.getRootByStatus(s.status);
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* 计算文件路径: {root}/{Type}/{c1}/{c2}/{c3}/{ID}-{name}.json
|
|
87
87
|
*/
|
|
88
88
|
getPath(t, e, s) {
|
|
89
|
-
const n = this.getRootById(e), i = e.padEnd(3, "_").substring(0, 3), [o,
|
|
90
|
-
return b(n, a, o,
|
|
89
|
+
const n = this.getRootById(e), i = e.padEnd(3, "_").substring(0, 3), [o, r, l] = [i[0], i[1], i[2]], a = N[t];
|
|
90
|
+
return b(n, a, o, r, l, `${e}-${_t(s)}.json`);
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* 保存条目并更新索引
|
|
94
94
|
*/
|
|
95
95
|
async saveItem(t, e, s) {
|
|
96
|
-
const n = s.title || s.书名 || "未命名", i = s.edition || "", o = i ? `${n}${i}` : n,
|
|
97
|
-
if (l && l !==
|
|
96
|
+
const n = s.title || s.书名 || "未命名", i = s.edition || "", o = i ? `${n}${i}` : n, r = this.getPath(t, e, o), l = await this.findFileById(e);
|
|
97
|
+
if (l && l !== r)
|
|
98
98
|
try {
|
|
99
99
|
await this.fs.deleteFile(l);
|
|
100
100
|
} catch {
|
|
101
101
|
}
|
|
102
|
-
const a =
|
|
103
|
-
await this.fs.mkdir(a), s.id = e, s.type = t, await this.fs.writeFile(
|
|
104
|
-
const
|
|
105
|
-
return await this.updateIndexEntry(
|
|
102
|
+
const a = r.substring(0, r.lastIndexOf("/"));
|
|
103
|
+
await this.fs.mkdir(a), s.id = e, s.type = t, await this.fs.writeFile(r, JSON.stringify(s, wt, 2));
|
|
104
|
+
const h = this.getRootById(e), u = r.substring(h.length + 1);
|
|
105
|
+
return await this.updateIndexEntry(h, s, t, u), r;
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* 更新索引分片中的条目
|
|
@@ -110,16 +110,16 @@ class it {
|
|
|
110
110
|
async updateIndexEntry(t, e, s, n) {
|
|
111
111
|
const i = e.id || "";
|
|
112
112
|
if (!i) return;
|
|
113
|
-
const o = `${s}s`,
|
|
113
|
+
const o = `${s}s`, r = await this.loadShard(t, o, i);
|
|
114
114
|
let l = "";
|
|
115
115
|
const a = e.authors;
|
|
116
116
|
if (Array.isArray(a) && a.length > 0) {
|
|
117
117
|
const y = a[0];
|
|
118
118
|
l = typeof y == "object" && y !== null ? y.name || "" : String(y);
|
|
119
119
|
} else typeof a == "string" && (l = a);
|
|
120
|
-
let
|
|
121
|
-
const
|
|
122
|
-
typeof
|
|
120
|
+
let h = "";
|
|
121
|
+
const u = e.publication_info;
|
|
122
|
+
typeof u == "object" && u !== null ? h = u.year || "" : typeof u == "string" && (h = u);
|
|
123
123
|
let d = "";
|
|
124
124
|
const f = e.current_location;
|
|
125
125
|
typeof f == "object" && f !== null ? d = f.name || "" : typeof f == "string" && (d = f);
|
|
@@ -127,18 +127,18 @@ class it {
|
|
|
127
127
|
let v;
|
|
128
128
|
const I = e.juan_count;
|
|
129
129
|
typeof I == "number" ? v = I : typeof I == "object" && I !== null && (v = I.number || void 0);
|
|
130
|
-
const
|
|
131
|
-
let
|
|
132
|
-
const
|
|
133
|
-
if (Array.isArray(
|
|
134
|
-
for (const y of
|
|
130
|
+
const A = typeof e.measure_info == "string" ? e.measure_info : "";
|
|
131
|
+
let C = !1, S = !1;
|
|
132
|
+
const P = e.resources;
|
|
133
|
+
if (Array.isArray(P))
|
|
134
|
+
for (const y of P) {
|
|
135
135
|
if (typeof y != "object" || y === null) continue;
|
|
136
136
|
const _ = y.types;
|
|
137
137
|
if (Array.isArray(_))
|
|
138
|
-
_.includes("text") && (
|
|
138
|
+
_.includes("text") && (C = !0), _.includes("image") && (S = !0);
|
|
139
139
|
else {
|
|
140
|
-
const
|
|
141
|
-
(
|
|
140
|
+
const E = y.type;
|
|
141
|
+
(E === "text" || E === "text+image") && (C = !0), (E === "image" || E === "text+image") && (S = !0);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
const m = {
|
|
@@ -147,12 +147,12 @@ class it {
|
|
|
147
147
|
type: N[s],
|
|
148
148
|
path: n,
|
|
149
149
|
author: l,
|
|
150
|
-
year:
|
|
150
|
+
year: h,
|
|
151
151
|
holder: d
|
|
152
152
|
};
|
|
153
|
-
p && p.length > 0 && (m.additional_titles = p), k && k.length > 0 && (m.attached_texts = k), v && (m.juan_count = v),
|
|
154
|
-
const
|
|
155
|
-
|
|
153
|
+
p && p.length > 0 && (m.additional_titles = p), k && k.length > 0 && (m.attached_texts = k), v && (m.juan_count = v), A && (m.measure_info = A);
|
|
154
|
+
const j = typeof e.edition == "string" ? e.edition : "";
|
|
155
|
+
j && (m.edition = j), C && (m.has_text = !0), S && (m.has_image = !0), r[i] = m, await this.saveShard(t, o, i, r);
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* 删除条目和索引记录
|
|
@@ -160,8 +160,8 @@ class it {
|
|
|
160
160
|
async deleteItem(t) {
|
|
161
161
|
const e = await this.findFileById(t);
|
|
162
162
|
if (!e) return !1;
|
|
163
|
-
const s = x(t), n =
|
|
164
|
-
return
|
|
163
|
+
const s = x(t), n = $(s), i = this.getRootByStatus(n.status), o = `${n.type}s`, r = await this.loadShard(i, o, t);
|
|
164
|
+
return r[t] && (delete r[t], await this.saveShard(i, o, t, r)), await this.fs.deleteFile(e), !0;
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
167
167
|
* 通过 ID 查找文件
|
|
@@ -169,12 +169,12 @@ class it {
|
|
|
169
169
|
async findFileById(t) {
|
|
170
170
|
const e = t.padEnd(3, "_").substring(0, 3), [s, n, i] = [e[0], e[1], e[2]];
|
|
171
171
|
for (const o of [this.officialRoot, this.draftRoot])
|
|
172
|
-
for (const
|
|
173
|
-
const l = b(o,
|
|
172
|
+
for (const r of ["Book", "Collection", "Work"]) {
|
|
173
|
+
const l = b(o, r, s, n, i);
|
|
174
174
|
if (await this.fs.exists(l))
|
|
175
175
|
try {
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
176
|
+
const h = (await this.fs.readdir(l)).find((u) => u.startsWith(`${t}-`) && u.endsWith(".json"));
|
|
177
|
+
if (h) return b(l, h);
|
|
178
178
|
} catch {
|
|
179
179
|
}
|
|
180
180
|
}
|
|
@@ -206,8 +206,8 @@ class it {
|
|
|
206
206
|
async loadEntries(t, e) {
|
|
207
207
|
const s = e ? [this.getRootByStatus(e)] : [this.officialRoot, this.draftRoot], n = [], i = `${t}s`;
|
|
208
208
|
for (const o of s) {
|
|
209
|
-
const
|
|
210
|
-
for (const [l, a] of Object.entries(
|
|
209
|
+
const r = await this.loadAllShards(o, i);
|
|
210
|
+
for (const [l, a] of Object.entries(r))
|
|
211
211
|
n.push({
|
|
212
212
|
id: l,
|
|
213
213
|
title: a.title,
|
|
@@ -262,47 +262,47 @@ class it {
|
|
|
262
262
|
async rebuildIndex(t) {
|
|
263
263
|
var n, i;
|
|
264
264
|
const e = this.getRootByStatus(t), s = {
|
|
265
|
-
books: Object.fromEntries(Array.from({ length: T }, (o,
|
|
265
|
+
books: Object.fromEntries(Array.from({ length: T }, (o, r) => [r, {}])),
|
|
266
266
|
collections: { 0: {} },
|
|
267
|
-
works: Object.fromEntries(Array.from({ length: T }, (o,
|
|
267
|
+
works: Object.fromEntries(Array.from({ length: T }, (o, r) => [r, {}]))
|
|
268
268
|
};
|
|
269
269
|
for (const o of ["Book", "Collection", "Work"]) {
|
|
270
|
-
const
|
|
271
|
-
if (!await this.fs.exists(
|
|
272
|
-
const a = `${
|
|
273
|
-
for (const
|
|
274
|
-
if (!
|
|
270
|
+
const r = b(e, o);
|
|
271
|
+
if (!await this.fs.exists(r)) continue;
|
|
272
|
+
const a = `${mt[o]}s`, h = await this.fs.glob(r, "**/*.json");
|
|
273
|
+
for (const u of h)
|
|
274
|
+
if (!u.includes("/index/"))
|
|
275
275
|
try {
|
|
276
|
-
const d = await this.loadMetadata(
|
|
276
|
+
const d = await this.loadMetadata(u);
|
|
277
277
|
let f = d.id || d.ID || "";
|
|
278
278
|
if (!f) {
|
|
279
|
-
const g =
|
|
279
|
+
const g = u.substring(u.lastIndexOf("/") + 1);
|
|
280
280
|
g.includes("-") && (f = g.split("-")[0]);
|
|
281
281
|
}
|
|
282
282
|
if (!f) continue;
|
|
283
|
-
const p =
|
|
283
|
+
const p = u.substring(e.length + 1);
|
|
284
284
|
let k = "";
|
|
285
285
|
const v = d.authors;
|
|
286
286
|
if (Array.isArray(v) && v.length > 0) {
|
|
287
287
|
const g = v[0];
|
|
288
288
|
k = typeof g == "object" && g !== null ? g.name || "" : String(g);
|
|
289
289
|
}
|
|
290
|
-
const I = Array.isArray(d.additional_titles) ? d.additional_titles.map((g) => typeof g == "string" ? g : g == null ? void 0 : g.book_title).filter(Boolean) : void 0,
|
|
291
|
-
let
|
|
290
|
+
const I = Array.isArray(d.additional_titles) ? d.additional_titles.map((g) => typeof g == "string" ? g : g == null ? void 0 : g.book_title).filter(Boolean) : void 0, A = Array.isArray(d.attached_texts) ? d.attached_texts.map((g) => typeof g == "string" ? g : g == null ? void 0 : g.book_title).filter(Boolean) : void 0;
|
|
291
|
+
let C;
|
|
292
292
|
const S = d.juan_count;
|
|
293
|
-
typeof S == "number" ?
|
|
294
|
-
const
|
|
295
|
-
let m = !1,
|
|
293
|
+
typeof S == "number" ? C = S : typeof S == "object" && S !== null && (C = S.number || void 0);
|
|
294
|
+
const P = typeof d.measure_info == "string" ? d.measure_info : "";
|
|
295
|
+
let m = !1, j = !1;
|
|
296
296
|
const y = d.resources;
|
|
297
297
|
if (Array.isArray(y))
|
|
298
298
|
for (const g of y) {
|
|
299
299
|
if (typeof g != "object" || g === null) continue;
|
|
300
|
-
const
|
|
301
|
-
if (Array.isArray(
|
|
302
|
-
|
|
300
|
+
const U = g.types;
|
|
301
|
+
if (Array.isArray(U))
|
|
302
|
+
U.includes("text") && (m = !0), U.includes("image") && (j = !0);
|
|
303
303
|
else {
|
|
304
304
|
const M = g.type;
|
|
305
|
-
(M === "text" || M === "text+image") && (m = !0), (M === "image" || M === "text+image") && (
|
|
305
|
+
(M === "text" || M === "text+image") && (m = !0), (M === "image" || M === "text+image") && (j = !0);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
const _ = {
|
|
@@ -314,18 +314,18 @@ class it {
|
|
|
314
314
|
year: typeof d.publication_info == "object" && ((n = d.publication_info) == null ? void 0 : n.year) || "",
|
|
315
315
|
holder: typeof d.current_location == "object" && ((i = d.current_location) == null ? void 0 : i.name) || ""
|
|
316
316
|
};
|
|
317
|
-
I && I.length > 0 && (_.additional_titles = I),
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
s[a][
|
|
317
|
+
I && I.length > 0 && (_.additional_titles = I), A && A.length > 0 && (_.attached_texts = A), C && (_.juan_count = C), P && (_.measure_info = P);
|
|
318
|
+
const E = typeof d.edition == "string" ? d.edition : "";
|
|
319
|
+
E && (_.edition = E), m && (_.has_text = !0), j && (_.has_image = !0);
|
|
320
|
+
const rt = a === "collections" ? 0 : J(f);
|
|
321
|
+
s[a][rt][f] = _;
|
|
322
322
|
} catch {
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
|
-
for (const [o,
|
|
326
|
-
for (const [l, a] of Object.entries(
|
|
327
|
-
const
|
|
328
|
-
await this.fs.mkdir(
|
|
325
|
+
for (const [o, r] of Object.entries(s))
|
|
326
|
+
for (const [l, a] of Object.entries(r)) {
|
|
327
|
+
const h = this.shardPath(e, o, Number(l)), u = h.substring(0, h.lastIndexOf("/"));
|
|
328
|
+
await this.fs.mkdir(u), await this.fs.writeFile(h, JSON.stringify(a, null, 2));
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
// ── Asset Directory ──
|
|
@@ -334,8 +334,8 @@ class it {
|
|
|
334
334
|
* 与 JSON 文件同级,以 ID 命名
|
|
335
335
|
*/
|
|
336
336
|
getAssetDir(t) {
|
|
337
|
-
const e = this.getRootById(t), s = x(t), i =
|
|
338
|
-
return b(e,
|
|
337
|
+
const e = this.getRootById(t), s = x(t), i = $(s).type, o = t.padEnd(3, "_").substring(0, 3), [r, l, a] = [o[0], o[1], o[2]], h = N[i];
|
|
338
|
+
return b(e, h, r, l, a, t);
|
|
339
339
|
}
|
|
340
340
|
/**
|
|
341
341
|
* 初始化资源目录:创建 {ID}/ 文件夹
|
|
@@ -357,7 +357,7 @@ class it {
|
|
|
357
357
|
return e === "collections" ? b(t, "index", "collections.json") : b(t, "index", e, `${s.toString(16)}.json`);
|
|
358
358
|
}
|
|
359
359
|
async loadShard(t, e, s) {
|
|
360
|
-
const n =
|
|
360
|
+
const n = J(s), i = this.shardPath(t, e, n);
|
|
361
361
|
try {
|
|
362
362
|
if (!await this.fs.exists(i)) return {};
|
|
363
363
|
const o = await this.fs.readFile(i);
|
|
@@ -367,8 +367,8 @@ class it {
|
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
async saveShard(t, e, s, n) {
|
|
370
|
-
const i =
|
|
371
|
-
await this.fs.mkdir(
|
|
370
|
+
const i = J(s), o = this.shardPath(t, e, i), r = o.substring(0, o.lastIndexOf("/"));
|
|
371
|
+
await this.fs.mkdir(r), await this.fs.writeFile(o, JSON.stringify(n, null, 2));
|
|
372
372
|
}
|
|
373
373
|
async loadAllShards(t, e) {
|
|
374
374
|
const s = {};
|
|
@@ -396,37 +396,37 @@ class it {
|
|
|
396
396
|
return s;
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
|
-
function
|
|
399
|
+
function W(c, t) {
|
|
400
400
|
const e = t.toLowerCase();
|
|
401
401
|
let s = 0;
|
|
402
|
-
const n =
|
|
402
|
+
const n = c.title.toLowerCase();
|
|
403
403
|
n === e ? s = 200 : n.startsWith(e) ? s = 150 : n.includes(e) && (s = 100);
|
|
404
|
-
const i = [...
|
|
404
|
+
const i = [...c.additional_titles || [], ...c.attached_texts || []];
|
|
405
405
|
for (const a of i) {
|
|
406
|
-
const
|
|
407
|
-
|
|
406
|
+
const h = a.toLowerCase();
|
|
407
|
+
h === e ? s = Math.max(s, 120) : h.startsWith(e) ? s = Math.max(s, 90) : h.includes(e) && (s = Math.max(s, 60));
|
|
408
408
|
}
|
|
409
409
|
let o = 0;
|
|
410
|
-
if (
|
|
411
|
-
const a =
|
|
410
|
+
if (c.author) {
|
|
411
|
+
const a = c.author.toLowerCase();
|
|
412
412
|
a === e ? o = 80 : a.includes(e) && (o = 50);
|
|
413
413
|
}
|
|
414
|
-
let
|
|
415
|
-
|
|
414
|
+
let r = 0;
|
|
415
|
+
c.dynasty && c.dynasty.toLowerCase().includes(e) && (r = 30);
|
|
416
416
|
let l = s;
|
|
417
|
-
return l === 0 && (l = Math.max(o,
|
|
417
|
+
return l === 0 && (l = Math.max(o, r)), l === 0 ? 0 : (l += Math.max(0, 20 - n.length), c.type === "work" ? l = Math.round(l * 1.05) : c.type === "collection" && (l = Math.round(l * 1.02)), c.has_text && (l += 3), c.has_image && (l += 2), l);
|
|
418
418
|
}
|
|
419
|
-
function
|
|
419
|
+
function wt(c, t) {
|
|
420
420
|
return t === null ? void 0 : t;
|
|
421
421
|
}
|
|
422
|
-
function B(
|
|
423
|
-
const e =
|
|
422
|
+
function B(c, t) {
|
|
423
|
+
const e = c.map((s) => ({ entry: s, score: W(s, t) })).filter((s) => s.score > 0);
|
|
424
424
|
return e.sort((s, n) => n.score !== s.score ? n.score - s.score : s.entry.title.length - n.entry.title.length), e.map((s) => s.entry);
|
|
425
425
|
}
|
|
426
|
-
function O(
|
|
427
|
-
const n =
|
|
428
|
-
const o =
|
|
429
|
-
let
|
|
426
|
+
function O(c, t, e, s) {
|
|
427
|
+
const n = c.map((i) => {
|
|
428
|
+
const o = W(i, t);
|
|
429
|
+
let r = 0;
|
|
430
430
|
const l = s[i.id];
|
|
431
431
|
if (l && e) {
|
|
432
432
|
const a = {
|
|
@@ -436,14 +436,14 @@ function O(r, t, e, s) {
|
|
|
436
436
|
additional_titles: l.at ?? i.additional_titles,
|
|
437
437
|
attached_texts: l.axt ?? i.attached_texts
|
|
438
438
|
};
|
|
439
|
-
|
|
439
|
+
r = W(a, e);
|
|
440
440
|
}
|
|
441
|
-
return { entry: i, score: Math.max(o,
|
|
441
|
+
return { entry: i, score: Math.max(o, r) };
|
|
442
442
|
}).filter((i) => i.score > 0);
|
|
443
443
|
return n.sort((i, o) => o.score !== i.score ? o.score - i.score : i.entry.title.length - o.entry.title.length), n.map((i) => i.entry);
|
|
444
444
|
}
|
|
445
|
-
function
|
|
446
|
-
const t =
|
|
445
|
+
function bt(c) {
|
|
446
|
+
const t = c.volumes ?? [];
|
|
447
447
|
let e, s;
|
|
448
448
|
if (t.length === 0)
|
|
449
449
|
e = [];
|
|
@@ -454,64 +454,64 @@ function wt(r) {
|
|
|
454
454
|
for (const i of t) {
|
|
455
455
|
const o = i.volume;
|
|
456
456
|
e.push(o);
|
|
457
|
-
const
|
|
457
|
+
const r = {};
|
|
458
458
|
for (const [l, a] of Object.entries(i))
|
|
459
|
-
l === "volume" || l === "status" || l === "file" || typeof a == "string" && (l.includes("url") || l.includes("id")) && (
|
|
459
|
+
l === "volume" || l === "status" || l === "file" || typeof a == "string" && (l.includes("url") || l.includes("id")) && (r[l] = a);
|
|
460
460
|
s.push({
|
|
461
461
|
volume: o,
|
|
462
462
|
status: i.status,
|
|
463
|
-
urls: Object.keys(
|
|
463
|
+
urls: Object.keys(r).length > 0 ? r : void 0,
|
|
464
464
|
file: i.file
|
|
465
465
|
});
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
const n = {
|
|
469
|
-
title:
|
|
470
|
-
book_id:
|
|
471
|
-
work_id:
|
|
469
|
+
title: c.title ?? "",
|
|
470
|
+
book_id: c.book_id ?? null,
|
|
471
|
+
work_id: c.work_id ?? null,
|
|
472
472
|
volumes: e,
|
|
473
|
-
section:
|
|
474
|
-
sub_items:
|
|
475
|
-
edition:
|
|
476
|
-
expected_volumes:
|
|
477
|
-
found_volumes:
|
|
478
|
-
missing_volumes:
|
|
473
|
+
section: c.section,
|
|
474
|
+
sub_items: c.sub_items,
|
|
475
|
+
edition: c.edition,
|
|
476
|
+
expected_volumes: c.expected_volumes,
|
|
477
|
+
found_volumes: c.found_volumes,
|
|
478
|
+
missing_volumes: c.missing_vols ?? c.missing_volumes
|
|
479
479
|
};
|
|
480
480
|
s && (n.volume_details = s);
|
|
481
481
|
for (const i of Object.keys(n))
|
|
482
482
|
n[i] === void 0 && delete n[i];
|
|
483
483
|
return n;
|
|
484
484
|
}
|
|
485
|
-
function
|
|
485
|
+
function kt(c) {
|
|
486
486
|
const t = {
|
|
487
|
-
total_books:
|
|
487
|
+
total_books: c.total_books ?? 0
|
|
488
488
|
};
|
|
489
|
-
return
|
|
489
|
+
return c.processed_volumes != null && (t.processed_volumes = c.processed_volumes), c.matched_works != null && (t.matched_works = c.matched_works), c.unmatched_works != null && (t.unmatched_works = c.unmatched_works), c.total_found_volumes != null && (t.total_found_volumes = c.total_found_volumes), t;
|
|
490
490
|
}
|
|
491
|
-
function ot(
|
|
491
|
+
function ot(c) {
|
|
492
492
|
var n;
|
|
493
|
-
const t =
|
|
493
|
+
const t = c, e = (t.books ?? []).map(bt), s = {
|
|
494
494
|
collection_id: t.collection_id ?? "",
|
|
495
495
|
title: t.title ?? "",
|
|
496
496
|
total_volumes: t.total_volumes ?? 0,
|
|
497
|
-
stats:
|
|
497
|
+
stats: kt(t.stats ?? {}),
|
|
498
498
|
books: e
|
|
499
499
|
};
|
|
500
500
|
return t.source && (s.source = t.source), t.resource_id && (s.resource_id = t.resource_id), t.resource_name && (s.resource_name = t.resource_name), (n = t.sections) != null && n.length && (s.sections = t.sections), t.volume_index && Object.keys(t.volume_index).length > 0 && (s.volume_index = t.volume_index), s;
|
|
501
501
|
}
|
|
502
|
-
const
|
|
502
|
+
const It = "https://raw.githubusercontent.com", St = [
|
|
503
503
|
"https://fastly.jsdelivr.net/gh",
|
|
504
504
|
"https://cdn.jsdelivr.net/gh"
|
|
505
|
-
],
|
|
505
|
+
], xt = 5e3;
|
|
506
506
|
class Lt {
|
|
507
507
|
// null=未加载, false=不可用
|
|
508
508
|
constructor(t) {
|
|
509
509
|
this.cache = null, this.cacheLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.searchSCache = null, this.t2sConverter = null, this.config = {
|
|
510
510
|
org: t.org,
|
|
511
511
|
repos: t.repos,
|
|
512
|
-
baseUrl: t.baseUrl ??
|
|
513
|
-
cdnUrls: t.cdnUrls ??
|
|
514
|
-
timeout: t.timeout ??
|
|
512
|
+
baseUrl: t.baseUrl ?? It,
|
|
513
|
+
cdnUrls: t.cdnUrls ?? St,
|
|
514
|
+
timeout: t.timeout ?? xt
|
|
515
515
|
};
|
|
516
516
|
}
|
|
517
517
|
/** 确保 index 数据已加载到缓存 */
|
|
@@ -566,9 +566,9 @@ class Lt {
|
|
|
566
566
|
} catch {
|
|
567
567
|
}
|
|
568
568
|
for (const o of this.config.cdnUrls) {
|
|
569
|
-
const
|
|
569
|
+
const r = `${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;
|
|
570
570
|
try {
|
|
571
|
-
if ((await fetch(
|
|
571
|
+
if ((await fetch(r, {
|
|
572
572
|
method: "HEAD",
|
|
573
573
|
signal: AbortSignal.timeout(this.config.timeout)
|
|
574
574
|
})).ok) return !0;
|
|
@@ -585,9 +585,9 @@ class Lt {
|
|
|
585
585
|
} catch {
|
|
586
586
|
}
|
|
587
587
|
for (const o of this.config.cdnUrls) {
|
|
588
|
-
const
|
|
588
|
+
const r = `${o}/${this.config.org}/${t}@main/${encodeURI(n)}`;
|
|
589
589
|
try {
|
|
590
|
-
if ((await fetch(
|
|
590
|
+
if ((await fetch(r, {
|
|
591
591
|
method: "HEAD",
|
|
592
592
|
signal: AbortSignal.timeout(this.config.timeout)
|
|
593
593
|
})).ok) return !0;
|
|
@@ -610,9 +610,9 @@ class Lt {
|
|
|
610
610
|
const n = [];
|
|
611
611
|
for (const i of ["books", "works"])
|
|
612
612
|
for (let o = 0; o < T; o++) {
|
|
613
|
-
const
|
|
613
|
+
const r = `index/${i}/${o.toString(16)}.json`;
|
|
614
614
|
n.push(
|
|
615
|
-
this.fetchFileWithFallback(t,
|
|
615
|
+
this.fetchFileWithFallback(t, r).then((l) => {
|
|
616
616
|
Object.assign(s[i], l);
|
|
617
617
|
}).catch(() => {
|
|
618
618
|
})
|
|
@@ -639,33 +639,33 @@ class Lt {
|
|
|
639
639
|
["works", "work"],
|
|
640
640
|
["entities", "entity"]
|
|
641
641
|
];
|
|
642
|
-
for (const [
|
|
643
|
-
const a = t[
|
|
642
|
+
for (const [r, l] of n) {
|
|
643
|
+
const a = t[r];
|
|
644
644
|
if (a)
|
|
645
|
-
for (const
|
|
646
|
-
const
|
|
645
|
+
for (const h of Object.values(a)) {
|
|
646
|
+
const u = h, d = l === "entity" ? u.primary_name || h.title || h.name || h.id : h.title || h.name || h.id;
|
|
647
647
|
s.push({
|
|
648
|
-
id:
|
|
648
|
+
id: h.id,
|
|
649
649
|
title: d,
|
|
650
650
|
type: l,
|
|
651
651
|
isDraft: e,
|
|
652
|
-
author:
|
|
653
|
-
dynasty:
|
|
654
|
-
role:
|
|
655
|
-
path:
|
|
656
|
-
additional_titles: (i =
|
|
657
|
-
attached_texts: (o =
|
|
658
|
-
edition:
|
|
659
|
-
juan_count:
|
|
660
|
-
has_text:
|
|
661
|
-
has_image:
|
|
662
|
-
has_collated:
|
|
663
|
-
subtype:
|
|
664
|
-
primary_name:
|
|
665
|
-
birth_year:
|
|
666
|
-
death_year:
|
|
667
|
-
cbdb_id:
|
|
668
|
-
}), this.pathMap.set(
|
|
652
|
+
author: h.author,
|
|
653
|
+
dynasty: h.dynasty,
|
|
654
|
+
role: h.role,
|
|
655
|
+
path: h.path,
|
|
656
|
+
additional_titles: (i = u.additional_titles) == null ? void 0 : i.map((f) => typeof f == "string" ? f : f == null ? void 0 : f.book_title).filter(Boolean),
|
|
657
|
+
attached_texts: (o = u.attached_texts) == null ? void 0 : o.map((f) => typeof f == "string" ? f : f == null ? void 0 : f.book_title).filter(Boolean),
|
|
658
|
+
edition: u.edition,
|
|
659
|
+
juan_count: u.juan_count,
|
|
660
|
+
has_text: u.has_text,
|
|
661
|
+
has_image: u.has_image,
|
|
662
|
+
has_collated: u.has_collated,
|
|
663
|
+
subtype: u.subtype,
|
|
664
|
+
primary_name: u.primary_name,
|
|
665
|
+
birth_year: u.birth_year,
|
|
666
|
+
death_year: u.death_year,
|
|
667
|
+
cbdb_id: u.cbdb_id
|
|
668
|
+
}), this.pathMap.set(h.id, { path: h.path, isDraft: e });
|
|
669
669
|
}
|
|
670
670
|
}
|
|
671
671
|
return s;
|
|
@@ -689,52 +689,52 @@ class Lt {
|
|
|
689
689
|
}
|
|
690
690
|
const t = await this.ensureLoaded(), e = this.t2sConverter, s = {};
|
|
691
691
|
for (const o of t) {
|
|
692
|
-
const
|
|
693
|
-
if (l !== o.title && (
|
|
692
|
+
const r = {}, l = e(o.title);
|
|
693
|
+
if (l !== o.title && (r.t = l), o.author) {
|
|
694
694
|
const a = e(o.author);
|
|
695
|
-
a !== o.author && (
|
|
695
|
+
a !== o.author && (r.a = a);
|
|
696
696
|
}
|
|
697
697
|
if ((n = o.additional_titles) != null && n.length) {
|
|
698
698
|
const a = o.additional_titles.map(e);
|
|
699
|
-
a.some((
|
|
699
|
+
a.some((h, u) => h !== o.additional_titles[u]) && (r.at = a);
|
|
700
700
|
}
|
|
701
701
|
if ((i = o.attached_texts) != null && i.length) {
|
|
702
702
|
const a = o.attached_texts.map(e);
|
|
703
|
-
a.some((
|
|
703
|
+
a.some((h, u) => h !== o.attached_texts[u]) && (r.axt = a);
|
|
704
704
|
}
|
|
705
|
-
Object.keys(
|
|
705
|
+
Object.keys(r).length > 0 && (s[o.id] = r);
|
|
706
706
|
}
|
|
707
707
|
return this.searchSCache = s, { searchS: s, converter: e };
|
|
708
708
|
}
|
|
709
709
|
// --- IndexStorage 实现 ---
|
|
710
710
|
async loadEntries(t, e) {
|
|
711
|
-
let n = (await this.ensureLoaded()).filter((
|
|
711
|
+
let n = (await this.ensureLoaded()).filter((u) => u.type === t);
|
|
712
712
|
const i = e.sortBy || "title", o = e.sortOrder || "asc";
|
|
713
|
-
n.sort((
|
|
714
|
-
const f = String(
|
|
713
|
+
n.sort((u, d) => {
|
|
714
|
+
const f = String(u[i] ?? ""), p = String(d[i] ?? ""), k = f.localeCompare(p, "zh");
|
|
715
715
|
return o === "asc" ? k : -k;
|
|
716
716
|
});
|
|
717
|
-
const
|
|
717
|
+
const r = e.page || 1, l = e.pageSize || 50, a = (r - 1) * l;
|
|
718
718
|
return {
|
|
719
719
|
entries: n.slice(a, a + l),
|
|
720
720
|
total: n.length,
|
|
721
|
-
page:
|
|
721
|
+
page: r,
|
|
722
722
|
pageSize: l
|
|
723
723
|
};
|
|
724
724
|
}
|
|
725
725
|
async search(t, e, s) {
|
|
726
|
-
const n = await this.ensureLoaded(), { searchS: i, converter: o } = await this.ensureSearchSBuilt(),
|
|
726
|
+
const n = await this.ensureLoaded(), { searchS: i, converter: o } = await this.ensureSearchSBuilt(), r = n.filter((p) => p.type === e), l = o ? o(t) : void 0, h = Object.keys(i).length > 0 ? O(r, t, l, i) : B(r, t), u = s.page || 1, d = s.pageSize || 50, f = (u - 1) * d;
|
|
727
727
|
return {
|
|
728
|
-
entries:
|
|
729
|
-
total:
|
|
730
|
-
page:
|
|
728
|
+
entries: h.slice(f, f + d),
|
|
729
|
+
total: h.length,
|
|
730
|
+
page: u,
|
|
731
731
|
pageSize: d
|
|
732
732
|
};
|
|
733
733
|
}
|
|
734
734
|
async searchAll(t, e = 5) {
|
|
735
|
-
const s = await this.ensureLoaded(), { searchS: n, converter: i } = await this.ensureSearchSBuilt(), o = ["work", "book", "collection"],
|
|
736
|
-
const
|
|
737
|
-
return l ? O(
|
|
735
|
+
const s = await this.ensureLoaded(), { searchS: n, converter: i } = await this.ensureSearchSBuilt(), o = ["work", "book", "collection"], r = i ? i(t) : void 0, l = Object.keys(n).length > 0, a = o.map((h) => {
|
|
736
|
+
const u = s.filter((d) => d.type === h);
|
|
737
|
+
return l ? O(u, t, r, n) : B(u, t);
|
|
738
738
|
});
|
|
739
739
|
return {
|
|
740
740
|
works: a[0].slice(0, e),
|
|
@@ -751,7 +751,7 @@ class Lt {
|
|
|
751
751
|
if (s) {
|
|
752
752
|
const i = s.isDraft ? this.config.repos.draft : this.config.repos.official;
|
|
753
753
|
if (n = await this.fetchItemByPath(i, s.path), n) {
|
|
754
|
-
const o = e.find((
|
|
754
|
+
const o = e.find((r) => r.id === t);
|
|
755
755
|
o != null && o.has_collated && (n.has_collated = !0);
|
|
756
756
|
}
|
|
757
757
|
} else
|
|
@@ -805,18 +805,18 @@ class Lt {
|
|
|
805
805
|
const e = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" };
|
|
806
806
|
let s, n;
|
|
807
807
|
try {
|
|
808
|
-
const
|
|
809
|
-
s =
|
|
808
|
+
const h = $(x(t));
|
|
809
|
+
s = h.type, n = h.status;
|
|
810
810
|
} catch {
|
|
811
811
|
return null;
|
|
812
812
|
}
|
|
813
|
-
const i = n === "draft" ? this.config.repos.draft : this.config.repos.official, o = e[s],
|
|
813
|
+
const i = n === "draft" ? this.config.repos.draft : this.config.repos.official, o = e[s], r = t.padEnd(3, "_").substring(0, 3), l = `${o}/${r[0]}/${r[1]}/${r[2]}`, a = `https://api.github.com/repos/${this.config.org}/${i}/contents/${l}`;
|
|
814
814
|
try {
|
|
815
|
-
const
|
|
815
|
+
const h = await fetch(a, {
|
|
816
816
|
signal: AbortSignal.timeout(this.config.timeout)
|
|
817
817
|
});
|
|
818
|
-
if (!
|
|
819
|
-
const d = (await
|
|
818
|
+
if (!h.ok) return null;
|
|
819
|
+
const d = (await h.json()).find((p) => p.name.startsWith(`${t}-`) && p.name.endsWith(".json"));
|
|
820
820
|
if (!d) return null;
|
|
821
821
|
const f = await this.fetchItemByPath(i, d.path);
|
|
822
822
|
return f && this.pathMap.set(t, { path: d.path, isDraft: n === "draft" }), f;
|
|
@@ -833,9 +833,9 @@ class Lt {
|
|
|
833
833
|
const a = o[0];
|
|
834
834
|
i = typeof a == "object" && a !== null ? a.name || "" : String(a);
|
|
835
835
|
}
|
|
836
|
-
let
|
|
836
|
+
let r = !0;
|
|
837
837
|
try {
|
|
838
|
-
|
|
838
|
+
r = $(x(t)).status === "draft";
|
|
839
839
|
} catch {
|
|
840
840
|
}
|
|
841
841
|
const l = this.pathMap.get(t);
|
|
@@ -843,7 +843,7 @@ class Lt {
|
|
|
843
843
|
id: t,
|
|
844
844
|
title: e.title || e.书名 || t,
|
|
845
845
|
type: n,
|
|
846
|
-
isDraft:
|
|
846
|
+
isDraft: r,
|
|
847
847
|
author: i,
|
|
848
848
|
dynasty: e.dynasty,
|
|
849
849
|
role: e.role,
|
|
@@ -887,7 +887,7 @@ class Lt {
|
|
|
887
887
|
if (n.length === 0) return null;
|
|
888
888
|
const i = [];
|
|
889
889
|
for (const o of n) {
|
|
890
|
-
const
|
|
890
|
+
const r = `${e.dir}/${t}/${o.id}/volume_book_mapping.json`, l = await this.fetchFile(e.repo, r);
|
|
891
891
|
l && i.push({
|
|
892
892
|
resource_id: o.id,
|
|
893
893
|
short_name: o.short_name,
|
|
@@ -935,7 +935,7 @@ class Lt {
|
|
|
935
935
|
}
|
|
936
936
|
}
|
|
937
937
|
const G = 255;
|
|
938
|
-
class
|
|
938
|
+
class at {
|
|
939
939
|
constructor(t) {
|
|
940
940
|
if (this.lastTimestamp = -1, this.lastStatus = null, this.sequence = 0, t < 0 || t > 2047)
|
|
941
941
|
throw new Error("Machine ID must be between 0 and 2047");
|
|
@@ -950,7 +950,7 @@ class rt {
|
|
|
950
950
|
throw new Error("Clock moved backwards. Refusing to generate ID.");
|
|
951
951
|
s === this.lastTimestamp && t === this.lastStatus ? (this.sequence = this.sequence + 1 & G, this.sequence === 0 && (s = this._tilNextUnit(this.lastTimestamp, t))) : this.sequence = 0, this.lastTimestamp = s, this.lastStatus = t;
|
|
952
952
|
const n = z(t, e, BigInt(s), this.machineId, this.sequence);
|
|
953
|
-
return
|
|
953
|
+
return D(n);
|
|
954
954
|
}
|
|
955
955
|
/**
|
|
956
956
|
* 生成下一个 ID(返回 bigint 原始值)
|
|
@@ -974,7 +974,7 @@ class rt {
|
|
|
974
974
|
}
|
|
975
975
|
class Bt {
|
|
976
976
|
constructor(t) {
|
|
977
|
-
this.recentEntities = [], this.storage = new it(t.fs, t.workspaceRoot), this.idGen = new
|
|
977
|
+
this.recentEntities = [], this.storage = new it(t.fs, t.workspaceRoot), this.idGen = new at(t.machineId ?? 0), this.fs = t.fs, this.workspaceRoot = t.workspaceRoot;
|
|
978
978
|
}
|
|
979
979
|
async loadEntries(t, e) {
|
|
980
980
|
const s = await this.storage.loadEntries(t);
|
|
@@ -1036,8 +1036,8 @@ class Bt {
|
|
|
1036
1036
|
if (e.contained_in && Array.isArray(e.contained_in) && e.contained_in.length > 0) {
|
|
1037
1037
|
const i = e.contained_in[0], o = typeof i == "string" ? i : i.id;
|
|
1038
1038
|
if (o) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1039
|
+
const r = await this.resolveEntity(o);
|
|
1040
|
+
r && (s.belongsToCollection = { ...r, type: "collection" });
|
|
1041
1041
|
}
|
|
1042
1042
|
}
|
|
1043
1043
|
} else if (n === "collection") {
|
|
@@ -1133,13 +1133,13 @@ class Bt {
|
|
|
1133
1133
|
const s = e && e !== "all" ? [e] : ["book", "collection", "work"], n = [];
|
|
1134
1134
|
for (const i of s) {
|
|
1135
1135
|
const o = await this.storage.searchEntries(t, i);
|
|
1136
|
-
for (const
|
|
1136
|
+
for (const r of o)
|
|
1137
1137
|
n.push({
|
|
1138
|
-
id:
|
|
1139
|
-
title:
|
|
1140
|
-
type:
|
|
1141
|
-
author:
|
|
1142
|
-
dynasty:
|
|
1138
|
+
id: r.id,
|
|
1139
|
+
title: r.title,
|
|
1140
|
+
type: r.type,
|
|
1141
|
+
author: r.author,
|
|
1142
|
+
dynasty: r.dynasty
|
|
1143
1143
|
});
|
|
1144
1144
|
}
|
|
1145
1145
|
return n;
|
|
@@ -1201,7 +1201,7 @@ class Bt {
|
|
|
1201
1201
|
extractTypeFromId(t) {
|
|
1202
1202
|
try {
|
|
1203
1203
|
const e = x(t);
|
|
1204
|
-
return
|
|
1204
|
+
return $(e).type;
|
|
1205
1205
|
} catch {
|
|
1206
1206
|
return "book";
|
|
1207
1207
|
}
|
|
@@ -1226,8 +1226,8 @@ class Bt {
|
|
|
1226
1226
|
const s = e.page ?? 1, n = e.pageSize ?? 50;
|
|
1227
1227
|
if (e.sortBy) {
|
|
1228
1228
|
const l = e.sortBy, a = e.sortOrder === "desc" ? -1 : 1;
|
|
1229
|
-
t.sort((
|
|
1230
|
-
const d =
|
|
1229
|
+
t.sort((h, u) => {
|
|
1230
|
+
const d = h[l] ?? "", f = u[l] ?? "";
|
|
1231
1231
|
return d < f ? -a : d > f ? a : 0;
|
|
1232
1232
|
});
|
|
1233
1233
|
}
|
|
@@ -1235,10 +1235,10 @@ class Bt {
|
|
|
1235
1235
|
return { entries: t.slice(o, o + n), total: i, page: s, pageSize: n };
|
|
1236
1236
|
}
|
|
1237
1237
|
}
|
|
1238
|
-
const
|
|
1238
|
+
const vt = "/data", Ct = 1e4;
|
|
1239
1239
|
class Ft {
|
|
1240
1240
|
constructor(t = {}) {
|
|
1241
|
-
this.indexCache = null, this.indexLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.chunkCache = /* @__PURE__ */ new Map(), this.chunkLoading = /* @__PURE__ */ new Map(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache = /* @__PURE__ */ new Map(), this.tiyaoLoading = /* @__PURE__ */ new Map(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null, this.basePath = t.basePath ??
|
|
1241
|
+
this.indexCache = null, this.indexLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.chunkCache = /* @__PURE__ */ new Map(), this.chunkLoading = /* @__PURE__ */ new Map(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache = /* @__PURE__ */ new Map(), this.tiyaoLoading = /* @__PURE__ */ new Map(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.metaCache = null, this.metaLoading = null, this.metaTried = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null, this.basePath = t.basePath ?? vt, this.timeout = t.timeout ?? Ct;
|
|
1242
1242
|
}
|
|
1243
1243
|
// ─── 内部工具 ───
|
|
1244
1244
|
/**
|
|
@@ -1282,23 +1282,23 @@ class Ft {
|
|
|
1282
1282
|
["works", "work"],
|
|
1283
1283
|
["entities", "entity"]
|
|
1284
1284
|
];
|
|
1285
|
-
for (const [o,
|
|
1285
|
+
for (const [o, r] of s) {
|
|
1286
1286
|
const l = t[o];
|
|
1287
1287
|
if (l)
|
|
1288
1288
|
for (const a of Object.values(l)) {
|
|
1289
|
-
const
|
|
1289
|
+
const h = r === "entity" ? a.primary_name || a.title || a.name || a.id : a.title || a.name || a.id;
|
|
1290
1290
|
e.push({
|
|
1291
1291
|
id: a.id,
|
|
1292
|
-
title:
|
|
1293
|
-
type:
|
|
1292
|
+
title: h,
|
|
1293
|
+
type: r,
|
|
1294
1294
|
isDraft: !0,
|
|
1295
1295
|
// bundle 目前只打包 draft 数据
|
|
1296
1296
|
author: a.author,
|
|
1297
1297
|
dynasty: a.dynasty,
|
|
1298
1298
|
role: a.role,
|
|
1299
1299
|
path: a.path,
|
|
1300
|
-
additional_titles: (n = a.additional_titles) == null ? void 0 : n.map((
|
|
1301
|
-
attached_texts: (i = a.attached_texts) == null ? void 0 : i.map((
|
|
1300
|
+
additional_titles: (n = a.additional_titles) == null ? void 0 : n.map((u) => typeof u == "string" ? u : u == null ? void 0 : u.book_title).filter(Boolean),
|
|
1301
|
+
attached_texts: (i = a.attached_texts) == null ? void 0 : i.map((u) => typeof u == "string" ? u : u == null ? void 0 : u.book_title).filter(Boolean),
|
|
1302
1302
|
edition: a.edition,
|
|
1303
1303
|
juan_count: a.juan_count,
|
|
1304
1304
|
has_text: a.has_text,
|
|
@@ -1426,11 +1426,11 @@ class Ft {
|
|
|
1426
1426
|
if (this.tiyaoCache.has(s)) return this.tiyaoCache.get(s);
|
|
1427
1427
|
const n = this.tiyaoLoading.get(s);
|
|
1428
1428
|
if (n) return n;
|
|
1429
|
-
const i = (
|
|
1430
|
-
const
|
|
1429
|
+
const i = (r) => String(r).padStart(3, "0"), o = (async () => {
|
|
1430
|
+
const r = await this.fetchJson(
|
|
1431
1431
|
`${this.basePath}/tiyao/juan-${i(t)}-${i(e)}.json`
|
|
1432
1432
|
);
|
|
1433
|
-
return this.tiyaoCache.set(s,
|
|
1433
|
+
return this.tiyaoCache.set(s, r), r;
|
|
1434
1434
|
})();
|
|
1435
1435
|
this.tiyaoLoading.set(s, o);
|
|
1436
1436
|
try {
|
|
@@ -1440,41 +1440,81 @@ class Ft {
|
|
|
1440
1440
|
}
|
|
1441
1441
|
}
|
|
1442
1442
|
// ─── IndexStorage 实现 ───
|
|
1443
|
-
|
|
1443
|
+
/**
|
|
1444
|
+
* 获取轻量元数据(< 1 KB)。优先读 /data/meta.json;
|
|
1445
|
+
* 若该文件不存在(旧 bundle),回退到 ensureLoaded 计算。
|
|
1446
|
+
*/
|
|
1447
|
+
async getCounts() {
|
|
1448
|
+
if (this.metaCache) return this.metaCache;
|
|
1449
|
+
if (this.metaLoading) {
|
|
1450
|
+
const h = await this.metaLoading;
|
|
1451
|
+
if (h) return h;
|
|
1452
|
+
} else {
|
|
1453
|
+
this.metaLoading = (async () => {
|
|
1454
|
+
try {
|
|
1455
|
+
const h = await this.fetchJson(`${this.basePath}/meta.json`);
|
|
1456
|
+
if (h && typeof h.works == "number")
|
|
1457
|
+
return this.metaCache = h, h;
|
|
1458
|
+
} catch {
|
|
1459
|
+
}
|
|
1460
|
+
return this.metaTried = !0, null;
|
|
1461
|
+
})();
|
|
1462
|
+
try {
|
|
1463
|
+
const h = await this.metaLoading;
|
|
1464
|
+
if (h) return h;
|
|
1465
|
+
} finally {
|
|
1466
|
+
this.metaLoading = null;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1444
1469
|
const t = await this.ensureLoaded();
|
|
1445
|
-
let e = 0, s = 0;
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1470
|
+
let e = 0, s = 0, n = 0, i = 0, o = 0, r = 0;
|
|
1471
|
+
const l = {};
|
|
1472
|
+
for (const h of t)
|
|
1473
|
+
h.type === "work" ? (e++, h.has_text && o++, h.has_image && r++, h.subtype && (l[h.subtype] = (l[h.subtype] ?? 0) + 1)) : h.type === "book" ? s++ : h.type === "collection" ? n++ : h.type === "entity" && i++;
|
|
1474
|
+
const a = {
|
|
1475
|
+
works: e,
|
|
1476
|
+
books: s,
|
|
1477
|
+
collections: n,
|
|
1478
|
+
entities: i,
|
|
1479
|
+
resourceCounts: { hasText: o, hasImage: r },
|
|
1480
|
+
subtypeStats: l
|
|
1481
|
+
};
|
|
1482
|
+
return this.metaCache = a, a;
|
|
1483
|
+
}
|
|
1484
|
+
async getResourceCounts() {
|
|
1485
|
+
return (await this.getCounts()).resourceCounts ?? { hasText: 0, hasImage: 0 };
|
|
1486
|
+
}
|
|
1487
|
+
async getSubtypeStats() {
|
|
1488
|
+
return (await this.getCounts()).subtypeStats ?? {};
|
|
1449
1489
|
}
|
|
1450
1490
|
async loadEntries(t, e) {
|
|
1451
|
-
let n = (await this.ensureLoaded()).filter((
|
|
1491
|
+
let n = (await this.ensureLoaded()).filter((h) => h.type === t);
|
|
1452
1492
|
const i = e.sortBy || "title", o = e.sortOrder || "asc";
|
|
1453
|
-
n.sort((
|
|
1454
|
-
const d = String(
|
|
1493
|
+
n.sort((h, u) => {
|
|
1494
|
+
const d = String(h[i] ?? ""), f = String(u[i] ?? ""), p = d.localeCompare(f, "zh");
|
|
1455
1495
|
return o === "asc" ? p : -p;
|
|
1456
1496
|
});
|
|
1457
|
-
const
|
|
1497
|
+
const r = e.page || 1, l = e.pageSize || 50, a = (r - 1) * l;
|
|
1458
1498
|
return {
|
|
1459
1499
|
entries: n.slice(a, a + l),
|
|
1460
1500
|
total: n.length,
|
|
1461
|
-
page:
|
|
1501
|
+
page: r,
|
|
1462
1502
|
pageSize: l
|
|
1463
1503
|
};
|
|
1464
1504
|
}
|
|
1465
1505
|
async search(t, e, s) {
|
|
1466
|
-
const n = await this.ensureLoaded(), i = await this.ensureSearchSLoaded(), o = await this.ensureT2S(),
|
|
1506
|
+
const n = await this.ensureLoaded(), i = await this.ensureSearchSLoaded(), o = await this.ensureT2S(), r = n.filter((p) => p.type === e), l = o ? o(t) : void 0, h = Object.keys(i).length > 0 ? O(r, t, l, i) : B(r, t), u = s.page || 1, d = s.pageSize || 50, f = (u - 1) * d;
|
|
1467
1507
|
return {
|
|
1468
|
-
entries:
|
|
1469
|
-
total:
|
|
1470
|
-
page:
|
|
1508
|
+
entries: h.slice(f, f + d),
|
|
1509
|
+
total: h.length,
|
|
1510
|
+
page: u,
|
|
1471
1511
|
pageSize: d
|
|
1472
1512
|
};
|
|
1473
1513
|
}
|
|
1474
1514
|
async searchAll(t, e = 5) {
|
|
1475
|
-
const s = await this.ensureLoaded(), n = await this.ensureSearchSLoaded(), i = await this.ensureT2S(), o = ["work", "book", "collection", "entity"],
|
|
1476
|
-
const
|
|
1477
|
-
return l ? O(
|
|
1515
|
+
const s = await this.ensureLoaded(), n = await this.ensureSearchSLoaded(), i = await this.ensureT2S(), o = ["work", "book", "collection", "entity"], r = i ? i(t) : void 0, l = Object.keys(n).length > 0, a = o.map((h) => {
|
|
1516
|
+
const u = s.filter((d) => d.type === h);
|
|
1517
|
+
return l ? O(u, t, r, n) : B(u, t);
|
|
1478
1518
|
});
|
|
1479
1519
|
return {
|
|
1480
1520
|
works: a[0].slice(0, e),
|
|
@@ -1490,17 +1530,46 @@ class Ft {
|
|
|
1490
1530
|
async getItem(t) {
|
|
1491
1531
|
try {
|
|
1492
1532
|
const s = (await this.loadChunkForId(t))[t] || null;
|
|
1493
|
-
|
|
1494
|
-
const n = (await this.ensureLoaded()).find((i) => i.id === t);
|
|
1495
|
-
n != null && n.has_collated && (s.has_collated = !0), s.type === "entity" && !s.title && s.primary_name && (s.title = s.primary_name);
|
|
1496
|
-
}
|
|
1497
|
-
return s;
|
|
1533
|
+
return s && s.type === "entity" && !s.title && s.primary_name && (s.title = s.primary_name), s;
|
|
1498
1534
|
} catch {
|
|
1499
1535
|
return null;
|
|
1500
1536
|
}
|
|
1501
1537
|
}
|
|
1538
|
+
/**
|
|
1539
|
+
* 优先用 chunk 构造 IndexEntry,避免触发 ensureLoaded() 拉全量 index.json。
|
|
1540
|
+
* 旧 bundle 没有把 has_collated 等字段注入 chunk 时回退到 ensureLoaded。
|
|
1541
|
+
*/
|
|
1502
1542
|
async getEntry(t) {
|
|
1503
|
-
|
|
1543
|
+
var s, n;
|
|
1544
|
+
try {
|
|
1545
|
+
const o = (await this.loadChunkForId(t))[t];
|
|
1546
|
+
if (o) {
|
|
1547
|
+
const r = pt(t), l = r === "entity" ? o.primary_name || o.title || o.name || t : o.title || o.name || t;
|
|
1548
|
+
return {
|
|
1549
|
+
id: t,
|
|
1550
|
+
title: l,
|
|
1551
|
+
type: r,
|
|
1552
|
+
isDraft: !0,
|
|
1553
|
+
author: o.author,
|
|
1554
|
+
dynasty: o.dynasty,
|
|
1555
|
+
role: o.role,
|
|
1556
|
+
additional_titles: (s = o.additional_titles) == null ? void 0 : s.map((a) => typeof a == "string" ? a : a == null ? void 0 : a.book_title).filter(Boolean),
|
|
1557
|
+
attached_texts: (n = o.attached_texts) == null ? void 0 : n.map((a) => typeof a == "string" ? a : a == null ? void 0 : a.book_title).filter(Boolean),
|
|
1558
|
+
edition: o.edition,
|
|
1559
|
+
juan_count: o.juan_count,
|
|
1560
|
+
has_text: o.has_text,
|
|
1561
|
+
has_image: o.has_image,
|
|
1562
|
+
has_collated: o.has_collated,
|
|
1563
|
+
subtype: o.subtype,
|
|
1564
|
+
primary_name: o.primary_name,
|
|
1565
|
+
birth_year: o.birth_year,
|
|
1566
|
+
death_year: o.death_year,
|
|
1567
|
+
cbdb_id: o.cbdb_id
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
} catch {
|
|
1571
|
+
}
|
|
1572
|
+
return (await this.ensureLoaded()).find((i) => i.id === t) || null;
|
|
1504
1573
|
}
|
|
1505
1574
|
async getAllEntries() {
|
|
1506
1575
|
return this.ensureLoaded();
|
|
@@ -1565,8 +1634,8 @@ class Ft {
|
|
|
1565
1634
|
if (e.includes("..") || !e.endsWith(".json")) return null;
|
|
1566
1635
|
const s = e.replace(/\.json$/, ".md"), n = await this.ensureVersion(), i = `${this.basePath}/items/${t}/collated_edition/text/${s}`, o = n ? `${i}?v=${n}` : i;
|
|
1567
1636
|
try {
|
|
1568
|
-
const
|
|
1569
|
-
return
|
|
1637
|
+
const r = await fetch(o);
|
|
1638
|
+
return r.ok ? await r.text() : null;
|
|
1570
1639
|
} catch {
|
|
1571
1640
|
return null;
|
|
1572
1641
|
}
|
|
@@ -1609,7 +1678,7 @@ class Ft {
|
|
|
1609
1678
|
}
|
|
1610
1679
|
// ─── 工具 ───
|
|
1611
1680
|
clearCache() {
|
|
1612
|
-
this.indexCache = null, this.indexLoading = null, this.pathMap.clear(), this.chunkCache.clear(), this.chunkLoading.clear(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache.clear(), this.tiyaoLoading.clear(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null;
|
|
1681
|
+
this.indexCache = null, this.indexLoading = null, this.pathMap.clear(), this.chunkCache.clear(), this.chunkLoading.clear(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache.clear(), this.tiyaoLoading.clear(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.metaCache = null, this.metaLoading = null, this.metaTried = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null;
|
|
1613
1682
|
}
|
|
1614
1683
|
}
|
|
1615
1684
|
class F extends Error {
|
|
@@ -1632,14 +1701,14 @@ class Ot extends F {
|
|
|
1632
1701
|
super(t), this.name = "ConfigError";
|
|
1633
1702
|
}
|
|
1634
1703
|
}
|
|
1635
|
-
class
|
|
1704
|
+
class Dt extends F {
|
|
1636
1705
|
constructor(t) {
|
|
1637
1706
|
super(t), this.name = "MigrationError";
|
|
1638
1707
|
}
|
|
1639
1708
|
}
|
|
1640
|
-
class
|
|
1709
|
+
class Ut {
|
|
1641
1710
|
constructor(t, e, s = 1) {
|
|
1642
|
-
this.storage = new it(t, e), this.idGen = new
|
|
1711
|
+
this.storage = new it(t, e), this.idGen = new at(s);
|
|
1643
1712
|
}
|
|
1644
1713
|
/** Generate a new unique ID (returns raw bigint). */
|
|
1645
1714
|
generateId(t = "book", e = "draft") {
|
|
@@ -1647,7 +1716,7 @@ class Dt {
|
|
|
1647
1716
|
}
|
|
1648
1717
|
/** Encode a bigint ID to Base36 string. */
|
|
1649
1718
|
encodeId(t) {
|
|
1650
|
-
return
|
|
1719
|
+
return D(t);
|
|
1651
1720
|
}
|
|
1652
1721
|
/** Decode an ID string to bigint (supports base36 and legacy base58). */
|
|
1653
1722
|
decodeId(t) {
|
|
@@ -1686,13 +1755,13 @@ class Dt {
|
|
|
1686
1755
|
资源: "resources",
|
|
1687
1756
|
收藏历史: "history",
|
|
1688
1757
|
其他版本: "related_books"
|
|
1689
|
-
},
|
|
1690
|
-
if (
|
|
1691
|
-
if (
|
|
1692
|
-
const a = i[
|
|
1693
|
-
i[
|
|
1758
|
+
}, r = e in o ? o[e] : e;
|
|
1759
|
+
if (r === null) return !1;
|
|
1760
|
+
if (r === "description" && typeof s == "string") {
|
|
1761
|
+
const a = i[r] || {};
|
|
1762
|
+
i[r] = { text: s, sources: a.sources || [] };
|
|
1694
1763
|
} else
|
|
1695
|
-
i[
|
|
1764
|
+
i[r] = s;
|
|
1696
1765
|
const l = L(t);
|
|
1697
1766
|
return await this.storage.saveItem(l.type, t, i), !0;
|
|
1698
1767
|
} catch {
|
|
@@ -1736,10 +1805,10 @@ const Et = {
|
|
|
1736
1805
|
"guji.artx": "guji-artx",
|
|
1737
1806
|
"digital.library": "digital-library"
|
|
1738
1807
|
}, q = /* @__PURE__ */ new Set(["text", "image", "text+image", "physical"]), Y = /* @__PURE__ */ new Set(["text", "image", "physical"]), $t = /* @__PURE__ */ new Set(["catalog", "search"]), At = /* @__PURE__ */ new Set(["com", "org", "net", "cn", "edu", "gov", "io", "jp", "tw", "hk"]);
|
|
1739
|
-
function Nt(
|
|
1740
|
-
if (!
|
|
1808
|
+
function Nt(c) {
|
|
1809
|
+
if (!c) return "";
|
|
1741
1810
|
try {
|
|
1742
|
-
const e = new URL(
|
|
1811
|
+
const e = new URL(c).hostname;
|
|
1743
1812
|
for (const [n, i] of Object.entries(Et))
|
|
1744
1813
|
if (e.includes(n)) return i;
|
|
1745
1814
|
const s = e.split(".");
|
|
@@ -1752,20 +1821,20 @@ function Nt(r) {
|
|
|
1752
1821
|
return "";
|
|
1753
1822
|
}
|
|
1754
1823
|
}
|
|
1755
|
-
function
|
|
1824
|
+
function Jt(c) {
|
|
1756
1825
|
const t = [];
|
|
1757
|
-
|
|
1826
|
+
c.name || t.push("name is required");
|
|
1758
1827
|
let e = !1;
|
|
1759
|
-
if (
|
|
1760
|
-
if (!Array.isArray(
|
|
1828
|
+
if (c.types !== void 0)
|
|
1829
|
+
if (!Array.isArray(c.types) || c.types.length === 0)
|
|
1761
1830
|
t.push("types must be a non-empty array when present");
|
|
1762
1831
|
else {
|
|
1763
|
-
for (const s of
|
|
1832
|
+
for (const s of c.types)
|
|
1764
1833
|
Y.has(s) || t.push(`invalid types atom '${s}', must be one of ${[...Y].join(", ")}`);
|
|
1765
|
-
e =
|
|
1834
|
+
e = c.types.length === 1 && c.types[0] === "physical";
|
|
1766
1835
|
}
|
|
1767
|
-
else
|
|
1768
|
-
return
|
|
1836
|
+
else c.type !== void 0 ? (q.has(c.type) || t.push(`invalid type '${c.type}', must be one of ${[...q].join(", ")}`), e = c.type === "physical") : t.push("either type or types is required");
|
|
1837
|
+
return c.root_type && !$t.has(c.root_type) && t.push(`invalid root_type '${c.root_type}'`), !e && !c.url && t.push("url is required for non-physical resources"), t;
|
|
1769
1838
|
}
|
|
1770
1839
|
const w = class w {
|
|
1771
1840
|
constructor(t, e = "") {
|
|
@@ -1777,7 +1846,7 @@ const w = class w {
|
|
|
1777
1846
|
this.idInt = 0n;
|
|
1778
1847
|
}
|
|
1779
1848
|
} else
|
|
1780
|
-
this.idInt = t, this.idStr =
|
|
1849
|
+
this.idInt = t, this.idStr = D(t);
|
|
1781
1850
|
if (this.idInt > 0n)
|
|
1782
1851
|
try {
|
|
1783
1852
|
const s = L(this.idStr);
|
|
@@ -1817,25 +1886,25 @@ export {
|
|
|
1817
1886
|
Lt as G,
|
|
1818
1887
|
Rt as I,
|
|
1819
1888
|
Bt as L,
|
|
1820
|
-
|
|
1889
|
+
Dt as M,
|
|
1821
1890
|
Mt as S,
|
|
1822
|
-
|
|
1891
|
+
pt as a,
|
|
1823
1892
|
F as b,
|
|
1824
|
-
|
|
1893
|
+
Ut as c,
|
|
1825
1894
|
it as d,
|
|
1826
1895
|
Tt as e,
|
|
1827
1896
|
Ft as f,
|
|
1828
|
-
|
|
1897
|
+
at as g,
|
|
1829
1898
|
st as h,
|
|
1830
|
-
|
|
1899
|
+
D as i,
|
|
1831
1900
|
gt as j,
|
|
1832
1901
|
z as k,
|
|
1833
1902
|
Pt as l,
|
|
1834
1903
|
L as m,
|
|
1835
|
-
|
|
1904
|
+
jt as n,
|
|
1836
1905
|
Nt as o,
|
|
1837
1906
|
ot as p,
|
|
1838
|
-
|
|
1907
|
+
$ as q,
|
|
1839
1908
|
x as s,
|
|
1840
|
-
|
|
1909
|
+
Jt as v
|
|
1841
1910
|
};
|