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.
- package/lib/index.js +218 -46
- 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
|
|
329
|
+
const rawContent = art.content ?? art.renderedContent ?? "";
|
|
151
330
|
const title = art.title ?? "";
|
|
152
|
-
const
|
|
153
|
-
const 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
|
-
|
|
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)
|
|
365
|
+
if (loaded === imgs.length) {
|
|
366
|
+
clearTimeout(timeout);
|
|
367
|
+
resolve(null);
|
|
368
|
+
}
|
|
183
369
|
}));
|
|
184
370
|
} catch (e) {
|
|
185
371
|
}
|
|
186
|
-
|
|
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
|
|
207
|
-
const title = paste.id
|
|
208
|
-
const
|
|
209
|
-
const 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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
}
|