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.
Files changed (2) hide show
  1. package/lib/index.js +38 -20
  2. 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 "Unknown";
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 Error" };
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: "Request Failed" };
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 = "Unknown";
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 > 100) summary = summary.substring(0, 100) + "...";
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: 340px; background: #fff; border-radius: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: flex; overflow: hidden; }
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 || "暂无数据"}</div>
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
- position: absolute; bottom: 15px; left: 0; right: 0; text-align: center;
383
- font-size: 12px; color: #aaa; font-family: sans-serif;
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
- .page-content { flex: 1; overflow: hidden; font-size: ${config.fontSize}px; line-height: 1.7; text-align: justify; }
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
- if (currentPageContent.scrollHeight > currentPageContent.clientHeight) {
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
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-fimtale-api",
3
3
  "description": "Koishi插件,从fimtale搜索/订阅/随机获取小说/解析链接等",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [