koishi-plugin-ll-bns-fortune 0.2.0 → 0.2.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.js +38 -45
- package/package.json +1 -1
- package/readme.md +1 -1
package/lib/index.js
CHANGED
|
@@ -36,7 +36,6 @@ exports.usage = `
|
|
|
36
36
|
{prefix}运势 查看今日运势(出图)
|
|
37
37
|
{prefix}运势 图片 强制出图
|
|
38
38
|
{prefix}运势 文字 强制发文字
|
|
39
|
-
{prefix}运势 @某人 帮别人看(受 atOthers 开关控制)
|
|
40
39
|
|
|
41
40
|
如果只发出文字、没有图片,说明没检测到可用的 canvas,任选一种解决:
|
|
42
41
|
1) 在插件目录执行 npm i @napi-rs/canvas(推荐,预编译二进制,不需要编译工具链)
|
|
@@ -128,17 +127,6 @@ const colorsSchema = Schema.object({
|
|
|
128
127
|
star: Schema.string().role('color').default('#C8434F').description('星星颜色'),
|
|
129
128
|
}).description('配色(默认按内置底图的暖色纸面调的)')
|
|
130
129
|
|
|
131
|
-
const perfSchema = Schema.object({
|
|
132
|
-
outputWidth: Schema.number().min(0).max(4096).default(1280)
|
|
133
|
-
.description('输出图片宽度(像素)。0 = 改用下面的倍率渲染。'
|
|
134
|
-
+ '默认 1280:出图快、群里也看得清;想要更锐利的文字可调到 1920(编码会慢一些)'),
|
|
135
|
-
}).description('出图性能')
|
|
136
|
-
|
|
137
|
-
const databaseSchema = Schema.object({
|
|
138
|
-
cache: Schema.boolean().default(true).description('把当天结果存库:同一天不再重算,且支持管理员手动指定'),
|
|
139
|
-
retentionDays: Schema.number().min(1).max(3650).default(60).description('历史记录保留天数(用于以后的历史查询功能)'),
|
|
140
|
-
}).description('数据存储')
|
|
141
|
-
|
|
142
130
|
exports.Config = Schema.intersect([
|
|
143
131
|
/* ============ 1. 基础设置(日常只需要看这一组) ============ */
|
|
144
132
|
Schema.object({
|
|
@@ -148,13 +136,13 @@ exports.Config = Schema.intersect([
|
|
|
148
136
|
.description('指令名(第一个是主指令,其余是别名)'),
|
|
149
137
|
keywordReply: Schema.boolean().default(false)
|
|
150
138
|
.description('关键词触发:群里有人说到关键词就自动发运势,不用敲指令。'
|
|
151
|
-
+ '
|
|
139
|
+
+ '和「指令名」重名的词会被忽略(不会重复响应),所以两边可以都开着'),
|
|
152
140
|
keywords: Schema.array(Schema.string())
|
|
153
|
-
.default(['
|
|
154
|
-
.description('
|
|
141
|
+
.default(['人品', '玄学', '求签', '今日运气'])
|
|
142
|
+
.description('关键词列表,也可以用正则(如「今日.*运势」)。'
|
|
143
|
+
+ '<b>不要填和上面「指令名」重复的词</b>,否则同一条消息会响应两次'),
|
|
155
144
|
cooldown: Schema.number().role('slider').min(0).max(600).step(5).default(5)
|
|
156
145
|
.description('每人冷却(秒),0 = 不限制'),
|
|
157
|
-
atOthers: Schema.boolean().default(false).description('允许通过 @某人 查看别人的运势'),
|
|
158
146
|
}).description('基础设置'),
|
|
159
147
|
|
|
160
148
|
/* ============ 2. 运势内容(文案池,最常改的都是这里) ============ */
|
|
@@ -273,9 +261,8 @@ exports.Config = Schema.intersect([
|
|
|
273
261
|
|
|
274
262
|
storage: Schema.object({
|
|
275
263
|
databaseCache: Schema.boolean().default(true)
|
|
276
|
-
.description('
|
|
277
|
-
|
|
278
|
-
.description('历史记录保留天数'),
|
|
264
|
+
.description('把当天结果存库:同一天不再重算(也方便以后加历史查询)。'
|
|
265
|
+
+ '关闭后每天首次查询都要重新计算,但功能不受影响'),
|
|
279
266
|
}).collapse().description('数据存储'),
|
|
280
267
|
}).description('外观与输出'),
|
|
281
268
|
])
|
|
@@ -330,7 +317,7 @@ function renderCfg (config) {
|
|
|
330
317
|
}
|
|
331
318
|
|
|
332
319
|
function storageCfg (config) {
|
|
333
|
-
return Object.assign({ databaseCache: true
|
|
320
|
+
return Object.assign({ databaseCache: true }, config && config.storage)
|
|
334
321
|
}
|
|
335
322
|
|
|
336
323
|
function kwMore (config) {
|
|
@@ -542,6 +529,14 @@ exports.apply = function apply (ctx, config) {
|
|
|
542
529
|
|
|
543
530
|
const logger = safeLogger(ctx, 'll-fortune')
|
|
544
531
|
|
|
532
|
+
// 折叠起来的子配置在旧配置里可能不存在,统一在最前面兜底。
|
|
533
|
+
// ⚠️ 必须定义在所有使用者之前:const 有暂时性死区,
|
|
534
|
+
// 放到后面会在启动时直接抛 "Cannot access 'xxx' before initialization"。
|
|
535
|
+
const geom = panelGeom(config)
|
|
536
|
+
const render = renderCfg(config)
|
|
537
|
+
const storage = storageCfg(config)
|
|
538
|
+
const keywordMore = kwMore(config)
|
|
539
|
+
|
|
545
540
|
/* ---------------- 数据库表 ---------------- */
|
|
546
541
|
if (storage.databaseCache && ctx.model) {
|
|
547
542
|
try {
|
|
@@ -588,12 +583,12 @@ exports.apply = function apply (ctx, config) {
|
|
|
588
583
|
}
|
|
589
584
|
}
|
|
590
585
|
|
|
591
|
-
/**
|
|
586
|
+
/** 顺手清掉过期记录(固定保留 60 天,不开放配置 —— 反正只是缓存,失败也无所谓) */
|
|
587
|
+
const RETENTION_DAYS = 60
|
|
588
|
+
|
|
592
589
|
async function cleanup () {
|
|
593
590
|
if (!useCache()) return
|
|
594
|
-
const
|
|
595
|
-
if (days >= 3650) return
|
|
596
|
-
const deadline = new Date(Date.now() - days * 86400000)
|
|
591
|
+
const deadline = new Date(Date.now() - RETENTION_DAYS * 86400000)
|
|
597
592
|
try {
|
|
598
593
|
await ctx.database.remove('ll_fortune', { createdAt: { $lt: deadline } })
|
|
599
594
|
} catch (error) { /* 忽略 */ }
|
|
@@ -642,12 +637,6 @@ exports.apply = function apply (ctx, config) {
|
|
|
642
637
|
}
|
|
643
638
|
|
|
644
639
|
/* ---------------- 出图 ---------------- */
|
|
645
|
-
// 折叠起来的子配置在旧配置里可能不存在,统一在这里兜底
|
|
646
|
-
const geom = panelGeom(config)
|
|
647
|
-
const render = renderCfg(config)
|
|
648
|
-
const storage = storageCfg(config)
|
|
649
|
-
const keywordMore = kwMore(config)
|
|
650
|
-
|
|
651
640
|
async function makeImage (fortune, formatOverride) {
|
|
652
641
|
const backgroundBuffer = await getBackground()
|
|
653
642
|
const values = templateValues(fortune, config)
|
|
@@ -698,7 +687,7 @@ exports.apply = function apply (ctx, config) {
|
|
|
698
687
|
},
|
|
699
688
|
backgroundBuffer,
|
|
700
689
|
})
|
|
701
|
-
logger.info('出图完成:%
|
|
690
|
+
logger.info('出图完成:%d x %d %s,耗时 %d ms', result.width, result.height, result.mime, Date.now() - started)
|
|
702
691
|
return result
|
|
703
692
|
}
|
|
704
693
|
|
|
@@ -801,23 +790,12 @@ exports.apply = function apply (ctx, config) {
|
|
|
801
790
|
const raw = String(session.content || '').trim()
|
|
802
791
|
const wantsText = /文字|文本|text/i.test(raw)
|
|
803
792
|
|
|
804
|
-
|
|
805
|
-
let targetName = ''
|
|
806
|
-
if (config.atOthers && session.elements) {
|
|
807
|
-
const at = session.elements.find(el => el && el.type === 'at' && el.attrs && el.attrs.id)
|
|
808
|
-
if (at) {
|
|
809
|
-
targetId = String(at.attrs.id)
|
|
810
|
-
targetName = at.attrs.name ? String(at.attrs.name) : ''
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
const self = targetId === String(session.userId)
|
|
815
|
-
const { fortune, header } = await getFortune(targetId, targetName)
|
|
793
|
+
const { fortune, header } = await getFortune(session.userId, '')
|
|
816
794
|
|
|
817
795
|
// 结果算完再判冷却,避免冷却拦下时白算一遍
|
|
818
|
-
const wait =
|
|
796
|
+
const wait = checkCooldown(session.userId)
|
|
819
797
|
if (wait) return `别急嘛,${wait} 秒后再来看运势吧~`
|
|
820
|
-
|
|
798
|
+
lastUsed.set(session.userId, Date.now())
|
|
821
799
|
|
|
822
800
|
return renderReply(fortune, header, wantsText)
|
|
823
801
|
})
|
|
@@ -836,7 +814,22 @@ exports.apply = function apply (ctx, config) {
|
|
|
836
814
|
return text.toLowerCase().includes(raw.toLowerCase())
|
|
837
815
|
}
|
|
838
816
|
|
|
817
|
+
/** 这条消息是不是在调用本插件的指令(指令名或别名)?
|
|
818
|
+
* 是的话就交给指令处理,关键词不再重复响应 —— 避免同一条消息发两张图 */
|
|
819
|
+
const commandNames = new Set(
|
|
820
|
+
(config.commands && config.commands.length ? config.commands : ['运势'])
|
|
821
|
+
.map(n => String(n).trim().toLowerCase())
|
|
822
|
+
.filter(Boolean),
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
function looksLikeCommand (text) {
|
|
826
|
+
// 取消息的第一个词,去掉可能的前缀(/ 或 !等)再比对
|
|
827
|
+
const first = String(text || '').trim().split(/\s+/)[0].replace(/^[!//!!.。]+/, '').toLowerCase()
|
|
828
|
+
return first ? commandNames.has(first) : false
|
|
829
|
+
}
|
|
830
|
+
|
|
839
831
|
function keywordHit (text) {
|
|
832
|
+
if (looksLikeCommand(text)) return null
|
|
840
833
|
const mode = keywordMore.keywordMatch || 'contains'
|
|
841
834
|
for (const keyword of (config.keywords || [])) {
|
|
842
835
|
if (testKeyword(text, keyword, mode)) return String(keyword).trim()
|
package/package.json
CHANGED