oicq-icalingua-plus-plus 1.24.0 → 1.24.2
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/index.d.ts +10 -1
- package/lib/client-ext.js +1 -1
- package/lib/client.js +29 -0
- package/lib/core/friendlist.js +2 -1
- package/lib/device.js +68 -0
- package/lib/message/builder.js +8 -0
- package/lib/message/image.js +110 -1
- package/lib/message/multi.js +14 -0
- package/lib/message/parser.js +120 -37
- package/lib/message/ptt.js +1 -0
- package/lib/oicq.js +1 -0
- package/lib/wtlogin/wt.js +2 -0
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -162,6 +162,7 @@ export interface MemberBaseInfo {
|
|
|
162
162
|
readonly role: GroupRole, //权限
|
|
163
163
|
readonly title: string, //头衔
|
|
164
164
|
readonly subid: number,
|
|
165
|
+
readonly uid: string,
|
|
165
166
|
}
|
|
166
167
|
/** 群员资料 */
|
|
167
168
|
export interface MemberInfo extends MemberBaseInfo {
|
|
@@ -195,7 +196,8 @@ export interface MemberInfo extends MemberBaseInfo {
|
|
|
195
196
|
*/
|
|
196
197
|
export type MessageElem = TextElem | AtElem | FaceElem | BfaceElem | MfaceElem |
|
|
197
198
|
ImgPttElem | LocationElem | MusicElem | ShareElem | JsonElem | XmlElem |
|
|
198
|
-
AnonymousElem | ReplyElem | NodeElem | ShakeElem | PokeElem | FileElem | VideoElem |
|
|
199
|
+
AnonymousElem | ReplyElem | NodeElem | ShakeElem | PokeElem | FileElem | VideoElem |
|
|
200
|
+
MiraiElem | RawElem | MarkdownElem;
|
|
199
201
|
|
|
200
202
|
export type Sendable = string | MessageElem | Iterable<MessageElem | string>
|
|
201
203
|
|
|
@@ -374,6 +376,13 @@ export interface MiraiElem {
|
|
|
374
376
|
}
|
|
375
377
|
}
|
|
376
378
|
|
|
379
|
+
/** Markdown消息 */
|
|
380
|
+
export interface MarkdownElem {
|
|
381
|
+
type: "markdown",
|
|
382
|
+
data: {
|
|
383
|
+
markdown: string
|
|
384
|
+
}
|
|
385
|
+
}
|
|
377
386
|
/** 该元素为需要直接发送的原始消息体,JSON 格式 */
|
|
378
387
|
export interface RawElem {
|
|
379
388
|
type: "raw",
|
package/lib/client-ext.js
CHANGED
|
@@ -102,7 +102,7 @@ Client.prototype.sendOidbSvcTrpcTcp = async function (cmd, body) {
|
|
|
102
102
|
1: type1,
|
|
103
103
|
2: isNaN(type2) ? 1 : type2,
|
|
104
104
|
4: body,
|
|
105
|
-
|
|
105
|
+
12: 0,
|
|
106
106
|
});
|
|
107
107
|
const payload = await this.sendUni(cmd, body);
|
|
108
108
|
const rsp = pb.decode(payload);
|
package/lib/client.js
CHANGED
|
@@ -278,6 +278,8 @@ class Client extends EventEmitter {
|
|
|
278
278
|
this.on("internal.login", onlineListener);
|
|
279
279
|
this.on("internal.packet", packetListener);
|
|
280
280
|
this.on("internal.network", networkErrorListener);
|
|
281
|
+
|
|
282
|
+
this.readStorageConfig();
|
|
281
283
|
}
|
|
282
284
|
|
|
283
285
|
/**
|
|
@@ -688,6 +690,33 @@ class Client extends EventEmitter {
|
|
|
688
690
|
acquireGfs(group_id) {
|
|
689
691
|
return new Gfs(this, group_id);
|
|
690
692
|
}
|
|
693
|
+
saveStorageConfig() {
|
|
694
|
+
try {
|
|
695
|
+
fs.writeFileSync(path.join(this.dir, "storage.json"), JSON.stringify({
|
|
696
|
+
sig_session: this.storage.sig_session.toString("base64"),
|
|
697
|
+
session_key: this.storage.session_key.toString("base64"),
|
|
698
|
+
ip: this.storage.ip,
|
|
699
|
+
port: this.storage.port,
|
|
700
|
+
}));
|
|
701
|
+
} catch (e) {
|
|
702
|
+
this.logger.error(e);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
readStorageConfig() {
|
|
706
|
+
try {
|
|
707
|
+
const bakPath = path.join(this.dir, "storage.json");
|
|
708
|
+
if (!fs.existsSync(bakPath))
|
|
709
|
+
return;
|
|
710
|
+
const bakJSON = fs.readFileSync(bakPath).toString();
|
|
711
|
+
const bakConfig = JSON.parse(bakJSON);
|
|
712
|
+
this.storage.sig_session = Buffer.from(bakConfig.sig_session, "base64");
|
|
713
|
+
this.storage.session_key = Buffer.from(bakConfig.session_key, "base64");
|
|
714
|
+
this.storage.ip = bakConfig.ip;
|
|
715
|
+
this.storage.port = bakConfig.port;
|
|
716
|
+
} catch (e) {
|
|
717
|
+
this.logger.error(e);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
691
720
|
}
|
|
692
721
|
|
|
693
722
|
function createDataDir(dir, uin) {
|
package/lib/core/friendlist.js
CHANGED
|
@@ -159,7 +159,7 @@ async function __getGML(group_id, next_uin) {
|
|
|
159
159
|
method: "GetTroopMemberListReq",
|
|
160
160
|
};
|
|
161
161
|
const body = jce.encodeWrapper({ GTML }, extra);
|
|
162
|
-
const blob = await this.sendUni("friendlist.
|
|
162
|
+
const blob = await this.sendUni("friendlist.GetTroopMemberList", body, 10);
|
|
163
163
|
const nested = jce.decode(blob);
|
|
164
164
|
const map = new Map(), next = nested[4];
|
|
165
165
|
for (let v of nested[3]) {
|
|
@@ -182,6 +182,7 @@ async function __getGML(group_id, next_uin) {
|
|
|
182
182
|
card_changeable: true,
|
|
183
183
|
shutup_time: v[30] * 1000 > Date.now() ? v[30] : 0,
|
|
184
184
|
update_time: 0,
|
|
185
|
+
uid: v[42] || "",
|
|
185
186
|
});
|
|
186
187
|
}
|
|
187
188
|
try {
|
package/lib/device.js
CHANGED
|
@@ -432,6 +432,58 @@ const apk = {
|
|
|
432
432
|
ssover: 21,
|
|
433
433
|
qua: 'V1_AND_SQ_9.0.0_5282_YYB_D',
|
|
434
434
|
},
|
|
435
|
+
|
|
436
|
+
//android phone 9.0.8
|
|
437
|
+
41: {
|
|
438
|
+
...DEFAULT_ANDROID_APK_INFO,
|
|
439
|
+
name: "A9.0.8.10368491",
|
|
440
|
+
version: "9.0.8.14755",
|
|
441
|
+
ver: "9.0.8",
|
|
442
|
+
buildtime: 1702888273,
|
|
443
|
+
subid: 537200218,
|
|
444
|
+
sdkver: "6.0.0.2558",
|
|
445
|
+
ssover: 21,
|
|
446
|
+
qua: 'V1_AND_SQ_9.0.8_5540_YYB_D',
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
//android phone 9.0.17
|
|
450
|
+
43: {
|
|
451
|
+
...DEFAULT_ANDROID_APK_INFO,
|
|
452
|
+
name: "A9.0.17.6a4a36ca",
|
|
453
|
+
version: "9.0.17.151855",
|
|
454
|
+
ver: "9.0.17",
|
|
455
|
+
buildtime: 1702888273,
|
|
456
|
+
subid: 537204056,
|
|
457
|
+
sdkver: "6.0.0.2558",
|
|
458
|
+
ssover: 21,
|
|
459
|
+
qua: 'V1_AND_SQ_9.0.17_5712_YYB_D',
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
//android phone 9.0.25
|
|
463
|
+
45: {
|
|
464
|
+
...DEFAULT_ANDROID_APK_INFO,
|
|
465
|
+
name: "A9.0.25.63b29b33",
|
|
466
|
+
version: "9.0.25.15760",
|
|
467
|
+
ver: "9.0.25",
|
|
468
|
+
buildtime: 1702888273,
|
|
469
|
+
subid: 537210084,
|
|
470
|
+
sdkver: "6.0.0.2558",
|
|
471
|
+
ssover: 21,
|
|
472
|
+
qua: 'V1_AND_SQ_9.0.25_5942_YYB_D',
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
//android phone 9.0.35
|
|
476
|
+
47: {
|
|
477
|
+
...DEFAULT_ANDROID_APK_INFO,
|
|
478
|
+
name: "A9.0.35.52ab3f26",
|
|
479
|
+
version: "9.0.35.16275",
|
|
480
|
+
ver: "9.0.35",
|
|
481
|
+
buildtime: 1710769234,
|
|
482
|
+
subid: 537215475,
|
|
483
|
+
sdkver: "6.0.0.2559",
|
|
484
|
+
ssover: 21,
|
|
485
|
+
qua: 'V1_AND_SQ_9.0.35_6150_YYB_D',
|
|
486
|
+
},
|
|
435
487
|
};
|
|
436
488
|
|
|
437
489
|
//apad
|
|
@@ -502,6 +554,22 @@ apk[38].subid = 537187437;
|
|
|
502
554
|
apk[40] = { ...apk[39] };
|
|
503
555
|
apk[40].subid = 537194390;
|
|
504
556
|
|
|
557
|
+
//apad 9.0.8
|
|
558
|
+
apk[42] = { ...apk[41] };
|
|
559
|
+
apk[42].subid = 537200257;
|
|
560
|
+
|
|
561
|
+
//apad 9.0.17
|
|
562
|
+
apk[44] = { ...apk[43] };
|
|
563
|
+
apk[44].subid = 537204095;
|
|
564
|
+
|
|
565
|
+
//apad 9.0.25
|
|
566
|
+
apk[46] = { ...apk[45] };
|
|
567
|
+
apk[46].subid = 537210123;
|
|
568
|
+
|
|
569
|
+
//apad 9.0.35
|
|
570
|
+
apk[48] = { ...apk[47] };
|
|
571
|
+
apk[48].subid = 537215514;
|
|
572
|
+
|
|
505
573
|
//ipad
|
|
506
574
|
apk[5] = { ...apk[1] };
|
|
507
575
|
apk[5].subid = 537155074;
|
package/lib/message/builder.js
CHANGED
|
@@ -879,6 +879,9 @@ class Builder {
|
|
|
879
879
|
case "mirai":
|
|
880
880
|
this.buildMiraiElem(data);
|
|
881
881
|
break;
|
|
882
|
+
case "markdown":
|
|
883
|
+
this.c.logger.warn("暂不支持发送markdown消息");
|
|
884
|
+
break;
|
|
882
885
|
case "raw":
|
|
883
886
|
try {
|
|
884
887
|
this.elems.push(...JSON.parse(data.data));
|
|
@@ -1068,6 +1071,11 @@ class Builder {
|
|
|
1068
1071
|
}
|
|
1069
1072
|
if (retcode === 0) {
|
|
1070
1073
|
if (this.type === 0) { //私聊
|
|
1074
|
+
if (rsp[14] === 0) {
|
|
1075
|
+
let emsg = rsp[2] ? String(rsp[2]) : "";
|
|
1076
|
+
this.c.logger.error(`send failed: [${TYPES[this.type]}: ${this.target}] ${emsg}`);
|
|
1077
|
+
return { result: -1, emsg };
|
|
1078
|
+
}
|
|
1071
1079
|
message_id = genC2CMessageId(this.target, this.seq, this.random, rsp[3], 1);
|
|
1072
1080
|
}
|
|
1073
1081
|
if (this.type === 1 && !message_id) { //群聊
|
package/lib/message/image.js
CHANGED
|
@@ -8,6 +8,7 @@ const fs = require("fs");
|
|
|
8
8
|
const path = require("path");
|
|
9
9
|
const { randomBytes } = require("crypto");
|
|
10
10
|
const probe = require("probe-image-size");
|
|
11
|
+
const axios = require("axios");
|
|
11
12
|
const pb = require("../algo/pb");
|
|
12
13
|
const common = require("../common");
|
|
13
14
|
const { downloadFromWeb, highwayUploadStream, MAX_UPLOAD_SIZE } = require("../service");
|
|
@@ -595,7 +596,115 @@ async function offNTPicDown(user_id, fileResId) {
|
|
|
595
596
|
return "https://gchat.qpic.cn" + String(rsp[11]);
|
|
596
597
|
}
|
|
597
598
|
|
|
599
|
+
/**
|
|
600
|
+
* 判断图片URL是否有效
|
|
601
|
+
* @this {import("../ref").Client}
|
|
602
|
+
* @param {string} url
|
|
603
|
+
*/
|
|
604
|
+
async function checkImgUrl(url) {
|
|
605
|
+
const data = await axios.get(url, {
|
|
606
|
+
headers: { Range: 'bytes=0-1' }
|
|
607
|
+
}).then(res => res.data).catch(() => null);
|
|
608
|
+
return !!data;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* 获取QQNT私聊图URL
|
|
613
|
+
* @this {import("../ref").Client}
|
|
614
|
+
* @param {Buffer} imgInfo
|
|
615
|
+
* @param {String} uid
|
|
616
|
+
*/
|
|
617
|
+
async function getOffNTPicURL(imgInfo, uid = String(this.uid || this.uin)) {
|
|
618
|
+
const body = pb.encode({
|
|
619
|
+
1: {
|
|
620
|
+
1: {
|
|
621
|
+
1: 1,
|
|
622
|
+
2: 200,
|
|
623
|
+
},
|
|
624
|
+
2: {
|
|
625
|
+
101: 2,
|
|
626
|
+
102: 1,
|
|
627
|
+
200: 1,
|
|
628
|
+
201: {
|
|
629
|
+
1: 2,
|
|
630
|
+
2: uid,
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
3: {
|
|
634
|
+
1: 2,
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
3: {
|
|
638
|
+
1: imgInfo,
|
|
639
|
+
2: {
|
|
640
|
+
2: {
|
|
641
|
+
1: 0,
|
|
642
|
+
3: 0,
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
try {
|
|
648
|
+
const rsp = await this.sendOidbSvcTrpcTcp("OidbSvcTrpcTcp.0x11c5_200", body);
|
|
649
|
+
const rkey = rsp[3][1];
|
|
650
|
+
if (!rkey)
|
|
651
|
+
throw new Error("rkey不存在");
|
|
652
|
+
return `https://${rsp[3][3][1]}${rsp[3][3][2]}${rkey}&spec=0`;
|
|
653
|
+
} catch (e) {
|
|
654
|
+
this.logger.warn("获取QQNT图片URL失败", e.message);
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* 获取QQNT群图URL
|
|
661
|
+
* @this {import("../ref").Client}
|
|
662
|
+
* @param {Buffer} imgInfo
|
|
663
|
+
* @param {number} gid
|
|
664
|
+
*/
|
|
665
|
+
async function getGroupNTPicURL(imgInfo, gid = 284840486) {
|
|
666
|
+
const body = pb.encode({
|
|
667
|
+
1: {
|
|
668
|
+
1: {
|
|
669
|
+
1: 1,
|
|
670
|
+
2: 200,
|
|
671
|
+
},
|
|
672
|
+
2: {
|
|
673
|
+
101: 2,
|
|
674
|
+
102: 1,
|
|
675
|
+
200: 2,
|
|
676
|
+
202: {
|
|
677
|
+
1: gid,
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
3: {
|
|
681
|
+
1: 2,
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
3: {
|
|
685
|
+
1: imgInfo,
|
|
686
|
+
2: {
|
|
687
|
+
2: {
|
|
688
|
+
1: 0,
|
|
689
|
+
3: 0,
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
try {
|
|
695
|
+
const rsp = await this.sendOidbSvcTrpcTcp("OidbSvcTrpcTcp.0x11c5_200", body);
|
|
696
|
+
const rkey = rsp[3][1];
|
|
697
|
+
if (!rkey)
|
|
698
|
+
throw new Error("rkey不存在");
|
|
699
|
+
return `https://${rsp[3][3][1]}${rsp[3][3][2]}${rkey}&spec=0`;
|
|
700
|
+
} catch (e) {
|
|
701
|
+
this.logger.warn("获取QQNT图片URL失败", e.message);
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
598
706
|
module.exports = {
|
|
599
707
|
ImageBuilder, uploadImages, buildImageFileParam,
|
|
600
|
-
groupNTPicDown, offNTPicDown,
|
|
708
|
+
groupNTPicDown, offNTPicDown, checkImgUrl,
|
|
709
|
+
getGroupNTPicURL, getOffNTPicURL,
|
|
601
710
|
};
|
package/lib/message/multi.js
CHANGED
|
@@ -334,6 +334,13 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
|
|
|
334
334
|
for (let i of msg[3][1][2]) {
|
|
335
335
|
if (i[9]) {
|
|
336
336
|
elements.push(i);
|
|
337
|
+
elements.push({
|
|
338
|
+
37: {
|
|
339
|
+
19: {
|
|
340
|
+
15: 65536
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
});
|
|
337
344
|
break;
|
|
338
345
|
}
|
|
339
346
|
}
|
|
@@ -348,6 +355,13 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
|
|
|
348
355
|
1: fake.bubble_id
|
|
349
356
|
}
|
|
350
357
|
});
|
|
358
|
+
elements.push({
|
|
359
|
+
37: {
|
|
360
|
+
19: {
|
|
361
|
+
15: 65536
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
351
365
|
}
|
|
352
366
|
nodes.push({
|
|
353
367
|
1: {
|
package/lib/message/parser.js
CHANGED
|
@@ -10,7 +10,7 @@ const pb = require("../algo/pb");
|
|
|
10
10
|
const face = require("./face");
|
|
11
11
|
const { getGroupMsgs } = require("./history");
|
|
12
12
|
const { int32ip2str } = require("../service");
|
|
13
|
-
const { buildImageFileParam, groupNTPicDown, offNTPicDown } = require("./image");
|
|
13
|
+
const { buildImageFileParam, groupNTPicDown, offNTPicDown, checkImgUrl, getOffNTPicURL, getGroupNTPicURL } = require("./image");
|
|
14
14
|
const { Gfs, getC2CFileUrl } = require("./file");
|
|
15
15
|
const { getVideoUrl, getPttUrl } = require("./ptt");
|
|
16
16
|
const { genC2CMessageId, genGroupMessageId, timestamp, parseFunString, code2uin, genRandom, unzip } = require("../common");
|
|
@@ -203,7 +203,7 @@ class Parser {
|
|
|
203
203
|
break;
|
|
204
204
|
case 3: //flash
|
|
205
205
|
msg.type = "flash";
|
|
206
|
-
msg.data = await this.parseImgElem(elem);
|
|
206
|
+
msg.data = await this.parseImgElem(type, elem);
|
|
207
207
|
brief = "[闪照]";
|
|
208
208
|
break;
|
|
209
209
|
case 0: //ptt
|
|
@@ -343,7 +343,7 @@ class Parser {
|
|
|
343
343
|
case 4:
|
|
344
344
|
case 8:
|
|
345
345
|
msg.type = "image";
|
|
346
|
-
msg.data = await this.parseImgElem(elem);
|
|
346
|
+
msg.data = await this.parseImgElem(type, elem);
|
|
347
347
|
brief = "[图片]";
|
|
348
348
|
break;
|
|
349
349
|
case 34: //sface
|
|
@@ -361,6 +361,21 @@ class Parser {
|
|
|
361
361
|
return;
|
|
362
362
|
}
|
|
363
363
|
break;
|
|
364
|
+
case 45: //markdown
|
|
365
|
+
msg.type = "markdown";
|
|
366
|
+
brief = String(elem[1]);
|
|
367
|
+
msg.data.markdown = brief;
|
|
368
|
+
break;
|
|
369
|
+
case 46: //markdown button
|
|
370
|
+
break;
|
|
371
|
+
case 48: //image of qqnt
|
|
372
|
+
const imgData = await this.parseNTImgElem(type, elem);
|
|
373
|
+
if (imgData) {
|
|
374
|
+
msg.type = "image";
|
|
375
|
+
msg.data = imgData;
|
|
376
|
+
brief = "[图片]";
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
364
379
|
default:
|
|
365
380
|
return;
|
|
366
381
|
}
|
|
@@ -450,8 +465,11 @@ class Parser {
|
|
|
450
465
|
} else if (elem[1] === 20) { //json only for mobileqq
|
|
451
466
|
await this.parseExclusiveElem(51, elem[2]);
|
|
452
467
|
} else if (elem[1] == 48) { //image prefix of qqnt
|
|
468
|
+
await this.parsePartialElem(48, elem[2]);
|
|
453
469
|
if (elem[2] && elem[2][1] && elem[2][1][2] && elem[2][1][2][1] && elem[2][1][2][3])
|
|
454
470
|
this.imgprefix = "https://" + String(elem[2][1][2][3]) + String(elem[2][1][2][1]);
|
|
471
|
+
} else if (elem[1] == 45) { //markdown
|
|
472
|
+
await this.parsePartialElem(type, elem[2]);
|
|
455
473
|
}
|
|
456
474
|
break;
|
|
457
475
|
case 45: //reply
|
|
@@ -465,50 +483,115 @@ class Parser {
|
|
|
465
483
|
}
|
|
466
484
|
|
|
467
485
|
/**
|
|
468
|
-
*
|
|
486
|
+
* 解析QQNT图片
|
|
469
487
|
* @private
|
|
488
|
+
* @param {number} type 48|3
|
|
470
489
|
* @param {import("../ref").Proto} elem
|
|
471
490
|
*/
|
|
472
|
-
async
|
|
491
|
+
async parseNTImgElem(type, elem) {
|
|
473
492
|
const data = { };
|
|
474
|
-
if (elem[
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
493
|
+
if (!elem[2] || !elem[2][1]) return null;
|
|
494
|
+
const dm = !!elem[2][1][11];
|
|
495
|
+
const extra = dm ? elem[2][1][11] : elem[2][1][12];
|
|
496
|
+
if (!extra) return null;
|
|
497
|
+
const ntPath = String(extra[30] || "");
|
|
498
|
+
|
|
499
|
+
const imgInfo = elem[1][1];
|
|
500
|
+
const md5 = imgInfo[1][2]; //string, not buffer
|
|
501
|
+
const sha1 = imgInfo[1][3];
|
|
502
|
+
const fileName = imgInfo[1][4];
|
|
503
|
+
const size = imgInfo[1][1];
|
|
504
|
+
const width = imgInfo[1][6];
|
|
505
|
+
const height = imgInfo[1][7];
|
|
506
|
+
const imgType = imgInfo[1][5][2];
|
|
507
|
+
|
|
508
|
+
const fileid = imgInfo[2];
|
|
509
|
+
const storeId = imgInfo[3];
|
|
510
|
+
const time = imgInfo[4];
|
|
511
|
+
|
|
512
|
+
data.file = buildImageFileParam(md5.toString(), size, width, height, imgType);
|
|
513
|
+
|
|
514
|
+
if (ntPath) {
|
|
515
|
+
data.url = `https://${elem[1][2][3]}${ntPath}&spec=0`;
|
|
516
|
+
} else {
|
|
517
|
+
data.url = `https://gchat.qpic.cn/gchatpic_new/0/0-0-${md5.toUpperCase()}/0`;
|
|
518
|
+
}
|
|
519
|
+
if (timestamp() - time > 60 * 60 || !(await checkImgUrl(data.url))) {
|
|
520
|
+
// 图片地址失效,尝试发包获取
|
|
521
|
+
let newURL = null;
|
|
522
|
+
if (dm) { //私聊
|
|
523
|
+
newURL = await getOffNTPicURL.call(this.c, imgInfo, String(this.uid));
|
|
524
|
+
} else { //群聊
|
|
525
|
+
newURL = await getGroupNTPicURL.call(this.c, imgInfo, this.gid);
|
|
481
526
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (this.imgprefix) {
|
|
485
|
-
data.file = buildImageFileParam(elem[13].toHex(), elem[25], elem[22], elem[23], elem[20]);
|
|
486
|
-
data.url = this.imgprefix + String(elem[34][30]) + "&spec=0";
|
|
487
|
-
this.imgprefix = null;
|
|
488
|
-
return data;
|
|
527
|
+
if (newURL) {
|
|
528
|
+
data.url = newURL;
|
|
489
529
|
}
|
|
490
530
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
531
|
+
return data;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* 解析图片
|
|
536
|
+
* @private
|
|
537
|
+
* @param {number} type 4|8|3
|
|
538
|
+
* @param {import("../ref").Proto} elem
|
|
539
|
+
*/
|
|
540
|
+
async parseImgElem(type, elem) {
|
|
541
|
+
const data = { };
|
|
542
|
+
const dm = type === 3 ? (!!elem[1]) : (type === 4); //私图
|
|
543
|
+
const md5 = dm ? elem[7] : elem[13];
|
|
544
|
+
const fileName = dm ? elem[1] : elem[2];
|
|
545
|
+
const fileid = dm ? elem[3] : elem[7];
|
|
546
|
+
const fileResId = dm ? elem[10] : undefined;
|
|
547
|
+
const extra = dm ? elem[29] : elem[34];
|
|
548
|
+
const ntPath = extra ? String(extra[30]) : null;
|
|
549
|
+
|
|
550
|
+
const size = dm ? elem[2] : elem[25];
|
|
551
|
+
const width = dm ? elem[9] : elem[22];
|
|
552
|
+
const height = dm ? elem[8] : elem[23];
|
|
553
|
+
const imgType = dm ? elem[5] : elem[20];
|
|
554
|
+
data.file = buildImageFileParam(md5.toHex(), size, width, height, imgType);
|
|
555
|
+
|
|
556
|
+
if (this.imgprefix && ntPath && ntPath.startsWith("&rkey=")) {
|
|
557
|
+
data.url = this.imgprefix + String(ntPath) + "&spec=0";
|
|
558
|
+
this.imgprefix = null;
|
|
559
|
+
if (await checkImgUrl(data.url))
|
|
560
|
+
return data;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (dm) { //私图
|
|
564
|
+
if (ntPath && ntPath.startsWith("/download") && ntPath.includes("rkey=")) {
|
|
565
|
+
data.url = "https://gchat.qpic.cn" + ntPath + "&spec=0";
|
|
566
|
+
} else if (elem[15]) {
|
|
567
|
+
data.url = "https://gchat.qpic.cn" + elem[15];
|
|
568
|
+
} else {
|
|
569
|
+
data.url = `https://gchat.qpic.cn/gchatpic_new/0/0-0-${md5.toHex().toUpperCase()}/0`
|
|
570
|
+
}
|
|
571
|
+
if (!(await checkImgUrl(data.url))) {
|
|
572
|
+
// 图片地址失效,尝试发包获取
|
|
573
|
+
if (elem[23]) { //QQNT 私聊合并转发到群聊图
|
|
574
|
+
data.url = await groupNTPicDown.call(this.c, this.gid || 284840486, elem[23], md5);
|
|
575
|
+
} else { //纯私聊图片
|
|
576
|
+
data.url = await offNTPicDown.call(this.c, this.uid, fileResId);
|
|
577
|
+
}
|
|
501
578
|
}
|
|
502
|
-
else if (elem[15])
|
|
503
|
-
data.url = "https://c2cpicdw.qpic.cn" + elem[15];
|
|
504
579
|
} else { //群图
|
|
505
|
-
|
|
506
|
-
|
|
580
|
+
if (ntPath && ntPath.startsWith("/download") && ntPath.includes("rkey=")) {
|
|
581
|
+
data.url = "https://gchat.qpic.cn" + ntPath + "&spec=0";
|
|
582
|
+
} else if (elem[16]) {
|
|
507
583
|
data.url = "https://gchat.qpic.cn" + elem[16];
|
|
508
|
-
else
|
|
509
|
-
data.url = `https://gchat.qpic.cn/gchatpic_new
|
|
510
|
-
|
|
511
|
-
|
|
584
|
+
} else {
|
|
585
|
+
data.url = `https://gchat.qpic.cn/gchatpic_new/0/0-0-${md5.toHex().toUpperCase()}/0`
|
|
586
|
+
}
|
|
587
|
+
if (!(await checkImgUrl(data.url))) {
|
|
588
|
+
// 图片地址失效,尝试发包获取
|
|
589
|
+
if (fileid) { //纯群聊图片
|
|
590
|
+
data.url = await groupNTPicDown.call(this.c, this.gid || 284840486, fileid, md5);
|
|
591
|
+
} else { //QQNT 群聊合并转发到私聊图
|
|
592
|
+
data.url = await offNTPicDown.call(this.c, this.uid, fileName);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
512
595
|
}
|
|
513
596
|
return data;
|
|
514
597
|
}
|
package/lib/message/ptt.js
CHANGED
package/lib/oicq.js
CHANGED
package/lib/wtlogin/wt.js
CHANGED
|
@@ -47,6 +47,8 @@ class WtLogin {
|
|
|
47
47
|
set nickname(val) { this.c.nickname = val; }
|
|
48
48
|
set sex(val) { this.c.sex = val; }
|
|
49
49
|
set age(val) { this.c.age = val; }
|
|
50
|
+
get uid() { return this.c.uid; }
|
|
51
|
+
set uid(val) { this.c.uid = val; }
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
54
|
* @param {import("../ref").Client} c
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oicq-icalingua-plus-plus",
|
|
3
3
|
"app_name": "oicq-icalingua-plus-plus",
|
|
4
|
-
"version": "1.24.
|
|
5
|
-
"app_version": "1.24.
|
|
6
|
-
"upday": "2024/
|
|
4
|
+
"version": "1.24.2",
|
|
5
|
+
"app_version": "1.24.2",
|
|
6
|
+
"upday": "2024/04/22",
|
|
7
7
|
"protocol_version": "v11",
|
|
8
8
|
"description": "oicq(https://github.com/takayama-lily/oicq) v1 for Icalingua++",
|
|
9
9
|
"main": "index.js",
|