koishi-plugin-fimtale-api 0.0.7 → 0.0.8
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.js +38 -20
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -47,6 +47,7 @@ var Config = import_koishi.Schema.object({
|
|
|
47
47
|
cookies: import_koishi.Schema.string().role("secret").description("浏览器 Cookie (用于解除安全模式,必填)"),
|
|
48
48
|
pollInterval: import_koishi.Schema.number().default(60 * 1e3).description("追更轮询间隔(ms)"),
|
|
49
49
|
autoParseLink: import_koishi.Schema.boolean().default(true).description("自动解析链接为预览卡片"),
|
|
50
|
+
// 渲染配置 (iPhone 12/13 Pro 比例)
|
|
50
51
|
deviceWidth: import_koishi.Schema.number().default(390).description("阅读器渲染宽度(px)"),
|
|
51
52
|
deviceHeight: import_koishi.Schema.number().default(844).description("阅读器渲染高度(px)"),
|
|
52
53
|
fontSize: import_koishi.Schema.number().default(20).description("正文字号(px)")
|
|
@@ -61,7 +62,7 @@ function apply(ctx, config) {
|
|
|
61
62
|
}, { primary: "id", autoInc: true });
|
|
62
63
|
const sleep = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "sleep");
|
|
63
64
|
const formatDate = /* @__PURE__ */ __name((timestamp) => {
|
|
64
|
-
if (!timestamp) return "
|
|
65
|
+
if (!timestamp) return "未知日期";
|
|
65
66
|
const date = new Date(timestamp * 1e3);
|
|
66
67
|
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
|
|
67
68
|
}, "formatDate");
|
|
@@ -99,7 +100,7 @@ function apply(ctx, config) {
|
|
|
99
100
|
const url = `${config.apiUrl}/t/${threadId}`;
|
|
100
101
|
const params = { APIKey: config.apiKey, APIPass: config.apiPass };
|
|
101
102
|
const res = await ctx.http.get(url, { params });
|
|
102
|
-
if (res.Status !== 1 || !res.TopicInfo) return { valid: false, msg: res.ErrorMessage || "API
|
|
103
|
+
if (res.Status !== 1 || !res.TopicInfo) return { valid: false, msg: res.ErrorMessage || "API 返回错误" };
|
|
103
104
|
return {
|
|
104
105
|
valid: true,
|
|
105
106
|
data: res.TopicInfo,
|
|
@@ -107,7 +108,7 @@ function apply(ctx, config) {
|
|
|
107
108
|
menu: res.Menu || []
|
|
108
109
|
};
|
|
109
110
|
} catch (e) {
|
|
110
|
-
return { valid: false, msg: "
|
|
111
|
+
return { valid: false, msg: "网络请求失败" };
|
|
111
112
|
}
|
|
112
113
|
}, "fetchThread");
|
|
113
114
|
const fetchRandomId = /* @__PURE__ */ __name(async () => {
|
|
@@ -147,7 +148,7 @@ function apply(ctx, config) {
|
|
|
147
148
|
const titleEl = card.querySelector(".card-title");
|
|
148
149
|
if (titleEl) title = titleEl.textContent?.trim() || "";
|
|
149
150
|
else title = link.textContent?.trim() || "";
|
|
150
|
-
let author = "
|
|
151
|
+
let author = "未知";
|
|
151
152
|
const authorEl = card.querySelector('a[href^="/u/"] span.grey-text');
|
|
152
153
|
if (authorEl) author = authorEl.textContent?.trim() || "";
|
|
153
154
|
let cover = void 0;
|
|
@@ -218,7 +219,7 @@ function apply(ctx, config) {
|
|
|
218
219
|
const bgStyle = displayCover ? `background-image: url('${displayCover}');` : `background: ${generateGradient(displayTitle)};`;
|
|
219
220
|
let summary = stripHtml(info.Content);
|
|
220
221
|
if (summary.length < 10 && parent && isChapter) summary = stripHtml(parent.Content);
|
|
221
|
-
if (summary.length >
|
|
222
|
+
if (summary.length > 110) summary = summary.substring(0, 110) + "...";
|
|
222
223
|
if (!summary) summary = "暂无简介";
|
|
223
224
|
const tagsArr = [];
|
|
224
225
|
if (displayTagsObj?.Type) tagsArr.push(displayTagsObj.Type);
|
|
@@ -233,11 +234,12 @@ function apply(ctx, config) {
|
|
|
233
234
|
<head>
|
|
234
235
|
<style>
|
|
235
236
|
body { margin: 0; padding: 0; font-family: ${fontStack}; background: transparent; }
|
|
236
|
-
.card { width: 620px; height:
|
|
237
|
+
.card { width: 620px; height: 360px; background: #fff; border-radius: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: flex; overflow: hidden; }
|
|
237
238
|
.cover { width: 220px; height: 100%; ${bgStyle} background-size: cover; background-position: center; position: relative; flex-shrink: 0; }
|
|
238
239
|
.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: monospace; }
|
|
239
240
|
.info { flex: 1; padding: 24px; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; }
|
|
240
241
|
|
|
242
|
+
.header-group { display: flex; flex-direction: column; }
|
|
241
243
|
.title {
|
|
242
244
|
font-size: 22px; font-weight: 700; color: #333; line-height: 1.35;
|
|
243
245
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
|
@@ -247,7 +249,6 @@ function apply(ctx, config) {
|
|
|
247
249
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
248
250
|
padding-left: 10px; border-left: 3px solid #e91e63;
|
|
249
251
|
}
|
|
250
|
-
|
|
251
252
|
.author { font-size: 13px; color: #888; margin-top: 8px; font-weight: 400; }
|
|
252
253
|
|
|
253
254
|
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; max-height: 56px; overflow: hidden; flex-shrink: 0;}
|
|
@@ -259,8 +260,7 @@ function apply(ctx, config) {
|
|
|
259
260
|
}
|
|
260
261
|
.summary {
|
|
261
262
|
font-size: 13px; color: #666; line-height: 1.6;
|
|
262
|
-
|
|
263
|
-
max-height: 6.4em;
|
|
263
|
+
max-height: 6.4em;
|
|
264
264
|
display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -277,13 +277,8 @@ function apply(ctx, config) {
|
|
|
277
277
|
${subTitle ? `<div class="subtitle">${subTitle}</div>` : ""}
|
|
278
278
|
<div class="author">@${info.UserName}</div>
|
|
279
279
|
</div>
|
|
280
|
-
|
|
281
280
|
<div class="tags">${displayTags.map((t) => `<span class="tag ${["文", "译", "R"].includes(t) ? "tag-imp" : ""}">${t}</span>`).join("")}</div>
|
|
282
|
-
|
|
283
|
-
<div class="summary-box">
|
|
284
|
-
<div class="summary">${summary}</div>
|
|
285
|
-
</div>
|
|
286
|
-
|
|
281
|
+
<div class="summary-box"><div class="summary">${summary}</div></div>
|
|
287
282
|
<div class="footer">
|
|
288
283
|
<span class="stat"><b style="color:#009688">热度</b>${views}</span>
|
|
289
284
|
<span class="stat"><b style="color:#673ab7">评论</b>${comments}</span>
|
|
@@ -343,7 +338,7 @@ function apply(ctx, config) {
|
|
|
343
338
|
<div class="top-row"><div class="title">${r.title}</div><div class="id-badge">ID: ${r.id}</div></div>
|
|
344
339
|
<div class="author">By ${r.author} ${r.status ? ` · ${r.status}` : ""}</div>
|
|
345
340
|
<div class="tags">${r.tags.map((t) => `<span class="tag">${t}</span>`).join("")}</div>
|
|
346
|
-
<div class="meta-row">${stats || "
|
|
341
|
+
<div class="meta-row">${stats || "No Data"}</div>
|
|
347
342
|
</div></div>`;
|
|
348
343
|
}).join("")}
|
|
349
344
|
</div>
|
|
@@ -367,22 +362,35 @@ function apply(ctx, config) {
|
|
|
367
362
|
<style>
|
|
368
363
|
body { margin: 0; padding: 0; width: ${config.deviceWidth}px; background-color: #f6f4ec; color: #2c2c2c; font-family: ${fontStack}; }
|
|
369
364
|
#source-container { display: none; }
|
|
365
|
+
|
|
366
|
+
/* 使用 Flex 布局,让页脚自然占据底部空间,不覆盖正文 */
|
|
370
367
|
.page {
|
|
371
368
|
width: ${config.deviceWidth}px; height: ${config.deviceHeight}px;
|
|
372
369
|
padding: 35px 28px; box-sizing: border-box;
|
|
373
370
|
position: relative; background: #f6f4ec; overflow: hidden;
|
|
374
371
|
display: flex; flex-direction: column;
|
|
375
372
|
}
|
|
373
|
+
|
|
376
374
|
.page-header {
|
|
377
375
|
font-size: 12px; color: #8d6e63; border-bottom: 2px solid #d7ccc8;
|
|
378
376
|
padding-bottom: 12px; margin-bottom: 15px; flex-shrink: 0;
|
|
379
377
|
display: flex; justify-content: space-between; font-weight: bold;
|
|
380
378
|
}
|
|
379
|
+
|
|
380
|
+
/* 页脚改为相对定位,并给予上边距 */
|
|
381
381
|
.page-footer {
|
|
382
|
-
|
|
383
|
-
|
|
382
|
+
text-align: center; font-size: 12px; color: #aaa; font-family: sans-serif;
|
|
383
|
+
flex-shrink: 0; padding-top: 10px; margin-top: auto;
|
|
384
384
|
}
|
|
385
|
-
|
|
385
|
+
|
|
386
|
+
.page-content {
|
|
387
|
+
flex: 1; /* 占据剩余所有空间 */
|
|
388
|
+
overflow: hidden; /* 隐藏溢出部分 */
|
|
389
|
+
font-size: ${config.fontSize}px;
|
|
390
|
+
line-height: 1.7;
|
|
391
|
+
text-align: justify;
|
|
392
|
+
}
|
|
393
|
+
|
|
386
394
|
p { margin: 0 0 0.6em 0; text-indent: 2em; }
|
|
387
395
|
img { max-width: 100%; height: auto; display: block; margin: 10px auto; border-radius: 6px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
|
388
396
|
h1, h2, h3 { font-size: 1.1em; margin: 0.5em 0; color: #5d4037; text-indent: 0; font-weight: bold; }
|
|
@@ -399,32 +407,42 @@ function apply(ctx, config) {
|
|
|
399
407
|
const author = source.querySelector('.meta-info').dataset.author;
|
|
400
408
|
let pageIndex = 1;
|
|
401
409
|
let currentPageContent = null;
|
|
410
|
+
|
|
402
411
|
function createNewPage() {
|
|
403
412
|
const page = document.createElement('div'); page.className = 'page';
|
|
404
413
|
const header = document.createElement('div'); header.className = 'page-header';
|
|
405
414
|
header.innerHTML = \`<span>\${title.substring(0, 12) + (title.length>12?'...':'')}</span><span>\${author}</span>\`;
|
|
406
415
|
page.appendChild(header);
|
|
416
|
+
|
|
407
417
|
const content = document.createElement('div'); content.className = 'page-content';
|
|
408
418
|
page.appendChild(content);
|
|
419
|
+
|
|
409
420
|
const footer = document.createElement('div'); footer.className = 'page-footer';
|
|
410
421
|
footer.id = 'footer-' + pageIndex;
|
|
411
422
|
page.appendChild(footer);
|
|
423
|
+
|
|
412
424
|
output.appendChild(page);
|
|
413
425
|
currentPageContent = content;
|
|
414
426
|
return page;
|
|
415
427
|
}
|
|
428
|
+
|
|
416
429
|
createNewPage();
|
|
417
430
|
const children = Array.from(source.children);
|
|
431
|
+
|
|
418
432
|
for (const child of children) {
|
|
419
433
|
if (child.className === 'meta-info') continue;
|
|
434
|
+
|
|
420
435
|
currentPageContent.appendChild(child.cloneNode(true));
|
|
421
|
-
|
|
436
|
+
|
|
437
|
+
// 核心修复:增加 10px 的安全缓冲,防止 descenders 被切
|
|
438
|
+
if (currentPageContent.scrollHeight > currentPageContent.clientHeight - 10) {
|
|
422
439
|
currentPageContent.removeChild(currentPageContent.lastChild);
|
|
423
440
|
pageIndex++;
|
|
424
441
|
createNewPage();
|
|
425
442
|
currentPageContent.appendChild(child.cloneNode(true));
|
|
426
443
|
}
|
|
427
444
|
}
|
|
445
|
+
|
|
428
446
|
for(let i=1; i<=pageIndex; i++) document.getElementById('footer-'+i).innerText = \`- \${i} / \${pageIndex} -\`;
|
|
429
447
|
return pageIndex;
|
|
430
448
|
}
|