koishi-plugin-cat-raising 0.3.0 → 1.0.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.
package/lib/index.d.ts CHANGED
@@ -1,21 +1,29 @@
1
- /**
2
- * @name cat-raising
3
- * @description 一个用于监控QQ群内B站直播间奖励信息,并自动转发到指定目标的Koishi插件。
4
- * 它能智能解析非结构化的文本,提取关键信息(直播间号、时间、奖励),并进行去重和信息补全。
5
- * @version 2.1.0
6
- * @author YourName
7
- */
8
1
  import { Context, Schema } from 'koishi';
9
2
  export declare const name = "cat-raising";
3
+ /** 监听群组的配置 */
10
4
  export interface MonitorGroupConfig {
5
+ /** 要监听的 QQ 群号 */
11
6
  groupId: string;
7
+ /** 是否在此群内发送“看到啦”之类的辅助/警告消息 */
12
8
  sendHelperMessages: boolean;
13
9
  }
10
+ /** 插件配置 */
14
11
  export interface Config {
12
+ /** 目标QQ号或QQ群号 */
15
13
  targetQQ: string;
14
+ /** 目标是否为QQ群 */
16
15
  isGroup: boolean;
16
+ /** 监听的群组列表及其配置 */
17
17
  monitorGroups: MonitorGroupConfig[];
18
+ /** 用于防复读的历史记录大小 */
18
19
  historySize: number;
20
+ /** 用于发送B站弹幕的 access_key 列表 */
21
+ biliAccessKeys: string[];
19
22
  }
20
23
  export declare const Config: Schema<Config>;
24
+ /**
25
+ * 插件的主应用函数。
26
+ * @param ctx Koishi 上下文。
27
+ * @param config 插件配置。
28
+ */
21
29
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
8
  var __export = (target, all) => {
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -26,16 +36,18 @@ __export(src_exports, {
26
36
  });
27
37
  module.exports = __toCommonJS(src_exports);
28
38
  var import_koishi = require("koishi");
39
+ var crypto = __toESM(require("crypto"));
40
+ var import_url = require("url");
29
41
  var name = "cat-raising";
30
42
  var Config = import_koishi.Schema.object({
31
43
  targetQQ: import_koishi.Schema.string().description("目标QQ号或QQ群号").required(),
32
44
  isGroup: import_koishi.Schema.boolean().description("是否为QQ群").default(false),
33
- // 【改动 3】修改 Schema 定义,使其成为一个对象数组
34
45
  monitorGroups: import_koishi.Schema.array(import_koishi.Schema.object({
35
46
  groupId: import_koishi.Schema.string().description("要监听的 QQ 群号").required(),
36
47
  sendHelperMessages: import_koishi.Schema.boolean().description("是否在此群内发送“看到啦”之类的辅助/警告消息").default(true)
37
48
  })).description("监听的群组列表及其配置").required(),
38
- historySize: import_koishi.Schema.number().description("用于防复读的历史记录大小,防止短期内对同一活动重复转发").default(30).min(5).max(100)
49
+ historySize: import_koishi.Schema.number().description("用于防复读的历史记录大小,防止短期内对同一活动重复转发").default(30).min(5).max(100),
50
+ biliAccessKeys: import_koishi.Schema.array(import_koishi.Schema.string()).description("用于发送B站弹幕的 access_key 列表。插件会随机选择一个使用。如果留空,则不执行发送弹幕功能。").default([])
39
51
  });
40
52
  function preprocessChineseNumerals(text) {
41
53
  const numMap = { "零": 0, "一": 1, "二": 2, "两": 2, "三": 3, "四": 4, "五": 5, "六": 6, "七": 7, "八": 8, "九": 9 };
@@ -74,7 +86,7 @@ __name(preprocessChineseNumerals, "preprocessChineseNumerals");
74
86
  function extractAllRoomIds(text) {
75
87
  const sanitizedText = text.replace(/<[^>]+>/g, "");
76
88
  const patterns = [
77
- /(?:播间号|房间号|直播间)[::\s]*(\d{6,15})/g,
89
+ /(?:播间号|房间号|直播间)[::\s]*(\d{3,15})/g,
78
90
  /\b(\d{6,15})\b/g
79
91
  // 使用单词边界确保匹配的是独立数字
80
92
  ];
@@ -138,6 +150,60 @@ var HARD_REJECTION_KEYWORDS = ["发言榜单"];
138
150
  var REJECTION_KEYWORDS = ["签到", "打卡"];
139
151
  var OVERRIDE_KEYWORDS = ["神金", "发"];
140
152
  var TRIGGER_REGEX = /神金|发|掉落|猫猫钻|w|\b\d{3,5}\b|一千|一百|十|九|八|七|六|五|四|三|两|二|一/i;
153
+ var BILI_APPKEY = "4409e2ce8ffd12b8";
154
+ var BILI_APPSECRET = "59b43e04ad6965f34319062b478f83dd";
155
+ function signBilibiliParams(params, appSecret) {
156
+ const sortedKeys = Object.keys(params).sort();
157
+ const queryString = sortedKeys.map((key) => `${key}=${params[key]}`).join("&");
158
+ const sign = crypto.createHash("md5").update(queryString + appSecret).digest("hex");
159
+ return sign;
160
+ }
161
+ __name(signBilibiliParams, "signBilibiliParams");
162
+ async function sendBilibiliDanmaku(ctx, config, roomId, message) {
163
+ if (!config.biliAccessKeys || config.biliAccessKeys.length === 0) {
164
+ ctx.logger.info("[弹幕] 未配置 access_key,跳过发送弹幕。");
165
+ return;
166
+ }
167
+ const accessKey = config.biliAccessKeys[Math.floor(Math.random() * config.biliAccessKeys.length)];
168
+ const url = "https://api.live.bilibili.com/xlive/app-room/v1/dM/sendmsg";
169
+ const ts = Math.floor(Date.now() / 1e3);
170
+ const baseParams = {
171
+ access_key: accessKey,
172
+ actionKey: "appkey",
173
+ appkey: BILI_APPKEY,
174
+ cid: roomId,
175
+ msg: message,
176
+ rnd: ts,
177
+ color: "16777215",
178
+ // 白色
179
+ fontsize: "25",
180
+ mode: "1",
181
+ // 滚动弹幕
182
+ ts
183
+ };
184
+ const sign = signBilibiliParams(baseParams, BILI_APPSECRET);
185
+ const params = { ...baseParams, sign };
186
+ const formData = new import_url.URLSearchParams();
187
+ for (const key in params) {
188
+ formData.append(key, params[key]);
189
+ }
190
+ try {
191
+ const response = await ctx.http.post(url, formData, {
192
+ headers: {
193
+ "Content-Type": "application/x-www-form-urlencoded",
194
+ "User-Agent": "Mozilla/5.0 BiliDroid/6.73.1 (bbcallen@gmail.com) os/android model/Mi 10 Pro mobi_app/android build/6731100 channel/xiaomi innerVer/6731110 osVer/12 network/2"
195
+ }
196
+ });
197
+ if (response.code === 0) {
198
+ ctx.logger.info(`[弹幕] 成功向直播间 ${roomId} 发送弹幕: "${message}"`);
199
+ } else {
200
+ ctx.logger.warn(`[弹幕] 发送失败,直播间 ${roomId}。原因: ${response.message || "未知错误"}`);
201
+ }
202
+ } catch (error) {
203
+ ctx.logger.error(`[弹幕] 发送请求时发生网络错误,直播间 ${roomId}:`, error);
204
+ }
205
+ }
206
+ __name(sendBilibiliDanmaku, "sendBilibiliDanmaku");
141
207
  async function fetchBilibiliInfo(ctx, roomId) {
142
208
  try {
143
209
  const roomInfo = await ctx.http.get(`https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${roomId}`);
@@ -191,9 +257,7 @@ function apply(ctx, config) {
191
257
  return;
192
258
  }
193
259
  const biliInfo = await fetchBilibiliInfo(ctx, roomId);
194
- if (!biliInfo) {
195
- return;
196
- }
260
+ if (!biliInfo) return;
197
261
  let helperMessageId;
198
262
  if (groupConfig.sendHelperMessages) {
199
263
  [helperMessageId] = await session.send(`直播间: ${roomId}
@@ -209,11 +273,12 @@ function apply(ctx, config) {
209
273
  originalMessageId: session.messageId,
210
274
  forwardedMessageId,
211
275
  helperMessageId,
212
- // helperMessageId 可能是 undefined,这没有问题
276
+ // helperMessageId 可能是 undefined
213
277
  roomId,
214
278
  dateTime
215
279
  });
216
280
  if (forwardedHistory.length > config.historySize) forwardedHistory.shift();
281
+ await sendBilibiliDanmaku(ctx, config, roomId, "喵喵喵");
217
282
  } catch (error) {
218
283
  session.send("🐱 - 转发失败,请检查目标QQ/群号配置是否正确");
219
284
  ctx.logger.error("[转发] 失败:", error);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-cat-raising",
3
3
  "description": "",
4
- "version": "0.3.0",
4
+ "version": "1.0.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [