oicq-icalingua-plus-plus 1.26.3 → 1.26.4

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 CHANGED
@@ -1076,8 +1076,10 @@ export class Client extends EventEmitter {
1076
1076
  /**
1077
1077
  * 制作一个合并转发消息,得到的XmlElem可直接发送
1078
1078
  * @param dm 默认(false)以群模式上传图片,设为true则以私聊模式上传图片
1079
+ * @param target 指定合并转发来源
1080
+ * @param nt 默认(true)使用NT协议上传,设为false则使用旧协议
1079
1081
  */
1080
- makeForwardMsg(fakes: FakeMessage | Iterable<FakeMessage>, dm?: boolean, target?: number): Promise<Ret<XmlElem>>;
1082
+ makeForwardMsg(fakes: FakeMessage | Iterable<FakeMessage>, dm?: boolean, target?: number, nt?: boolean): Promise<Ret<XmlElem>>;
1081
1083
 
1082
1084
  /** 发简易群公告 */
1083
1085
  sendGroupNotice(group_id: number, content: string): Promise<Ret>;
package/lib/client.js CHANGED
@@ -495,7 +495,7 @@ class Client extends EventEmitter {
495
495
  getForwardMsg(id, fileName = "MultiMsg") {
496
496
  return this._useProtocol(chat.getForwardMsg, arguments);
497
497
  }
498
- makeForwardMsg(fakes, dm = false, target = 0) {
498
+ makeForwardMsg(fakes, dm = false, target = 0, nt = true) {
499
499
  return this._useProtocol(multi.makeForwardMsg, arguments);
500
500
  }
501
501
 
@@ -296,6 +296,19 @@ class ImageBuilder {
296
296
  */
297
297
  async download() {
298
298
  this.c.logger.debug("开始下载网络图片: " + this.address);
299
+ if (this.address.includes('&fileid=') && (this.address.startsWith('https://multimedia.nt.qq.com.cn/download') || this.address.startsWith('https://gchat.qpic.cn/download'))) {
300
+ // 如果是QQNT图片,尝试获取rkey刷新URL
301
+ try {
302
+ const url = new URL(this.address);
303
+ const fileid = url.searchParams.get('fileid');
304
+ if (fileid) {
305
+ this.address = await getNTPicURLbyFileid.call(this.c, fileid);
306
+ this.c.logger.debug("下载QQNT网络图片: " + this.address);
307
+ }
308
+ } catch (e) {
309
+ this.c.logger.warn(`获取QQNT图片rkey失败: ${e.message}`);
310
+ }
311
+ }
299
312
  try {
300
313
  this.tmpfile = this.filepath + common.uuid() + ".img";
301
314
  var res = await downloadFromWeb(this.address, this.headers);
@@ -53,12 +53,12 @@ function buildFaceElem(id) {
53
53
  }
54
54
  }
55
55
 
56
- async function buildXmlElem(xml, svcid = 60) {
56
+ async function buildXmlElem(xml, svcid = 35) {
57
57
  svcid = parseInt(svcid);
58
58
  return {
59
59
  12: {
60
60
  1: Buffer.concat([BUF1, await deflate(String(xml))]),
61
- 2: svcid > 0 ? svcid : 60,
61
+ 2: svcid > 0 ? svcid : 35,
62
62
  }
63
63
  };
64
64
  }
@@ -155,11 +155,46 @@ async function _downloadMultiMsg(resid, bu) {
155
155
  });
156
156
  }
157
157
 
158
+ /**
159
+ * @this {import("../ref").Client}
160
+ * @param {Buffer} resid
161
+ * @param {Number} bu
162
+ * @returns {Promise<Buffer>}
163
+ */
164
+ async function _downloadMultiMsgNt(resid, bu) {
165
+ const body = pb.encode({
166
+ 1: {
167
+ 1: {
168
+ 2: this.uin,
169
+ },
170
+ 2: resid,
171
+ 3: bu === 2 ? 3 : 1,
172
+ },
173
+ 15: {
174
+ 1: 2,
175
+ 2: 2,
176
+ 3: 9,
177
+ 4: 0,
178
+ },
179
+ });
180
+ const payload = await this.sendUni("trpc.group.long_msg_interface.MsgService.SsoRecvLongMsg", body);
181
+ try {
182
+ const rsp = pb.decode(payload)[1];
183
+ return common.unzip(rsp[4].toBuffer());
184
+ } catch (e) {
185
+ e.message = "wrong resid";
186
+ throw e;
187
+ }
188
+ }
189
+
158
190
  /**
159
191
  * @this {import("../ref").Client}
160
192
  * @param {import("../ref").FakeMessage[]} iterable
193
+ * @param {boolean} dm
194
+ * @param {number} target
195
+ * @param {boolean} nt
161
196
  */
162
- async function makeForwardMsg(iterable, dm = false, target = 0) {
197
+ async function makeForwardMsg(iterable, dm = false, target = 0, nt = true) {
163
198
 
164
199
  if (typeof iterable[Symbol.iterator] !== "function")
165
200
  iterable = [iterable];
@@ -284,7 +319,7 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
284
319
  if (resIdRegex.test(elem.data.data) && fileNameRegex.test(elem.data.data)) {
285
320
  const resId = resIdRegex.exec(elem.data.data)[1];
286
321
  const fileName = fileNameRegex.exec(elem.data.data)[1];
287
- const buf = await _downloadMultiMsg.call(this, resId, 2);
322
+ const buf = await (nt ? _downloadMultiMsgNt : _downloadMultiMsg).call(this, resId, 2);
288
323
  let msgs = pb.decode(buf)[2];
289
324
  if (!Array.isArray(msgs)) {
290
325
  msgs = [msgs];
@@ -316,7 +351,7 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
316
351
  }
317
352
  } catch {}
318
353
  if (resId && fileName) {
319
- const buf = await _downloadMultiMsg.call(this, resId, 2);
354
+ const buf = await (nt ? _downloadMultiMsgNt : _downloadMultiMsg).call(this, resId, 2);
320
355
  let msgs = pb.decode(buf)[2];
321
356
  if (!Array.isArray(msgs)) {
322
357
  msgs = [msgs];
@@ -394,31 +429,67 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
394
429
  }
395
430
  });
396
431
  }
397
- nodes.push({
398
- 1: {
399
- 1: fake.user_id,
400
- 2: !target ? this.uin : target,
401
- 3: dm ? 166 : 82,
402
- 4: dm ? 11 : null,
403
- 5: seq,
404
- 6: fake.time || common.timestamp(),
405
- 7: common.genMessageUuid(random),
406
- 9: dm ? null : {
407
- 1: !target ? this.uin : target,
408
- 4: fake.nickname,
432
+ if (!nt) {
433
+ nodes.push({
434
+ 1: {
435
+ 1: fake.user_id,
436
+ 2: !target ? this.uin : target,
437
+ 3: dm ? 166 : 82,
438
+ 4: dm ? 11 : null,
439
+ 5: seq,
440
+ 6: fake.time || common.timestamp(),
441
+ 7: common.genMessageUuid(random),
442
+ 9: dm ? null : {
443
+ 1: !target ? this.uin : target,
444
+ 4: fake.nickname,
445
+ },
446
+ 14: dm ? fake.nickname : null,
447
+ 20: {
448
+ 1: 0,
449
+ 2: random
450
+ }
409
451
  },
410
- 14: dm ? fake.nickname : null,
411
- 20: {
412
- 1: 0,
413
- 2: random
452
+ 3: {
453
+ 1: {
454
+ 2: elements
455
+ }
414
456
  }
415
- },
416
- 3: {
457
+ });
458
+ } else {
459
+ nodes.push({
417
460
  1: {
418
- 2: elements
461
+ 1: fake.user_id,
462
+ //2: this.uid,
463
+ 5: dm ? this.uin : null,
464
+ 6: dm ? this.uid || null : null,
465
+ 7: dm ? { 6: fake.nickname } : null,
466
+ 8: dm ? null : { 1: target || this.uin, 4: fake.nickname },
467
+ },
468
+ 2: {
469
+ 1: dm ? 166 : 82,
470
+ 2: dm ? 11 : null,
471
+ 3: dm ? 11 : null,
472
+ 4: random,
473
+ 5: seq,
474
+ 6: fake.time || common.timestamp(),
475
+ 7: 1,
476
+ 8: 0,
477
+ 9: 0,
478
+ 15: {
479
+ 1: 0,
480
+ 2: 0,
481
+ 3: 0,
482
+ 4: "",
483
+ 5: "",
484
+ },
485
+ },
486
+ 3: {
487
+ 1: {
488
+ 2: elements
489
+ }
419
490
  }
420
- }
421
- });
491
+ });
492
+ }
422
493
  if (cnt < 4) {
423
494
  ++cnt
424
495
  preview += `<title color="#777777" size="26">${common.escapeXml(fake.nickname)}: ${common.escapeXml(brief.slice(0, 50))}</title>`;
@@ -442,9 +513,14 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
442
513
  2: Multi
443
514
  }));
444
515
  try {
445
- var resid = await uploadMultiMsg.call(this, this.uin, compressed);
516
+ var resid = await (nt ? uploadMultiMsgNt : uploadMultiMsg).call(this, target, compressed, dm);
446
517
  } catch (e) {
447
- throw new Error("failed to upload forward msg");
518
+ if (String(e.message).includes("-10122")) {
519
+ // 设备类型不支持nt
520
+ this.logger.warn("failed to upload forward msg with NT protocol, try old protocol -> " + e.message);
521
+ return makeForwardMsg.call(this, iterable, dm, target, false);
522
+ }
523
+ throw new Error("failed to upload forward msg -> " + e.message);
448
524
  }
449
525
 
450
526
  const xml = `<?xml version="1.0" encoding="utf-8"?>
@@ -464,9 +540,10 @@ async function makeForwardMsg(iterable, dm = false, target = 0) {
464
540
  * @this {import("../ref").Client}
465
541
  * @param {number} target
466
542
  * @param {Buffer} compressed
543
+ * @param {boolean} dm 是否为私聊消息
467
544
  * @returns {Promise<Buffer>} resid
468
545
  */
469
- async function uploadMultiMsg(target, compressed) {
546
+ async function uploadMultiMsg(target, compressed, dm = false) {
470
547
  const body = pb.encode({
471
548
  1: 1,
472
549
  2: 5,
@@ -491,7 +568,7 @@ async function uploadMultiMsg(target, compressed) {
491
568
  2: 5,
492
569
  3: 9,
493
570
  4: [{
494
- //1: 3,
571
+ 1: dm ? 1 : 3,
495
572
  2: target,
496
573
  4: compressed,
497
574
  5: 2,
@@ -514,6 +591,35 @@ async function uploadMultiMsg(target, compressed) {
514
591
  return rsp[2].toBuffer();
515
592
  }
516
593
 
594
+ /**
595
+ * @this {import("../ref").Client}
596
+ * @param {number} target
597
+ * @param {Buffer} compressed
598
+ * @param {boolean} dm 是否为私聊消息
599
+ * @returns {Promise<Buffer>} resid
600
+ */
601
+ async function uploadMultiMsgNt(target, compressed, dm = false) {
602
+ const body = pb.encode({
603
+ 2: {
604
+ 1: dm ? 1 : 3,
605
+ 2: {
606
+ 2: this.uin,
607
+ },
608
+ 3: dm ? 0 : target,
609
+ 4: compressed,
610
+ },
611
+ 15: {
612
+ 1: 4,
613
+ 2: 2,
614
+ 3: 9,
615
+ 4: 0,
616
+ },
617
+ });
618
+ const payload = await this.sendUni("trpc.group.long_msg_interface.MsgService.SsoSendLongMsg", body);
619
+ const rsp = pb.decode(payload)[2];
620
+ return rsp[3].toString();
621
+ }
622
+
517
623
  module.exports = {
518
- makeForwardMsg, uploadMultiMsg,
624
+ makeForwardMsg, uploadMultiMsg, uploadMultiMsgNt
519
625
  };
@@ -89,6 +89,38 @@ async function _downloadMultiMsg(resid, bu) {
89
89
  });
90
90
  }
91
91
 
92
+ /**
93
+ * @this {import("../ref").Client}
94
+ * @param {Buffer} resid
95
+ * @param {Number} bu
96
+ * @returns {Promise<Buffer>}
97
+ */
98
+ async function _downloadMultiMsgNt(resid, bu) {
99
+ const body = pb.encode({
100
+ 1: {
101
+ 1: {
102
+ 2: this.uin,
103
+ },
104
+ 2: resid,
105
+ 3: bu === 2 ? 3 : 1,
106
+ },
107
+ 15: {
108
+ 1: 2,
109
+ 2: 2,
110
+ 3: 9,
111
+ 4: 0,
112
+ },
113
+ });
114
+ const payload = await this.sendUni("trpc.group.long_msg_interface.MsgService.SsoRecvLongMsg", body);
115
+ try {
116
+ const rsp = pb.decode(payload)[1];
117
+ return unzip(rsp[4].toBuffer());
118
+ } catch (e) {
119
+ e.message = "wrong resid";
120
+ throw e;
121
+ }
122
+ }
123
+
92
124
  /**
93
125
  * 解析消息
94
126
  */
@@ -486,7 +518,7 @@ class Parser {
486
518
  } else if (type === 37) { //generalFlags 超长消息,气泡等
487
519
  if (elem[6] === 1 && elem[7]) {
488
520
  try {
489
- const buf = await _downloadMultiMsg.call(this.c, elem[7].toBuffer(), 1);
521
+ const buf = await _downloadMultiMsgNt.call(this.c, elem[7].toBuffer(), 1);
490
522
  let msg = pb.decode(buf)[1];
491
523
  if (Array.isArray(msg)) msg = msg[0];
492
524
  const parser = Parser.invoke(this.c, this.uid, this.gid, msg[3][1]);
@@ -1042,11 +1074,12 @@ async function parseDiscussMsg(msg) {
1042
1074
  * 解析转发消息
1043
1075
  * @this {import("../ref").Client}
1044
1076
  * @param {string} resid
1077
+ * @param {string} fileName
1045
1078
  * @returns {import("../ref").ProtocolResponse}
1046
1079
  */
1047
1080
  async function parseForwardMsg(resid, fileName) {
1048
1081
  const data = [];
1049
- const blob = await _downloadMultiMsg.call(this, String(resid), 2);
1082
+ const blob = await _downloadMultiMsgNt.call(this, String(resid), 2);
1050
1083
  /**
1051
1084
  * @type {import("../ref").Msg[]}
1052
1085
  */
@@ -1067,30 +1100,32 @@ async function parseForwardMsg(resid, fileName) {
1067
1100
  msgs = [msgs];
1068
1101
  for (let msg of msgs) {
1069
1102
  const head = msg[1];
1070
- let time = head[6];
1071
- let seq = head[5];
1103
+ const content = msg[2];
1104
+ const body = msg[3];
1105
+ let time = content[6];
1106
+ let seq = content[5];
1072
1107
  let user_id = head[1], nickname = "unknown", group_id;
1073
1108
  let head_img = "";
1074
- if (head[14]) {
1075
- nickname = String(head[14]);
1109
+ if (head[8]) { // group
1110
+ nickname = String(head[8][4]);
1076
1111
  try {
1077
- group_id = head[9][1];
1112
+ group_id = head[8][1];
1078
1113
  } catch { }
1079
- } else {
1114
+ } else { // c2c
1080
1115
  try {
1081
- nickname = String(head[9][4]);
1082
- group_id = head[9][1];
1116
+ nickname = String(head[7][6]);
1117
+ group_id = head[8][1];
1083
1118
  } catch { }
1084
1119
  }
1085
1120
  try {
1086
- head_img = String(head[20][5]);
1121
+ head_img = String(content[15][5]);
1087
1122
  } catch { }
1088
1123
  try {
1089
1124
  let parser;
1090
- if (head[3] === 529 && head[4] === 4 && msg[3][2]) {
1091
- const file_msg = msg[3][2];
1125
+ if (content[1] === 529 && content[2] === 4 && body[2]) { // 合并转发的文件
1126
+ const file_msg = body[2];
1092
1127
  try {
1093
- if (String(file_msg[6][2][4])[0] === "/") {
1128
+ if (String(file_msg[6][2][4])[0] === "/") { // 合并转发目的地是群
1094
1129
  const gid = file_msg[6][2][3];
1095
1130
  const fid = file_msg[6][2][4];
1096
1131
  const gfs = new Gfs(this, gid);
@@ -1105,9 +1140,9 @@ async function parseForwardMsg(resid, fileName) {
1105
1140
  }
1106
1141
  }
1107
1142
  } catch { }
1108
- parser = parser ?? await _parseC2CFileElem.call(this, file_msg[1]);
1143
+ parser = parser ?? await _parseC2CFileElem.call(this, file_msg[1]); // 合并转发目的地是私聊
1109
1144
  } else {
1110
- parser = await Parser.invoke(this, user_id, group_id, msg[3][1]);
1145
+ parser = await Parser.invoke(this, user_id, group_id, body[1]); // 普通消息
1111
1146
  }
1112
1147
  data.push({
1113
1148
  group_id, user_id, nickname, time, seq,
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.26.3",
5
- "app_version": "1.26.3",
6
- "upday": "2026/06/28",
4
+ "version": "1.26.4",
5
+ "app_version": "1.26.4",
6
+ "upday": "2026/06/30",
7
7
  "protocol_version": "v11",
8
8
  "description": "oicq(https://github.com/takayama-lily/oicq) v1 for Icalingua++",
9
9
  "main": "index.js",
@@ -21,7 +21,7 @@
21
21
  "author": "The Icalingua++ Authors",
22
22
  "license": "MPL-2.0",
23
23
  "dependencies": {
24
- "axios": "1.14.0",
24
+ "axios": "1.18.1",
25
25
  "jsqr": "1.4.0",
26
26
  "log4js": "6.9.1",
27
27
  "long": "4.0.0",