koishi-plugin-ll-schedule 1.0.3 → 1.0.5
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/index.js +233 -50
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// koishi-plugin-ll-schedule
|
|
4
4
|
// 定时发送插件:设置时间自动向指定群发送文字/图片
|
|
5
|
-
// v1.0.
|
|
6
|
-
// 官机的群 ID 是 openid(不是数字群号),本插件通过"学习"机器人收到的群消息来记录群,
|
|
7
|
-
// 用 schedule.groups 命令查看已知群并填入 tasks.groups;留空则发送给所有已知群。
|
|
5
|
+
// v1.0.4:群内订阅(发关键词即可让本群加入推送列表,官机自动用 openid,无需手动填群号)
|
|
8
6
|
|
|
9
7
|
const { Schema, h } = require('koishi')
|
|
10
8
|
|
|
@@ -12,30 +10,34 @@ exports.name = 'll-schedule'
|
|
|
12
10
|
|
|
13
11
|
exports.usage = `定时发送插件:设置时间自动向指定群发送文字/图片。
|
|
14
12
|
|
|
15
|
-
##
|
|
13
|
+
## 快速上手(推荐用法)
|
|
14
|
+
|
|
15
|
+
1. 在插件设置页的 \`tasks\` 表格中添加任务:**键=任务名**,设置 \`time\`(发送时间)和 \`text\`/\`image\`(推送内容)
|
|
16
|
+
2. 在任意群里 @机器人 发:\`订阅 任务名\` → 这个群就加入了该任务的推送列表(自动记录,重启不丢)
|
|
17
|
+
3. 到点后插件自动把内容推送到所有订阅了该任务的群
|
|
18
|
+
|
|
19
|
+
## 群内命令
|
|
20
|
+
|
|
21
|
+
- \`订阅 [任务名]\`:当前群订阅指定任务的推送(不填任务名时,只有一个启用任务则自动选它)
|
|
22
|
+
- \`取消订阅 [任务名]\`:当前群取消订阅
|
|
23
|
+
- \`订阅列表\`:查看所有任务的订阅群
|
|
24
|
+
- \`schedule.list\`:查看任务列表
|
|
25
|
+
- \`schedule.test <任务名>\`:立即测试发送
|
|
26
|
+
- \`lls.*\`:以上命令的备用入口(lls.sub / lls.unsub / lls.sublist / lls.list / lls.test)
|
|
27
|
+
|
|
28
|
+
订阅/取消订阅的权限等级可在设置页 \`subscribeAuthority\` 调整(默认 2=群管理)。
|
|
16
29
|
|
|
17
|
-
|
|
30
|
+
## 任务配置
|
|
18
31
|
|
|
19
32
|
- \`time\`:发送时间,HH:MM 格式(24小时制)
|
|
20
|
-
- \`groups
|
|
33
|
+
- \`groups\`:手动指定的目标群列表(**推荐留空**,用群内"订阅"命令添加更省事;留空且无订阅 = 发给所有已知群)
|
|
21
34
|
- \`text\`:文字内容(可留空)
|
|
22
35
|
- \`image\`:图片 URL(可留空)
|
|
23
36
|
- \`enabled\`:是否启用
|
|
24
37
|
|
|
25
38
|
## 官机(官方QQ机器人)说明
|
|
26
39
|
|
|
27
|
-
官方平台没有"群号",只有 openid
|
|
28
|
-
|
|
29
|
-
- 命令 \`schedule.groups\` 查看所有已知群(显示群名和 openid)
|
|
30
|
-
- 把 openid 填进任务的 \`groups\` 里即可
|
|
31
|
-
- 注意:官机主动发群消息有平台频率限制,且机器人需在群里
|
|
32
|
-
|
|
33
|
-
## 命令
|
|
34
|
-
|
|
35
|
-
- \`schedule\` 帮助
|
|
36
|
-
- \`schedule.list\` 查看任务
|
|
37
|
-
- \`schedule.groups\` 查看机器人已知的群(官机显示 openid)
|
|
38
|
-
- \`schedule.test <任务名>\` 立即测试发送
|
|
40
|
+
官方平台没有"群号",只有 openid——用群内"订阅"命令即可,插件会自动记录当前群的 openid,无需手动填写。手动填 \`groups\` 时可用 \`schedule.groups\` 查看已知群的 openid。官机主动发群消息有平台频率限制,且机器人需在群里。
|
|
39
41
|
`
|
|
40
42
|
|
|
41
43
|
const TaskItem = Schema.object({
|
|
@@ -44,7 +46,7 @@ const TaskItem = Schema.object({
|
|
|
44
46
|
.description('发送时间,HH:MM 格式(24小时制),如 08:30、21:00'),
|
|
45
47
|
groups: Schema.array(Schema.string())
|
|
46
48
|
.default([])
|
|
47
|
-
.description('
|
|
49
|
+
.description('手动指定的目标群 ID(可留空;推荐用群内"订阅"命令自动添加,无需手动填 openid)'),
|
|
48
50
|
text: Schema.string()
|
|
49
51
|
.default('')
|
|
50
52
|
.description('文字内容(可留空)'),
|
|
@@ -59,10 +61,19 @@ const TaskItem = Schema.object({
|
|
|
59
61
|
const Config = Schema.object({
|
|
60
62
|
tasks: Schema.dict(TaskItem)
|
|
61
63
|
.default({})
|
|
62
|
-
.description('📋
|
|
64
|
+
.description('📋 定时任务表格(键=任务名,设置时间和推送内容)'),
|
|
65
|
+
subscribeKeyword: Schema.string()
|
|
66
|
+
.default('订阅')
|
|
67
|
+
.description('群内订阅推送的关键词(如"订阅 任务名",只输关键词则订阅唯一启用的任务)'),
|
|
68
|
+
unsubscribeKeyword: Schema.string()
|
|
69
|
+
.default('取消订阅')
|
|
70
|
+
.description('群内取消订阅的关键词(如"取消订阅 任务名")'),
|
|
71
|
+
subscribeAuthority: Schema.number()
|
|
72
|
+
.min(1).max(4).default(2)
|
|
73
|
+
.description('订阅/取消订阅所需权限等级(1=所有人 2=群管理 3=群主 4=管理员)'),
|
|
63
74
|
sendAllWhenEmpty: Schema.boolean()
|
|
64
75
|
.default(true)
|
|
65
|
-
.description('
|
|
76
|
+
.description('任务未指定群也没有群订阅时,发送给该机器人所有已知群'),
|
|
66
77
|
verbose: Schema.boolean()
|
|
67
78
|
.default(false)
|
|
68
79
|
.description('调试:控制台打印每次发送详情'),
|
|
@@ -102,6 +113,64 @@ function apply(ctx, config) {
|
|
|
102
113
|
platform: 'string',
|
|
103
114
|
learnedAt: 'unsigned',
|
|
104
115
|
}, { primary: ['botSid', 'guildId'] })
|
|
116
|
+
// 群订阅表:taskName + botSid + guildId(群内"订阅"命令注册的推送目标)
|
|
117
|
+
ctx.model.extend('ll_schedule_subs', {
|
|
118
|
+
taskName: 'string',
|
|
119
|
+
botSid: 'string',
|
|
120
|
+
guildId: 'string',
|
|
121
|
+
createdAt: 'unsigned',
|
|
122
|
+
}, { primary: ['taskName', 'botSid', 'guildId'] })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ===== 群订阅(群内发关键词注册推送目标) =====
|
|
126
|
+
// subs: Map<taskName, Map<`${botSid}:${guildId}`, { botSid, guildId, createdAt }>>
|
|
127
|
+
const subs = new Map()
|
|
128
|
+
|
|
129
|
+
function getTaskSubs(taskName) {
|
|
130
|
+
let taskSubs = subs.get(taskName)
|
|
131
|
+
if (!taskSubs) {
|
|
132
|
+
taskSubs = new Map()
|
|
133
|
+
subs.set(taskName, taskSubs)
|
|
134
|
+
}
|
|
135
|
+
return taskSubs
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function loadSubs() {
|
|
139
|
+
if (!ctx.database) return
|
|
140
|
+
try {
|
|
141
|
+
const rows = await ctx.database.get('ll_schedule_subs', {})
|
|
142
|
+
for (const row of rows) {
|
|
143
|
+
getTaskSubs(row.taskName).set(`${row.botSid}:${row.guildId}`, {
|
|
144
|
+
botSid: row.botSid,
|
|
145
|
+
guildId: row.guildId,
|
|
146
|
+
createdAt: row.createdAt,
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
if (rows.length) logger.info(`[schedule] 已从数据库加载 ${rows.length} 条群订阅`)
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
logger.warn('[schedule] 加载群订阅失败:', e)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function persistSub(taskName, entry) {
|
|
157
|
+
if (!ctx.database) return
|
|
158
|
+
try {
|
|
159
|
+
await ctx.database.upsert('ll_schedule_subs', [{ ...entry, taskName }], ['taskName', 'botSid', 'guildId'])
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
logger.warn('[schedule] 保存群订阅失败:', e)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function removeSub(taskName, botSid, guildId) {
|
|
167
|
+
if (!ctx.database) return
|
|
168
|
+
try {
|
|
169
|
+
await ctx.database.remove('ll_schedule_subs', { taskName, botSid, guildId })
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
logger.warn('[schedule] 删除群订阅失败:', e)
|
|
173
|
+
}
|
|
105
174
|
}
|
|
106
175
|
|
|
107
176
|
async function loadKnownGroups() {
|
|
@@ -224,15 +293,21 @@ function apply(ctx, config) {
|
|
|
224
293
|
if (!bots.length) return
|
|
225
294
|
|
|
226
295
|
const groups = (task.groups && task.groups.length > 0) ? task.groups : null
|
|
296
|
+
const taskSubs = subs.get(name)
|
|
227
297
|
|
|
228
298
|
for (const bot of bots) {
|
|
229
|
-
|
|
230
|
-
|
|
299
|
+
// 该任务下、该机器人订阅的群(群内"订阅"命令注册的)
|
|
300
|
+
const subTargets = taskSubs
|
|
301
|
+
? [...taskSubs.values()].filter(s => s.botSid === bot.sid).map(s => s.guildId)
|
|
302
|
+
: []
|
|
303
|
+
|
|
304
|
+
if (groups || subTargets.length) {
|
|
305
|
+
for (const rawTarget of groups || []) {
|
|
231
306
|
const target = String(rawTarget).trim()
|
|
232
307
|
if (!target) continue
|
|
233
308
|
// 官机:群 ID 是 openid;数字群号在官机上无法直接使用
|
|
234
309
|
if (bot.platform === 'qq' && /^\d+$/.test(target)) {
|
|
235
|
-
logger.warn(`[schedule] 任务 "${name}":官方QQ机器人不能用数字群号 "${target}"
|
|
310
|
+
logger.warn(`[schedule] 任务 "${name}":官方QQ机器人不能用数字群号 "${target}" 发送,请用群内"订阅"命令或 schedule.groups 查看 openid`)
|
|
236
311
|
continue
|
|
237
312
|
}
|
|
238
313
|
try {
|
|
@@ -243,9 +318,18 @@ function apply(ctx, config) {
|
|
|
243
318
|
logger.error(`[schedule] 发送到 ${bot.sid}:${target} 失败: ${e.message}`)
|
|
244
319
|
}
|
|
245
320
|
}
|
|
321
|
+
for (const target of subTargets) {
|
|
322
|
+
try {
|
|
323
|
+
await bot.sendMessage(target, parts)
|
|
324
|
+
if (config.verbose) logger.info(`[schedule] 已发送任务 "${name}" 到订阅群 ${bot.sid}:${target}`)
|
|
325
|
+
}
|
|
326
|
+
catch (e) {
|
|
327
|
+
logger.error(`[schedule] 发送到订阅群 ${bot.sid}:${target} 失败: ${e.message}`)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
246
330
|
}
|
|
247
331
|
else if (config.sendAllWhenEmpty) {
|
|
248
|
-
//
|
|
332
|
+
// 未指定群也没有订阅 → 发送给该 bot 所有已知群
|
|
249
333
|
const targets = [...knownGroups.values()].filter(g => g.botSid === bot.sid)
|
|
250
334
|
if (!targets.length) {
|
|
251
335
|
logger.warn(`[schedule] 任务 "${name}" 未指定群且机器人 ${bot.sid} 暂无已知群(先让机器人收过该群消息,或用 schedule.groups 查看)`)
|
|
@@ -285,25 +369,33 @@ function apply(ctx, config) {
|
|
|
285
369
|
return '📋 机器人已知群:\n' + lines.join('\n') + '\n(官机的群 ID 是 openid,填入任务 groups 即可)'
|
|
286
370
|
}
|
|
287
371
|
|
|
372
|
+
function formatTaskList() {
|
|
373
|
+
const tasks = config.tasks || {}
|
|
374
|
+
const keys = Object.keys(tasks)
|
|
375
|
+
if (!keys.length) return '暂无定时任务\n请在插件设置页的 tasks 表格中添加'
|
|
376
|
+
return keys.map(k => {
|
|
377
|
+
const t = tasks[k]
|
|
378
|
+
const s = t.enabled === false ? '⛔' : '✅'
|
|
379
|
+
const content = [t.text && '文字', t.image && '图片'].filter(Boolean).join('+') || '(空)'
|
|
380
|
+
const staticGroups = (t.groups || []).join(',')
|
|
381
|
+
const subCount = (subs.get(k) || new Map()).size
|
|
382
|
+
const target = staticGroups ? staticGroups : (subCount ? `订阅${subCount}群` : '所有已知群')
|
|
383
|
+
return `${s} ${k} @ ${t.time} → ${content} → 群:${target}${subCount && staticGroups ? ` +订阅${subCount}群` : ''}`
|
|
384
|
+
}).join('\n')
|
|
385
|
+
}
|
|
386
|
+
|
|
288
387
|
ctx.command('schedule', '定时发送管理')
|
|
289
388
|
.action(() => {
|
|
290
389
|
logger.info('[schedule] 命令被调用: schedule')
|
|
291
|
-
return '⚙️ 管理:插件设置页 → ll-schedule → tasks
|
|
292
|
-
|
|
390
|
+
return '⚙️ 管理:插件设置页 → ll-schedule → tasks 表格设置时间和内容\n' +
|
|
391
|
+
`群内发"${config.subscribeKeyword} 任务名"即可让本群订阅推送\n` +
|
|
392
|
+
`命令:${config.subscribeKeyword} | ${config.unsubscribeKeyword} | 订阅列表 | schedule.list | schedule.groups | schedule.test <任务名>`
|
|
293
393
|
})
|
|
294
394
|
|
|
295
395
|
ctx.command('schedule.list', '查看定时任务')
|
|
296
396
|
.action(() => {
|
|
297
397
|
logger.info('[schedule] 命令被调用: schedule.list')
|
|
298
|
-
|
|
299
|
-
const keys = Object.keys(tasks)
|
|
300
|
-
if (!keys.length) return '暂无定时任务\n请在插件设置页的 tasks 表格中添加'
|
|
301
|
-
return keys.map(k => {
|
|
302
|
-
const t = tasks[k]
|
|
303
|
-
const s = t.enabled === false ? '⛔' : '✅'
|
|
304
|
-
const content = [t.text && '文字', t.image && '图片'].filter(Boolean).join('+') || '(空)'
|
|
305
|
-
return `${s} ${k} @ ${t.time} → ${content} → 群:${(t.groups || []).join(',') || '所有已知群'}`
|
|
306
|
-
}).join('\n')
|
|
398
|
+
return formatTaskList()
|
|
307
399
|
})
|
|
308
400
|
|
|
309
401
|
ctx.command('schedule.groups', '查看机器人已知的群(官机显示 openid)')
|
|
@@ -318,7 +410,7 @@ function apply(ctx, config) {
|
|
|
318
410
|
const tasks = config.tasks || {}
|
|
319
411
|
const task = tasks[name]
|
|
320
412
|
if (!task) return `未找到任务 "${name}",可用 schedule.list 查看任务名`
|
|
321
|
-
//
|
|
413
|
+
// 测试时:任务没配群也没订阅就发到当前群
|
|
322
414
|
const testTask = { ...task }
|
|
323
415
|
if (!testTask.groups || !testTask.groups.length) {
|
|
324
416
|
testTask.groups = session.guildId ? [String(session.guildId)] : []
|
|
@@ -327,25 +419,115 @@ function apply(ctx, config) {
|
|
|
327
419
|
return `✅ 已发送任务 "${name}"`
|
|
328
420
|
})
|
|
329
421
|
|
|
422
|
+
// ===== 群内订阅命令 =====
|
|
423
|
+
// 解析订阅命令的任务名:明确指定 → 用它;不填且只有一个启用任务 → 用它;否则返回提示
|
|
424
|
+
function resolveSubscribeTaskName(taskName) {
|
|
425
|
+
const tasks = config.tasks || {}
|
|
426
|
+
if (taskName) {
|
|
427
|
+
if (!tasks[taskName]) return { name: null, hint: `未找到任务 "${taskName}",可用"订阅列表"或 lls.list 查看任务名` }
|
|
428
|
+
return { name: taskName, hint: null }
|
|
429
|
+
}
|
|
430
|
+
const names = Object.keys(tasks).filter(k => tasks[k] && tasks[k].enabled !== false)
|
|
431
|
+
if (names.length === 1) return { name: names[0], hint: null }
|
|
432
|
+
if (names.length === 0) return { name: null, hint: '暂无启用的任务,请先在插件设置页的 tasks 表格中添加' }
|
|
433
|
+
return { name: null, hint: `有多个任务,请指定任务名:${names.join(' / ')}` }
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async function subscribeCurrentGroup(session, taskName) {
|
|
437
|
+
logger.info(`[schedule] 命令被调用: 订阅 taskName=${taskName || '(自动)'}`)
|
|
438
|
+
if (!session.guildId || !session.bot) return '❌ 订阅只能在群聊里使用'
|
|
439
|
+
const { name, hint } = resolveSubscribeTaskName(taskName)
|
|
440
|
+
if (!name) return hint
|
|
441
|
+
const task = config.tasks[name]
|
|
442
|
+
const key = `${session.bot.sid}:${session.guildId}`
|
|
443
|
+
const taskSubs = getTaskSubs(name)
|
|
444
|
+
if (taskSubs.has(key)) return `ℹ️ 本群已在任务 "${name}" 的推送列表里`
|
|
445
|
+
const entry = { botSid: session.bot.sid, guildId: session.guildId, createdAt: Date.now() }
|
|
446
|
+
taskSubs.set(key, entry)
|
|
447
|
+
persistSub(name, entry)
|
|
448
|
+
logger.info(`[schedule] 群 ${session.guildId} 已订阅任务 "${name}"`)
|
|
449
|
+
return `✅ 本群已加入任务 "${name}" 的推送列表\n时间:${task.time}\n内容:${task.text || '(图片)'}`
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function unsubscribeCurrentGroup(session, taskName) {
|
|
453
|
+
logger.info(`[schedule] 命令被调用: 取消订阅 taskName=${taskName || '(自动)'}`)
|
|
454
|
+
if (!session.guildId || !session.bot) return '❌ 取消订阅只能在群聊里使用'
|
|
455
|
+
const { name, hint } = resolveSubscribeTaskName(taskName)
|
|
456
|
+
if (!name) return hint
|
|
457
|
+
const taskSubs = subs.get(name)
|
|
458
|
+
const key = `${session.bot.sid}:${session.guildId}`
|
|
459
|
+
if (!taskSubs || !taskSubs.has(key)) return `ℹ️ 本群不在任务 "${name}" 的推送列表里`
|
|
460
|
+
taskSubs.delete(key)
|
|
461
|
+
removeSub(name, session.bot.sid, session.guildId)
|
|
462
|
+
logger.info(`[schedule] 群 ${session.guildId} 已取消订阅任务 "${name}"`)
|
|
463
|
+
return `✅ 本群已取消订阅任务 "${name}"`
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
ctx.command(config.subscribeKeyword + ' [taskName:text]', '让当前群订阅指定任务的推送', { authority: config.subscribeAuthority })
|
|
467
|
+
.action(async ({ session }, taskName) => {
|
|
468
|
+
return await subscribeCurrentGroup(session, taskName)
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
ctx.command('lls.sub [taskName:text]', '订阅推送(备用入口)', { authority: config.subscribeAuthority })
|
|
472
|
+
.action(async ({ session }, taskName) => {
|
|
473
|
+
return await subscribeCurrentGroup(session, taskName)
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
ctx.command(config.unsubscribeKeyword + ' [taskName:text]', '让当前群取消订阅指定任务的推送', { authority: config.subscribeAuthority })
|
|
477
|
+
.action(async ({ session }, taskName) => {
|
|
478
|
+
return await unsubscribeCurrentGroup(session, taskName)
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
ctx.command('lls.unsub [taskName:text]', '取消订阅(备用入口)', { authority: config.subscribeAuthority })
|
|
482
|
+
.action(async ({ session }, taskName) => {
|
|
483
|
+
return await unsubscribeCurrentGroup(session, taskName)
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
ctx.command('订阅列表', '查看所有任务的订阅群')
|
|
487
|
+
.action(async () => {
|
|
488
|
+
logger.info('[schedule] 命令被调用: 订阅列表')
|
|
489
|
+
if (!subs.size) return '暂无任何群订阅。群内发"' + config.subscribeKeyword + ' 任务名"即可订阅'
|
|
490
|
+
const lines = []
|
|
491
|
+
for (const [taskName, taskSubs] of subs) {
|
|
492
|
+
const entries = [...taskSubs.values()]
|
|
493
|
+
lines.push(`【${taskName}】${entries.length} 个群`)
|
|
494
|
+
for (const s of entries) {
|
|
495
|
+
const bot = ctx.bots.find(b => b.sid === s.botSid)
|
|
496
|
+
const name = bot ? await resolveGroupName(bot, s.guildId) : ''
|
|
497
|
+
lines.push(` · ${name || '未知群名'} (${s.guildId})`)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return '📋 订阅列表:\n' + lines.join('\n')
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
ctx.command('lls.sublist', '查看订阅列表(备用入口)')
|
|
504
|
+
.action(async () => {
|
|
505
|
+
logger.info('[schedule] 命令被调用: lls.sublist')
|
|
506
|
+
if (!subs.size) return '暂无任何群订阅。群内发"' + config.subscribeKeyword + ' 任务名"即可订阅'
|
|
507
|
+
const lines = []
|
|
508
|
+
for (const [taskName, taskSubs] of subs) {
|
|
509
|
+
const entries = [...taskSubs.values()]
|
|
510
|
+
lines.push(`【${taskName}】${entries.length} 个群`)
|
|
511
|
+
for (const s of entries) {
|
|
512
|
+
const bot = ctx.bots.find(b => b.sid === s.botSid)
|
|
513
|
+
const name = bot ? await resolveGroupName(bot, s.guildId) : ''
|
|
514
|
+
lines.push(` · ${name || '未知群名'} (${s.guildId})`)
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return '📋 订阅列表:\n' + lines.join('\n')
|
|
518
|
+
})
|
|
519
|
+
|
|
330
520
|
// 备用命令入口(避免与其他插件的 schedule 命令冲突)
|
|
331
521
|
ctx.command('lls', 'll-schedule 管理(备用入口)')
|
|
332
522
|
.action(() => {
|
|
333
523
|
logger.info('[schedule] 命令被调用: lls')
|
|
334
|
-
return
|
|
524
|
+
return `⚙️ 备用入口:lls.list / lls.groups / lls.test <任务名> / lls.sub / lls.unsub / lls.sublist`
|
|
335
525
|
})
|
|
336
526
|
|
|
337
527
|
ctx.command('lls.list', '查看定时任务(备用入口)')
|
|
338
528
|
.action(() => {
|
|
339
529
|
logger.info('[schedule] 命令被调用: lls.list')
|
|
340
|
-
|
|
341
|
-
const keys = Object.keys(tasks)
|
|
342
|
-
if (!keys.length) return '暂无定时任务\n请在插件设置页的 tasks 表格中添加'
|
|
343
|
-
return keys.map(k => {
|
|
344
|
-
const t = tasks[k]
|
|
345
|
-
const s = t.enabled === false ? '⛔' : '✅'
|
|
346
|
-
const content = [t.text && '文字', t.image && '图片'].filter(Boolean).join('+') || '(空)'
|
|
347
|
-
return `${s} ${k} @ ${t.time} → ${content} → 群:${(t.groups || []).join(',') || '所有已知群'}`
|
|
348
|
-
}).join('\n')
|
|
530
|
+
return formatTaskList()
|
|
349
531
|
})
|
|
350
532
|
|
|
351
533
|
ctx.command('lls.groups', '查看机器人已知的群(备用入口,官机显示 openid)')
|
|
@@ -368,10 +550,11 @@ function apply(ctx, config) {
|
|
|
368
550
|
return `✅ 已发送任务 "${name}"`
|
|
369
551
|
})
|
|
370
552
|
|
|
371
|
-
logger.info('[schedule] 命令已注册: schedule / schedule.list / schedule.groups / schedule.test /
|
|
553
|
+
logger.info('[schedule] 命令已注册: schedule / schedule.list / schedule.groups / schedule.test / ' +
|
|
554
|
+
`"${config.subscribeKeyword}" / "${config.unsubscribeKeyword}" / 订阅列表 / lls.*`)
|
|
372
555
|
|
|
373
|
-
// 启动时:加载已知群 + 立即检查一次
|
|
374
|
-
loadKnownGroups().then(() => checkAndSend())
|
|
556
|
+
// 启动时:加载已知群 + 订阅 + 立即检查一次
|
|
557
|
+
Promise.all([loadKnownGroups(), loadSubs()]).then(() => checkAndSend())
|
|
375
558
|
}
|
|
376
559
|
|
|
377
560
|
exports.apply = apply
|