koishi-plugin-cat-raising 1.3.8 → 1.3.9

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 CHANGED
@@ -28,6 +28,8 @@ export interface Config {
28
28
  biliAccessKeys: BiliAccessKeyConfig[];
29
29
  /** 硬拒绝关键词列表 */
30
30
  hardRejectionKeywords: string[];
31
+ /** 仅弹幕模式关键词(包含任一关键词则只发弹幕不转发) */
32
+ danmakuOnlyKeywords: string[];
31
33
  /** 发送弹幕的延迟下限(秒) */
32
34
  danmakuDelayMinSeconds?: number;
33
35
  /** 发送弹幕的延迟上限(秒) */
package/lib/index.js CHANGED
@@ -60,7 +60,8 @@ var Config = import_koishi.Schema.intersect([
60
60
  danmakuDelayMaxSeconds: import_koishi.Schema.number().description("弹幕延迟上限(秒)").role("slider", { min: 0, max: 60, step: 1 }).default(10)
61
61
  }).description("弹幕设置"),
62
62
  import_koishi.Schema.object({
63
- hardRejectionKeywords: import_koishi.Schema.array(import_koishi.Schema.string()).description("命中则忽略的关键词(硬拒绝)").default(["发言榜单", "投稿数:", "预告"])
63
+ hardRejectionKeywords: import_koishi.Schema.array(import_koishi.Schema.string()).description("命中则忽略的关键词(硬拒绝)").default(["发言榜单", "投稿数:", "预告"]),
64
+ danmakuOnlyKeywords: import_koishi.Schema.array(import_koishi.Schema.string()).description("仅弹幕模式关键词(包含任一关键词则只发弹幕不转发)").default(["闪击"])
64
65
  }).description("过滤规则")
65
66
  ]);
66
67
  function preprocessChineseNumerals(text) {
@@ -317,6 +318,7 @@ function apply(ctx, config) {
317
318
  const warningMessageMap = /* @__PURE__ */ new Map();
318
319
  const pendingDanmakuTimersByMessage = /* @__PURE__ */ new Map();
319
320
  const pendingDanmakuTimersByRoom = /* @__PURE__ */ new Map();
321
+ const pendingDanmakuRoomMap = /* @__PURE__ */ new Map();
320
322
  ctx.on("message", async (session) => {
321
323
  const groupConfig = config.monitorGroups.find((g) => g.groupId === session.channelId);
322
324
  if (!groupConfig) return;
@@ -344,8 +346,10 @@ function apply(ctx, config) {
344
346
  if (!hasStrongContext && !hasTime) return;
345
347
  const biliInfo = await fetchBilibiliInfo(ctx, roomId);
346
348
  if (!biliInfo) return;
349
+ const danmakuOnlyKeywords = config.danmakuOnlyKeywords || ["闪击"];
350
+ const isDanmakuOnly = danmakuOnlyKeywords.some((keyword) => preprocessedMessage.includes(keyword));
347
351
  let helperMessageId;
348
- if (groupConfig.sendHelperMessages) {
352
+ if (!isDanmakuOnly && groupConfig.sendHelperMessages) {
349
353
  try {
350
354
  const displayAnchor = biliInfo.anchorName;
351
355
  [helperMessageId] = await session.send(`直播间: ${roomId}
@@ -356,66 +360,87 @@ function apply(ctx, config) {
356
360
  }
357
361
  }
358
362
  const { dateTime } = parsedEvent;
359
- if (forwardedHistory.some((entry) => entry.roomId === roomId && entry.dateTime === dateTime)) {
363
+ if (!isDanmakuOnly && forwardedHistory.some((entry) => entry.roomId === roomId && entry.dateTime === dateTime)) {
360
364
  ctx.logger.info(`[防复读] 检测到重复活动,已发送辅助信息,跳过转发: 房间=${roomId}, 时间=${dateTime}`);
361
365
  return;
362
366
  }
363
- try {
364
- const displayAnchor = biliInfo.anchorName;
365
- const forwardMessage = `${session.content}
367
+ if (!isDanmakuOnly) {
368
+ try {
369
+ const displayAnchor = biliInfo.anchorName;
370
+ const forwardMessage = `${session.content}
366
371
 
367
372
  ---
368
373
  主播: ${displayAnchor}
369
374
  投稿数: ${biliInfo.videoCount}`;
370
- const [forwardedMessageId] = config.isGroup ? await session.bot.sendMessage(config.targetQQ, forwardMessage) : await session.bot.sendPrivateMessage(config.targetQQ, forwardMessage);
371
- forwardedHistory.push({
372
- originalMessageId: session.messageId,
373
- forwardedMessageId,
374
- helperMessageId,
375
- // 存储辅助消息ID用于撤回联动
376
- roomId,
377
- dateTime
378
- });
379
- if (forwardedHistory.length > config.historySize) forwardedHistory.shift();
380
- if (config.biliAccessKeys && config.biliAccessKeys.length > 0) {
381
- const min = Math.max(0, config.danmakuDelayMinSeconds ?? 8);
382
- const max = Math.max(min, config.danmakuDelayMaxSeconds ?? 10);
383
- const delayMs = (Math.floor(Math.random() * (max - min + 1)) + min) * 1e3;
384
- ctx.logger.info(`[弹幕] ${config.biliAccessKeys.length} 个账号将于 ${Math.round(delayMs / 1e3)} 秒后发送弹幕到直播间 ${roomId}。`);
385
- const timer = setTimeout(() => {
386
- const list1 = pendingDanmakuTimersByMessage.get(session.messageId);
387
- if (list1) pendingDanmakuTimersByMessage.set(session.messageId, list1.filter((t) => t !== timer));
388
- const list2 = pendingDanmakuTimersByRoom.get(roomId);
389
- if (list2) pendingDanmakuTimersByRoom.set(roomId, list2.filter((t) => t !== timer));
390
- const danmakuPromises = config.biliAccessKeys.map(
391
- (keyConfig) => sendBilibiliDanmaku(ctx, keyConfig, roomId, "喵喵喵")
392
- );
393
- Promise.allSettled(danmakuPromises);
394
- }, delayMs);
395
- const byMsg = pendingDanmakuTimersByMessage.get(session.messageId) || [];
396
- byMsg.push(timer);
397
- pendingDanmakuTimersByMessage.set(session.messageId, byMsg);
398
- const byRoom = pendingDanmakuTimersByRoom.get(roomId) || [];
399
- byRoom.push(timer);
400
- pendingDanmakuTimersByRoom.set(roomId, byRoom);
375
+ const [forwardedMessageId] = config.isGroup ? await session.bot.sendMessage(config.targetQQ, forwardMessage) : await session.bot.sendPrivateMessage(config.targetQQ, forwardMessage);
376
+ forwardedHistory.push({
377
+ originalMessageId: session.messageId,
378
+ forwardedMessageId,
379
+ helperMessageId,
380
+ // 存储辅助消息ID用于撤回联动
381
+ roomId,
382
+ dateTime
383
+ });
384
+ if (forwardedHistory.length > config.historySize) forwardedHistory.shift();
385
+ } catch (error) {
386
+ session.send("🐱 - 转发失败,请检查目标QQ/群号配置是否正确");
387
+ ctx.logger.error("[转发] 失败:", error);
401
388
  }
402
- } catch (error) {
403
- session.send("🐱 - 转发失败,请检查目标QQ/群号配置是否正确");
404
- ctx.logger.error("[转发] 失败:", error);
389
+ }
390
+ if (config.biliAccessKeys && config.biliAccessKeys.length > 0) {
391
+ const min = Math.max(0, config.danmakuDelayMinSeconds ?? 8);
392
+ const max = Math.max(min, config.danmakuDelayMaxSeconds ?? 10);
393
+ const delayMs = (Math.floor(Math.random() * (max - min + 1)) + min) * 1e3;
394
+ ctx.logger.info(`[弹幕] ${config.biliAccessKeys.length} 个账号将于 ${Math.round(delayMs / 1e3)} 秒后发送弹幕到直播间 ${roomId}。`);
395
+ const timer = setTimeout(() => {
396
+ const list1 = pendingDanmakuTimersByMessage.get(session.messageId);
397
+ if (list1) {
398
+ const newList = list1.filter((t) => t !== timer);
399
+ if (newList.length === 0) {
400
+ pendingDanmakuTimersByMessage.delete(session.messageId);
401
+ pendingDanmakuRoomMap.delete(session.messageId);
402
+ } else {
403
+ pendingDanmakuTimersByMessage.set(session.messageId, newList);
404
+ }
405
+ }
406
+ const list2 = pendingDanmakuTimersByRoom.get(roomId);
407
+ if (list2) {
408
+ const newList = list2.filter((t) => t !== timer);
409
+ if (newList.length === 0) {
410
+ pendingDanmakuTimersByRoom.delete(roomId);
411
+ } else {
412
+ pendingDanmakuTimersByRoom.set(roomId, newList);
413
+ }
414
+ }
415
+ const danmakuPromises = config.biliAccessKeys.map(
416
+ (keyConfig) => sendBilibiliDanmaku(ctx, keyConfig, roomId, "喵喵喵")
417
+ );
418
+ Promise.allSettled(danmakuPromises);
419
+ }, delayMs);
420
+ const byMsg = pendingDanmakuTimersByMessage.get(session.messageId) || [];
421
+ byMsg.push(timer);
422
+ pendingDanmakuTimersByMessage.set(session.messageId, byMsg);
423
+ pendingDanmakuRoomMap.set(session.messageId, roomId);
424
+ const byRoom = pendingDanmakuTimersByRoom.get(roomId) || [];
425
+ byRoom.push(timer);
426
+ pendingDanmakuTimersByRoom.set(roomId, byRoom);
405
427
  }
406
428
  });
407
429
  ctx.on("message-deleted", async (session) => {
408
430
  const isMonitored = config.monitorGroups.some((g) => g.groupId === session.channelId);
409
431
  if (!isMonitored) return;
410
432
  const originalMessageId = session.messageId;
433
+ const timersByMsg = pendingDanmakuTimersByMessage.get(originalMessageId);
434
+ if (timersByMsg) {
435
+ for (const t of timersByMsg) clearTimeout(t);
436
+ pendingDanmakuTimersByMessage.delete(originalMessageId);
437
+ const roomId = pendingDanmakuRoomMap.get(originalMessageId);
438
+ pendingDanmakuRoomMap.delete(originalMessageId);
439
+ ctx.logger.info(`[撤回] 已取消源消息 ${originalMessageId}${roomId ? ` (直播间: ${roomId})` : ""} 的延迟弹幕。`);
440
+ }
411
441
  const entryIndex = forwardedHistory.findIndex((entry) => entry.originalMessageId === originalMessageId);
412
442
  if (entryIndex !== -1) {
413
443
  const entry = forwardedHistory[entryIndex];
414
- const timersByMsg = pendingDanmakuTimersByMessage.get(originalMessageId);
415
- if (timersByMsg) {
416
- for (const t of timersByMsg) clearTimeout(t);
417
- pendingDanmakuTimersByMessage.delete(originalMessageId);
418
- }
419
444
  const timersByRoom = pendingDanmakuTimersByRoom.get(entry.roomId);
420
445
  if (timersByRoom) {
421
446
  for (const t of timersByRoom) clearTimeout(t);
@@ -435,7 +460,7 @@ function apply(ctx, config) {
435
460
  ctx.logger.warn(`[撤回] 转发消息 (ID: ${entry.forwardedMessageId}) 失败:`, e);
436
461
  } finally {
437
462
  forwardedHistory.splice(entryIndex, 1);
438
- ctx.logger.info(`[撤回] 已联动撤回与源消息 ${originalMessageId} 相关的转发。`);
463
+ ctx.logger.info(`[撤回] 已联动撤回与源消息 ${originalMessageId} (直播间: ${entry.roomId}) 相关的转发。`);
439
464
  }
440
465
  }
441
466
  if (warningMessageMap.has(originalMessageId)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-cat-raising",
3
3
  "description": "",
4
- "version": "1.3.8",
4
+ "version": "1.3.9",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [