koishi-plugin-bns-fortune 1.0.1 → 1.0.2
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.d.ts +2 -0
- package/lib/index.js +8 -34
- package/lib/render.d.ts +2 -17
- package/lib/render.js +9 -8
- package/package.json +4 -11
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -5,6 +5,8 @@ exports.apply = apply;
|
|
|
5
5
|
/**
|
|
6
6
|
* koishi-plugin-bns-fortune
|
|
7
7
|
* 剑灵风格每日好运签 —— Canvas 绘制,每日一签,文字可变
|
|
8
|
+
*
|
|
9
|
+
* 直接使用 node-canvas 包绘制,不依赖 Koishi 的 canvas 服务(避免与其他插件的服务名冲突)。
|
|
8
10
|
*/
|
|
9
11
|
const koishi_1 = require("koishi");
|
|
10
12
|
const node_path_1 = require("node:path");
|
|
@@ -55,18 +57,6 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
55
57
|
exports.config = exports.Config;
|
|
56
58
|
exports.name = 'bns-fortune';
|
|
57
59
|
exports.reusable = true;
|
|
58
|
-
/**
|
|
59
|
-
* 获取 canvas 服务。
|
|
60
|
-
* koishi-plugin-canvas(基于 skia-canvas)会注入 ctx.canvas。
|
|
61
|
-
*/
|
|
62
|
-
function getCanvas(ctx) {
|
|
63
|
-
// koishi-plugin-canvas 注入的服务挂载在 ctx.canvas
|
|
64
|
-
const canvas = ctx.canvas;
|
|
65
|
-
if (!canvas) {
|
|
66
|
-
throw new Error('未检测到 canvas 服务。请在 Koishi 中安装并启用 "koishi-plugin-canvas" 插件,本插件依赖它来绘制签图。');
|
|
67
|
-
}
|
|
68
|
-
return canvas;
|
|
69
|
-
}
|
|
70
60
|
/** 注册字体目录下的 ttf/otf(若提供) */
|
|
71
61
|
function tryRegisterFonts(dir) {
|
|
72
62
|
if (!dir)
|
|
@@ -84,8 +74,6 @@ function tryRegisterFonts(dir) {
|
|
|
84
74
|
logger.warn('读取字体目录失败:%o', e);
|
|
85
75
|
return;
|
|
86
76
|
}
|
|
87
|
-
// skia-canvas 提供 Fontlibrary.use;node-canvas 提供 registerFont。
|
|
88
|
-
// 两者都尝试,命中其一即可。
|
|
89
77
|
for (const f of files) {
|
|
90
78
|
const lower = f.toLowerCase();
|
|
91
79
|
if (!lower.endsWith('.ttf') && !lower.endsWith('.otf'))
|
|
@@ -93,19 +81,10 @@ function tryRegisterFonts(dir) {
|
|
|
93
81
|
const full = (0, node_path_1.resolve)(abs, f);
|
|
94
82
|
const family = f.replace(/\.(ttf|otf)$/i, '');
|
|
95
83
|
try {
|
|
96
|
-
//
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch { /* ignore */ }
|
|
104
|
-
try {
|
|
105
|
-
// node-canvas
|
|
106
|
-
const nodeCanvas = require('canvas');
|
|
107
|
-
if (typeof nodeCanvas.registerFont === 'function') {
|
|
108
|
-
nodeCanvas.registerFont(full, { family });
|
|
84
|
+
// @napi-rs/canvas 的 GlobalFonts.register
|
|
85
|
+
const { GlobalFonts } = require('@napi-rs/canvas');
|
|
86
|
+
if (GlobalFonts?.register) {
|
|
87
|
+
GlobalFonts.register(full, { family });
|
|
109
88
|
}
|
|
110
89
|
}
|
|
111
90
|
catch { /* ignore */ }
|
|
@@ -123,12 +102,7 @@ function apply(ctx, config) {
|
|
|
123
102
|
? config.results
|
|
124
103
|
: fortunes_1.FORTUNES;
|
|
125
104
|
const theme = render_1.THEMES[config.theme] ?? render_1.THEMES.ink;
|
|
126
|
-
|
|
127
|
-
function getRenderer() {
|
|
128
|
-
if (!renderer)
|
|
129
|
-
renderer = new render_1.FortuneRenderer(getCanvas(ctx));
|
|
130
|
-
return renderer;
|
|
131
|
-
}
|
|
105
|
+
const renderer = new render_1.FortuneRenderer();
|
|
132
106
|
// 每日每用户渲染缓存:key = `${date}|${userId}`
|
|
133
107
|
const renderCache = new Map();
|
|
134
108
|
// 每天换日时清理
|
|
@@ -148,7 +122,7 @@ function apply(ctx, config) {
|
|
|
148
122
|
return koishi_1.h.image(cached, 'image/png');
|
|
149
123
|
try {
|
|
150
124
|
const { fortune } = (0, fortune_1.drawFortune)(date, session.userId, config.masterKey, library);
|
|
151
|
-
const png = await
|
|
125
|
+
const png = await renderer.render({
|
|
152
126
|
fortune,
|
|
153
127
|
date,
|
|
154
128
|
nickname: session.username || session.author?.nickname,
|
package/lib/render.d.ts
CHANGED
|
@@ -6,23 +6,10 @@
|
|
|
6
6
|
* 支持 customBackground 配置项替换为外部图片。
|
|
7
7
|
* - 动态文字(签等级/签诗/解签/运势/日期/昵称/签号)每次叠加在背景之上。
|
|
8
8
|
* - 配色用剑灵水墨风(墨黑 / 朱砂红 / 赤金 / 米色),装饰加入剑气、符文元素。
|
|
9
|
+
*
|
|
10
|
+
* 直接使用 node-canvas 包,不依赖 Koishi 的 canvas 服务(避免服务名冲突)。
|
|
9
11
|
*/
|
|
10
12
|
import { Fortune } from './fortunes';
|
|
11
|
-
export interface CanvasLike {
|
|
12
|
-
width: number;
|
|
13
|
-
height: number;
|
|
14
|
-
getContext(type: '2d'): CanvasRenderingContext2D;
|
|
15
|
-
/** 兼容 skia-canvas / node-canvas:不传参数时两者都默认返回 PNG Buffer */
|
|
16
|
-
toBuffer(format?: string, config?: unknown): Buffer;
|
|
17
|
-
}
|
|
18
|
-
export interface ImageLike {
|
|
19
|
-
width: number;
|
|
20
|
-
height: number;
|
|
21
|
-
}
|
|
22
|
-
export interface CanvasService {
|
|
23
|
-
createCanvas(width: number, height: number): CanvasLike;
|
|
24
|
-
loadImage(source: string | Buffer): Promise<ImageLike>;
|
|
25
|
-
}
|
|
26
13
|
export interface Theme {
|
|
27
14
|
/** 主题名 */
|
|
28
15
|
name: string;
|
|
@@ -58,14 +45,12 @@ export interface RenderInput {
|
|
|
58
45
|
customBackground?: string;
|
|
59
46
|
}
|
|
60
47
|
export declare class FortuneRenderer {
|
|
61
|
-
private canvas;
|
|
62
48
|
/** 背景缓存:key = `${themeName}|${customBg ?? 'builtin'}` */
|
|
63
49
|
private bgCache;
|
|
64
50
|
/** 自定义背景图缓存:key = url */
|
|
65
51
|
private imageCache;
|
|
66
52
|
/** 缓存条数上限 */
|
|
67
53
|
private static MAX_CACHE;
|
|
68
|
-
constructor(canvas: CanvasService);
|
|
69
54
|
private evict;
|
|
70
55
|
/** 字体声明字符串,含中文回退 */
|
|
71
56
|
private fontStack;
|
package/lib/render.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FortuneRenderer = exports.H = exports.W = exports.THEMES = void 0;
|
|
4
|
+
const canvas_1 = require("@napi-rs/canvas");
|
|
4
5
|
exports.THEMES = {
|
|
5
6
|
/** 剑灵·水墨:墨黑朱砂赤金 */
|
|
6
7
|
ink: {
|
|
@@ -31,8 +32,7 @@ exports.THEMES = {
|
|
|
31
32
|
exports.W = 600;
|
|
32
33
|
exports.H = 860;
|
|
33
34
|
class FortuneRenderer {
|
|
34
|
-
constructor(
|
|
35
|
-
this.canvas = canvas;
|
|
35
|
+
constructor() {
|
|
36
36
|
/** 背景缓存:key = `${themeName}|${customBg ?? 'builtin'}` */
|
|
37
37
|
this.bgCache = new Map();
|
|
38
38
|
/** 自定义背景图缓存:key = url */
|
|
@@ -61,11 +61,11 @@ class FortuneRenderer {
|
|
|
61
61
|
// 自定义背景:加载图片并缩放绘制到画布
|
|
62
62
|
let img = this.imageCache.get(customBg);
|
|
63
63
|
if (!img) {
|
|
64
|
-
img = await
|
|
64
|
+
img = await (0, canvas_1.loadImage)(customBg);
|
|
65
65
|
this.imageCache.set(customBg, img);
|
|
66
66
|
this.evict(this.imageCache);
|
|
67
67
|
}
|
|
68
|
-
bg =
|
|
68
|
+
bg = (0, canvas_1.createCanvas)(exports.W, exports.H);
|
|
69
69
|
const ctx = bg.getContext('2d');
|
|
70
70
|
// 先填底色,避免透明
|
|
71
71
|
ctx.fillStyle = theme.bg;
|
|
@@ -80,7 +80,7 @@ class FortuneRenderer {
|
|
|
80
80
|
drawBorder(ctx, exports.W, exports.H, theme);
|
|
81
81
|
}
|
|
82
82
|
else {
|
|
83
|
-
bg =
|
|
83
|
+
bg = (0, canvas_1.createCanvas)(exports.W, exports.H);
|
|
84
84
|
const ctx = bg.getContext('2d');
|
|
85
85
|
drawBackground(ctx, exports.W, exports.H, theme);
|
|
86
86
|
}
|
|
@@ -92,8 +92,9 @@ class FortuneRenderer {
|
|
|
92
92
|
async render(input) {
|
|
93
93
|
const { fortune, date, nickname, fontFamily, theme, customBackground } = input;
|
|
94
94
|
const bg = await this.getBackground(theme, customBackground);
|
|
95
|
-
const canvas =
|
|
95
|
+
const canvas = (0, canvas_1.createCanvas)(exports.W, exports.H);
|
|
96
96
|
const ctx = canvas.getContext('2d');
|
|
97
|
+
// 1. 复制缓存背景
|
|
97
98
|
ctx.drawImage(bg, 0, 0);
|
|
98
99
|
// 2. 顶部绸带 + 签等级标题(动态)
|
|
99
100
|
drawRibbon(ctx, exports.W / 2, 78, theme);
|
|
@@ -108,8 +109,8 @@ class FortuneRenderer {
|
|
|
108
109
|
drawLuckTags(ctx, exports.W / 2, 638, fortune.luck, this.fontStack(fontFamily), theme);
|
|
109
110
|
// 7. 底部:日期 / 昵称 / 签号
|
|
110
111
|
drawFooter(ctx, exports.W, exports.H, date, nickname, fortune.number, this.fontStack(fontFamily), theme);
|
|
111
|
-
//
|
|
112
|
-
return canvas.toBuffer();
|
|
112
|
+
// @napi-rs/canvas 需要传 mime type
|
|
113
|
+
return canvas.toBuffer('image/png');
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
exports.FortuneRenderer = FortuneRenderer;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-bns-fortune",
|
|
3
3
|
"description": "剑灵风格每日好运签:每日一签,Canvas 绘制签图,文字可变,支持自定义背景与主题。",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -10,11 +10,6 @@
|
|
|
10
10
|
"koishi": {
|
|
11
11
|
"description": {
|
|
12
12
|
"zh": "剑灵好运签(每日一签)"
|
|
13
|
-
},
|
|
14
|
-
"manifest": {
|
|
15
|
-
"services": [
|
|
16
|
-
"canvas"
|
|
17
|
-
]
|
|
18
13
|
}
|
|
19
14
|
},
|
|
20
15
|
"keywords": [
|
|
@@ -35,17 +30,15 @@
|
|
|
35
30
|
},
|
|
36
31
|
"peerDependencies": {
|
|
37
32
|
"koishi": "^4.15.0",
|
|
38
|
-
"
|
|
39
|
-
"canvas": "^2.0.0"
|
|
33
|
+
"@napi-rs/canvas": "^0.1.0"
|
|
40
34
|
},
|
|
41
35
|
"peerDependenciesMeta": {
|
|
42
|
-
"canvas": {
|
|
43
|
-
"optional":
|
|
36
|
+
"@napi-rs/canvas": {
|
|
37
|
+
"optional": false
|
|
44
38
|
}
|
|
45
39
|
},
|
|
46
40
|
"devDependencies": {
|
|
47
41
|
"koishi": "^4.15.0",
|
|
48
|
-
"koishi-plugin-canvas": "^0.2.2",
|
|
49
42
|
"rimraf": "^5.0.0",
|
|
50
43
|
"typescript": "^5.4.0"
|
|
51
44
|
}
|