@zaofan/dsh-qqbot 1.6.1 → 1.6.3

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,84 @@
1
+ export interface QunCookie {
2
+ uin: string;
3
+ skey: string;
4
+ p_skey?: string;
5
+ at?: number;
6
+ }
7
+ /** QQ 登录令牌算法(ptqrtoken) */
8
+ export declare function hash33(s: string): number;
9
+ /** 业务接口签名(bkn) */
10
+ export declare function getBkn(skey: string): number;
11
+ export declare function qunCookieFile(dataRoot: string): string;
12
+ export declare function loadQunCookie(dataRoot: string): QunCookie | null;
13
+ export declare function saveQunCookie(dataRoot: string, c: QunCookie): void;
14
+ export declare function clearQunCookie(dataRoot: string): void;
15
+ /**
16
+ * 第一步:拿到二维码 PNG(存盘),返回路径给上层发出去。
17
+ * 之后用 qunLoginPoll 轮询扫码结果。
18
+ */
19
+ export declare function qunLoginStart(dataRoot: string): Promise<{
20
+ ok: boolean;
21
+ msg: string;
22
+ qrPath?: string;
23
+ }>;
24
+ /**
25
+ * 第二步:轮询扫码结果(最多等 budgetMs,默认 20 秒一轮,避免工具调用卡太久)。
26
+ * 返回 done=true 表示已登录并写好了凭据。
27
+ */
28
+ export declare function qunLoginPoll(dataRoot: string, budgetMs?: number): Promise<{
29
+ ok: boolean;
30
+ done: boolean;
31
+ msg: string;
32
+ }>;
33
+ export declare function qunLoginPending(dataRoot: string): boolean;
34
+ export interface QunGroup {
35
+ gc: string;
36
+ gn: string;
37
+ role: '我创建' | '我管理';
38
+ }
39
+ export declare function qunGroups(dataRoot: string): Promise<QunGroup[]>;
40
+ /**
41
+ * 验证凭据是否**真的**还有效。
42
+ *
43
+ * ⚠️ 为什么必须有这一层:浏览器页面只判断"cookie 在不在"(不会因为 skey 失效就跳登录页),
44
+ * 所以很容易出现**看起来已登录、服务端却早就不认账**的情况(接口返回 `{"ec":4,"em":"no login"}`)。
45
+ * 实测踩过:`/qun/status` 报 logged=true/valid=true,但群列表是空的 —— 就是 skey 被顶掉了。
46
+ * 一切"已登录"的判断都应该过这一关。
47
+ */
48
+ export declare function verifyQunCookie(dataRoot: string): Promise<boolean>;
49
+ /** 同一个验证,但直接对一份内存里的凭据做(浏览器那边读到 cookie 后立刻验一次) */
50
+ export declare function verifyQunCookieRaw(c: QunCookie): Promise<boolean>;
51
+ /** 群号直通;群名做模糊匹配(多个命中就报错让人用群号) */
52
+ export declare function qunResolveGc(dataRoot: string, gcOrName: string): Promise<{
53
+ ok: true;
54
+ gc: string;
55
+ gn: string;
56
+ } | {
57
+ ok: false;
58
+ msg: string;
59
+ }>;
60
+ export interface QunMember {
61
+ uin: string;
62
+ nick: string;
63
+ role?: number;
64
+ }
65
+ /**
66
+ * 查群成员。
67
+ * keyword 给 uin → 服务端精确查(快且准);给昵称 → 先试服务端 key,不行再全量分页本地过滤。
68
+ * 返回 count 是群总人数(服务端给的)。
69
+ */
70
+ export declare function qunMembers(dataRoot: string, gc: string, keyword?: string): Promise<{
71
+ ok: boolean;
72
+ count?: number;
73
+ members: QunMember[];
74
+ note?: string;
75
+ }>;
76
+ /** 按 uin 精确存在性判断(踢完验证用,也最快) */
77
+ export declare function qunHasMember(dataRoot: string, gc: string, uin: string): Promise<boolean>;
78
+ /** 踢人(可多个)。返回逐条结果。 */
79
+ export declare function qunKick(dataRoot: string, gc: string, uins: string[]): Promise<Array<{
80
+ uin: string;
81
+ ec: number;
82
+ msg: string;
83
+ }>>;
84
+ //# sourceMappingURL=qun-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qun-admin.d.ts","sourceRoot":"","sources":["../../src/features/qun-admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,367 @@
1
+ /**
2
+ * qun-admin.ts — QQ 群管理(纯 HTTP,不依赖浏览器,不依赖任何外部脚本)
3
+ *
4
+ * 走 QQ 群官网 qun.qq.com 的 qun_mgr 老接口:
5
+ * get_group_list / search_group_members / delete_group_member
6
+ * 登录链路:xlogin(拿 login_sig) → ptqrshow(出二维码) → ptqrlogin(轮询扫码) → checkurl(取 cookie) → skey → bkn
7
+ *
8
+ * ⚠️ 实测踩过的坑(别改回去):
9
+ * ① 业务接口的 User-Agent 必须用朴素的 'Mozilla/5.0':
10
+ * 用完整浏览器 UA 会被服务端判成非法请求,直接 404。
11
+ * ② 接口路径不要再叠 qun_mgr/ 前缀(API_BASE 已含 cgi-bin/)。
12
+ * ③ delete_group_member 的成员参数名是 **ul**(不是 uin),且要放 POST body:
13
+ * body: gc=xxx&ul=xxx → {"ec":0,"ul":[xxx]} 成功
14
+ * 传 uin → {"ec":5} 参数错误
15
+ * 目标不在群里 → {"ec":3}
16
+ * 群不存在 / 无权限 → {"ec":-100005}
17
+ * ④ search_group_members 的 key 参数只在 st=0&end=20 时生效;
18
+ * 分页会丢页(684 人的群只拉回 661),所以能按 key 精确查就别全量拉。
19
+ * ⑤ ptqrlogin 轮询必须带 qrsig cookie + login_sig,否则连接被重置。
20
+ */
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
22
+ import { dirname, join } from 'node:path';
23
+ const APPID = '715030901';
24
+ const UA_BROWSER = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0';
25
+ /** 业务接口专用:朴素 UA(见坑①) */
26
+ const UA_API = 'Mozilla/5.0';
27
+ const API_BASE = 'https://qun.qq.com/cgi-bin/';
28
+ const sleep = (ms) => new Promise((r) => { setTimeout(r, ms); });
29
+ /** QQ 登录令牌算法(ptqrtoken) */
30
+ export function hash33(s) {
31
+ let e = 0;
32
+ for (let i = 0; i < s.length; i++)
33
+ e += (e << 5) + s.charCodeAt(i);
34
+ return e & 0x7fffffff;
35
+ }
36
+ /** 业务接口签名(bkn) */
37
+ export function getBkn(skey) {
38
+ let h = 5381;
39
+ for (let i = 0; i < skey.length; i++)
40
+ h += (h << 5) + skey.charCodeAt(i);
41
+ return h & 0x7fffffff;
42
+ }
43
+ // ───────────────────────── 凭据存取 ─────────────────────────
44
+ export function qunCookieFile(dataRoot) {
45
+ return join(dataRoot, 'qun-cookie.json');
46
+ }
47
+ export function loadQunCookie(dataRoot) {
48
+ const f = qunCookieFile(dataRoot);
49
+ if (!existsSync(f))
50
+ return null;
51
+ try {
52
+ const c = JSON.parse(readFileSync(f, 'utf8'));
53
+ return c && c.uin && c.skey ? c : null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ export function saveQunCookie(dataRoot, c) {
60
+ const f = qunCookieFile(dataRoot);
61
+ try {
62
+ mkdirSync(dirname(f), { recursive: true });
63
+ }
64
+ catch { /* ignore */ }
65
+ writeFileSync(f, JSON.stringify({ ...c, at: c.at ?? Date.now() }), 'utf8');
66
+ }
67
+ export function clearQunCookie(dataRoot) {
68
+ try {
69
+ rmSync(qunCookieFile(dataRoot), { force: true });
70
+ }
71
+ catch { /* ignore */ }
72
+ }
73
+ function cookieHeader(c) {
74
+ return `uin=o${c.uin}; skey=${c.skey}; p_uin=o${c.uin}; p_skey=${c.p_skey || ''};`;
75
+ }
76
+ // ───────────────────────── 业务接口 ─────────────────────────
77
+ /**
78
+ * 调 qun_mgr 业务接口。
79
+ * @param post 传对象时,extra+post 走 POST body(写操作必须这样);不传则全部走 query。
80
+ */
81
+ async function callMgr(dataRoot, path, gc, extra = {}, post = null) {
82
+ const c = loadQunCookie(dataRoot);
83
+ if (!c)
84
+ throw new Error('NOT_LOGGED_IN');
85
+ const qs = new URLSearchParams({
86
+ bkn: String(getBkn(c.skey)),
87
+ ts: String(Date.now()),
88
+ ...(gc ? { gc: String(gc) } : {}),
89
+ ...(post ? {} : extra),
90
+ });
91
+ const res = await fetch(API_BASE + path + '?' + qs, {
92
+ method: 'POST',
93
+ headers: {
94
+ 'User-Agent': UA_API,
95
+ Cookie: cookieHeader(c),
96
+ Referer: 'https://qun.qq.com/',
97
+ ...(post ? { 'Content-Type': 'application/x-www-form-urlencoded' } : {}),
98
+ },
99
+ body: post ? new URLSearchParams({ ...extra, ...post }).toString() : '',
100
+ });
101
+ const txt = await res.text();
102
+ try {
103
+ return JSON.parse(txt);
104
+ }
105
+ catch {
106
+ return { _raw: txt.slice(0, 300), _status: res.status };
107
+ }
108
+ }
109
+ /** 登录中间态放内存:一个进程内同一个 dataRoot 只保留最近一次(二维码 3 分钟有效) */
110
+ const loginStates = new Map();
111
+ /**
112
+ * 第一步:拿到二维码 PNG(存盘),返回路径给上层发出去。
113
+ * 之后用 qunLoginPoll 轮询扫码结果。
114
+ */
115
+ export async function qunLoginStart(dataRoot) {
116
+ const u1 = encodeURIComponent('https://qun.qq.com/');
117
+ // ① xlogin:拿 login_sig(轮询必须带,否则 ECONNRESET)
118
+ let loginSig = '';
119
+ try {
120
+ const rx = await fetch('https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=' + APPID
121
+ + '&daid=73&style=20&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1'
122
+ + '&link_target=blank&proj_self_def=1&s_url=' + encodeURIComponent('https://qun.qq.com/'), { headers: { 'User-Agent': UA_BROWSER, Referer: 'https://qun.qq.com/' } });
123
+ const scx = (rx.headers.getSetCookie ? rx.headers.getSetCookie() : []).join(';');
124
+ loginSig = (/(?:^|;|\s)login_sig=([^;]+)/.exec(scx) || [])[1] || '';
125
+ }
126
+ catch { /* login_sig 拿不到也能试 */ }
127
+ // ② ptqrshow:拿二维码图片 + qrsig cookie
128
+ const r1 = await fetch(`https://xui.ptlogin2.qq.com/ssl/ptqrshow?appid=${APPID}&e=2&l=M&s=3&d=72&v=4&t=${Math.random()}&daid=73&pt_3rd_aid=0&u1=${u1}`, { headers: { 'User-Agent': UA_BROWSER, Referer: 'https://xui.ptlogin2.qq.com/' } });
129
+ const sc = (r1.headers.getSetCookie ? r1.headers.getSetCookie() : []).join(';');
130
+ const qrsig = (/qrsig=([^;]+)/.exec(sc) || [])[1] || '';
131
+ if (!qrsig)
132
+ return { ok: false, msg: '没能从 QQ 拿到二维码(qrsig 为空),稍后重试' };
133
+ const qrPath = join(dataRoot, 'qun-login-qr.png');
134
+ try {
135
+ mkdirSync(dirname(qrPath), { recursive: true });
136
+ }
137
+ catch { /* ignore */ }
138
+ writeFileSync(qrPath, Buffer.from(await r1.arrayBuffer()));
139
+ loginStates.set(dataRoot, { qrsig, ptqrtoken: hash33(qrsig), loginSig, at: Date.now(), qrPath, u1 });
140
+ return {
141
+ ok: true,
142
+ qrPath,
143
+ msg: '二维码已生成(3 分钟内有效,手机 QQ 扫它)。'
144
+ + '请立刻用 send_media 把这个图片发给主人,然后调 status 等扫码结果。',
145
+ };
146
+ }
147
+ /**
148
+ * 第二步:轮询扫码结果(最多等 budgetMs,默认 20 秒一轮,避免工具调用卡太久)。
149
+ * 返回 done=true 表示已登录并写好了凭据。
150
+ */
151
+ export async function qunLoginPoll(dataRoot, budgetMs = 20000) {
152
+ const st = loginStates.get(dataRoot);
153
+ if (!st)
154
+ return { ok: false, done: false, msg: '没有正在进行的扫码(二维码可能已过期),先调 login 重新出码' };
155
+ if (Date.now() - st.at > 170000) {
156
+ loginStates.delete(dataRoot);
157
+ return { ok: false, done: false, msg: '二维码已过期(超过 3 分钟),请重新调 login' };
158
+ }
159
+ const common = `u1=${st.u1}&ptqrtoken=${st.ptqrtoken}&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052`
160
+ + `&js_ver=26092315&js_type=1&login_sig=${encodeURIComponent(st.loginSig)}&pt_uistyle=40&aid=${APPID}&daid=73&has_onekey=1`;
161
+ const ck = 'qrsig=' + st.qrsig + (st.loginSig ? '; login_sig=' + st.loginSig : '');
162
+ const deadline = Date.now() + Math.max(3000, budgetMs);
163
+ let last = '等待扫码…';
164
+ while (Date.now() < deadline) {
165
+ await sleep(3000);
166
+ let txt = '';
167
+ try {
168
+ const r = await fetch(`https://xui.ptlogin2.qq.com/ssl/ptqrlogin?${common}&action=0-0-${Date.now()}`, { headers: { 'User-Agent': UA_BROWSER, Referer: 'https://xui.ptlogin2.qq.com/cgi-bin/qlogin', Cookie: ck } });
169
+ txt = await r.text();
170
+ }
171
+ catch {
172
+ last = '网络抖动,继续等…';
173
+ continue;
174
+ }
175
+ const m = /ptuiCB\('(\d+)','(\d+)','([^']*)','[^']*','([^']*)'/.exec(txt);
176
+ if (!m)
177
+ continue;
178
+ const code = m[1];
179
+ if (code === '66') {
180
+ last = '等待扫码…';
181
+ continue;
182
+ }
183
+ if (code === '65') {
184
+ last = '已扫码,等手机上点「确认登录」…';
185
+ continue;
186
+ }
187
+ if (code === '67') {
188
+ loginStates.delete(dataRoot);
189
+ return { ok: false, done: false, msg: '二维码已失效,请重新调 login' };
190
+ }
191
+ if (code === '0') {
192
+ const checkUrl = m[3];
193
+ if (!checkUrl)
194
+ continue;
195
+ const r3 = await fetch(checkUrl, { headers: { 'User-Agent': UA_BROWSER, Referer: 'https://xui.ptlogin2.qq.com/' }, redirect: 'manual' });
196
+ const sc3 = (r3.headers.getSetCookie ? r3.headers.getSetCookie() : []).join(';');
197
+ const get = (k) => { const mm = new RegExp(k + '=([^;]+)').exec(sc3); return mm && mm[1] ? decodeURIComponent(mm[1]) : ''; };
198
+ let uin = (/(\d{5,12})/.exec(get('uin') || get('superuin') || '') || [])[1] || '';
199
+ if (!uin) {
200
+ const mm = /uin=o(\d+)/.exec(sc3);
201
+ uin = mm && mm[1] ? mm[1] : '';
202
+ }
203
+ const skey = get('skey');
204
+ if (!uin || !skey)
205
+ return { ok: false, done: false, msg: '拿到了跳转但解析不出 uin/skey,请重新调 login' };
206
+ saveQunCookie(dataRoot, { uin, skey, p_skey: get('p_skey'), at: Date.now() });
207
+ loginStates.delete(dataRoot);
208
+ return { ok: true, done: true, msg: `登录成功,uin=${uin}。现在可以 groups / members / kick 了。` };
209
+ }
210
+ }
211
+ return { ok: true, done: false, msg: `${last}(这一轮没等到;可以再调 status 继续等,二维码还有效)` };
212
+ }
213
+ export function qunLoginPending(dataRoot) {
214
+ return loginStates.has(dataRoot);
215
+ }
216
+ export async function qunGroups(dataRoot) {
217
+ const d = await callMgr(dataRoot, 'qun_mgr/get_group_list', null);
218
+ const out = [];
219
+ for (const g of (d.create || []))
220
+ out.push({ gc: String(g.gc), gn: String(g.gn), role: '我创建' });
221
+ for (const g of (d.manage || []))
222
+ out.push({ gc: String(g.gc), gn: String(g.gn), role: '我管理' });
223
+ return out;
224
+ }
225
+ /**
226
+ * 验证凭据是否**真的**还有效。
227
+ *
228
+ * ⚠️ 为什么必须有这一层:浏览器页面只判断"cookie 在不在"(不会因为 skey 失效就跳登录页),
229
+ * 所以很容易出现**看起来已登录、服务端却早就不认账**的情况(接口返回 `{"ec":4,"em":"no login"}`)。
230
+ * 实测踩过:`/qun/status` 报 logged=true/valid=true,但群列表是空的 —— 就是 skey 被顶掉了。
231
+ * 一切"已登录"的判断都应该过这一关。
232
+ */
233
+ export async function verifyQunCookie(dataRoot) {
234
+ const c = loadQunCookie(dataRoot);
235
+ if (!c)
236
+ return false;
237
+ return verifyQunCookieRaw(c);
238
+ }
239
+ /** 同一个验证,但直接对一份内存里的凭据做(浏览器那边读到 cookie 后立刻验一次) */
240
+ export async function verifyQunCookieRaw(c) {
241
+ try {
242
+ // ⚠️ 这里刻意用 get_group_list 而不是 qunwelcome/myinfo:
243
+ // myinfo 对某些账号/场景返回非 0(实测:明明能正常拉群列表,却一直被判定"无效"),
244
+ // 而 get_group_list 是群里所有功能都依赖的主接口,它通了才算真通。
245
+ const qs = new URLSearchParams({ bkn: String(getBkn(c.skey)), ts: String(Date.now()) });
246
+ const res = await fetch(`https://qun.qq.com/cgi-bin/qun_mgr/get_group_list?${qs}`, {
247
+ method: 'POST',
248
+ headers: {
249
+ 'User-Agent': UA_API,
250
+ Cookie: cookieHeader(c),
251
+ Referer: 'https://qun.qq.com/',
252
+ },
253
+ body: '',
254
+ });
255
+ const j = (await res.json());
256
+ if (Number(j.ec) === 0)
257
+ return true;
258
+ // create/manage 只要有一个是数组,就说明服务端认了这份凭据
259
+ return Array.isArray(j.create) || Array.isArray(j.manage);
260
+ }
261
+ catch {
262
+ return false;
263
+ }
264
+ }
265
+ /** 群号直通;群名做模糊匹配(多个命中就报错让人用群号) */
266
+ export async function qunResolveGc(dataRoot, gcOrName) {
267
+ const s = String(gcOrName || '').trim();
268
+ if (/^\d+$/.test(s))
269
+ return { ok: true, gc: s, gn: '' };
270
+ if (!s)
271
+ return { ok: false, msg: '请给群号或群名' };
272
+ const all = await qunGroups(dataRoot);
273
+ const hit = all.filter((g) => g.gn.includes(s));
274
+ if (!hit.length)
275
+ return { ok: false, msg: `没找到群「${s}」。我管的群:${all.map((g) => `${g.gn}(${g.gc})`).join('、') || '(空)'}` };
276
+ if (hit.length > 1)
277
+ return { ok: false, msg: `匹配到多个群:${hit.map((g) => `${g.gn}(${g.gc})`).join('、')},请改用群号` };
278
+ return { ok: true, gc: hit[0].gc, gn: hit[0].gn };
279
+ }
280
+ function mapMembers(ms) {
281
+ return ms.map((m) => ({ uin: String(m.uin ?? ''), nick: String(m.nick || m.name || ''), role: m.role }));
282
+ }
283
+ /**
284
+ * 查群成员。
285
+ * keyword 给 uin → 服务端精确查(快且准);给昵称 → 先试服务端 key,不行再全量分页本地过滤。
286
+ * 返回 count 是群总人数(服务端给的)。
287
+ */
288
+ export async function qunMembers(dataRoot, gc, keyword) {
289
+ const kw = String(keyword || '').trim();
290
+ // 有关键词:先用 key 精确查(服务端只在 st=0&end=20 时认 key)
291
+ if (kw) {
292
+ const d = await callMgr(dataRoot, 'qun_mgr/search_group_members', gc, { st: '0', end: '20', sort: '0', key: kw });
293
+ const hit = mapMembers(d.mems || []);
294
+ if (hit.length)
295
+ return { ok: true, count: d.count, members: hit };
296
+ // 服务端 key 查不到 → 全量分页兜底(可能丢页,见坑④)
297
+ const all = await qunMembersAll(dataRoot, gc);
298
+ const low = kw.toLowerCase();
299
+ const filtered = all.members.filter((m) => m.uin === kw || m.nick.toLowerCase().includes(low));
300
+ return {
301
+ ok: true,
302
+ count: all.count,
303
+ members: filtered,
304
+ note: filtered.length ? '(服务端 key 查不到,这是全量分页过滤的结果,分页可能丢页)' : undefined,
305
+ };
306
+ }
307
+ const all = await qunMembersAll(dataRoot, gc);
308
+ return { ok: true, count: all.count, members: all.members };
309
+ }
310
+ async function qunMembersAll(dataRoot, gc) {
311
+ let all = [];
312
+ let count;
313
+ // ⚠️ 服务端把 st/end 当**闭区间**:st=0&end=20 会返回 21 条。
314
+ // 必须按**实际返回条数**步进,否则每页重叠 1 条、去重后总数偏少(实测 683 人的群只拉回 661)。
315
+ let st = 0;
316
+ for (let guard = 0; guard < 200; guard++) {
317
+ const d = await callMgr(dataRoot, 'qun_mgr/search_group_members', gc, { st: String(st), end: String(st + 20), sort: '0' });
318
+ const ms = d.mems || [];
319
+ if (d.count)
320
+ count = d.count;
321
+ if (!ms.length)
322
+ break;
323
+ all = all.concat(ms);
324
+ if (count && all.length >= count)
325
+ break;
326
+ st += ms.length;
327
+ }
328
+ const seen = new Set();
329
+ const members = mapMembers(all).filter((m) => (seen.has(m.uin) ? false : (seen.add(m.uin), true)));
330
+ return { count, members };
331
+ }
332
+ /** 按 uin 精确存在性判断(踢完验证用,也最快) */
333
+ export async function qunHasMember(dataRoot, gc, uin) {
334
+ const d = await callMgr(dataRoot, 'qun_mgr/search_group_members', gc, { st: '0', end: '20', sort: '0', key: String(uin) });
335
+ return (d.mems || []).some((m) => String(m.uin) === String(uin));
336
+ }
337
+ /** ec 码解释(实测 + 社区经验) */
338
+ function explainEc(ec) {
339
+ if (ec === 0)
340
+ return '成功';
341
+ if (ec === 3)
342
+ return '该成员不在这个群里(或没有可移除的身份)';
343
+ if (ec === 5)
344
+ return '参数错误(ul 传法不对)';
345
+ if (ec === -100005)
346
+ return '群不存在,或当前账号对这个群没有管理权限';
347
+ if (ec === 1)
348
+ return '权限不足';
349
+ return '未知错误';
350
+ }
351
+ /** 踢人(可多个)。返回逐条结果。 */
352
+ export async function qunKick(dataRoot, gc, uins) {
353
+ const out = [];
354
+ for (const u of uins) {
355
+ const d = await callMgr(dataRoot, 'qun_mgr/delete_group_member', gc, { ul: String(u) }, { ul: String(u) });
356
+ const ec = Number(d.ec ?? NaN);
357
+ let msg = explainEc(ec);
358
+ if (ec === 5 && d.em)
359
+ msg += ' raw=' + String(d.em).slice(0, 60);
360
+ if (!Number.isFinite(ec))
361
+ msg = '返回无法解析: ' + JSON.stringify(d).slice(0, 120);
362
+ out.push({ uin: String(u), ec: Number.isFinite(ec) ? ec : -999, msg });
363
+ await sleep(400);
364
+ }
365
+ return out;
366
+ }
367
+ //# sourceMappingURL=qun-admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qun-admin.js","sourceRoot":"","sources":["../../src/features/qun-admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export interface QunCookie {
2
+ uin: string;
3
+ skey: string;
4
+ p_skey?: string;
5
+ }
6
+ export interface StartResult {
7
+ ok: boolean;
8
+ msg: string;
9
+ /** 需要扫码时给出二维码图片路径(上层用 send_media 发给用户) */
10
+ qrPath?: string;
11
+ /** 自动点头像成功时直接给出凭据 */
12
+ cookie?: QunCookie;
13
+ }
14
+ /** 找系统浏览器(Edge 优先:Windows 必装)。可用 QUN_BROWSER 环境变量覆盖。 */
15
+ export declare function findSystemBrowser(): string | null;
16
+ export declare function qunLoginSessionAlive(dataRoot: string): boolean;
17
+ export declare function qunLoginSessionClose(dataRoot: string): void;
18
+ /**
19
+ * 第一步:开浏览器 → 有头像就自动点(免扫码),没头像就出二维码。
20
+ * 拿到凭据就返回 cookie 并关掉浏览器;需要扫码则**保留浏览器**,让上层把 qrPath 发给用户,
21
+ * 之后用 qunBrowserLoginWait 继续等。
22
+ */
23
+ export declare function qunBrowserLoginStart(dataRoot: string, opts?: {
24
+ headless?: boolean;
25
+ profileDir?: string;
26
+ }): Promise<StartResult>;
27
+ /**
28
+ * 第二步:在已开的会话上继续等(扫码 or 点头像跳转完成)。
29
+ * budgetMs 默认 25 秒 —— 别让工具调用卡太久,用户可以多次调。
30
+ */
31
+ export declare function qunBrowserLoginWait(dataRoot: string, budgetMs?: number): Promise<{
32
+ ok: boolean;
33
+ done: boolean;
34
+ msg: string;
35
+ cookie?: QunCookie;
36
+ }>;
37
+ /** 退出登录:清掉浏览器 profile 里的 QQ 登录态(一般不用,留着以后"切换账号"用) */
38
+ export declare function clearBrowserProfile(dataRoot: string): void;
39
+ //# sourceMappingURL=qun-login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qun-login.d.ts","sourceRoot":"","sources":["../../src/features/qun-login.ts"],"names":[],"mappings":"AAmDA,MAAM,WAAW,SAAS;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AAEzE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAMD,wDAAwD;AACxD,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAoBjD;AA8MD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE3D;AA0GD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,OAAO,CAAC,WAAW,CAAC,CAkNtB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,SAAQ,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAyB1E;AAED,qDAAqD;AACrD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAG1D"}