koishi-plugin-luogu-saver-bot 0.1.3 → 0.1.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.
Files changed (2) hide show
  1. package/lib/index.js +218 -46
  2. package/package.json +7 -4
package/lib/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
8
  var __export = (target, all) => {
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -43,6 +53,8 @@ function statusToString(status) {
43
53
  __name(statusToString, "statusToString");
44
54
 
45
55
  // src/index.ts
56
+ var import_markdown_it = __toESM(require("markdown-it"));
57
+ var import_plugin_katex = require("@mdit/plugin-katex");
46
58
  var name = "luogu-saver-bot";
47
59
  var inject = ["puppeteer"];
48
60
  var Config = import_koishi.Schema.object({
@@ -62,7 +74,6 @@ var LuoguSaverClient = class {
62
74
  buildUrl(path) {
63
75
  const base = this.endpoint.replace(/\/$/, "");
64
76
  if (!base) return path;
65
- console.log(`${base}${path}`);
66
77
  if (path.startsWith("/")) return `${base}${path}`;
67
78
  return `${base}/${path}`;
68
79
  }
@@ -119,6 +130,174 @@ var LuoguSaverClient = class {
119
130
  return res.data;
120
131
  }
121
132
  };
133
+ var md = new import_markdown_it.default({
134
+ html: true,
135
+ breaks: true
136
+ }).use(import_plugin_katex.katex, {
137
+ allowFunctionInTextMode: true,
138
+ // 允许在文本模式下使用函数
139
+ strict: false
140
+ // 禁用严格模式,防止因不标准语法报错
141
+ });
142
+ function generateHtml(title, authorInfo, markdownContent) {
143
+ const renderedBody = md.render(markdownContent);
144
+ return `<!doctype html>
145
+ <html>
146
+ <head>
147
+ <meta charset="utf-8">
148
+ <meta name="viewport" content="width=device-width,initial-scale=1">
149
+
150
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/styles/github.min.css">
151
+
152
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css">
153
+
154
+ <style>
155
+ /* 基础重置与变量 */
156
+ :root {
157
+ --bg-color: #f6f8fa;
158
+ --card-bg: #ffffff;
159
+ --text-primary: #24292f;
160
+ --text-secondary: #57606a;
161
+ --border-color: #d0d7de;
162
+ --accent-color: #0969da;
163
+ }
164
+
165
+ body {
166
+ margin: 0;
167
+ padding: 40px;
168
+ background-color: var(--bg-color);
169
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
170
+ color: var(--text-primary);
171
+ line-height: 1.5;
172
+ }
173
+
174
+ .container {
175
+ max-width: 900px;
176
+ margin: 0 auto;
177
+ }
178
+
179
+ .card {
180
+ background: var(--card-bg);
181
+ border: 1px solid var(--border-color);
182
+ border-radius: 6px;
183
+ padding: 32px 40px;
184
+ box-shadow: 0 3px 6px rgba(140, 149, 159, 0.15);
185
+ }
186
+
187
+ /* 头部信息 */
188
+ header {
189
+ border-bottom: 1px solid var(--border-color);
190
+ padding-bottom: 20px;
191
+ margin-bottom: 24px;
192
+ }
193
+
194
+ h1.title {
195
+ margin: 0 0 8px 0;
196
+ font-size: 28px;
197
+ font-weight: 600;
198
+ }
199
+
200
+ .meta {
201
+ font-size: 14px;
202
+ color: var(--text-secondary);
203
+ }
204
+
205
+ /* Markdown 内容美化 (仿 GitHub 风格) */
206
+ .markdown-body {
207
+ font-size: 16px;
208
+ line-height: 1.6;
209
+ }
210
+
211
+ .markdown-body h1, .markdown-body h2, .markdown-body h3 {
212
+ margin-top: 24px;
213
+ margin-bottom: 16px;
214
+ font-weight: 600;
215
+ line-height: 1.25;
216
+ }
217
+ .markdown-body h1 { font-size: 2em; padding-bottom: .3em; border-bottom: 1px solid #d0d7de; }
218
+ .markdown-body h2 { font-size: 1.5em; padding-bottom: .3em; border-bottom: 1px solid #d0d7de; }
219
+ .markdown-body h3 { font-size: 1.25em; }
220
+
221
+ .markdown-body p { margin-bottom: 16px; }
222
+
223
+ .markdown-body a { color: var(--accent-color); text-decoration: none; }
224
+ .markdown-body a:hover { text-decoration: underline; }
225
+
226
+ .markdown-body blockquote {
227
+ margin: 0 0 16px;
228
+ padding: 0 1em;
229
+ color: var(--text-secondary);
230
+ border-left: 0.25em solid var(--border-color);
231
+ }
232
+
233
+ .markdown-body ul, .markdown-body ol { padding-left: 2em; margin-bottom: 16px; }
234
+
235
+ /* 表格样式 */
236
+ .markdown-body table {
237
+ border-spacing: 0;
238
+ border-collapse: collapse;
239
+ margin-bottom: 16px;
240
+ width: max-content;
241
+ max-width: 100%;
242
+ overflow: auto;
243
+ display: block;
244
+ }
245
+ .markdown-body table th, .markdown-body table td {
246
+ padding: 6px 13px;
247
+ border: 1px solid var(--border-color);
248
+ }
249
+ .markdown-body table tr { background-color: #fff; border-top: 1px solid #c6cbd1; }
250
+ .markdown-body table tr:nth-child(2n) { background-color: #f6f8fa; }
251
+
252
+ /* 代码块微调 */
253
+ .markdown-body pre {
254
+ padding: 16px;
255
+ overflow: auto;
256
+ font-size: 85%;
257
+ line-height: 1.45;
258
+ background-color: #f6f8fa;
259
+ border-radius: 6px;
260
+ }
261
+ .markdown-body code {
262
+ padding: 0.2em 0.4em;
263
+ margin: 0;
264
+ font-size: 85%;
265
+ background-color: rgba(175,184,193,0.2);
266
+ border-radius: 6px;
267
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
268
+ }
269
+ .markdown-body pre code {
270
+ padding: 0;
271
+ background-color: transparent;
272
+ }
273
+
274
+ /* 图片自适应 */
275
+ .markdown-body img {
276
+ max-width: 100%;
277
+ box-sizing: content-box;
278
+ background-color: #fff;
279
+ }
280
+
281
+ /* KaTeX 字体修复 */
282
+ .katex { font-size: 1.1em; }
283
+ </style>
284
+ </head>
285
+ <body>
286
+ <div class="container">
287
+ <div class="card">
288
+ <header>
289
+ <h1 class="title">${md.utils.escapeHtml(title)}</h1>
290
+ <div class="meta">${md.utils.escapeHtml(authorInfo)}</div>
291
+ </header>
292
+ <article class="markdown-body">
293
+ ${renderedBody}
294
+ </article>
295
+ </div>
296
+ </div>
297
+ </body>
298
+ </html>`;
299
+ }
300
+ __name(generateHtml, "generateHtml");
122
301
  function apply(ctx, config = {}) {
123
302
  const endpoint = config.endpoint || "";
124
303
  const userAgent = config.userAgent || "Uptime-Kuma";
@@ -147,50 +326,50 @@ function apply(ctx, config = {}) {
147
326
  if (!id) return "请提供文章 ID";
148
327
  const art = await ctx.luogu_saver.getArticle(id);
149
328
  if (!art) return "未找到文章";
150
- const content = art.renderedContent ?? art.content ?? "";
329
+ const rawContent = art.content ?? art.renderedContent ?? "";
151
330
  const title = art.title ?? "";
152
- const escapeHtml = /* @__PURE__ */ __name((s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escapeHtml");
153
- const html = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{--bg:#f4f6fb;--card:#ffffff;--text:#111;--muted:#6b7280;--accent:#2563eb}html,body{height:100%}body{margin:0;background:var(--bg);-webkit-font-smoothing:antialiased;font-family:Inter,-apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial;padding:40px;color:var(--text)}.container{max-width:900px;margin:0 auto}.card{background:var(--card);padding:32px;border-radius:12px;box-shadow:0 10px 30px rgba(2,6,23,0.08)}h1{font-size:28px;margin:0 0 12px}.meta{color:var(--muted);font-size:13px;margin-bottom:12px}article{line-height:1.75;color:var(--text)}img{max-width:100%;border-radius:8px}pre,code{background:#f6f8fa;padding:12px;border-radius:8px;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}blockquote{border-left:4px solid #e6e9ef;padding:8px 16px;color:var(--muted);margin:8px 0}a{color:var(--accent)}</style></head><body><div class="container"><div class="card"><h1>${escapeHtml(title)}</h1><div class="meta">作者 ${escapeHtml(String(art.authorId))}</div><article>${content}</article></div></div></body></html>`;
331
+ const authorInfo = `作者 UID: ${art.authorId}`;
332
+ const html = generateHtml(title, authorInfo, rawContent);
154
333
  if (!ctx.puppeteer) return "当前没有可用的 puppeteer 服务。";
155
334
  const page = await ctx.puppeteer.page();
156
335
  try {
157
336
  const width = Number(options.width) || 960;
158
337
  await page.setViewport({ width, height: 800, deviceScaleFactor: 2 });
159
- if (typeof page.emulateMediaFeatures === "function") {
160
- await page.emulateMediaFeatures([{ name: "prefers-color-scheme", value: "light" }]);
161
- }
162
338
  await page.setContent(html, { waitUntil: "networkidle0" });
339
+ try {
340
+ await page.evaluate(() => document.fonts.ready);
341
+ } catch (e) {
342
+ ctx.logger.warn("等待字体加载超时或失败", e);
343
+ }
163
344
  try {
164
345
  await page.evaluate(() => new Promise((resolve) => {
165
346
  const imgs = Array.from(document.images);
166
347
  if (!imgs.length) return resolve(null);
167
348
  let loaded = 0;
349
+ const timeout = setTimeout(() => resolve(null), 5e3);
350
+ const handler = /* @__PURE__ */ __name(() => {
351
+ loaded++;
352
+ if (loaded === imgs.length) {
353
+ clearTimeout(timeout);
354
+ resolve(null);
355
+ }
356
+ }, "handler");
168
357
  imgs.forEach((img) => {
169
358
  if (img.complete) {
170
359
  loaded++;
171
- return;
360
+ } else {
361
+ img.addEventListener("load", handler);
362
+ img.addEventListener("error", handler);
172
363
  }
173
- img.addEventListener("load", () => {
174
- loaded++;
175
- if (loaded === imgs.length) resolve(null);
176
- });
177
- img.addEventListener("error", () => {
178
- loaded++;
179
- if (loaded === imgs.length) resolve(null);
180
- });
181
364
  });
182
- if (loaded === imgs.length) resolve(null);
365
+ if (loaded === imgs.length) {
366
+ clearTimeout(timeout);
367
+ resolve(null);
368
+ }
183
369
  }));
184
370
  } catch (e) {
185
371
  }
186
- try {
187
- await page.evaluate(() => {
188
- document.documentElement.style.background = "#ffffff";
189
- if (document.body) document.body.style.background = "#ffffff";
190
- });
191
- } catch (e) {
192
- }
193
- const buffer = await page.screenshot({ fullPage: true, type: "png", omitBackground: false });
372
+ const buffer = await page.screenshot({ fullPage: true, type: "png" });
194
373
  return import_koishi.h.image(buffer, "image/png");
195
374
  } catch (err) {
196
375
  ctx.logger.error("截图文章失败", err);
@@ -203,19 +382,20 @@ function apply(ctx, config = {}) {
203
382
  if (!id) return "请提供剪贴板 ID";
204
383
  const paste = await ctx.luogu_saver.getPaste(id);
205
384
  if (!paste) return "未找到剪贴板内容";
206
- const content = paste.renderedContent ?? paste.content ?? "";
207
- const title = paste.id ?? "";
208
- const escapeHtml = /* @__PURE__ */ __name((s) => s.replace(/[&<>\"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escapeHtml");
209
- const html = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{--bg:#f4f6fb;--card:#ffffff;--text:#111;--muted:#6b7280;--accent:#2563eb}html,body{height:100%}body{margin:0;background:var(--bg);-webkit-font-smoothing:antialiased;font-family:Inter,-apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial;padding:40px;color:var(--text)}.container{max-width:900px;margin:0 auto}.card{background:var(--card);padding:24px;border-radius:12px;box-shadow:0 8px 20px rgba(2,6,23,0.06)}h1{font-size:20px;margin:0 0 8px}pre,code{white-space:pre-wrap;word-break:break-word;background:#f6f8fa;padding:12px;border-radius:8px;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}img{max-width:100%;border-radius:6px}a{color:var(--accent)}</style></head><body><div class="container"><div class="card"><h1>${escapeHtml(title)}</h1><article>${content}</article></div></div></body></html>`;
385
+ const rawContent = paste.content ?? paste.renderedContent ?? "";
386
+ const title = `剪贴板: ${paste.id}`;
387
+ const authorInfo = paste.author ? `创建者: ${paste.author.name} (UID: ${paste.author.id})` : `创建者 UID: ${paste.authorId}`;
388
+ const html = generateHtml(title, authorInfo, rawContent);
210
389
  if (!ctx.puppeteer) return "当前没有可用的 puppeteer 服务。";
211
390
  const page = await ctx.puppeteer.page();
212
391
  try {
213
392
  const width = Number(options.width) || 960;
214
393
  await page.setViewport({ width, height: 800, deviceScaleFactor: 2 });
215
- if (typeof page.emulateMediaFeatures === "function") {
216
- await page.emulateMediaFeatures([{ name: "prefers-color-scheme", value: "light" }]);
217
- }
218
394
  await page.setContent(html, { waitUntil: "networkidle0" });
395
+ try {
396
+ await page.waitForFunction("window.__katex_render_done === true", { timeout: 2e4 });
397
+ } catch (e) {
398
+ }
219
399
  try {
220
400
  await page.evaluate(() => new Promise((resolve) => {
221
401
  const imgs = Array.from(document.images);
@@ -226,27 +406,19 @@ function apply(ctx, config = {}) {
226
406
  loaded++;
227
407
  return;
228
408
  }
229
- img.addEventListener("load", () => {
230
- loaded++;
231
- if (loaded === imgs.length) resolve(null);
232
- });
233
- img.addEventListener("error", () => {
409
+ const handler = /* @__PURE__ */ __name(() => {
234
410
  loaded++;
235
411
  if (loaded === imgs.length) resolve(null);
236
- });
412
+ }, "handler");
413
+ img.addEventListener("load", handler);
414
+ img.addEventListener("error", handler);
237
415
  });
238
416
  if (loaded === imgs.length) resolve(null);
417
+ setTimeout(() => resolve(null), 5e3);
239
418
  }));
240
419
  } catch (e) {
241
420
  }
242
- try {
243
- await page.evaluate(() => {
244
- document.documentElement.style.background = "#ffffff";
245
- if (document.body) document.body.style.background = "#ffffff";
246
- });
247
- } catch (e) {
248
- }
249
- const buffer = await page.screenshot({ fullPage: true, type: "png", omitBackground: false });
421
+ const buffer = await page.screenshot({ fullPage: true, type: "png" });
250
422
  return import_koishi.h.image(buffer, "image/png");
251
423
  } catch (err) {
252
424
  ctx.logger.error("截图剪贴板失败", err);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-luogu-saver-bot",
3
3
  "description": "洛谷保存站机器人",
4
- "version": "0.1.3",
4
+ "version": "0.1.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -15,9 +15,12 @@
15
15
  "koishi",
16
16
  "plugin"
17
17
  ],
18
- "devDependencies": {},
19
18
  "peerDependencies": {
20
- "koishi": "^4.18.7",
21
- "puppeteer": "^3.9.0"
19
+ "koishi": "^4.18.7"
20
+ },
21
+ "dependencies": {
22
+ "@mdit/plugin-katex": "^0.24.1",
23
+ "highlight.js": "^11.11.1",
24
+ "markdown-it": "^14.1.0"
22
25
  }
23
26
  }