koishi-plugin-cat-raising 0.3.1 → 1.0.1
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 +15 -7
- package/lib/index.js +72 -7
- package/package.json +1 -1
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 };
|
|
@@ -134,10 +146,64 @@ function parseEventFromText(text) {
|
|
|
134
146
|
return allRewards.length > 0 ? { dateTime: globalDateTime || "时间未知", rewards: allRewards } : null;
|
|
135
147
|
}
|
|
136
148
|
__name(parseEventFromText, "parseEventFromText");
|
|
137
|
-
var HARD_REJECTION_KEYWORDS = ["发言榜单"];
|
|
149
|
+
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);
|