koishi-plugin-chat-patch 1.0.10 → 1.0.11

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.
@@ -0,0 +1,17 @@
1
+ import { FileManager } from './file-manager';
2
+ import { Context } from 'koishi';
3
+ import { Config } from './config';
4
+ export declare class ApiHandlers {
5
+ private ctx;
6
+ private config;
7
+ private fileManager;
8
+ private logger;
9
+ constructor(ctx: Context, config: Config, fileManager: FileManager);
10
+ registerApiHandlers(): void;
11
+ private isFileUrl;
12
+ private createFileUrl;
13
+ private handleLocalFileRequest;
14
+ private setupTempFileCleanup;
15
+ private cleanupTempImagesByCount;
16
+ private logInfo;
17
+ }
@@ -0,0 +1,18 @@
1
+ import { ChatData, MessageInfo } from './types';
2
+ import { Context } from 'koishi';
3
+ import { Config } from './config';
4
+ export declare class FileManager {
5
+ private ctx;
6
+ private config;
7
+ private dataFilePath;
8
+ private fileOperationLock;
9
+ private logger;
10
+ private utils;
11
+ constructor(ctx: Context, config: Config);
12
+ private ensureDataDir;
13
+ readChatDataFromFile(): ChatData;
14
+ writeChatDataToFile(data: ChatData): void;
15
+ cleanExcessMessages(data: ChatData): ChatData;
16
+ addMessageToFile(messageInfo: MessageInfo): Promise<void>;
17
+ private logInfo;
18
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ export declare const name = "chat-patch";
4
+ export declare const reusable = false;
5
+ export declare const filter = true;
6
+ export declare const inject: {
7
+ required: string[];
8
+ };
9
+ export declare const usage = "\n\n---\n\n\u5F00\u542F\u540E\uFF0C\u5373\u53EF\u5728koishi\u63A7\u5236\u53F0\u64CD\u4F5C\u673A\u5668\u4EBA\u6536\u53D1\u6D88\u606F\u5566\n\n\u6682\u65F6\u53EA\u652F\u6301\u63A5\u53D7\u56FE\u6587\u6D88\u606F / \u53D1\u9001\u6587\u5B57\u6D88\u606F\n\n---\n";
10
+ export { Config } from './config';
11
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
package/lib/index.js CHANGED
@@ -41,10 +41,6 @@ __export(src_exports, {
41
41
  module.exports = __toCommonJS(src_exports);
42
42
  var import_node_path2 = __toESM(require("node:path"));
43
43
 
44
- // src/file-manager.ts
45
- var import_node_path = __toESM(require("node:path"));
46
- var import_node_fs = __toESM(require("node:fs"));
47
-
48
44
  // src/utils.ts
49
45
  var Utils = class {
50
46
  constructor(config) {
@@ -128,147 +124,6 @@ var Utils = class {
128
124
  }
129
125
  };
130
126
 
131
- // src/file-manager.ts
132
- var FileManager = class {
133
- constructor(ctx, config) {
134
- this.ctx = ctx;
135
- this.config = config;
136
- this.dataFilePath = import_node_path.default.resolve(ctx.baseDir, "data", "chat-patch", "chat-data.json");
137
- this.logger = ctx.logger("chat-patch");
138
- this.utils = new Utils(config);
139
- }
140
- static {
141
- __name(this, "FileManager");
142
- }
143
- dataFilePath;
144
- fileOperationLock = Promise.resolve();
145
- logger;
146
- utils;
147
- // 确保目录存在
148
- ensureDataDir() {
149
- const dir = import_node_path.default.dirname(this.dataFilePath);
150
- if (!import_node_fs.default.existsSync(dir)) {
151
- import_node_fs.default.mkdirSync(dir, { recursive: true });
152
- }
153
- }
154
- // 从JSON文件读取数据
155
- readChatDataFromFile() {
156
- try {
157
- if (import_node_fs.default.existsSync(this.dataFilePath)) {
158
- const jsonData = import_node_fs.default.readFileSync(this.dataFilePath, "utf8");
159
- const data = JSON.parse(jsonData);
160
- return {
161
- bots: data.bots || {},
162
- channels: data.channels || {},
163
- messages: data.messages || {},
164
- pinnedBots: data.pinnedBots || [],
165
- pinnedChannels: data.pinnedChannels || [],
166
- lastSaveTime: data.lastSaveTime
167
- };
168
- }
169
- } catch (error) {
170
- this.logger.error("读取聊天数据失败:", error);
171
- }
172
- return {
173
- bots: {},
174
- channels: {},
175
- messages: {},
176
- pinnedBots: [],
177
- pinnedChannels: []
178
- };
179
- }
180
- // 写入数据到JSON文件
181
- writeChatDataToFile(data) {
182
- try {
183
- this.ensureDataDir();
184
- data.lastSaveTime = Date.now();
185
- const jsonData = JSON.stringify(data, null, 2);
186
- import_node_fs.default.writeFileSync(this.dataFilePath, jsonData, "utf8");
187
- } catch (error) {
188
- this.logger.error("写入聊天数据失败:", error);
189
- }
190
- }
191
- // 清理超量消息
192
- cleanExcessMessages(data) {
193
- let cleanedCount = 0;
194
- const cleanedMessages = {};
195
- for (const [channelKey, messages] of Object.entries(data.messages)) {
196
- if (messages.length > this.config.maxMessagesPerChannel) {
197
- const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp);
198
- const keptMessages = sortedMessages.slice(-this.config.maxMessagesPerChannel);
199
- cleanedCount += messages.length - keptMessages.length;
200
- cleanedMessages[channelKey] = keptMessages;
201
- this.logInfo(`频道 ${channelKey} 清理了 ${messages.length - keptMessages.length} 条旧消息,保留最新 ${keptMessages.length} 条`);
202
- } else {
203
- cleanedMessages[channelKey] = messages;
204
- }
205
- }
206
- if (cleanedCount > 0) {
207
- this.logInfo("总共清理超量消息:", cleanedCount, "条");
208
- }
209
- return {
210
- ...data,
211
- messages: cleanedMessages
212
- };
213
- }
214
- // 添加消息到JSON文件(使用锁机制防止并发冲突)
215
- async addMessageToFile(messageInfo) {
216
- this.fileOperationLock = this.fileOperationLock.then(async () => {
217
- const data = this.readChatDataFromFile();
218
- const channelKey = `${messageInfo.selfId}:${messageInfo.channelId}`;
219
- if (!data.messages[channelKey]) {
220
- data.messages[channelKey] = [];
221
- }
222
- const existingMessage = data.messages[channelKey].find((m) => m.id === messageInfo.id);
223
- if (existingMessage) {
224
- this.logInfo("消息已存在,跳过保存:", {
225
- channelKey,
226
- messageId: messageInfo.id,
227
- existingType: existingMessage.type,
228
- existingContent: existingMessage.content,
229
- newType: messageInfo.type,
230
- newContent: messageInfo.content
231
- });
232
- return;
233
- }
234
- if (!messageInfo.timestamp) {
235
- messageInfo.timestamp = Date.now();
236
- }
237
- const cleanedMessageInfo = this.utils.cleanBase64Content(messageInfo);
238
- const beforeCount = data.messages[channelKey].length;
239
- data.messages[channelKey].push(cleanedMessageInfo);
240
- const afterCount = data.messages[channelKey].length;
241
- if (data.messages[channelKey].length > this.config.maxMessagesPerChannel) {
242
- data.messages[channelKey].sort((a, b) => a.timestamp - b.timestamp);
243
- const removedCount = data.messages[channelKey].length - this.config.maxMessagesPerChannel;
244
- data.messages[channelKey] = data.messages[channelKey].slice(-this.config.maxMessagesPerChannel);
245
- this.logInfo(`频道 ${channelKey} 达到消息上限,清理了 ${removedCount} 条旧消息`);
246
- }
247
- this.writeChatDataToFile(data);
248
- const isCommandMessage = messageInfo.content?.startsWith("++") || messageInfo.content?.startsWith(".");
249
- this.logInfo("添加消息到文件:", {
250
- channelKey,
251
- messageId: messageInfo.id,
252
- content: messageInfo.content,
253
- type: messageInfo.type,
254
- userId: messageInfo.userId,
255
- username: messageInfo.username,
256
- timestamp: messageInfo.timestamp,
257
- isCommandMessage,
258
- 消息数变化: `${beforeCount} -> ${afterCount} -> ${data.messages[channelKey].length}`
259
- });
260
- }).catch((error) => {
261
- this.logger.error("保存消息时发生错误:", error);
262
- });
263
- await this.fileOperationLock;
264
- }
265
- logInfo(...args) {
266
- if (this.config.loggerinfo) {
267
- this.logger.info(...args);
268
- }
269
- }
270
- };
271
-
272
127
  // src/message-handler.ts
273
128
  var MessageHandler = class {
274
129
  constructor(ctx, config, fileManager) {
@@ -472,6 +327,149 @@ var MessageHandler = class {
472
327
  }
473
328
  };
474
329
 
330
+ // src/file-manager.ts
331
+ var import_node_path = __toESM(require("node:path"));
332
+ var import_node_fs = __toESM(require("node:fs"));
333
+ var FileManager = class {
334
+ constructor(ctx, config) {
335
+ this.ctx = ctx;
336
+ this.config = config;
337
+ this.dataFilePath = import_node_path.default.resolve(ctx.baseDir, "data", "chat-patch", "chat-data.json");
338
+ this.logger = ctx.logger("chat-patch");
339
+ this.utils = new Utils(config);
340
+ }
341
+ static {
342
+ __name(this, "FileManager");
343
+ }
344
+ dataFilePath;
345
+ fileOperationLock = Promise.resolve();
346
+ logger;
347
+ utils;
348
+ // 确保目录存在
349
+ ensureDataDir() {
350
+ const dir = import_node_path.default.dirname(this.dataFilePath);
351
+ if (!import_node_fs.default.existsSync(dir)) {
352
+ import_node_fs.default.mkdirSync(dir, { recursive: true });
353
+ }
354
+ }
355
+ // 从JSON文件读取数据
356
+ readChatDataFromFile() {
357
+ try {
358
+ if (import_node_fs.default.existsSync(this.dataFilePath)) {
359
+ const jsonData = import_node_fs.default.readFileSync(this.dataFilePath, "utf8");
360
+ const data = JSON.parse(jsonData);
361
+ return {
362
+ bots: data.bots || {},
363
+ channels: data.channels || {},
364
+ messages: data.messages || {},
365
+ pinnedBots: data.pinnedBots || [],
366
+ pinnedChannels: data.pinnedChannels || [],
367
+ lastSaveTime: data.lastSaveTime
368
+ };
369
+ }
370
+ } catch (error) {
371
+ this.logger.error("读取聊天数据失败:", error);
372
+ }
373
+ return {
374
+ bots: {},
375
+ channels: {},
376
+ messages: {},
377
+ pinnedBots: [],
378
+ pinnedChannels: []
379
+ };
380
+ }
381
+ // 写入数据到JSON文件
382
+ writeChatDataToFile(data) {
383
+ try {
384
+ this.ensureDataDir();
385
+ data.lastSaveTime = Date.now();
386
+ const jsonData = JSON.stringify(data, null, 2);
387
+ import_node_fs.default.writeFileSync(this.dataFilePath, jsonData, "utf8");
388
+ } catch (error) {
389
+ this.logger.error("写入聊天数据失败:", error);
390
+ }
391
+ }
392
+ // 清理超量消息
393
+ cleanExcessMessages(data) {
394
+ let cleanedCount = 0;
395
+ const cleanedMessages = {};
396
+ for (const [channelKey, messages] of Object.entries(data.messages)) {
397
+ if (messages.length > this.config.maxMessagesPerChannel) {
398
+ const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp);
399
+ const keptMessages = sortedMessages.slice(-this.config.maxMessagesPerChannel);
400
+ cleanedCount += messages.length - keptMessages.length;
401
+ cleanedMessages[channelKey] = keptMessages;
402
+ this.logInfo(`频道 ${channelKey} 清理了 ${messages.length - keptMessages.length} 条旧消息,保留最新 ${keptMessages.length} 条`);
403
+ } else {
404
+ cleanedMessages[channelKey] = messages;
405
+ }
406
+ }
407
+ if (cleanedCount > 0) {
408
+ this.logInfo("总共清理超量消息:", cleanedCount, "条");
409
+ }
410
+ return {
411
+ ...data,
412
+ messages: cleanedMessages
413
+ };
414
+ }
415
+ // 添加消息到JSON文件(使用锁机制防止并发冲突)
416
+ async addMessageToFile(messageInfo) {
417
+ this.fileOperationLock = this.fileOperationLock.then(async () => {
418
+ const data = this.readChatDataFromFile();
419
+ const channelKey = `${messageInfo.selfId}:${messageInfo.channelId}`;
420
+ if (!data.messages[channelKey]) {
421
+ data.messages[channelKey] = [];
422
+ }
423
+ const existingMessage = data.messages[channelKey].find((m) => m.id === messageInfo.id);
424
+ if (existingMessage) {
425
+ this.logInfo("消息已存在,跳过保存:", {
426
+ channelKey,
427
+ messageId: messageInfo.id,
428
+ existingType: existingMessage.type,
429
+ existingContent: existingMessage.content,
430
+ newType: messageInfo.type,
431
+ newContent: messageInfo.content
432
+ });
433
+ return;
434
+ }
435
+ if (!messageInfo.timestamp) {
436
+ messageInfo.timestamp = Date.now();
437
+ }
438
+ const cleanedMessageInfo = this.utils.cleanBase64Content(messageInfo);
439
+ const beforeCount = data.messages[channelKey].length;
440
+ data.messages[channelKey].push(cleanedMessageInfo);
441
+ const afterCount = data.messages[channelKey].length;
442
+ if (data.messages[channelKey].length > this.config.maxMessagesPerChannel) {
443
+ data.messages[channelKey].sort((a, b) => a.timestamp - b.timestamp);
444
+ const removedCount = data.messages[channelKey].length - this.config.maxMessagesPerChannel;
445
+ data.messages[channelKey] = data.messages[channelKey].slice(-this.config.maxMessagesPerChannel);
446
+ this.logInfo(`频道 ${channelKey} 达到消息上限,清理了 ${removedCount} 条旧消息`);
447
+ }
448
+ this.writeChatDataToFile(data);
449
+ const isCommandMessage = messageInfo.content?.startsWith("++") || messageInfo.content?.startsWith(".");
450
+ this.logInfo("添加消息到文件:", {
451
+ channelKey,
452
+ messageId: messageInfo.id,
453
+ content: messageInfo.content,
454
+ type: messageInfo.type,
455
+ userId: messageInfo.userId,
456
+ username: messageInfo.username,
457
+ timestamp: messageInfo.timestamp,
458
+ isCommandMessage,
459
+ 消息数变化: `${beforeCount} -> ${afterCount} -> ${data.messages[channelKey].length}`
460
+ });
461
+ }).catch((error) => {
462
+ this.logger.error("保存消息时发生错误:", error);
463
+ });
464
+ await this.fileOperationLock;
465
+ }
466
+ logInfo(...args) {
467
+ if (this.config.loggerinfo) {
468
+ this.logger.info(...args);
469
+ }
470
+ }
471
+ };
472
+
475
473
  // src/api-handlers.ts
476
474
  var import_koishi = require("koishi");
477
475
  var import_node_url = require("node:url");
@@ -956,7 +954,7 @@ var Config = import_koishi2.Schema.intersect([
956
954
  // src/index.ts
957
955
  var name = "chat-patch";
958
956
  var reusable = false;
959
- var filter = false;
957
+ var filter = true;
960
958
  var inject = {
961
959
  required: ["console"]
962
960
  };
@@ -0,0 +1,16 @@
1
+ import { Context, Session } from 'koishi';
2
+ import { FileManager } from './file-manager';
3
+ import { Config } from './config';
4
+ export declare class MessageHandler {
5
+ private ctx;
6
+ private config;
7
+ private fileManager;
8
+ private logger;
9
+ private utils;
10
+ constructor(ctx: Context, config: Config, fileManager: FileManager);
11
+ updateBotInfoToFile(session: Session): Promise<void>;
12
+ updateChannelInfoToFile(session: Session): Promise<string>;
13
+ broadcastMessageEvent(session: Session): Promise<void>;
14
+ broadcastBotMessageEvent(session: Session): Promise<void>;
15
+ private logInfo;
16
+ }
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": "1.0.10",
4
+ "version": "1.0.11",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -1,6 +1,7 @@
1
+ import { FileManager } from './file-manager'
1
2
  import { Context, h, Logger } from 'koishi'
2
3
  import { Config } from './config'
3
- import { FileManager } from './file-manager'
4
+
4
5
  import { URL, pathToFileURL } from 'node:url'
5
6
 
6
7
  export class ApiHandlers {
@@ -1,10 +1,11 @@
1
- import path from 'node:path'
2
- import fs from 'node:fs'
3
- import { Context, Logger } from 'koishi'
4
1
  import { ChatData, MessageInfo } from './types'
2
+ import { Context, Logger } from 'koishi'
5
3
  import { Config } from './config'
6
4
  import { Utils } from './utils'
7
5
 
6
+ import path from 'node:path'
7
+ import fs from 'node:fs'
8
+
8
9
  export class FileManager {
9
10
  private dataFilePath: string
10
11
  private fileOperationLock = Promise.resolve()
package/src/index.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { Context } from 'koishi'
1
+
2
2
  import { } from '@koishijs/plugin-console'
3
+ import { Context } from 'koishi'
3
4
  import path from 'node:path'
4
- import fs from 'node:fs'
5
5
 
6
- import { Config } from './config'
7
- import { FileManager } from './file-manager'
8
6
  import { MessageHandler } from './message-handler'
7
+ import { FileManager } from './file-manager'
9
8
  import { ApiHandlers } from './api-handlers'
9
+ import { Config } from './config'
10
10
  import { Utils } from './utils'
11
11
 
12
12
  export const name = 'chat-patch'
13
13
  export const reusable = false
14
- export const filter = false
14
+ export const filter = true
15
15
  export const inject = {
16
16
  required: ['console']
17
17
  }
@@ -1,8 +1,8 @@
1
+ import { BotInfo, ChannelInfo, MessageInfo, QuoteInfo } from './types'
1
2
  import { Context, Session, h, Logger } from 'koishi'
2
- import { Config } from './config'
3
3
  import { FileManager } from './file-manager'
4
+ import { Config } from './config'
4
5
  import { Utils } from './utils'
5
- import { BotInfo, ChannelInfo, MessageInfo, QuoteInfo } from './types'
6
6
 
7
7
  export class MessageHandler {
8
8
  private logger: Logger