koishi-plugin-ll-mc 3.1.4 → 3.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 +27 -11
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -357,6 +357,7 @@ async function apply(ctx, config) {
|
|
|
357
357
|
const fontsPath = import_path.default.join(messageCounterRoot, "fonts");
|
|
358
358
|
const avatarsPath = import_path.default.join(messageCounterRoot, "avatars");
|
|
359
359
|
const emptyHtmlPath = import_path.default.join(messageCounterRoot, "emptyHtml.html").replace(/\\/g, "/");
|
|
360
|
+
const templateHtmlPath = import_path.default.join(messageCounterRoot, "leaderboard-template.html").replace(/\\/g, "/");
|
|
360
361
|
const oldIconsPath = import_path.default.join(dataRoot, "messageCounterIcons");
|
|
361
362
|
const oldBarBgImgsPath = import_path.default.join(dataRoot, "messageCounterBarBgImgs");
|
|
362
363
|
await fs.mkdir(fontsPath, { recursive: true });
|
|
@@ -2519,7 +2520,6 @@ ${targetUserRecord[0].username}
|
|
|
2519
2520
|
}[ch]));
|
|
2520
2521
|
}
|
|
2521
2522
|
__name(escapeHtml, "escapeHtml");
|
|
2522
|
-
const BAR_LIGHT_TRACK = "#F3F4F6";
|
|
2523
2523
|
const BAR_FILL_COLORS = [
|
|
2524
2524
|
"#F472B6", // pink
|
|
2525
2525
|
"#A78BFA", // violet
|
|
@@ -2540,8 +2540,7 @@ ${targetUserRecord[0].username}
|
|
|
2540
2540
|
const avatar = escapeHtml(item.avatar || "");
|
|
2541
2541
|
const name = escapeHtml(item.name || "");
|
|
2542
2542
|
const count = item.count;
|
|
2543
|
-
//
|
|
2544
|
-
const barBg = BAR_LIGHT_TRACK;
|
|
2543
|
+
// 柱子未发言部分用半透明玻璃(毛玻璃),发言部分用彩色区分
|
|
2545
2544
|
const fill = isHero
|
|
2546
2545
|
? 'linear-gradient(to right, #6366F1, #A855F7, #EC4899)'
|
|
2547
2546
|
: fillColor;
|
|
@@ -2551,7 +2550,7 @@ ${targetUserRecord[0].username}
|
|
|
2551
2550
|
: "";
|
|
2552
2551
|
return `<div class="row">
|
|
2553
2552
|
<div class="avatar"><img src="${avatar}" alt="avatar"></div>
|
|
2554
|
-
<div class="bar"
|
|
2553
|
+
<div class="bar">
|
|
2555
2554
|
<div class="fill" style="width:${width}%;background:${fill};"></div>
|
|
2556
2555
|
<div class="bar-content" style="color:${textColor};">
|
|
2557
2556
|
<span class="row-name${isHero ? " is-hero" : ""}">${star}${name}</span>
|
|
@@ -2561,7 +2560,7 @@ ${targetUserRecord[0].username}
|
|
|
2561
2560
|
</div>`;
|
|
2562
2561
|
}
|
|
2563
2562
|
__name(buildLeaderboardRow, "buildLeaderboardRow");
|
|
2564
|
-
function buildLeaderboardHtml(title, date, items, backgroundCss) {
|
|
2563
|
+
function buildLeaderboardHtml(title, date, items, backgroundCss, fontFaces) {
|
|
2565
2564
|
const maxCount = Math.max(1, ...items.map((item) => item.count || 0));
|
|
2566
2565
|
const rows = items.map((item, index) => buildLeaderboardRow(item, index, maxCount)).join("\n");
|
|
2567
2566
|
return `<!DOCTYPE html>
|
|
@@ -2570,6 +2569,7 @@ ${targetUserRecord[0].username}
|
|
|
2570
2569
|
<meta charset="UTF-8">
|
|
2571
2570
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2572
2571
|
<style>
|
|
2572
|
+
${fontFaces || ""}
|
|
2573
2573
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2574
2574
|
html, body {
|
|
2575
2575
|
width: 900px;
|
|
@@ -2578,7 +2578,7 @@ ${targetUserRecord[0].username}
|
|
|
2578
2578
|
background-color: #F5F7FA;
|
|
2579
2579
|
}
|
|
2580
2580
|
body {
|
|
2581
|
-
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
2581
|
+
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "NotoEmoji", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
|
|
2582
2582
|
-webkit-font-smoothing: antialiased;
|
|
2583
2583
|
}
|
|
2584
2584
|
.card {
|
|
@@ -2594,7 +2594,7 @@ ${targetUserRecord[0].username}
|
|
|
2594
2594
|
.row { display: flex; align-items: center; gap: 12px; width: 100%; }
|
|
2595
2595
|
.avatar { width: 40px; height: 40px; flex-shrink: 0; }
|
|
2596
2596
|
.avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; box-shadow: 0 1px 2px rgba(0,0,0,0.08); background: #fff; padding: 2px; }
|
|
2597
|
-
.bar { position: relative; flex-grow: 1; height: 40px; border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: space-between; padding: 0 12px; }
|
|
2597
|
+
.bar { position: relative; flex-grow: 1; height: 40px; border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: space-between; padding: 0 12px; background: rgba(255,255,255,0.34); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.45); box-shadow: 0 1px 2px rgba(0,0,0,0.04); }
|
|
2598
2598
|
.bar::after { content: ''; position: absolute; inset: 0; background-image: linear-gradient(to right, transparent 99%, rgba(255,255,255,0.2) 100%); background-size: 10% 100%; pointer-events: none; }
|
|
2599
2599
|
.fill { position: absolute; left: 0; top: 0; height: 100%; border-radius: 8px 0 0 8px; z-index: 0; }
|
|
2600
2600
|
.bar-content { position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; width: 100%; }
|
|
@@ -2623,14 +2623,30 @@ ${rows}
|
|
|
2623
2623
|
if (typeof ctx.puppeteer?.page !== "function") return null;
|
|
2624
2624
|
let page;
|
|
2625
2625
|
try {
|
|
2626
|
-
|
|
2626
|
+
// 复用图表的内置字体(含纯 emoji 的 NotoEmoji),以相对路径 fonts/<file> 加载,
|
|
2627
|
+
// 所以必须把模板写到 data/messageCounter/ 目录里再用 file:// 访问,相对路径才能解析。
|
|
2628
|
+
const fontFaces = generateFontFacesCSS(["HarmonyOS_Sans_Medium.ttf", "NotoEmoji.ttf"]);
|
|
2629
|
+
const html = buildLeaderboardHtml(title, date, items, backgroundCss, fontFaces);
|
|
2627
2630
|
page = await ctx.puppeteer.page();
|
|
2628
2631
|
await page.setViewport({ width: 900, height: 400, deviceScaleFactor: 2 });
|
|
2632
|
+
const pageUrl = templateHtmlPath.includes(":") ? `file:///${templateHtmlPath}` : `file://${templateHtmlPath}`;
|
|
2629
2633
|
try {
|
|
2630
|
-
await
|
|
2631
|
-
} catch (
|
|
2632
|
-
logger.warn("
|
|
2634
|
+
await fs.writeFile(templateHtmlPath, html);
|
|
2635
|
+
} catch (writeError) {
|
|
2636
|
+
logger.warn("无法写入排行榜模板文件,改用 setContent:", writeError?.message);
|
|
2633
2637
|
}
|
|
2638
|
+
if (typeof page.goto === "function") {
|
|
2639
|
+
try {
|
|
2640
|
+
await page.goto(pageUrl, { waitUntil: "load", timeout: 20000 });
|
|
2641
|
+
} catch (e) {
|
|
2642
|
+
logger.warn("Leaderboard template goto failed, using setContent:", e?.message);
|
|
2643
|
+
await page.setContent(html, { waitUntil: "networkidle0", timeout: 20000 }).catch(() => {});
|
|
2644
|
+
}
|
|
2645
|
+
} else {
|
|
2646
|
+
await page.setContent(html, { waitUntil: "networkidle0", timeout: 20000 }).catch(() => {});
|
|
2647
|
+
}
|
|
2648
|
+
// 确保 emoji 字体就绪再截图
|
|
2649
|
+
await page.evaluate(() => document.fonts.ready).catch(() => {});
|
|
2634
2650
|
await page.waitForSelector(".card").catch(() => {});
|
|
2635
2651
|
// 背景(自定义 CSS/API 背景)是加在 html 上的,必须截整页才能把卡片外的背景一起截进来;
|
|
2636
2652
|
// body 高度由内容撑开(无 min-height),所以 fullPage 不会产生多余空白。
|