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 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 | MiraiElem | RawElem;
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
- 6: "android " + this.apk.ver,
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) {
@@ -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.GetTroopMemberListReq", body, 10);
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;
@@ -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) { //群聊
@@ -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
  };
@@ -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: {
@@ -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 parseImgElem(elem) {
491
+ async parseNTImgElem(type, elem) {
473
492
  const data = { };
474
- if (elem[29] && elem[29][30] && String(elem[29][30]).startsWith("&rkey=")) {
475
- //QQNT 私图
476
- if (this.imgprefix) {
477
- data.file = buildImageFileParam(elem[7].toHex(), elem[2], elem[9], elem[8], elem[5]);
478
- data.url = this.imgprefix + String(elem[29][30]) + "&spec=0";
479
- this.imgprefix = null;
480
- return data;
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
- } else if (elem[34] && elem[34][30] && String(elem[34][30]).startsWith("&rkey=")) {
483
- //QQNT 群图
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
- if (!elem[7]) { //QQNT 群聊转发到私聊图
492
- data.file = buildImageFileParam(elem[13].toHex(), elem[25], elem[22], elem[23], elem[20]);
493
- data.url = await offNTPicDown.call(this.c, this.uid, elem[2]);
494
- } else if (elem[7].toHex) { //私图
495
- data.file = buildImageFileParam(elem[7].toHex(), elem[2], elem[9], elem[8], elem[5]);
496
- if (elem[10]) {
497
- if (elem[23])
498
- data.url = await groupNTPicDown.call(this.c, this.gid, elem[23], elem[7]);
499
- else
500
- data.url = await offNTPicDown.call(this.c, this.uid, elem[10]);
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
- data.file = buildImageFileParam(elem[13].toHex(), elem[25], elem[22], elem[23], elem[20]);
506
- if (elem[16])
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/${this.uid}/${code2uin(this.gid)||0}-${elem[7]>>>0}-${elem[13].toHex().toUpperCase()}/0?term=2`;
510
- if (!data.url.includes("gchatpic_new"))
511
- data.url = await groupNTPicDown.call(this.c, this.gid, elem[7], elem[13]);
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
  }
@@ -286,6 +286,7 @@ async function getVideoUrl(elem) {
286
286
  8: 3,
287
287
  10: 0,
288
288
  11: elem[18],
289
+ 12: 1,
289
290
  14: 2,
290
291
  15: 1,
291
292
  },
package/lib/oicq.js CHANGED
@@ -104,6 +104,7 @@ function pushReqListener(blob, seq) {
104
104
  this.storage.ip = int32ip2str(v[2][0][2]);
105
105
  }
106
106
  }
107
+ this.saveStorageConfig();
107
108
  }
108
109
  }
109
110
 
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.0",
5
- "app_version": "1.24.0",
6
- "upday": "2024/01/05",
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",