koishi-plugin-group-analysis-mx 1.2.8 → 1.3.0
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/service/renderer.js +43 -34
- package/package.json +1 -1
- package/resources/fonts/NotoEmoji.ttf +0 -0
- package/resources/fonts/00.woff2 +0 -0
- package/resources/fonts/01.woff2 +0 -0
- package/resources/fonts/02.woff2 +0 -0
- package/resources/fonts/03.woff2 +0 -0
- package/resources/fonts/04.woff2 +0 -0
- package/resources/fonts/05.woff2 +0 -0
- package/resources/fonts/06.woff2 +0 -0
- package/resources/fonts/07.woff2 +0 -0
- package/resources/fonts/08.woff2 +0 -0
- package/resources/fonts/09.woff2 +0 -0
package/lib/service/renderer.js
CHANGED
|
@@ -76,42 +76,34 @@ class RendererService extends koishi_1.Service {
|
|
|
76
76
|
async injectEmojiFont(html) {
|
|
77
77
|
if (!html || typeof html !== 'string')
|
|
78
78
|
return html;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
emojiCss = await this.buildEmojiFontCss();
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
this.ctx.logger.warn('构建 emoji 字体 CSS 失败:', e);
|
|
85
|
-
}
|
|
86
|
-
const style = `<style>${emojiCss}html,body{font-family:-apple-system,'Segoe UI','Segoe UI Emoji','NotoColorEmoji','Noto Sans SC','Noto Color Emoji','Apple Color Emoji','Microsoft YaHei','Hiragino Sans GB',sans-serif !important;}</style>`;
|
|
79
|
+
const emojiCss = this.buildEmojiFontCss();
|
|
80
|
+
const style = `<style>${emojiCss}html,body{font-family:-apple-system,'Segoe UI','Segoe UI Emoji','Noto Color Emoji','NotoEmoji','Apple Color Emoji','Microsoft YaHei','Hiragino Sans GB',sans-serif !important;}</style>`;
|
|
87
81
|
if (html.includes('</head>'))
|
|
88
82
|
return html.replace('</head>', style + '</head>');
|
|
89
83
|
return html;
|
|
90
84
|
}
|
|
91
|
-
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
for (let i = 0; i < EMOJI_RANGES.length; i++) {
|
|
98
|
-
const file = path_1.default.join(dir, `${String(i).padStart(2, '0')}.woff2`);
|
|
99
|
-
try {
|
|
100
|
-
const buf = await fs_1.promises.readFile(file);
|
|
101
|
-
const b64 = buf.toString('base64');
|
|
102
|
-
css += `@font-face{font-family:'NotoColorEmoji';font-style:normal;font-weight:400;src:url(data:font/woff2;base64,${b64}) format('woff2');unicode-range:${EMOJI_RANGES[i]};}`;
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
this.ctx.logger.warn(`加载 emoji 字体分片 ${i} 失败: ${e}`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
_emojiFontCssCache = css;
|
|
109
|
-
return css;
|
|
85
|
+
/**
|
|
86
|
+
* 生成引用同层 fonts/NotoEmoji.ttf 的 @font-face(单文件 ttf,Chromium 稳定加载)。
|
|
87
|
+
* 注意:必须与渲染 HTML 处于同一目录树(HTML 在 <skin>/,字体在 <skin>/fonts/),跨目录 file:// 加载会被 Chromium 拒绝。
|
|
88
|
+
*/
|
|
89
|
+
buildEmojiFontCss() {
|
|
90
|
+
return `@font-face{font-family:'NotoEmoji';font-style:normal;font-weight:400;src:url('fonts/NotoEmoji.ttf') format('truetype');}`;
|
|
110
91
|
}
|
|
111
92
|
async init() {
|
|
112
93
|
const resourcesDir = __dirname + '/../../resources';
|
|
113
94
|
const templateDir = this.templateDir;
|
|
114
95
|
const skin = this.config.skin || 'md3';
|
|
96
|
+
// 拷贝内嵌的 emoji 字体到当前皮肤目录的 fonts/ 子目录(与渲染 HTML 同层;跨目录 file:// 加载会被 Chromium 拒绝)
|
|
97
|
+
const skinFontsDir = ORIGINAL_SKINS.includes(skin)
|
|
98
|
+
? path_1.default.resolve(templateDir, 'original', skin, 'fonts')
|
|
99
|
+
: path_1.default.resolve(templateDir, skin, 'fonts');
|
|
100
|
+
await fs_1.promises.mkdir(skinFontsDir, { recursive: true });
|
|
101
|
+
await fs_1.promises.cp(path_1.default.resolve(resourcesDir, 'fonts'), skinFontsDir, { recursive: true });
|
|
102
|
+
// 创建空 HTML 占位:渲染时先 goto 它(建立 file:// base),再 setContent 注入内容,@font-face 相对字体才能被加载
|
|
103
|
+
const emptyHtmlPath = ORIGINAL_SKINS.includes(skin)
|
|
104
|
+
? path_1.default.resolve(templateDir, 'original', skin, 'emptyHtml.html')
|
|
105
|
+
: path_1.default.resolve(templateDir, skin, 'emptyHtml.html');
|
|
106
|
+
await fs_1.promises.writeFile(emptyHtmlPath, '');
|
|
115
107
|
// 拷贝原项目皮肤模板(nunjucks 渲染用)
|
|
116
108
|
const originalSourceDir = path_1.default.resolve(resourcesDir, 'original');
|
|
117
109
|
const originalDestDir = path_1.default.resolve(templateDir, 'original');
|
|
@@ -156,6 +148,13 @@ class RendererService extends koishi_1.Service {
|
|
|
156
148
|
}
|
|
157
149
|
}, 3 * 60 * 1000);
|
|
158
150
|
}
|
|
151
|
+
/** 当前皮肤目录下用于建立 file:// base 的空 HTML 占位路径。 */
|
|
152
|
+
emptyHtmlPath() {
|
|
153
|
+
const skin = this.config.skin || 'md3';
|
|
154
|
+
return ORIGINAL_SKINS.includes(skin)
|
|
155
|
+
? path_1.default.resolve(this.templateDir, 'original', skin, 'emptyHtml.html')
|
|
156
|
+
: path_1.default.resolve(this.templateDir, skin, 'emptyHtml.html');
|
|
157
|
+
}
|
|
159
158
|
async renderGroupAnalysisToPdf(data) {
|
|
160
159
|
let theme = this.config.theme;
|
|
161
160
|
if (theme === 'auto') {
|
|
@@ -241,8 +240,11 @@ class RendererService extends koishi_1.Service {
|
|
|
241
240
|
await fs_1.promises.writeFile(outTemplateHtmlPath, await this.injectEmojiFont(filledHtml));
|
|
242
241
|
this.ctx.logger.info('HTML 模板填充完成,正在调用 Puppeteer 进行渲染...');
|
|
243
242
|
const page = await this.ctx.puppeteer.page();
|
|
244
|
-
//
|
|
245
|
-
await page.goto('file://' +
|
|
243
|
+
// 先 goto 空 HTML 建立 file:// base,再 setContent 注入内容(@font-face 相对字体才能被加载)
|
|
244
|
+
await page.goto('file://' + this.emptyHtmlPath(), {
|
|
245
|
+
waitUntil: 'domcontentloaded'
|
|
246
|
+
});
|
|
247
|
+
await page.setContent(await this.injectEmojiFont(filledHtml), {
|
|
246
248
|
waitUntil: 'domcontentloaded'
|
|
247
249
|
});
|
|
248
250
|
this.ctx.logger.info('网页加载完成,开始等待字体加载。');
|
|
@@ -309,14 +311,18 @@ class RendererService extends koishi_1.Service {
|
|
|
309
311
|
const html = env.render('html_template.html', context);
|
|
310
312
|
const randomId = Math.random().toString(36).substring(2, 15);
|
|
311
313
|
const outTemplateHtmlPath = path_1.default.resolve(skinDir, `${randomId}.html`);
|
|
312
|
-
|
|
314
|
+
const emojiHtmlOriginal = await this.injectEmojiFont(html);
|
|
315
|
+
await fs_1.promises.writeFile(outTemplateHtmlPath, emojiHtmlOriginal);
|
|
313
316
|
this.ctx.logger.info(`原项目皮肤 ${skin} HTML 生成完成,正在调用 Puppeteer 渲染...`);
|
|
314
317
|
const page = await this.ctx.puppeteer.page();
|
|
315
318
|
await page.setViewport({ width: 1080, height: 1920, deviceScaleFactor: 2 });
|
|
316
|
-
await page.goto('file://' +
|
|
319
|
+
await page.goto('file://' + this.emptyHtmlPath(), {
|
|
320
|
+
waitUntil: 'domcontentloaded'
|
|
321
|
+
});
|
|
322
|
+
await page.setContent(emojiHtmlOriginal, {
|
|
317
323
|
waitUntil: 'networkidle0',
|
|
318
324
|
timeout: 60000
|
|
319
|
-
}).catch(() => page.
|
|
325
|
+
}).catch(() => page.setContent(emojiHtmlOriginal, {
|
|
320
326
|
waitUntil: 'domcontentloaded',
|
|
321
327
|
timeout: 60000
|
|
322
328
|
}));
|
|
@@ -528,8 +534,11 @@ class RendererService extends koishi_1.Service {
|
|
|
528
534
|
await fs_1.promises.writeFile(outTemplateHtmlPath, await this.injectEmojiFont(filledHtml));
|
|
529
535
|
this.ctx.logger.info('用户画像 HTML 模板填充完成,正在调用 Puppeteer 进行渲染...');
|
|
530
536
|
const page = await this.ctx.puppeteer.page();
|
|
531
|
-
//
|
|
532
|
-
await page.goto('file://' +
|
|
537
|
+
// 先 goto 空 HTML 建立 file:// base,再 setContent 注入内容(@font-face 相对字体才能被加载)
|
|
538
|
+
await page.goto('file://' + this.emptyHtmlPath(), {
|
|
539
|
+
waitUntil: 'domcontentloaded'
|
|
540
|
+
});
|
|
541
|
+
await page.setContent(await this.injectEmojiFont(filledHtml), {
|
|
533
542
|
waitUntil: 'domcontentloaded'
|
|
534
543
|
});
|
|
535
544
|
this.ctx.logger.info('网页加载完成,开始等待字体加载。');
|
package/package.json
CHANGED
|
Binary file
|
package/resources/fonts/00.woff2
DELETED
|
Binary file
|
package/resources/fonts/01.woff2
DELETED
|
Binary file
|
package/resources/fonts/02.woff2
DELETED
|
Binary file
|
package/resources/fonts/03.woff2
DELETED
|
Binary file
|
package/resources/fonts/04.woff2
DELETED
|
Binary file
|
package/resources/fonts/05.woff2
DELETED
|
Binary file
|
package/resources/fonts/06.woff2
DELETED
|
Binary file
|
package/resources/fonts/07.woff2
DELETED
|
Binary file
|
package/resources/fonts/08.woff2
DELETED
|
Binary file
|
package/resources/fonts/09.woff2
DELETED
|
Binary file
|