koishi-plugin-chat-patch 2.2.0 → 2.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.
@@ -9,13 +9,15 @@ export declare class MessageHandler {
9
9
  private utils;
10
10
  private correctChannelIds;
11
11
  constructor(ctx: Context, config: Config, fileManager: FileManager);
12
+ recordUserMessage(session: Session, timestamp: number): void;
13
+ recordBotMessage(session: Session, timestamp: number): void;
12
14
  setCorrectChannelId(selfId: string, channelId: string): void;
13
15
  getCorrectChannelId(selfId: string): string | undefined;
14
- updateBotInfoToFile(session: Session): Promise<void>;
15
- updateChannelInfoToFile(session: Session): Promise<string>;
16
+ updateBotInfoToFile(session: Session): void;
17
+ updateChannelInfoToFile(session: Session): string;
16
18
  downloadAndCacheMedia(url: string, type: 'image' | 'media' | 'avatar'): Promise<any>;
17
- private processMediaElements;
18
- broadcastMessageEvent(session: Session): Promise<void>;
19
- broadcastBotMessageEvent(session: Session): Promise<void>;
19
+ private processMediaElementsAsync;
20
+ private processUserMessage;
21
+ private processBotMessage;
20
22
  private logInfo;
21
23
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-chat-patch",
3
3
  "description": "[<ruby>chat-patch<rp>(</rp><rt>点我预览效果</rt><rp>)</rp></ruby>](https://i0.hdslb.com/bfs/openplatform/71074dfc9e5256fc3333d8bd8478bec1af874046.png) 视奸小插件((bushi( (低性能警告)。手机端适配。灵感来自 chat 插件。",
4
- "version": "2.2.0",
4
+ "version": "2.3.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -1,25 +1,25 @@
1
- # koishi-plugin-chat-patch
2
-
3
- [![npm](https://img.shields.io/npm/v/koishi-plugin-chat-patch?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-chat-patch) [![npm downloads](https://img.shields.io/npm/dm/koishi-plugin-chat-patch)](https://www.npmjs.com/package/koishi-plugin-chat-patch)
4
-
5
- Koishi 控制台聊天插件,允许用户直接在控制台中管理机器人、频道和消息。
6
-
7
- 支持消息的收发、图片缓存、频道置顶等。
8
-
9
- ## ✨ 功能特性
10
-
11
- - **聊天界面**:在 Koishi 控制台内直接查看机器人的聊天记录。
12
- - **消息收发**:支持接收文本、图片等多种类型的消息。
13
- - **图片缓存**:通过 IndexedDB 缓存图片,优化加载速度并减少网络请求。
14
- - **手机端优化**:针对手机端进行适配,提供滑动返回等手势操作,并可配置聊天容器高度以防止输入框被遮挡。
15
- - **平台屏蔽**:可配置屏蔽特定平台的消息,避免不必要的干扰。
16
-
17
- ## 🛠️ 开发与贡献
18
-
19
- 欢迎 PR ~
20
-
21
- PR 方式请参考 -> <https://github.com/koishi-shangxue-plugins/koishi-shangxue-apps/tree/main?tab=readme-ov-file#%E5%A6%82%E4%BD%95%E5%9C%A8%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF%E4%B8%AD%E5%BC%80%E5%8F%91%E6%AD%A4%E4%BB%93%E5%BA%93>
22
-
23
- ## 许可证
24
-
25
- 本项目采用 [MIT 许可证](LICENSE) 开源。
1
+ # koishi-plugin-chat-patch
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-chat-patch?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-chat-patch) [![npm downloads](https://img.shields.io/npm/dm/koishi-plugin-chat-patch)](https://www.npmjs.com/package/koishi-plugin-chat-patch)
4
+
5
+ Koishi 控制台聊天插件,允许用户直接在控制台中管理机器人、频道和消息。
6
+
7
+ 支持消息的收发、图片缓存、频道置顶等。
8
+
9
+ ## ✨ 功能特性
10
+
11
+ - **聊天界面**:在 Koishi 控制台内直接查看机器人的聊天记录。
12
+ - **消息收发**:支持接收文本、图片等多种类型的消息。
13
+ - **图片缓存**:通过 IndexedDB 缓存图片,优化加载速度并减少网络请求。
14
+ - **手机端优化**:针对手机端进行适配,提供滑动返回等手势操作,并可配置聊天容器高度以防止输入框被遮挡。
15
+ - **平台屏蔽**:可配置屏蔽特定平台的消息,避免不必要的干扰。
16
+
17
+ ## 🛠️ 开发与贡献
18
+
19
+ 欢迎 PR ~
20
+
21
+ PR 方式请参考 -> <https://github.com/koishi-shangxue-plugins/koishi-shangxue-apps/tree/main?tab=readme-ov-file#%E5%A6%82%E4%BD%95%E5%9C%A8%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF%E4%B8%AD%E5%BC%80%E5%8F%91%E6%AD%A4%E4%BB%93%E5%BA%93>
22
+
23
+ ## 许可证
24
+
25
+ 本项目采用 [MIT 许可证](LICENSE) 开源。
@@ -9,7 +9,7 @@ import * as mime from 'mime-types'
9
9
 
10
10
  export class ApiHandlers {
11
11
  private logger: Logger
12
- // 当前临时缓存的视频文件路径
12
+
13
13
  private currentTempVideo: string | null = null
14
14
 
15
15
  constructor(
@@ -25,7 +25,7 @@ export class ApiHandlers {
25
25
  this.ctx.console.addListener('clear-all-indexeddb-data' as any, async () => {
26
26
  try {
27
27
  this.logInfo('收到清空 IndexedDB 数据请求')
28
- // 这个 API 主要用于前端调用,后端不直接操作 IndexedDB
28
+
29
29
  return { success: true, message: '可以清空 IndexedDB' }
30
30
  } catch (error: any) {
31
31
  this.logger.error('清空 IndexedDB 数据失败:', error)
@@ -33,10 +33,9 @@ export class ApiHandlers {
33
33
  }
34
34
  })
35
35
 
36
- // 获取所有聊天数据的 API
37
36
  this.ctx.console.addListener('get-chat-data' as any, async () => {
38
37
  try {
39
- // 优化性能:只读取基础信息,不读取庞大的消息体
38
+
40
39
  const data = this.fileManager.readChatDataFromFile()
41
40
 
42
41
  this.logInfo('获取基础聊天数据')
@@ -48,7 +47,7 @@ export class ApiHandlers {
48
47
  channels: data.channels || {},
49
48
  pinnedBots: data.pinnedBots || [],
50
49
  pinnedChannels: data.pinnedChannels || [],
51
- // 不返回 messages,由前端按需拉取
50
+
52
51
  messages: {}
53
52
  }
54
53
  }
@@ -58,7 +57,6 @@ export class ApiHandlers {
58
57
  }
59
58
  })
60
59
 
61
- // 获取历史消息的 API
62
60
  this.ctx.console.addListener('get-history-messages' as any, async (requestData: {
63
61
  selfId: string
64
62
  channelId: string
@@ -70,18 +68,16 @@ export class ApiHandlers {
70
68
  const channelKey = `${requestData.selfId}:${requestData.channelId}`
71
69
  let messages = data.messages[channelKey] || []
72
70
 
73
- // 按时间戳降序排列(最新的消息在前面)
74
71
  const sortedMessages = messages.sort((a, b) => b.timestamp - a.timestamp)
75
72
 
76
- // 如果提供了分页参数,则进行分页处理
77
73
  if (requestData.limit !== undefined) {
78
74
  const limit = requestData.limit
79
75
  const offset = requestData.offset || 0
80
76
  messages = sortedMessages.slice(offset, offset + limit)
81
- // 重新按时间戳升序排列,以保持消息显示顺序
77
+
82
78
  messages = messages.sort((a, b) => a.timestamp - b.timestamp)
83
79
  } else {
84
- // 默认返回所有消息,按时间戳升序排列
80
+
85
81
  messages = sortedMessages.sort((a, b) => a.timestamp - b.timestamp)
86
82
  }
87
83
 
@@ -98,7 +94,6 @@ export class ApiHandlers {
98
94
  }
99
95
  })
100
96
 
101
- // 获取所有频道消息数量的 API
102
97
  this.ctx.console.addListener('get-all-channel-message-counts' as any, async () => {
103
98
  try {
104
99
  const data = this.fileManager.readChatDataFromFile()
@@ -123,16 +118,14 @@ export class ApiHandlers {
123
118
  }
124
119
  })
125
120
 
126
- // 图片获取 API
127
121
  this.ctx.console.addListener('fetch-image' as any, async (data: { url: string }) => {
128
122
  try {
129
- // 检查是否是本地文件路径
123
+
130
124
  if (this.isFileUrl(data.url)) {
131
125
  this.logInfo('处理本地文件请求:', data.url)
132
126
  return await this.handleLocalFileRequest(data.url)
133
127
  }
134
128
 
135
- // 处理网络图片
136
129
  const response = await fetch(data.url, {
137
130
  headers: {
138
131
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
@@ -158,7 +151,6 @@ export class ApiHandlers {
158
151
  }
159
152
  })
160
153
 
161
- // 清理频道历史记录的 API
162
154
  this.ctx.console.addListener('clear-channel-history' as any, async (data: {
163
155
  selfId: string
164
156
  channelId: string
@@ -208,7 +200,6 @@ export class ApiHandlers {
208
200
  }
209
201
  })
210
202
 
211
- // 发送消息的 API
212
203
  this.ctx.console.addListener('send-message' as any, async (data: {
213
204
  selfId: string
214
205
  channelId: string
@@ -221,14 +212,12 @@ export class ApiHandlers {
221
212
  try {
222
213
  this.logInfo('收到发送消息请求:', data)
223
214
 
224
- // 优化机器人查找逻辑
225
215
  const bot = this.ctx.bots.find((bot: any) => bot.selfId === data.selfId || bot.user?.id === data.selfId)
226
216
  if (!bot) {
227
217
  this.logger.error('未找到机器人:', data.selfId, '当前可用机器人:', this.ctx.bots.map((b: any) => b.selfId))
228
218
  return { success: false, error: `未找到机器人 ${data.selfId},请检查机器人是否在线` }
229
219
  }
230
220
 
231
- // 检查机器人状态
232
221
  if (bot.status !== Universal.Status.ONLINE) {
233
222
  this.logger.error('机器人离线:', data.selfId, '状态:', bot.status)
234
223
  return { success: false, error: `机器人 ${data.selfId} 当前离线` }
@@ -236,7 +225,6 @@ export class ApiHandlers {
236
225
 
237
226
  let messageContent = data.content
238
227
 
239
- // 如果有图片,添加图片元素
240
228
  if (data.images && data.images.length > 0) {
241
229
  const tempDir = this.ctx.baseDir + '/data/chat-patch/temp'
242
230
 
@@ -247,7 +235,7 @@ export class ApiHandlers {
247
235
 
248
236
  if (files.length > 0) {
249
237
  const imagePath = `${tempDir}/${files[0]}`
250
- // 使用 pathToFileURL 创建正确的文件 URL
238
+
251
239
  const fileUrl = this.createFileUrl(imagePath)
252
240
  messageContent += h.image(fileUrl).toString()
253
241
  this.logInfo('添加图片到消息:', { imagePath, fileUrl })
@@ -257,7 +245,6 @@ export class ApiHandlers {
257
245
 
258
246
  const parsedContent = h.parse(messageContent)
259
247
 
260
- // 在发送消息前,通知 MessageHandler 正确的 channelId
261
248
  this.messageHandler.setCorrectChannelId(data.selfId, data.channelId)
262
249
 
263
250
  const result = await bot.sendMessage(data.channelId, parsedContent)
@@ -265,19 +252,17 @@ export class ApiHandlers {
265
252
 
266
253
  const messageId = Array.isArray(result) ? result[0] : result;
267
254
 
268
- // 发送成功后,更新本地存储中的虚拟消息为真实 ID
269
255
  if (messageId) {
270
256
  const chatData = this.fileManager.readChatDataFromFile()
271
257
  const channelKey = `${data.selfId}:${data.channelId}`
272
258
  const messages = chatData.messages[channelKey] || []
273
- // 找到最近的一条正在发送的机器人消息
259
+
274
260
  const msg = [...messages].reverse().find(m => m.type === 'bot' && m.sending)
275
261
  if (msg) {
276
262
  msg.realId = messageId;
277
263
  msg.sending = false;
278
264
  this.fileManager.writeChatDataToFile(chatData)
279
265
 
280
- // 广播更新事件给前端
281
266
  this.ctx.console.broadcast('bot-message-updated', {
282
267
  channelKey,
283
268
  tempId: msg.id,
@@ -297,14 +282,12 @@ export class ApiHandlers {
297
282
  }
298
283
  })
299
284
 
300
- // 清理临时图片的 API(由前端在消息发送成功后调用)
301
285
  this.ctx.console.addListener('cleanup-temp-images' as any, async (data: {
302
286
  tempImageIds: string[]
303
287
  }) => {
304
288
  try {
305
289
  this.logInfo('收到清理临时图片请求:', data.tempImageIds)
306
290
 
307
- // 不立即删除,只是记录日志,让定时任务处理清理
308
291
  this.logInfo('临时图片将由定时任务清理,保持文件可用性')
309
292
 
310
293
  return { success: true, cleanedCount: 0 }
@@ -314,7 +297,6 @@ export class ApiHandlers {
314
297
  }
315
298
  })
316
299
 
317
- // 删除机器人所有数据的 API
318
300
  this.ctx.console.addListener('delete-bot-data' as any, async (data: {
319
301
  selfId: string
320
302
  }) => {
@@ -356,7 +338,6 @@ export class ApiHandlers {
356
338
  }
357
339
  })
358
340
 
359
- // 删除频道所有数据的 API
360
341
  this.ctx.console.addListener('delete-channel-data' as any, async (data: {
361
342
  selfId: string
362
343
  channelId: string
@@ -394,7 +375,6 @@ export class ApiHandlers {
394
375
  }
395
376
  })
396
377
 
397
- // 设置置顶机器人列表的 API
398
378
  this.ctx.console.addListener('set-pinned-bots' as any, async (data: {
399
379
  pinnedBots: string[]
400
380
  }) => {
@@ -410,7 +390,6 @@ export class ApiHandlers {
410
390
  }
411
391
  })
412
392
 
413
- // 设置置顶频道列表的 API
414
393
  this.ctx.console.addListener('set-pinned-channels' as any, async (data: {
415
394
  pinnedChannels: string[]
416
395
  }) => {
@@ -426,26 +405,22 @@ export class ApiHandlers {
426
405
  }
427
406
  })
428
407
 
429
- // 上传图片的 API
430
408
  this.ctx.console.addListener('upload-image' as any, async (data: {
431
- file: string // base64 encoded image
409
+ file: string
432
410
  filename: string
433
411
  mimeType: string
434
- isGif?: boolean // 是否为GIF图片
412
+ isGif?: boolean
435
413
  }) => {
436
414
  try {
437
415
  this.logInfo('收到图片上传请求:', { filename: data.filename, mimeType: data.mimeType, isGif: data.isGif })
438
416
 
439
- // 将base64转换为Buffer
440
417
  const base64Data = data.file.replace(/^data:image\/\w+;base64,/, '')
441
418
  const buffer = Buffer.from(base64Data, 'base64')
442
419
 
443
- // 生成临时文件路径,保持原始扩展名以保持GIF格式
444
420
  const tempId = Date.now() + '_' + Math.random().toString(36).substring(2, 11)
445
421
  const extension = data.filename.split('.').pop()?.toLowerCase() || (data.isGif ? 'gif' : 'jpg')
446
422
  const tempFilename = `temp_${tempId}.${extension}`
447
423
 
448
- // 保存到临时目录
449
424
  const tempDir = this.ctx.baseDir + '/data/chat-patch/temp'
450
425
  if (!require('fs').existsSync(tempDir)) {
451
426
  require('fs').mkdirSync(tempDir, { recursive: true })
@@ -453,7 +428,6 @@ export class ApiHandlers {
453
428
 
454
429
  const tempPath = `${tempDir}/${tempFilename}`
455
430
 
456
- // 对于GIF文件,直接保存原始数据以保持动画
457
431
  require('fs').writeFileSync(tempPath, buffer)
458
432
 
459
433
  this.logInfo('图片上传成功:', { tempPath, size: buffer.length, isGif: data.isGif })
@@ -472,7 +446,6 @@ export class ApiHandlers {
472
446
  }
473
447
  })
474
448
 
475
- // 删除临时图片的 API
476
449
  this.ctx.console.addListener('delete-temp-image' as any, async (data: {
477
450
  tempId: string
478
451
  }) => {
@@ -497,10 +470,8 @@ export class ApiHandlers {
497
470
  }
498
471
  })
499
472
 
500
- // 定时清理过期临时文件(备用机制)
501
473
  this.setupTempFileCleanup()
502
474
 
503
- // 获取插件配置的 API
504
475
  this.ctx.console.addListener('get-plugin-config' as any, async () => {
505
476
  try {
506
477
  return {
@@ -520,13 +491,11 @@ export class ApiHandlers {
520
491
  }
521
492
  })
522
493
 
523
- // 获取用户信息 API
524
494
  this.ctx.console.addListener('get-user-info' as any, async (data: { selfId: string, userId: string, guildId?: string }) => {
525
495
  try {
526
496
  const bot = this.ctx.bots.find(b => b.selfId === data.selfId)
527
497
  if (!bot) return { success: false, error: '机器人不存在' }
528
498
 
529
- // 检查平台是否支持 getUser 方法
530
499
  if (!bot.getUser || typeof bot.getUser !== 'function') {
531
500
  return { success: false, error: '此平台不支持查看用户信息' }
532
501
  }
@@ -534,7 +503,7 @@ export class ApiHandlers {
534
503
  const user = await bot.getUser(data.userId, data.guildId)
535
504
 
536
505
  if (user) {
537
- // 缓存头像到本地
506
+
538
507
  if (user.avatar) {
539
508
  user.avatar = await this.messageHandler.downloadAndCacheMedia(user.avatar, 'avatar')
540
509
  }
@@ -542,10 +511,8 @@ export class ApiHandlers {
542
511
  const chatData = this.fileManager.readChatDataFromFile()
543
512
  let changed = false
544
513
 
545
- // 1. 如果是私聊,更新频道名 - 支持多种私聊ID格式
546
514
  const botChannels = chatData.channels[data.selfId] || {}
547
515
 
548
- // 查找所有可能的私聊频道ID格式
549
516
  const possibleChannelIds = [
550
517
  data.userId,
551
518
  `private:${data.userId}`,
@@ -564,7 +531,6 @@ export class ApiHandlers {
564
531
  }
565
532
  }
566
533
 
567
- // 2. 更新该用户在所有历史消息中的头像和昵称(持久化缓存)
568
534
  const channelKeyPrefix = `${data.selfId}:`
569
535
  for (const [key, messages] of Object.entries(chatData.messages)) {
570
536
  if (key.startsWith(channelKeyPrefix)) {
@@ -585,7 +551,7 @@ export class ApiHandlers {
585
551
 
586
552
  if (changed) {
587
553
  this.fileManager.writeChatDataToFile(chatData)
588
- // 广播更新事件,让前端实时刷新
554
+
589
555
  this.ctx.console.broadcast('chat-data-updated', {})
590
556
  }
591
557
  }
@@ -596,7 +562,6 @@ export class ApiHandlers {
596
562
  }
597
563
  })
598
564
 
599
- // 调试API:获取原始文件数据
600
565
  this.ctx.console.addListener('debug-get-raw-data' as any, async () => {
601
566
  try {
602
567
  const data = this.fileManager.readChatDataFromFile()
@@ -610,18 +575,15 @@ export class ApiHandlers {
610
575
  }
611
576
  })
612
577
 
613
- // 按需加载视频的临时缓存 API - 返回 base64 供前端转换为 blob
614
578
  this.ctx.console.addListener('fetch-video-temp' as any, async (data: { url: string }) => {
615
579
  try {
616
580
  this.logInfo('收到视频临时加载请求:', data.url)
617
581
 
618
- // 检查是否是本地文件
619
582
  if (this.isFileUrl(data.url)) {
620
583
  const result = await this.handleLocalFileRequest(data.url)
621
584
  return result
622
585
  }
623
586
 
624
- // 下载视频并返回 base64
625
587
  const response = await fetch(data.url, {
626
588
  headers: {
627
589
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
@@ -636,7 +598,6 @@ export class ApiHandlers {
636
598
  const buffer = await response.arrayBuffer()
637
599
  const base64 = Buffer.from(buffer).toString('base64')
638
600
 
639
- // 尝试从 Content-Type 获取 MIME 类型
640
601
  const contentType = response.headers.get('content-type') || 'video/mp4'
641
602
 
642
603
  this.logInfo('视频下载成功:', { size: buffer.byteLength, contentType })
@@ -655,7 +616,6 @@ export class ApiHandlers {
655
616
  })
656
617
  }
657
618
 
658
- // 检查是否为文件 URL
659
619
  private isFileUrl(url: string): boolean {
660
620
  try {
661
621
  const parsedUrl = new URL(url)
@@ -665,28 +625,24 @@ export class ApiHandlers {
665
625
  }
666
626
  }
667
627
 
668
- // 创建文件 URL
669
628
  private createFileUrl(filePath: string): string {
670
629
  try {
671
630
  return pathToFileURL(filePath).href
672
631
  } catch (error) {
673
632
  this.logger.error('创建文件URL失败:', { filePath, error })
674
- // 回退到简单的字符串拼接
633
+
675
634
  return `file://${filePath}`
676
635
  }
677
636
  }
678
637
 
679
- // 处理本地文件请求
680
638
  private async handleLocalFileRequest(fileUrl: string) {
681
639
  try {
682
- // 使用 fileURLToPath 转换 file:// URL 为系统路径
640
+
683
641
  const filePath = fileURLToPath(fileUrl)
684
642
 
685
- // 改用 node:fs 直接读取文件,避免 ctx.http.file 可能存在的编码或协议处理问题
686
643
  const buffer = readFileSync(filePath)
687
644
  const base64 = buffer.toString('base64')
688
645
 
689
- // 使用 mime-types 库精确推断 MIME 类型
690
646
  const contentType = mime.lookup(filePath) || 'application/octet-stream'
691
647
 
692
648
  this.logInfo('成功读取本地文件:', { fileUrl, filePath, contentType })
@@ -706,15 +662,13 @@ export class ApiHandlers {
706
662
  }
707
663
  }
708
664
 
709
- // 设置定时清理临时文件
710
665
  private setupTempFileCleanup() {
711
- // 每5分钟执行一次基于数量的清理
712
- setInterval(() => {
666
+
667
+ this.ctx.setInterval(() => {
713
668
  this.cleanupMediaCache()
714
669
  }, 5 * 60 * 1000)
715
670
  }
716
671
 
717
- // 统一清理媒体缓存
718
672
  private async cleanupMediaCache() {
719
673
  const baseDir = this.ctx.baseDir + '/data/chat-patch/persist-media'
720
674
  if (!require('node:fs').existsSync(baseDir)) return
@@ -738,8 +692,8 @@ export class ApiHandlers {
738
692
  }
739
693
  }
740
694
 
741
- cleanupDir('images', 100) // 图片缓存100个
742
- cleanupDir('media', 20) // 富媒体缓存20个
695
+ cleanupDir('images', 100)
696
+ cleanupDir('media', 20)
743
697
  }
744
698
 
745
699
  private logInfo(...args: any[]) {
package/src/config.ts CHANGED
@@ -1,46 +1,45 @@
1
- import { Schema } from 'koishi'
2
-
3
- export interface Config {
4
- loggerinfo: boolean
5
- clearIndexedDBOnStart: boolean
6
- maxMessagesPerChannel: number
7
- keepMessagesOnClear: number
8
- maxPersistImages: number
9
- blockedPlatforms: Array<{
10
- platformName: string
11
- exactMatch: boolean
12
- }>
13
- }
14
-
15
- export const Config: Schema<Config> = Schema.intersect([
16
- Schema.object({
17
- maxMessagesPerChannel: Schema.number().default(500).description('每个群组最大保存消息数量').min(50).max(1500).step(1),
18
- keepMessagesOnClear: Schema.number().default(50).description('手动清理历史记录时保留的消息数量').min(0).max(1000).step(1),
19
- maxPersistImages: Schema.number().default(100).description('持久化存储的图片缓存数量').min(10).max(500).step(1),
20
- blockedPlatforms: Schema.array(Schema.object({
21
- platformName: Schema.string().description('平台名称或关键词'),
22
- exactMatch: Schema.boolean().default(false).description('完全匹配?如果关闭,包含关键词即屏蔽').default(true)
23
- })).role('table').description('屏蔽的平台列表').default(
24
- [
25
- {
26
- "platformName": "qq",
27
- "exactMatch": true
28
- },
29
- {
30
- "platformName": "qqguild",
31
- "exactMatch": true
32
- },
33
- {
34
- "platformName": "sandbox",
35
- "exactMatch": false
36
- }
37
- ]
38
- ),
39
- }).description('基础设置'),
40
-
41
-
42
- Schema.object({
43
- clearIndexedDBOnStart: Schema.boolean().default(true).description('启动时强制清空IndexedDB缓存(适用于紧急情况,防止浏览器卡死)'),
44
- loggerinfo: Schema.boolean().default(false).description('日志调试模式').experimental(),
45
- }).description('开发者选项'),
46
- ])
1
+ import { Schema } from 'koishi'
2
+
3
+ export interface Config {
4
+ loggerinfo: boolean
5
+ clearIndexedDBOnStart: boolean
6
+ maxMessagesPerChannel: number
7
+ keepMessagesOnClear: number
8
+ maxPersistImages: number
9
+ blockedPlatforms: Array<{
10
+ platformName: string
11
+ exactMatch: boolean
12
+ }>
13
+ }
14
+
15
+ export const Config: Schema<Config> = Schema.intersect([
16
+ Schema.object({
17
+ maxMessagesPerChannel: Schema.number().default(500).description('每个群组最大保存消息数量').min(50).max(1500).step(1),
18
+ keepMessagesOnClear: Schema.number().default(50).description('手动清理历史记录时保留的消息数量').min(0).max(1000).step(1),
19
+ maxPersistImages: Schema.number().default(100).description('持久化存储的图片缓存数量').min(10).max(500).step(1),
20
+ blockedPlatforms: Schema.array(Schema.object({
21
+ platformName: Schema.string().description('平台名称或关键词'),
22
+ exactMatch: Schema.boolean().default(false).description('完全匹配?如果关闭,包含关键词即屏蔽').default(true)
23
+ })).role('table').description('屏蔽的平台列表').default(
24
+ [
25
+ {
26
+ "platformName": "qq",
27
+ "exactMatch": true
28
+ },
29
+ {
30
+ "platformName": "qqguild",
31
+ "exactMatch": true
32
+ },
33
+ {
34
+ "platformName": "sandbox",
35
+ "exactMatch": false
36
+ }
37
+ ]
38
+ ),
39
+ }).description('基础设置'),
40
+
41
+ Schema.object({
42
+ clearIndexedDBOnStart: Schema.boolean().default(true).description('启动时强制清空IndexedDB缓存(适用于紧急情况,防止浏览器卡死)'),
43
+ loggerinfo: Schema.boolean().default(false).description('日志调试模式').experimental(),
44
+ }).description('开发者选项'),
45
+ ])