koishi-plugin-fimtale-api 1.0.5 → 1.0.6
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/lib/index.d.ts +1 -1
- package/lib/index.js +120 -31
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -38,7 +38,7 @@ __export(src_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(src_exports);
|
|
39
39
|
var import_koishi = require("koishi");
|
|
40
40
|
var import_crypto = __toESM(require("crypto"));
|
|
41
|
-
var name = "fimtale-
|
|
41
|
+
var name = "fimtale-api";
|
|
42
42
|
var inject = ["puppeteer", "database", "http"];
|
|
43
43
|
var Config = import_koishi.Schema.object({
|
|
44
44
|
apiUrl: import_koishi.Schema.string().default("https://fimtale.com/api/v1").description("Fimtale API 基础路径"),
|
|
@@ -84,7 +84,7 @@ function apply(ctx, config) {
|
|
|
84
84
|
processed = processed.replace(/<div class="card-panel[\s\S]*?<\/div>/i, "");
|
|
85
85
|
processed = processed.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gmi, "");
|
|
86
86
|
processed = processed.replace(/<style\b[^>]*>([\s\S]*?)<\/style>/gmi, "");
|
|
87
|
-
processed = processed.replace(/<iframe[^>]*>.*?<\/iframe>/gmi, '<p class="align-center" style="color:#
|
|
87
|
+
processed = processed.replace(/<iframe[^>]*>.*?<\/iframe>/gmi, '<p class="align-center" style="color:#78909C;font-size:0.8em;">[多媒体内容]</p>');
|
|
88
88
|
processed = processed.replace(
|
|
89
89
|
/<div class="material-placeholder">([\s\S]*?)<\/div>/gi,
|
|
90
90
|
(match, content) => {
|
|
@@ -211,41 +211,80 @@ function apply(ctx, config) {
|
|
|
211
211
|
const likes = isChapter && parent ? parent.Upvotes || 0 : info.Upvotes || 0;
|
|
212
212
|
const html = `<!DOCTYPE html><html><head><style>
|
|
213
213
|
body { margin: 0; padding: 0; font-family: ${fontStack}; background: transparent; }
|
|
214
|
-
|
|
215
|
-
.
|
|
216
|
-
.cover { width: 220px; height: 100%; ${bgStyle} background-size: cover; background-position: center; position: relative; flex-shrink: 0; }
|
|
217
|
-
/* 更改 ID 字体 */
|
|
218
|
-
.id-tag { position: absolute; top: 12px; left: 12px; background: rgba(0,0,0,0.6); color: #fff; padding: 4px 10px; border-radius: 6px; font-size: 13px; font-weight: bold; backdrop-filter: blur(4px); font-family: "Impact", "Arial Black", sans-serif; letter-spacing: 1px; }
|
|
219
|
-
.info { flex: 1; padding: 24px; display: flex; flex-direction: column; overflow: hidden; position: relative; }
|
|
214
|
+
.card { width: 620px; min-height: 420px; background: #fff; border-radius: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: flex; overflow: hidden; }
|
|
215
|
+
.cover { width: 220px; min-height: 100%; ${bgStyle} background-size: cover; background-position: center; position: relative; flex-shrink: 0; }
|
|
220
216
|
|
|
221
|
-
|
|
222
|
-
.
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
/* ID Badge 分体式:使用 flex 强制垂直居中,消除字体基线差异 */
|
|
218
|
+
.id-badge-container {
|
|
219
|
+
position: absolute; top: 15px; left: 15px;
|
|
220
|
+
display: flex;
|
|
221
|
+
box-shadow: 0 4px 12px rgba(238,110,115, 0.3);
|
|
222
|
+
border-radius: 6px;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
border: 1px solid rgba(255,255,255,0.3);
|
|
225
|
+
height: 28px; /* 强制高度 */
|
|
226
|
+
}
|
|
227
|
+
.id-label {
|
|
228
|
+
background: #EE6E73;
|
|
229
|
+
color: #fff;
|
|
230
|
+
padding: 0 10px;
|
|
231
|
+
font-size: 12px;
|
|
232
|
+
font-weight: bold;
|
|
233
|
+
font-family: sans-serif;
|
|
234
|
+
text-transform: uppercase;
|
|
235
|
+
display: flex; align-items: center; justify-content: center;
|
|
236
|
+
height: 100%;
|
|
237
|
+
line-height: 1; margin: 0; /* 修复对齐 */
|
|
238
|
+
}
|
|
239
|
+
.id-val {
|
|
240
|
+
background: #fff;
|
|
241
|
+
color: #EE6E73;
|
|
242
|
+
padding: 0 12px;
|
|
243
|
+
font-family: "Consolas", "Monaco", monospace;
|
|
244
|
+
font-size: 15px;
|
|
245
|
+
font-weight: 900;
|
|
246
|
+
display: flex; align-items: center; justify-content: center;
|
|
247
|
+
height: 100%;
|
|
248
|
+
line-height: 1; margin: 0; /* 修复对齐 */
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.info { flex: 1; padding: 26px; display: flex; flex-direction: column; overflow: hidden; position: relative; }
|
|
225
252
|
|
|
226
|
-
.
|
|
253
|
+
.header-group { flex-shrink: 0; margin-bottom: 16px; border-bottom: 2px solid #f5f5f5; padding-bottom: 12px; }
|
|
254
|
+
.title { font-size: 24px; font-weight: 700; color: #333; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-bottom: 6px; }
|
|
255
|
+
.subtitle { font-size: 16px; color: #78909C; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-left: 12px; border-left: 4px solid #EE6E73; margin-top: 6px; }
|
|
256
|
+
|
|
257
|
+
.author { font-size: 14px; color: #78909C; margin-top: 12px; font-weight: 400; display:flex; align-items:center; }
|
|
258
|
+
|
|
259
|
+
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; flex-shrink: 0; }
|
|
227
260
|
.tag { background: #eff2f5; color: #5c6b7f; padding: 3px 9px; border-radius: 4px; font-size: 11px; font-weight: 500; }
|
|
228
261
|
|
|
229
|
-
|
|
230
|
-
.summary
|
|
231
|
-
|
|
232
|
-
.footer { border-top: 1px solid #eee; padding-top: 14px; display: flex; justify-content: space-between; font-size:
|
|
233
|
-
.stat b { color: #
|
|
262
|
+
.summary-box { flex: 1; position: relative; overflow: hidden; min-height: 0; margin-bottom: 16px; }
|
|
263
|
+
.summary { font-size: 14px; color: #546e7a; line-height: 1.7; display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; text-align: justify; }
|
|
264
|
+
|
|
265
|
+
.footer { border-top: 1px solid #eee; padding-top: 14px; display: flex; justify-content: space-between; font-size: 13px; color: #78909C; margin-top: auto; flex-shrink: 0; }
|
|
266
|
+
.stat b { color: #455a64; font-weight: bold; margin-right: 3px;}
|
|
234
267
|
</style></head><body>
|
|
235
|
-
<div class="card"
|
|
268
|
+
<div class="card">
|
|
269
|
+
<div class="cover">
|
|
270
|
+
<div class="id-badge-container">
|
|
271
|
+
<div class="id-label">ID</div>
|
|
272
|
+
<div class="id-val">${info.ID}</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
236
275
|
<div class="info">
|
|
237
276
|
<div class="header-group"><div class="title">${displayTitle}</div>${subTitle ? `<div class="subtitle">${subTitle}</div>` : ""}<div class="author">@${info.UserName}</div></div>
|
|
238
277
|
<div class="tags">${tagsArr.slice(0, 10).map((t) => `<span class="tag">${t}</span>`).join("")}</div>
|
|
239
278
|
<div class="summary-box"><div class="summary">${summary}</div></div>
|
|
240
279
|
<div class="footer">
|
|
241
|
-
<span class="stat"><b style="color:#009688">热度</b>${info.Views || 0}</span><span class="stat"><b style="color:#
|
|
242
|
-
<span class="stat"><b style="color:#4caf50">赞</b>${likes}</span><span class="stat"><b style="color:#
|
|
280
|
+
<span class="stat"><b style="color:#009688">热度</b>${info.Views || 0}</span><span class="stat"><b style="color:#7e57c2">评论</b>${info.Comments || 0}</span>
|
|
281
|
+
<span class="stat"><b style="color:#4caf50">赞</b>${likes}</span><span class="stat"><b style="color:#8d6e63">字数</b>${info.WordCount || 0}</span>
|
|
243
282
|
</div></div></div></body></html>`;
|
|
244
283
|
const page = await ctx.puppeteer.page();
|
|
245
284
|
try {
|
|
246
285
|
await injectCookies(page);
|
|
247
286
|
await page.setContent(html);
|
|
248
|
-
await page.setViewport({ width: 660, height:
|
|
287
|
+
await page.setViewport({ width: 660, height: 480, deviceScaleFactor: 3 });
|
|
249
288
|
const img = await page.$(".card").then((e) => e.screenshot({ type: "jpeg", quality: 100 }));
|
|
250
289
|
return img;
|
|
251
290
|
} finally {
|
|
@@ -265,8 +304,40 @@ function apply(ctx, config) {
|
|
|
265
304
|
.content { flex: 1; display: flex; flex-direction: column; justify-content: space-between; height: 100%; min-width: 0; }
|
|
266
305
|
.top-row { display: flex; justify-content: space-between; align-items: flex-start; }
|
|
267
306
|
.title { font-size: 16px; font-weight: bold; color: #222; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; flex:1; margin-right: 8px;}
|
|
268
|
-
|
|
269
|
-
|
|
307
|
+
|
|
308
|
+
/* ID Badge Search: 迷你分体式,保持与大图风格一致但更紧凑 */
|
|
309
|
+
.id-badge {
|
|
310
|
+
display: flex;
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
overflow: hidden;
|
|
313
|
+
border: 1px solid #EE6E73;
|
|
314
|
+
flex-shrink: 0;
|
|
315
|
+
height: 18px;
|
|
316
|
+
}
|
|
317
|
+
.id-label {
|
|
318
|
+
background: #EE6E73;
|
|
319
|
+
color: #fff;
|
|
320
|
+
padding: 0 4px;
|
|
321
|
+
font-family: sans-serif;
|
|
322
|
+
font-size: 10px;
|
|
323
|
+
font-weight: bold;
|
|
324
|
+
display: flex; align-items: center; justify-content: center;
|
|
325
|
+
height: 100%;
|
|
326
|
+
line-height: 1; margin: 0; /* 修复对齐 */
|
|
327
|
+
}
|
|
328
|
+
.id-val {
|
|
329
|
+
background: #fff;
|
|
330
|
+
color: #EE6E73;
|
|
331
|
+
padding: 0 6px;
|
|
332
|
+
font-family: "Consolas", monospace;
|
|
333
|
+
font-size: 11px;
|
|
334
|
+
font-weight: bold;
|
|
335
|
+
display: flex; align-items: center; justify-content: center;
|
|
336
|
+
height: 100%;
|
|
337
|
+
line-height: 1; margin: 0; /* 修复对齐 */
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.author { font-size: 12px; color: #78909C; }
|
|
270
341
|
.tags { display: flex; gap: 4px; flex-wrap: wrap; height: 18px; overflow: hidden; margin-top: 4px; }
|
|
271
342
|
.tag { background: #f3f3f3; color: #666; padding: 0 5px; border-radius: 3px; font-size: 10px; white-space: nowrap; line-height: 1.6;}
|
|
272
343
|
.meta-row { display: flex; gap: 10px; font-size: 11px; color: #999; margin-top: auto; border-top: 1px dashed #eee; padding-top: 5px; }
|
|
@@ -275,10 +346,15 @@ function apply(ctx, config) {
|
|
|
275
346
|
${results.map((r) => {
|
|
276
347
|
const bg = r.cover ? `<img class="cover-img" src="${r.cover}"/>` : `<div style="width:100%;height:100%;background:${generateGradient(r.title)}"></div>`;
|
|
277
348
|
return `<div class="item"><div class="cover-box">${bg}</div><div class="content">
|
|
278
|
-
<div class="top-row"><div class="title">${r.title}</div
|
|
349
|
+
<div class="top-row"><div class="title">${r.title}</div>
|
|
350
|
+
<div class="id-badge">
|
|
351
|
+
<div class="id-label">ID</div>
|
|
352
|
+
<div class="id-val">${r.id}</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
279
355
|
<div class="author">By ${r.author} ${r.status ? ` · ${r.status}` : ""}</div>
|
|
280
356
|
<div class="tags">${r.tags.map((t) => `<span class="tag">${t}</span>`).join("")}</div>
|
|
281
|
-
<div class="meta-row"><span style="color:#009688"><b>热</b>${r.stats.views}</span><span style="color:#
|
|
357
|
+
<div class="meta-row"><span style="color:#009688"><b>热</b>${r.stats.views}</span><span style="color:#7e57c2"><b>评</b>${r.stats.comments}</span><span style="color:#4caf50"><b>赞</b>${r.stats.likes}</span><span style="margin-left:auto;color:#757575">${r.updateTime}</span></div>
|
|
282
358
|
</div></div>`;
|
|
283
359
|
}).join("")}
|
|
284
360
|
</div></div></body></html>`;
|
|
@@ -308,15 +384,25 @@ function apply(ctx, config) {
|
|
|
308
384
|
const marginTop = Math.floor((maxContentHeight - optimalContentHeight) / 2) + headerHeight;
|
|
309
385
|
const html = `<!DOCTYPE html><html><head><style>
|
|
310
386
|
body { margin: 0; padding: 0; width: ${config.deviceWidth}px; height: ${config.deviceHeight}px; background-color: #f6f4ec; color: #2c2c2c; font-family: ${fontSerif}; overflow: hidden; position: relative;}
|
|
311
|
-
|
|
312
|
-
.fixed-
|
|
387
|
+
/* Header Padding reduced to 12px to align closer to left edge */
|
|
388
|
+
.fixed-header { position: absolute; top: 0; left: 0; width: 100%; height: ${headerHeight}px; border-bottom: 2px solid #EE6E73; box-sizing: border-box; padding: 0 12px; display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: #EE6E73; background: #f6f4ec; z-index: 5; font-weight: bold; }
|
|
389
|
+
.fixed-footer { position: absolute; bottom: 0; left: 0; width: 100%; height: ${footerHeight}px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #78909C; background: #f6f4ec; z-index: 5; }
|
|
390
|
+
/* 修复1: 强制重置 header 和 footer 的缩进,防止 p, div 全局规则影响 */
|
|
391
|
+
.fixed-header, .fixed-footer, .header-title, .header-author { text-indent: 0 !important; }
|
|
392
|
+
|
|
313
393
|
#viewport { position: absolute; top: ${marginTop}px; left: ${paddingX}px; width: ${contentWidth}px; height: ${optimalContentHeight}px; overflow: hidden; }
|
|
314
394
|
#content-scroller { height: 100%; width: 100%; column-width: ${contentWidth}px; column-gap: ${columnGap}px; column-fill: auto; padding: ${paddingY}px 0; box-sizing: border-box; font-size: ${config.fontSize}px; line-height: ${lineHeightRatio}; text-align: left; transform: translateX(0); transition: none; }
|
|
395
|
+
|
|
315
396
|
p, div { margin: 0 0 0.2em 0; text-indent: 2em; word-wrap: break-word; overflow-wrap: break-word; }
|
|
316
397
|
.align-center { text-align: center !important; text-align-last: center !important; text-indent: 0 !important; margin: 0.8em 0; font-weight: bold; color: #5d4037; }
|
|
317
398
|
.align-right { text-align: right !important; text-indent: 0 !important; margin-top: 0.5em; color: #666; font-style: italic; }
|
|
318
399
|
.no-indent { text-indent: 0 !important; }
|
|
319
|
-
|
|
400
|
+
|
|
401
|
+
/* Header Title absolute left */
|
|
402
|
+
.header-title { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left; min-width: 0; margin-right: 10px; }
|
|
403
|
+
.header-author { flex-shrink: 0; color: #78909C; max-width: 35%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
|
|
404
|
+
|
|
405
|
+
blockquote { margin: 1em 0.5em; padding-left: 1em; border-left: 4px solid #EE6E73; color: #666; }
|
|
320
406
|
blockquote p { text-indent: 0; margin: 0.3em 0; }
|
|
321
407
|
ul, ol { margin: 0.5em 0; padding-left: 1.5em; }
|
|
322
408
|
li { margin-bottom: 0.2em; }
|
|
@@ -331,7 +417,7 @@ function apply(ctx, config) {
|
|
|
331
417
|
sup, sub { font-size: 0.75em; line-height: 0; position: relative; vertical-align: baseline; }
|
|
332
418
|
sup { top: -0.5em; }
|
|
333
419
|
sub { bottom: -0.25em; }
|
|
334
|
-
a { color: #
|
|
420
|
+
a { color: #EE6E73; text-decoration: none; }
|
|
335
421
|
figure.img-box { display: flex; justify-content: center; align-items: center; margin: 0.5em 0; width: 100%; }
|
|
336
422
|
img { max-width: 100%; height: auto; display: block; border-radius: 6px; box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
|
|
337
423
|
h1, h2, h3 { font-size: 1.1em; margin: 0.8em 0; color: #5d4037; text-indent: 0; font-weight: bold; text-align: center; text-align-last: center; break-after: avoid; }
|
|
@@ -339,7 +425,10 @@ function apply(ctx, config) {
|
|
|
339
425
|
em, i { font-style: italic; }
|
|
340
426
|
p:last-child { margin-bottom: 0; }
|
|
341
427
|
</style></head><body>
|
|
342
|
-
<div class="fixed-header"
|
|
428
|
+
<div class="fixed-header">
|
|
429
|
+
<div class="header-title">${info.Title}</div>
|
|
430
|
+
<div class="header-author">${info.UserName}</div>
|
|
431
|
+
</div>
|
|
343
432
|
<div id="viewport"><div id="content-scroller">${content}</div></div>
|
|
344
433
|
<div class="fixed-footer" id="page-indicator">- 1 -</div></body></html>`;
|
|
345
434
|
const page = await ctx.puppeteer.page();
|