wechaty-puppet-matrix 0.0.54 → 0.0.56
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/dist/cjs/src/engine-schema.d.ts +1 -0
- package/dist/cjs/src/engine-schema.d.ts.map +1 -1
- package/dist/cjs/src/matrix/messages/message-contact-card.d.ts +16 -0
- package/dist/cjs/src/matrix/messages/message-contact-card.d.ts.map +1 -0
- package/dist/cjs/src/matrix/messages/message-contact-card.js +25 -0
- package/dist/cjs/src/matrix/messages/message-emotion.d.ts +7 -0
- package/dist/cjs/src/matrix/messages/message-emotion.d.ts.map +1 -1
- package/dist/cjs/src/matrix/messages/message-emotion.js +20 -0
- package/dist/cjs/src/matrix/messages/message-image.d.ts +8 -0
- package/dist/cjs/src/matrix/messages/message-image.d.ts.map +1 -1
- package/dist/cjs/src/matrix/messages/message-image.js +38 -2
- package/dist/cjs/src/matrix/messages/message-image.spec.d.ts +3 -0
- package/dist/cjs/src/matrix/messages/message-image.spec.d.ts.map +1 -0
- package/dist/cjs/src/matrix/messages/message-image.spec.js +66 -0
- package/dist/cjs/src/matrix/messages/message-video.d.ts +6 -0
- package/dist/cjs/src/matrix/messages/message-video.d.ts.map +1 -1
- package/dist/cjs/src/matrix/messages/message-video.js +20 -0
- package/dist/cjs/src/matrix/messages/message-video.spec.d.ts +3 -0
- package/dist/cjs/src/matrix/messages/message-video.spec.d.ts.map +1 -0
- package/dist/cjs/src/matrix/messages/message-video.spec.js +27 -0
- package/dist/cjs/src/matrix/service/request.d.ts +21 -0
- package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.js +194 -32
- package/dist/cjs/src/matrix/utils/file-type.d.ts +4 -0
- package/dist/cjs/src/matrix/utils/file-type.d.ts.map +1 -0
- package/dist/cjs/src/matrix/utils/file-type.js +55 -0
- package/dist/cjs/src/matrix/utils/file-type.spec.d.ts +3 -0
- package/dist/cjs/src/matrix/utils/file-type.spec.d.ts.map +1 -0
- package/dist/cjs/src/matrix/utils/file-type.spec.js +25 -0
- package/dist/cjs/src/puppet-matrix.d.ts +3 -0
- package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
- package/dist/cjs/src/puppet-matrix.js +121 -33
- package/dist/esm/src/engine-schema.d.ts +1 -0
- package/dist/esm/src/engine-schema.d.ts.map +1 -1
- package/dist/esm/src/matrix/messages/message-contact-card.d.ts +16 -0
- package/dist/esm/src/matrix/messages/message-contact-card.d.ts.map +1 -0
- package/dist/esm/src/matrix/messages/message-contact-card.js +22 -0
- package/dist/esm/src/matrix/messages/message-emotion.d.ts +7 -0
- package/dist/esm/src/matrix/messages/message-emotion.d.ts.map +1 -1
- package/dist/esm/src/matrix/messages/message-emotion.js +19 -0
- package/dist/esm/src/matrix/messages/message-image.d.ts +8 -0
- package/dist/esm/src/matrix/messages/message-image.d.ts.map +1 -1
- package/dist/esm/src/matrix/messages/message-image.js +37 -2
- package/dist/esm/src/matrix/messages/message-image.spec.d.ts +3 -0
- package/dist/esm/src/matrix/messages/message-image.spec.d.ts.map +1 -0
- package/dist/esm/src/matrix/messages/message-image.spec.js +64 -0
- package/dist/esm/src/matrix/messages/message-video.d.ts +6 -0
- package/dist/esm/src/matrix/messages/message-video.d.ts.map +1 -1
- package/dist/esm/src/matrix/messages/message-video.js +19 -0
- package/dist/esm/src/matrix/messages/message-video.spec.d.ts +3 -0
- package/dist/esm/src/matrix/messages/message-video.spec.d.ts.map +1 -0
- package/dist/esm/src/matrix/messages/message-video.spec.js +25 -0
- package/dist/esm/src/matrix/service/request.d.ts +21 -0
- package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.js +193 -32
- package/dist/esm/src/matrix/utils/file-type.d.ts +4 -0
- package/dist/esm/src/matrix/utils/file-type.d.ts.map +1 -0
- package/dist/esm/src/matrix/utils/file-type.js +47 -0
- package/dist/esm/src/matrix/utils/file-type.spec.d.ts +3 -0
- package/dist/esm/src/matrix/utils/file-type.spec.d.ts.map +1 -0
- package/dist/esm/src/matrix/utils/file-type.spec.js +23 -0
- package/dist/esm/src/puppet-matrix.d.ts +3 -0
- package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
- package/dist/esm/src/puppet-matrix.js +121 -33
- package/package.json +1 -1
- package/src/engine-schema.ts +1 -0
- package/src/matrix/messages/message-contact-card.ts +48 -0
- package/src/matrix/messages/message-emotion.ts +36 -0
- package/src/matrix/messages/message-image.spec.ts +107 -0
- package/src/matrix/messages/message-image.ts +63 -2
- package/src/matrix/messages/message-video.spec.ts +37 -0
- package/src/matrix/messages/message-video.ts +28 -1
- package/src/matrix/service/request.ts +274 -32
- package/src/matrix/utils/file-type.spec.ts +29 -0
- package/src/matrix/utils/file-type.ts +59 -0
- package/src/puppet-matrix.ts +150 -35
|
@@ -44,6 +44,7 @@ const types_js_1 = require("./matrix/types.js");
|
|
|
44
44
|
const request_js_1 = __importDefault(require("./matrix/service/request.js"));
|
|
45
45
|
const date_fns_1 = require("date-fns");
|
|
46
46
|
const index_js_1 = require("./matrix/utils/index.js");
|
|
47
|
+
const file_type_js_1 = require("./matrix/utils/file-type.js");
|
|
47
48
|
const path_1 = __importDefault(require("path"));
|
|
48
49
|
const cache_manager_js_1 = require("./matrix/cache-manager.js");
|
|
49
50
|
const is_type_js_1 = require("./matrix/utils/is-type.js");
|
|
@@ -55,6 +56,7 @@ const message_image_js_1 = require("./matrix/messages/message-image.js");
|
|
|
55
56
|
const message_audio_js_1 = require("./matrix/messages/message-audio.js");
|
|
56
57
|
const message_video_js_1 = require("./matrix/messages/message-video.js");
|
|
57
58
|
const message_location_js_1 = require("./matrix/messages/message-location.js");
|
|
59
|
+
const message_contact_card_js_1 = require("./matrix/messages/message-contact-card.js");
|
|
58
60
|
const cached_promise_js_1 = require("./matrix/utils/cached-promise.js");
|
|
59
61
|
const message_js_1 = require("./matrix/schema-mapper/message.js");
|
|
60
62
|
const contact_js_1 = require("./matrix/schema-mapper/contact.js");
|
|
@@ -62,7 +64,6 @@ const room_js_1 = require("./matrix/schema-mapper/room.js");
|
|
|
62
64
|
const mod_js_1 = require("./matrix/events/mod.js");
|
|
63
65
|
const cleanup_js_1 = require("./cleanup.js");
|
|
64
66
|
const package_json_js_1 = require("./package-json.js");
|
|
65
|
-
const xml_to_json_js_1 = require("./matrix/utils/xml-to-json.js");
|
|
66
67
|
const VERSION = package_json_js_1.packageJson.version || '0.0.0';
|
|
67
68
|
exports.VERSION = VERSION;
|
|
68
69
|
const PRE = '[PuppetMatrix]';
|
|
@@ -560,7 +561,7 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
560
561
|
hello = option.hello;
|
|
561
562
|
}
|
|
562
563
|
}
|
|
563
|
-
await this._client?.addFriendByWxid({ content: hello, ticket, scene: addContactScene, wxid: contactId });
|
|
564
|
+
await this._client?.addFriendByWxid({ content: hello, ticket, scene: addContactScene, wxid: cachedContactSearch?.wxid || contactId });
|
|
564
565
|
}
|
|
565
566
|
async friendshipSearchPhone(phone) {
|
|
566
567
|
return this._friendshipSearch(phone, '15');
|
|
@@ -597,7 +598,58 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
597
598
|
}
|
|
598
599
|
async messageContact(messageId) {
|
|
599
600
|
wechaty_puppet_1.log.verbose('PuppetWeChat', 'messageContact(%s)', messageId);
|
|
600
|
-
|
|
601
|
+
const rawPayload = await this.messageRawPayload(messageId);
|
|
602
|
+
if (rawPayload.msgType !== types_js_1.WechatMessageType.ShareCard) {
|
|
603
|
+
throw new Error(`message ${messageId} is not a contact card`);
|
|
604
|
+
}
|
|
605
|
+
const card = await (0, message_contact_card_js_1.parseContactCardMessagePayload)(rawPayload.msg);
|
|
606
|
+
if (!card) {
|
|
607
|
+
throw new Error(`can not parse contact card from message ${messageId}`);
|
|
608
|
+
}
|
|
609
|
+
if (!card.username.includes(STRANGER_SUFFIX)) {
|
|
610
|
+
return card.username;
|
|
611
|
+
}
|
|
612
|
+
const friendId = await this._findFriendByCard(card);
|
|
613
|
+
if (friendId) {
|
|
614
|
+
wechaty_puppet_1.log.verbose(PRE, 'messageContact(%s) matched friend %s', messageId, friendId);
|
|
615
|
+
return friendId;
|
|
616
|
+
}
|
|
617
|
+
const searchId = `${SEARCH_CONTACT_PREFIX}${card.username}`;
|
|
618
|
+
await this._cacheMgr.setContactSearch(searchId, {
|
|
619
|
+
alias: '',
|
|
620
|
+
avatar: card.avatar,
|
|
621
|
+
city: card.city,
|
|
622
|
+
country: '',
|
|
623
|
+
isFriend: 0,
|
|
624
|
+
name: card.nickname,
|
|
625
|
+
province: card.province,
|
|
626
|
+
scene: card.scene,
|
|
627
|
+
sex: card.sex,
|
|
628
|
+
sign: card.sign,
|
|
629
|
+
ticket: card.antispamticket,
|
|
630
|
+
wxNum: card.alias,
|
|
631
|
+
wxid: card.username,
|
|
632
|
+
});
|
|
633
|
+
return searchId;
|
|
634
|
+
}
|
|
635
|
+
async _findFriendByCard(card) {
|
|
636
|
+
const avatarKey = (url) => (url || '').replace(/^https?:\/\//, '').replace(/\/\d+$/, '');
|
|
637
|
+
const cardAvatar = avatarKey(card.avatar);
|
|
638
|
+
const contacts = (await this._cacheMgr.getAllContacts())
|
|
639
|
+
.filter(c => c.wxid && !(0, is_type_js_1.isRoomId)(c.wxid) && !c.wxid.includes(STRANGER_SUFFIX) && c.isFriend !== 0);
|
|
640
|
+
if (cardAvatar) {
|
|
641
|
+
const byAvatar = contacts.find(c => avatarKey(c.avatar) === cardAvatar);
|
|
642
|
+
if (byAvatar) {
|
|
643
|
+
return byAvatar.wxid;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (card.nickname) {
|
|
647
|
+
const byName = contacts.filter(c => c.name === card.nickname);
|
|
648
|
+
if (byName.length === 1) {
|
|
649
|
+
return byName[0].wxid;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return undefined;
|
|
601
653
|
}
|
|
602
654
|
async messageChannel(messageId) {
|
|
603
655
|
wechaty_puppet_1.log.verbose('PuppetService', 'messageChannel(%s)', messageId);
|
|
@@ -636,12 +688,20 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
636
688
|
return this._getMessageFileFileBox(messageId, messagePayload);
|
|
637
689
|
case PUPPET.types.Message.Emoticon: {
|
|
638
690
|
const emotionPayload = await (0, message_emotion_js_1.parseEmotionMessagePayload)(messagePayload);
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
691
|
+
const url = emotionPayload.is_ww
|
|
692
|
+
? (await this._client?.downloadWWMedia({
|
|
693
|
+
aes_key: emotionPayload.aeskey || '',
|
|
694
|
+
auth_key: emotionPayload.authkey || '',
|
|
695
|
+
file_id: emotionPayload.cdnurl || '',
|
|
696
|
+
file_name: `message-${messageId}-emoticon.gif`,
|
|
697
|
+
}, 3)) || ''
|
|
698
|
+
: emotionPayload.cdnurl;
|
|
699
|
+
if (!url) {
|
|
700
|
+
throw new Error(`Can not get emoticon url for message: ${messageId}`);
|
|
701
|
+
}
|
|
702
|
+
const head = await (0, file_type_js_1.fetchRemoteHead)(url);
|
|
703
|
+
const ext = (head && (0, file_type_js_1.detectImageExt)(head)) || (emotionPayload.type === 2 && !emotionPayload.game ? 'gif' : 'png');
|
|
704
|
+
const emoticonBox = file_box_1.FileBox.fromUrl(url, { name: `message-${messageId}-emoticon.${ext}` });
|
|
645
705
|
emoticonBox.metadata = {
|
|
646
706
|
payload: emotionPayload,
|
|
647
707
|
type: 'emoticon',
|
|
@@ -776,28 +836,14 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
776
836
|
}
|
|
777
837
|
}
|
|
778
838
|
async messageSendContact(toUserId, contactId) {
|
|
779
|
-
wechaty_puppet_1.log.verbose('PuppetWeChat', '
|
|
839
|
+
wechaty_puppet_1.log.verbose('PuppetWeChat', 'messageSendContact("%s", %s)', toUserId, contactId);
|
|
780
840
|
const contactPayload = await this.contactRawPayload(contactId);
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
city: contactPayload?.city,
|
|
788
|
-
fullpy: contactPayload?.name,
|
|
789
|
-
imagestatus: '3',
|
|
790
|
-
nickname: contactPayload?.name,
|
|
791
|
-
province: contactPayload?.province,
|
|
792
|
-
regionCode: 'CN_Shanghai',
|
|
793
|
-
scene: '17',
|
|
794
|
-
sex: contactPayload?.sex,
|
|
795
|
-
smallheadimgurl: contactPayload?.avatar,
|
|
796
|
-
username: contactPayload?.ticket,
|
|
797
|
-
},
|
|
798
|
-
};
|
|
799
|
-
const xml = (0, xml_to_json_js_1.JsonToXml)(xmlObj);
|
|
800
|
-
const res = await this._client?.sendContactCard(toUserId, xml, this._self?.wxid);
|
|
841
|
+
const res = await this._client?.sendContact({
|
|
842
|
+
shareHeadImg: contactPayload?.avatar,
|
|
843
|
+
shareId: contactPayload?.wxid || contactId,
|
|
844
|
+
shareNickname: contactPayload?.name,
|
|
845
|
+
toId: toUserId,
|
|
846
|
+
}, this._self?.wxid);
|
|
801
847
|
if (res) {
|
|
802
848
|
await this._cacheMgr?.setMessage(res.id, res);
|
|
803
849
|
return res.id;
|
|
@@ -810,7 +856,16 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
810
856
|
: path_1.default.extname(fileBox.name);
|
|
811
857
|
const fileUrl = fileBox.remoteUrl || '';
|
|
812
858
|
if (metadata.type === 'emoticon') {
|
|
813
|
-
|
|
859
|
+
const emoji = metadata.payload;
|
|
860
|
+
const byMd5 = emoji?.md5 && emoji.len
|
|
861
|
+
? await this._client?.sendEmojiMd5(conversationId, emoji.md5, emoji.len, this._self?.wxid)
|
|
862
|
+
: undefined;
|
|
863
|
+
const msgInfo = byMd5 || (fileUrl ? await this._client?.sendEmojiUrl(conversationId, fileUrl, this._self?.wxid) : undefined);
|
|
864
|
+
if (!msgInfo) {
|
|
865
|
+
throw new Error(`send emoticon failed: ${fileBox.name}`);
|
|
866
|
+
}
|
|
867
|
+
await this._cacheMgr?.setMessage(msgInfo.id, msgInfo);
|
|
868
|
+
return msgInfo.id;
|
|
814
869
|
}
|
|
815
870
|
else if (fileBox.mediaType.startsWith('image/')) {
|
|
816
871
|
if (fileUrl) {
|
|
@@ -915,8 +970,27 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
915
970
|
throw new Error(`Wrong Post!!! please check your Post payload to make sure it right ${conversationId}`);
|
|
916
971
|
}
|
|
917
972
|
}
|
|
973
|
+
async sendPat(conversationId, contactId) {
|
|
974
|
+
wechaty_puppet_1.log.verbose(PRE, 'sendPat(%s, %s)', conversationId, contactId);
|
|
975
|
+
const patted = contactId || conversationId;
|
|
976
|
+
if ((0, is_type_js_1.isRoomId)(patted)) {
|
|
977
|
+
throw new Error('sendPat: contactId is required in room');
|
|
978
|
+
}
|
|
979
|
+
return (await this._client?.sendPat(conversationId, patted)) || false;
|
|
980
|
+
}
|
|
918
981
|
async messageRecall(messageId) {
|
|
919
|
-
|
|
982
|
+
wechaty_puppet_1.log.verbose(PRE, 'messageRecall(%s)', messageId);
|
|
983
|
+
const payload = await this._cacheMgr?.getMessage(messageId);
|
|
984
|
+
if (!payload) {
|
|
985
|
+
wechaty_puppet_1.log.warn(PRE, 'messageRecall(%s): message not found in cache', messageId);
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
const toId = payload.listenerId || payload.fromWxid || '';
|
|
989
|
+
if (!toId) {
|
|
990
|
+
wechaty_puppet_1.log.warn(PRE, 'messageRecall(%s): can not find conversation id', messageId);
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
return (await this._client?.revokeMsg(toId, messageId, payload.clientMsgId)) || false;
|
|
920
994
|
}
|
|
921
995
|
async messageForward(toUserName, messageId) {
|
|
922
996
|
const messagePayload = await this.messageRawPayload(messageId);
|
|
@@ -1496,7 +1570,21 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
1496
1570
|
wechaty_puppet_1.log.error(`Can not get file for message: ${messageId}`);
|
|
1497
1571
|
}
|
|
1498
1572
|
const url = imageInfo.is_ww ? await this._client?.downloadWWMedia(imageInfo, 1) : await this._client?.downloadImage(imageInfo);
|
|
1499
|
-
return this._fileBoxFromUrl(url, messageId);
|
|
1573
|
+
return this._fileBoxFromUrl(url, messageId, url ? await this._imageNameByHead(url) : undefined);
|
|
1574
|
+
}
|
|
1575
|
+
async _imageNameByHead(url) {
|
|
1576
|
+
const head = await (0, file_type_js_1.fetchRemoteHead)(url);
|
|
1577
|
+
const ext = head && (0, file_type_js_1.detectImageExt)(head);
|
|
1578
|
+
if (!ext) {
|
|
1579
|
+
return undefined;
|
|
1580
|
+
}
|
|
1581
|
+
let rawName = 'image';
|
|
1582
|
+
try {
|
|
1583
|
+
rawName = decodeURIComponent(new URL(url).pathname.split('/').pop() || rawName);
|
|
1584
|
+
}
|
|
1585
|
+
catch {
|
|
1586
|
+
}
|
|
1587
|
+
return (0, file_type_js_1.replaceExt)(rawName, ext);
|
|
1500
1588
|
}
|
|
1501
1589
|
async _getMessageAudioFileBox(messageId, messagePayload) {
|
|
1502
1590
|
const audioInfo = await (0, message_audio_js_1.parseAudioMessagePayload)(messagePayload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-schema.d.ts","sourceRoot":"","sources":["../../../src/engine-schema.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"engine-schema.d.ts","sourceRoot":"","sources":["../../../src/engine-schema.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAGD,oBAAY,OAAO;IACjB,GAAG,IAAI;IACP,MAAM,IAAI;CACX;AAKD,aAAK,aAAa;IAChB,OAAO,IAAI;IACX,IAAI,IAAI;IACR,MAAM,IAAI;CACX;AAED,MAAM,WAAW,cAAc;IAI7B,MAAM,EAAE,MAAM,CAAC;IAIf,IAAI,EAAE,MAAM,CAAC;IAIb,OAAO,EAAE,MAAM,CAAC;IAIhB,SAAS,CAAC,EAAE,MAAM,CAAC;IAInB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAIhC,IAAI,EAAE,MAAM,CAAC;IAIb,KAAK,EAAE,MAAM,CAAC;IAId,QAAQ,EAAE,MAAM,CAAC;IAIjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,GAAG,EAAE,aAAa,CAAC;IAInB,IAAI,CAAC,EAAE,MAAM,CAAC;IAKd,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,IAAI,EAAE,MAAM,CAAC;IAIb,KAAK,EAAE,MAAM,CAAC;IAId,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAI9B,OAAO,CAAC,EAAE,MAAM,CAAC;IAIjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IAItB,QAAQ,CAAC,EAAE,MAAM,CAAA;IAIjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAKlB,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAC,MAAM,CAAC;IACX,OAAO,EAAC,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ContactCardPayload {
|
|
2
|
+
username: string;
|
|
3
|
+
nickname: string;
|
|
4
|
+
alias: string;
|
|
5
|
+
avatar: string;
|
|
6
|
+
province: string;
|
|
7
|
+
city: string;
|
|
8
|
+
sex: number;
|
|
9
|
+
sign: string;
|
|
10
|
+
scene: string;
|
|
11
|
+
antispamticket: string;
|
|
12
|
+
brandType: number;
|
|
13
|
+
certflag: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function parseContactCardMessagePayload(content: string): Promise<ContactCardPayload | undefined>;
|
|
16
|
+
//# sourceMappingURL=message-contact-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-contact-card.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-contact-card.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IAEjC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAEhB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IAEb,cAAc,EAAE,MAAM,CAAA;IAEtB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,wBAAsB,8BAA8B,CAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAoB9G"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { xmlToJson } from '../utils/xml-to-json.js';
|
|
2
|
+
export async function parseContactCardMessagePayload(content) {
|
|
3
|
+
const json = await xmlToJson(content);
|
|
4
|
+
const attrs = json?.msg?.$;
|
|
5
|
+
if (!attrs?.username) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
alias: attrs.alias || '',
|
|
10
|
+
antispamticket: attrs.antispamticket || '',
|
|
11
|
+
avatar: attrs.bigheadimgurl || attrs.smallheadimgurl || '',
|
|
12
|
+
brandType: parseInt(attrs.brandType, 10) || 0,
|
|
13
|
+
certflag: parseInt(attrs.certflag, 10) || 0,
|
|
14
|
+
city: attrs.city || '',
|
|
15
|
+
nickname: attrs.nickname || '',
|
|
16
|
+
province: attrs.province || '',
|
|
17
|
+
scene: attrs.scene || '17',
|
|
18
|
+
sex: parseInt(attrs.sex, 10) || 0,
|
|
19
|
+
sign: attrs.sign || '',
|
|
20
|
+
username: attrs.username,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { MessagePayload } from '../../engine-schema.js';
|
|
2
|
+
export interface EmojiGamePayload {
|
|
3
|
+
kind: 'rps' | 'dice';
|
|
4
|
+
value: string | number;
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseEmojiGame(type: number, content: number): EmojiGamePayload | undefined;
|
|
2
8
|
export interface EmojiMessagePayload {
|
|
3
9
|
type: number;
|
|
4
10
|
len: number;
|
|
@@ -7,6 +13,7 @@ export interface EmojiMessagePayload {
|
|
|
7
13
|
width: number;
|
|
8
14
|
height: number;
|
|
9
15
|
gameext?: string;
|
|
16
|
+
game?: EmojiGamePayload;
|
|
10
17
|
aeskey?: string;
|
|
11
18
|
authkey?: string;
|
|
12
19
|
is_ww: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-emotion.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-emotion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"message-emotion.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-emotion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAgC5D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IAErB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEvB,IAAI,EAAE,MAAM,CAAC;CACd;AAQD,wBAAgB,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,0BAA0B,CAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgCvG;AAED,wBAAgB,sBAAsB,CAAE,mBAAmB,EAAE,mBAAmB,GAAG,MAAM,CAIxF"}
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { xmlToJson } from '../utils/xml-to-json.js';
|
|
2
|
+
const RPS = {
|
|
3
|
+
1: ['scissors', '剪刀'],
|
|
4
|
+
2: ['rock', '石头'],
|
|
5
|
+
3: ['paper', '布'],
|
|
6
|
+
};
|
|
7
|
+
export function parseEmojiGame(type, content) {
|
|
8
|
+
if (type === 1 && RPS[content]) {
|
|
9
|
+
const [value, text] = RPS[content];
|
|
10
|
+
return { kind: 'rps', text, value };
|
|
11
|
+
}
|
|
12
|
+
if (type === 2 && content >= 4 && content <= 9) {
|
|
13
|
+
const point = content - 3;
|
|
14
|
+
return { kind: 'dice', text: `${point}点`, value: point };
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
2
18
|
export async function parseEmotionMessagePayload(message) {
|
|
3
19
|
const jsonPayload = await xmlToJson(message.msg);
|
|
4
20
|
const len = parseInt(jsonPayload.msg.emoji.$.len, 10) || 0;
|
|
@@ -8,16 +24,19 @@ export async function parseEmotionMessagePayload(message) {
|
|
|
8
24
|
const type = parseInt(jsonPayload.msg.emoji.$.type, 10) || 0;
|
|
9
25
|
const md5 = jsonPayload.msg.emoji.$.md5;
|
|
10
26
|
let gameext;
|
|
27
|
+
let game;
|
|
11
28
|
if (jsonPayload.msg.gameext) {
|
|
12
29
|
const gameextType = parseInt(jsonPayload.msg.gameext.$.type, 10) || 0;
|
|
13
30
|
const gameextContent = parseInt(jsonPayload.msg.gameext.$.content, 10) || 0;
|
|
14
31
|
gameext = `<gameext type="${gameextType}" content="${gameextContent}" ></gameext>`;
|
|
32
|
+
game = parseEmojiGame(gameextType, gameextContent);
|
|
15
33
|
}
|
|
16
34
|
return {
|
|
17
35
|
authkey: jsonPayload.msg.emoji.$?.tpauthkey,
|
|
18
36
|
aeskey: jsonPayload.msg.emoji.$?.aeskey,
|
|
19
37
|
is_ww: !!jsonPayload.msg.emoji.$?.tpurl,
|
|
20
38
|
cdnurl,
|
|
39
|
+
game,
|
|
21
40
|
gameext,
|
|
22
41
|
height,
|
|
23
42
|
len,
|
|
@@ -18,6 +18,8 @@ export interface ImageXmlSchema {
|
|
|
18
18
|
length: string;
|
|
19
19
|
cdnbigimgurl: string;
|
|
20
20
|
hdlength: string;
|
|
21
|
+
hevc_mid_size?: string;
|
|
22
|
+
cdnmidimgurl_size?: string;
|
|
21
23
|
md5: string;
|
|
22
24
|
tpurl?: string;
|
|
23
25
|
tpauthkey?: string;
|
|
@@ -25,6 +27,10 @@ export interface ImageXmlSchema {
|
|
|
25
27
|
};
|
|
26
28
|
};
|
|
27
29
|
}
|
|
30
|
+
export interface ImageFileCandidate {
|
|
31
|
+
file_id: string;
|
|
32
|
+
file_size: string;
|
|
33
|
+
}
|
|
28
34
|
export interface ImageMessagePayload {
|
|
29
35
|
aes_key: string;
|
|
30
36
|
auth_key: string;
|
|
@@ -32,6 +38,8 @@ export interface ImageMessagePayload {
|
|
|
32
38
|
file_size: string;
|
|
33
39
|
file_name: string;
|
|
34
40
|
is_ww: boolean;
|
|
41
|
+
candidates?: ImageFileCandidate[];
|
|
35
42
|
}
|
|
36
43
|
export declare function parseImageMessagePayload(rawPayload: MessagePayload): Promise<ImageMessagePayload>;
|
|
44
|
+
export declare function buildImageCandidates(schema: ImageXmlSchema['msg']['img']['$']): ImageFileCandidate[];
|
|
37
45
|
//# sourceMappingURL=message-image.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-image.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvD,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE;QACD,GAAG,EAAE;YACD,CAAC,EAAE;gBACC,MAAM,EAAE,MAAM,CAAA;gBACd,QAAQ,EAAE,MAAM,CAAA;gBAChB,cAAc,EAAE,MAAM,CAAA;gBACtB,WAAW,EAAE,MAAM,CAAA;gBACnB,cAAc,EAAE,MAAM,CAAA;gBACtB,cAAc,EAAE,MAAM,CAAA;gBACtB,aAAa,EAAE,MAAM,CAAA;gBACrB,YAAY,EAAE,MAAM,CAAA;gBACpB,WAAW,EAAE,MAAM,CAAA;gBACnB,WAAW,EAAE,MAAM,CAAA;gBACnB,UAAU,EAAE,MAAM,CAAA;gBAClB,YAAY,EAAE,MAAM,CAAA;gBACpB,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;gBACpB,QAAQ,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"message-image.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvD,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE;QACD,GAAG,EAAE;YACD,CAAC,EAAE;gBACC,MAAM,EAAE,MAAM,CAAA;gBACd,QAAQ,EAAE,MAAM,CAAA;gBAChB,cAAc,EAAE,MAAM,CAAA;gBACtB,WAAW,EAAE,MAAM,CAAA;gBACnB,cAAc,EAAE,MAAM,CAAA;gBACtB,cAAc,EAAE,MAAM,CAAA;gBACtB,aAAa,EAAE,MAAM,CAAA;gBACrB,YAAY,EAAE,MAAM,CAAA;gBACpB,WAAW,EAAE,MAAM,CAAA;gBACnB,WAAW,EAAE,MAAM,CAAA;gBACnB,UAAU,EAAE,MAAM,CAAA;gBAClB,YAAY,EAAE,MAAM,CAAA;gBACpB,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;gBACpB,QAAQ,EAAE,MAAM,CAAA;gBAEhB,aAAa,CAAC,EAAE,MAAM,CAAA;gBACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;gBAC1B,GAAG,EAAE,MAAM,CAAA;gBACX,KAAK,CAAC,EAAE,MAAM,CAAA;gBACd,SAAS,CAAC,EAAE,MAAM,CAAA;aACrB,CAAA;SACJ,CAAA;KACJ,CAAA;CACJ;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IAKf,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACnC;AAED,wBAAsB,wBAAwB,CAAE,UAAU,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgBxG;AAYD,wBAAgB,oBAAoB,CAAE,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,kBAAkB,EAAE,CAgCrG"}
|
|
@@ -2,12 +2,47 @@ import { xmlToJson } from '../utils/xml-to-json.js';
|
|
|
2
2
|
export async function parseImageMessagePayload(rawPayload) {
|
|
3
3
|
const imageXml = await xmlToJson(rawPayload.msg);
|
|
4
4
|
const schema = imageXml.msg.img.$;
|
|
5
|
+
const candidates = buildImageCandidates(schema);
|
|
6
|
+
const primary = candidates[0] || { file_id: schema.cdnmidimgurl || schema.tpurl || '', file_size: schema.length };
|
|
5
7
|
return {
|
|
6
8
|
is_ww: !!schema.tpurl,
|
|
7
9
|
aes_key: schema.aeskey,
|
|
8
10
|
auth_key: schema.tpauthkey || '',
|
|
9
|
-
file_id:
|
|
10
|
-
file_size:
|
|
11
|
+
file_id: primary.file_id,
|
|
12
|
+
file_size: primary.file_size,
|
|
11
13
|
file_name: '',
|
|
14
|
+
candidates: candidates.length ? candidates : [primary],
|
|
12
15
|
};
|
|
13
16
|
}
|
|
17
|
+
const isPositiveSize = (size) => !!size && Number(size) > 0;
|
|
18
|
+
export function buildImageCandidates(schema) {
|
|
19
|
+
if (schema.tpurl) {
|
|
20
|
+
return [{ file_id: schema.cdnmidimgurl || schema.tpurl, file_size: schema.length }];
|
|
21
|
+
}
|
|
22
|
+
const midUrl = schema.cdnmidimgurl;
|
|
23
|
+
const bigUrl = schema.cdnbigimgurl;
|
|
24
|
+
const list = [
|
|
25
|
+
[midUrl, schema.cdnmidimgurl_size],
|
|
26
|
+
[midUrl, schema.hevc_mid_size],
|
|
27
|
+
];
|
|
28
|
+
if (isPositiveSize(schema.hdlength)) {
|
|
29
|
+
list.push([midUrl, schema.length], [bigUrl, schema.hdlength]);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
list.push([bigUrl, schema.length], [midUrl, schema.length]);
|
|
33
|
+
}
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
const candidates = [];
|
|
36
|
+
for (const [fileId, fileSize] of list) {
|
|
37
|
+
if (!fileId || !isPositiveSize(fileSize)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const key = `${fileId}|${fileSize}`;
|
|
41
|
+
if (seen.has(key)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
seen.add(key);
|
|
45
|
+
candidates.push({ file_id: fileId, file_size: fileSize });
|
|
46
|
+
}
|
|
47
|
+
return candidates;
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-image.spec.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-image.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env -S node -r ts-node/register
|
|
2
|
+
import { test } from 'tstest';
|
|
3
|
+
import { parseImageMessagePayload } from './message-image.js';
|
|
4
|
+
const buildPayload = (imgAttrs) => ({
|
|
5
|
+
msg: `<?xml version="1.0"?>\n<msg>\n\t<img ${imgAttrs}>\n\t</img>\n</msg>\n`,
|
|
6
|
+
});
|
|
7
|
+
test('parseImageMessagePayload uses hevc_mid_size when downloading mid image', async (t) => {
|
|
8
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" length="157626" md5="md5" hevc_mid_size="53274"'));
|
|
9
|
+
t.equal(payload.file_id, 'mid-url', 'should use mid image url');
|
|
10
|
+
t.equal(payload.file_size, '53274', 'size should match the mid image, not the origin length');
|
|
11
|
+
t.equal(payload.is_ww, false, 'should not be ww image');
|
|
12
|
+
});
|
|
13
|
+
test('parseImageMessagePayload prefers cdnmidimgurl_size', async (t) => {
|
|
14
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" length="157626" hevc_mid_size="53274" cdnmidimgurl_size="60000"'));
|
|
15
|
+
t.equal(payload.file_size, '60000', 'cdnmidimgurl_size should win');
|
|
16
|
+
});
|
|
17
|
+
test('parseImageMessagePayload falls back to length for legacy xml', async (t) => {
|
|
18
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" length="12345" hevc_mid_size="0"'));
|
|
19
|
+
t.equal(payload.file_size, '12345', 'length should be used when no mid size is available');
|
|
20
|
+
});
|
|
21
|
+
test('parseImageMessagePayload falls back to length when mid size attrs are absent', async (t) => {
|
|
22
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" length="12345" md5="md5"'));
|
|
23
|
+
t.equal(payload.file_size, '12345', 'length should be used when hevc_mid_size is missing');
|
|
24
|
+
});
|
|
25
|
+
test('parseImageMessagePayload uses big image url when mid size is missing', async (t) => {
|
|
26
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" cdnbigimgurl="big-url" length="157626"'));
|
|
27
|
+
t.equal(payload.file_id, 'big-url', 'should switch to origin image url');
|
|
28
|
+
t.equal(payload.file_size, '157626', 'size should be origin length');
|
|
29
|
+
});
|
|
30
|
+
test('parseImageMessagePayload keeps mid url for legacy xml with hdlength', async (t) => {
|
|
31
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" cdnbigimgurl="big-url" length="12345" hdlength="99999"'));
|
|
32
|
+
t.equal(payload.file_id, 'mid-url', 'legacy xml should still use mid url');
|
|
33
|
+
t.equal(payload.file_size, '12345', 'legacy length is mid image size');
|
|
34
|
+
});
|
|
35
|
+
test('parseImageMessagePayload keeps length for ww image', async (t) => {
|
|
36
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" tpurl="tp-url" tpauthkey="auth" length="888" hevc_mid_size="111"'));
|
|
37
|
+
t.equal(payload.is_ww, true, 'should be ww image');
|
|
38
|
+
t.equal(payload.file_id, 'tp-url', 'should use tpurl');
|
|
39
|
+
t.equal(payload.file_size, '888', 'ww image should keep length');
|
|
40
|
+
});
|
|
41
|
+
test('parseImageMessagePayload builds fallback candidates for new xml', async (t) => {
|
|
42
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" cdnbigimgurl="big-url" length="157626" hevc_mid_size="53274"'));
|
|
43
|
+
t.same(payload.candidates, [
|
|
44
|
+
{ file_id: 'mid-url', file_size: '53274' },
|
|
45
|
+
{ file_id: 'big-url', file_size: '157626' },
|
|
46
|
+
{ file_id: 'mid-url', file_size: '157626' },
|
|
47
|
+
], 'should try mid size first, then origin, then legacy combination');
|
|
48
|
+
t.equal(payload.file_id, payload.candidates?.[0]?.file_id, 'file_id should be first candidate');
|
|
49
|
+
t.equal(payload.file_size, payload.candidates?.[0]?.file_size, 'file_size should be first candidate');
|
|
50
|
+
});
|
|
51
|
+
test('parseImageMessagePayload builds fallback candidates for legacy xml', async (t) => {
|
|
52
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" cdnbigimgurl="big-url" length="12345" hdlength="99999"'));
|
|
53
|
+
t.same(payload.candidates, [
|
|
54
|
+
{ file_id: 'mid-url', file_size: '12345' },
|
|
55
|
+
{ file_id: 'big-url', file_size: '99999' },
|
|
56
|
+
], 'legacy xml should try mid + length, then big + hdlength');
|
|
57
|
+
});
|
|
58
|
+
test('parseImageMessagePayload dedupes candidates', async (t) => {
|
|
59
|
+
const payload = await parseImageMessagePayload(buildPayload('aeskey="key" cdnmidimgurl="mid-url" length="157626" hevc_mid_size="53274" cdnmidimgurl_size="53274"'));
|
|
60
|
+
t.same(payload.candidates, [
|
|
61
|
+
{ file_id: 'mid-url', file_size: '53274' },
|
|
62
|
+
{ file_id: 'mid-url', file_size: '157626' },
|
|
63
|
+
], 'same url + size should only appear once');
|
|
64
|
+
});
|
|
@@ -48,6 +48,12 @@ export interface VideoMessagePayload {
|
|
|
48
48
|
thumb_width: string;
|
|
49
49
|
thumb_height: string;
|
|
50
50
|
file_name: '';
|
|
51
|
+
candidates?: Array<{
|
|
52
|
+
file_id: string;
|
|
53
|
+
file_size: string;
|
|
54
|
+
aes_key?: string;
|
|
55
|
+
}>;
|
|
51
56
|
}
|
|
52
57
|
export declare function parseVideoMessagePayload(rawPayload: MessagePayload): Promise<VideoMessagePayload>;
|
|
58
|
+
export declare function buildVideoCandidates(schema: VideoXmlSchema['msg']['videomsg']['$']): VideoMessagePayload['candidates'];
|
|
53
59
|
//# sourceMappingURL=message-video.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-video.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE;QACD,QAAQ,EAAE;YACN,CAAC,EAAE;gBACC,MAAM,EAAE,MAAM,CAAA;gBACd,WAAW,EAAE,MAAM,CAAA;gBACnB,cAAc,EAAE,MAAM,CAAA;gBACtB,WAAW,EAAE,MAAM,CAAA;gBACnB,MAAM,EAAE,MAAM,CAAA;gBACd,UAAU,EAAE,MAAM,CAAA;gBAClB,cAAc,EAAE,MAAM,CAAA;gBACtB,aAAa,EAAE,MAAM,CAAA;gBACrB,cAAc,EAAE,MAAM,CAAA;gBACtB,YAAY,EAAE,MAAM,CAAA;gBACpB,GAAG,EAAE,MAAM,CAAA;gBACX,MAAM,EAAE,MAAM,CAAA;gBACd,aAAa,EAAE,MAAM,CAAA;gBACrB,MAAM,EAAE,MAAM,CAAA;gBACd,SAAS,EAAE,MAAM,CAAA;gBACjB,cAAc,EAAE,MAAM,CAAA;gBACtB,iBAAiB,EAAE,MAAM,CAAA;gBACzB,iBAAiB,EAAE,MAAM,CAAA;gBACzB,eAAe,EAAE,MAAM,CAAA;gBACvB,IAAI,EAAE,MAAM,CAAA;gBACZ,UAAU,CAAC,EAAE,MAAM,CAAA;gBACnB,SAAS,CAAC,EAAE,MAAM,CAAA;gBAClB,UAAU,CAAC,EAAE,MAAM,CAAA;gBACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;gBACjB,aAAa,CAAC,EAAE,MAAM,CAAA;gBACtB,YAAY,CAAC,EAAE,MAAM,CAAA;gBACrB,aAAa,CAAC,EAAE,MAAM,CAAA;gBACtB,aAAa,CAAC,EAAE,MAAM,CAAA;aACzB,CAAA;SACJ,CAAA;KACJ,CAAA;CACF;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"message-video.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE;QACD,QAAQ,EAAE;YACN,CAAC,EAAE;gBACC,MAAM,EAAE,MAAM,CAAA;gBACd,WAAW,EAAE,MAAM,CAAA;gBACnB,cAAc,EAAE,MAAM,CAAA;gBACtB,WAAW,EAAE,MAAM,CAAA;gBACnB,MAAM,EAAE,MAAM,CAAA;gBACd,UAAU,EAAE,MAAM,CAAA;gBAClB,cAAc,EAAE,MAAM,CAAA;gBACtB,aAAa,EAAE,MAAM,CAAA;gBACrB,cAAc,EAAE,MAAM,CAAA;gBACtB,YAAY,EAAE,MAAM,CAAA;gBACpB,GAAG,EAAE,MAAM,CAAA;gBACX,MAAM,EAAE,MAAM,CAAA;gBACd,aAAa,EAAE,MAAM,CAAA;gBACrB,MAAM,EAAE,MAAM,CAAA;gBACd,SAAS,EAAE,MAAM,CAAA;gBACjB,cAAc,EAAE,MAAM,CAAA;gBACtB,iBAAiB,EAAE,MAAM,CAAA;gBACzB,iBAAiB,EAAE,MAAM,CAAA;gBACzB,eAAe,EAAE,MAAM,CAAA;gBACvB,IAAI,EAAE,MAAM,CAAA;gBACZ,UAAU,CAAC,EAAE,MAAM,CAAA;gBACnB,SAAS,CAAC,EAAE,MAAM,CAAA;gBAClB,UAAU,CAAC,EAAE,MAAM,CAAA;gBACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;gBACjB,aAAa,CAAC,EAAE,MAAM,CAAA;gBACtB,YAAY,CAAC,EAAE,MAAM,CAAA;gBACrB,aAAa,CAAC,EAAE,MAAM,CAAA;gBACtB,aAAa,CAAC,EAAE,MAAM,CAAA;aACzB,CAAA;SACJ,CAAA;KACJ,CAAA;CACF;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,EAAE,CAAC;IAMd,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E;AAID,wBAAsB,wBAAwB,CAAE,UAAU,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmBxG;AAED,wBAAgB,oBAAoB,CAAE,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAgBvH"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { xmlToJson } from '../utils/xml-to-json.js';
|
|
2
|
+
const isPositiveSize = (size) => !!size && Number(size) > 0;
|
|
2
3
|
export async function parseVideoMessagePayload(rawPayload) {
|
|
3
4
|
const videoXml = await xmlToJson(rawPayload.msg);
|
|
4
5
|
const videoSchema = videoXml.msg.videomsg.$;
|
|
@@ -15,5 +16,23 @@ export async function parseVideoMessagePayload(rawPayload) {
|
|
|
15
16
|
thumb_width: videoSchema.cdnthumbwidth || videoSchema.tpthumbwidth || '',
|
|
16
17
|
thumb_height: videoSchema.cdnthumbheight || videoSchema.tpthumbheight || '',
|
|
17
18
|
file_name: '',
|
|
19
|
+
candidates: buildVideoCandidates(videoSchema),
|
|
18
20
|
};
|
|
19
21
|
}
|
|
22
|
+
export function buildVideoCandidates(schema) {
|
|
23
|
+
if (schema.tpvideourl) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const candidates = [];
|
|
27
|
+
if (schema.cdnvideourl && isPositiveSize(schema.length)) {
|
|
28
|
+
candidates.push({ file_id: schema.cdnvideourl, file_size: schema.length });
|
|
29
|
+
}
|
|
30
|
+
if (schema.cdnrawvideourl && isPositiveSize(schema.rawlength)) {
|
|
31
|
+
candidates.push({
|
|
32
|
+
file_id: schema.cdnrawvideourl,
|
|
33
|
+
file_size: schema.rawlength,
|
|
34
|
+
aes_key: schema.cdnrawvideoaeskey || schema.aeskey,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return candidates.length ? candidates : undefined;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-video.spec.d.ts","sourceRoot":"","sources":["../../../../../src/matrix/messages/message-video.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env -S node -r ts-node/register
|
|
2
|
+
import { test } from 'tstest';
|
|
3
|
+
import { parseVideoMessagePayload } from './message-video.js';
|
|
4
|
+
import { parseSizeMismatch } from '../service/request.js';
|
|
5
|
+
const buildPayload = (attrs) => ({
|
|
6
|
+
msg: `<?xml version="1.0"?>\n<msg>\n\t<videomsg ${attrs} />\n</msg>\n`,
|
|
7
|
+
});
|
|
8
|
+
test('parseVideoMessagePayload adds raw video as fallback candidate', async (t) => {
|
|
9
|
+
const payload = await parseVideoMessagePayload(buildPayload('aeskey="key" cdnvideourl="video-url" length="766838" playlength="5" rawlength="769445" cdnrawvideourl="raw-url" cdnrawvideoaeskey="raw-key"'));
|
|
10
|
+
t.equal(payload.file_id, 'video-url', 'primary file_id unchanged');
|
|
11
|
+
t.equal(payload.file_size, '766838', 'primary file_size unchanged');
|
|
12
|
+
t.same(payload.candidates, [
|
|
13
|
+
{ file_id: 'video-url', file_size: '766838' },
|
|
14
|
+
{ file_id: 'raw-url', file_size: '769445', aes_key: 'raw-key' },
|
|
15
|
+
], 'raw video should be second candidate with its own aes key');
|
|
16
|
+
});
|
|
17
|
+
test('parseVideoMessagePayload skips empty raw video', async (t) => {
|
|
18
|
+
const payload = await parseVideoMessagePayload(buildPayload('aeskey="key" cdnvideourl="video-url" length="766838" playlength="5" rawlength="0" cdnrawvideourl="" cdnrawvideoaeskey=""'));
|
|
19
|
+
t.same(payload.candidates, [{ file_id: 'video-url', file_size: '766838' }], 'only cdn video candidate');
|
|
20
|
+
});
|
|
21
|
+
test('parseSizeMismatch extracts actual size from backend error', async (t) => {
|
|
22
|
+
t.equal(parseSizeMismatch('download plaintext size differs: expected 766838, got 1228708'), '1228708', 'should return actual size');
|
|
23
|
+
t.equal(parseSizeMismatch('timeout'), undefined, 'other errors return undefined');
|
|
24
|
+
t.equal(parseSizeMismatch(undefined), undefined, 'undefined returns undefined');
|
|
25
|
+
});
|