wechaty-puppet-matrix 0.0.10 → 0.0.13
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/matrix/cache-manager.js +1 -1
- package/dist/cjs/src/matrix/messages/message-location.d.ts +2 -0
- package/dist/cjs/src/matrix/messages/message-location.d.ts.map +1 -0
- package/dist/cjs/src/matrix/messages/message-location.js +18 -0
- package/dist/cjs/src/matrix/service/request.d.ts +55 -0
- package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.js +365 -1
- package/dist/cjs/src/matrix/utils/index.d.ts +3 -0
- package/dist/cjs/src/matrix/utils/index.d.ts.map +1 -1
- package/dist/cjs/src/matrix/utils/index.js +31 -0
- package/dist/cjs/src/puppet-matrix.d.ts +7 -0
- package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
- package/dist/cjs/src/puppet-matrix.js +94 -0
- package/dist/cjs/src/utils/normalize-filebox.d.ts +6 -0
- package/dist/cjs/src/utils/normalize-filebox.d.ts.map +1 -0
- package/dist/cjs/src/utils/normalize-filebox.js +46 -0
- package/dist/cjs/src/utils/sns-xml-generator.d.ts +19 -0
- package/dist/cjs/src/utils/sns-xml-generator.d.ts.map +1 -0
- package/dist/cjs/src/utils/sns-xml-generator.js +171 -0
- package/dist/esm/src/matrix/cache-manager.js +1 -1
- package/dist/esm/src/matrix/messages/message-location.d.ts +2 -0
- package/dist/esm/src/matrix/messages/message-location.d.ts.map +1 -0
- package/dist/esm/src/matrix/messages/message-location.js +15 -0
- package/dist/esm/src/matrix/service/request.d.ts +55 -0
- package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.js +365 -1
- package/dist/esm/src/matrix/utils/index.d.ts +3 -0
- package/dist/esm/src/matrix/utils/index.d.ts.map +1 -1
- package/dist/esm/src/matrix/utils/index.js +28 -0
- package/dist/esm/src/puppet-matrix.d.ts +7 -0
- package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
- package/dist/esm/src/puppet-matrix.js +95 -1
- package/dist/esm/src/utils/normalize-filebox.d.ts +6 -0
- package/dist/esm/src/utils/normalize-filebox.d.ts.map +1 -0
- package/dist/esm/src/utils/normalize-filebox.js +42 -0
- package/dist/esm/src/utils/sns-xml-generator.d.ts +19 -0
- package/dist/esm/src/utils/sns-xml-generator.d.ts.map +1 -0
- package/dist/esm/src/utils/sns-xml-generator.js +165 -0
- package/package.json +6 -5
- package/src/matrix/cache-manager.ts +1 -1
- package/src/matrix/messages/message-location.ts +46 -0
- package/src/matrix/service/request.ts +483 -2
- package/src/matrix/utils/index.ts +62 -0
- package/src/puppet-matrix.ts +130 -1
- package/src/utils/normalize-filebox.ts +90 -0
- package/src/utils/sns-xml-generator.ts +184 -0
package/src/puppet-matrix.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { log } from '@juzi/wechaty-puppet'
|
|
2
2
|
import * as PUPPET from '@juzi/wechaty-puppet'
|
|
3
3
|
import type { FileBoxInterface } from 'file-box'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
FileBox,
|
|
6
|
+
FileBoxType,
|
|
7
|
+
} from 'file-box'
|
|
5
8
|
import type { ContactPayload, MessagePayload } from './engine-schema.js'
|
|
6
9
|
import type { FileBoxMetadataMessage } from './matrix/types.js'
|
|
7
10
|
import Client from './matrix/service/request.js'
|
|
@@ -18,6 +21,7 @@ import { parseEmotionMessagePayload } from './matrix/messages/message-emotion.js
|
|
|
18
21
|
import { ImageMessagePayload, parseImageMessagePayload } from './matrix/messages/message-image.js'
|
|
19
22
|
import { parseAudioMessagePayload, AudioMessagePayload } from './matrix/messages/message-audio.js'
|
|
20
23
|
import { parseVideoMessagePayload, VideoMessagePayload } from './matrix/messages/message-video.js'
|
|
24
|
+
import { parseLocationMessagePayload } from './matrix/messages/message-location.js'
|
|
21
25
|
import { CachedPromiseFunc } from './matrix/utils/cached-promise.js'
|
|
22
26
|
import { engineMessageToWechaty } from './matrix/schema-mapper/message.js'
|
|
23
27
|
import { engineContactToWechaty } from './matrix/schema-mapper/contact.js'
|
|
@@ -54,6 +58,11 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
54
58
|
private _verifyInterval?: ReturnType<typeof setInterval> | null
|
|
55
59
|
private _qrcodeStatuasInterval?: ReturnType<typeof setInterval> | null
|
|
56
60
|
public static override readonly VERSION = VERSION
|
|
61
|
+
/**
|
|
62
|
+
* UUIDify:
|
|
63
|
+
* We need to clone a FileBox
|
|
64
|
+
* to set uuid loader/saver with this grpc client
|
|
65
|
+
*/
|
|
57
66
|
|
|
58
67
|
constructor (public override options: PuppetEngineOptions = {} as PuppetEngineOptions) {
|
|
59
68
|
super(options)
|
|
@@ -750,6 +759,23 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
750
759
|
}
|
|
751
760
|
}
|
|
752
761
|
|
|
762
|
+
/**
|
|
763
|
+
* 解析h5链接
|
|
764
|
+
* @param messageId
|
|
765
|
+
*/
|
|
766
|
+
override async messageLocation (messageId: string) : Promise<PUPPET.payloads.Location> {
|
|
767
|
+
const rawPayload = await this.messageRawPayload(messageId)
|
|
768
|
+
const payload = await this.messageRawPayloadParser(rawPayload)
|
|
769
|
+
|
|
770
|
+
if (payload.type !== PUPPET.types.Message.Location) {
|
|
771
|
+
throw new Error('Can not get location from non location payload')
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// FIXME: thumb may not in appPayload.thumburl, but in appPayload.appAttachPayload
|
|
775
|
+
const locationPayload = await parseLocationMessagePayload(rawPayload.msg) as PUPPET.payloads.Location
|
|
776
|
+
return locationPayload
|
|
777
|
+
}
|
|
778
|
+
|
|
753
779
|
/****************************************************************************
|
|
754
780
|
* send message
|
|
755
781
|
***************************************************************************/
|
|
@@ -1160,6 +1186,109 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
1160
1186
|
|
|
1161
1187
|
return ret
|
|
1162
1188
|
}
|
|
1189
|
+
|
|
1190
|
+
/****************************************************************************
|
|
1191
|
+
* moment section
|
|
1192
|
+
***************************************************************************/
|
|
1193
|
+
/**
|
|
1194
|
+
* 发布朋友圈
|
|
1195
|
+
* @param payload
|
|
1196
|
+
*/
|
|
1197
|
+
override async postPublish (payload: PUPPET.payloads.Post): Promise<void | string> {
|
|
1198
|
+
log.verbose(PRE, 'postPublish(%s)', payload)
|
|
1199
|
+
if (!PUPPET.payloads.isPostClient(payload)) {
|
|
1200
|
+
throw new Error('can only publish client post now')
|
|
1201
|
+
}
|
|
1202
|
+
const momentInfo:any = {
|
|
1203
|
+
content: '',
|
|
1204
|
+
mentionIdList: [],
|
|
1205
|
+
visibledList: [],
|
|
1206
|
+
imageUrls: [],
|
|
1207
|
+
videoUrl: '',
|
|
1208
|
+
urlLink: null,
|
|
1209
|
+
channel: null,
|
|
1210
|
+
miniInfo: null,
|
|
1211
|
+
location: null,
|
|
1212
|
+
rootId: '',
|
|
1213
|
+
parentId: '',
|
|
1214
|
+
}
|
|
1215
|
+
for (const item of payload.sayableList) {
|
|
1216
|
+
switch (item.type) {
|
|
1217
|
+
case PUPPET.types.Sayable.Text:
|
|
1218
|
+
momentInfo.content = `${momentInfo.content ? momentInfo.content + '\n' : ''}${item.payload.text}`
|
|
1219
|
+
momentInfo.mentionIdList = item.payload.mentions
|
|
1220
|
+
break
|
|
1221
|
+
case PUPPET.types.Sayable.Attachment: {
|
|
1222
|
+
const fileBox = item.payload.filebox as FileBoxInterface
|
|
1223
|
+
if (typeof item.payload.filebox !== 'string' && (fileBox as FileBoxInterface).type === FileBoxType.Url) {
|
|
1224
|
+
const fileType = fileBox.mediaType && fileBox.mediaType !== 'application/octet-stream' ? fileBox.mediaType : path.extname(fileBox.name)
|
|
1225
|
+
// @ts-ignore
|
|
1226
|
+
const fileUrl = fileBox.remoteUrl || ''
|
|
1227
|
+
if (fileBox.mediaType.startsWith('image/')) {
|
|
1228
|
+
momentInfo.imageUrls.push(fileUrl)
|
|
1229
|
+
} else if (fileType.includes('video/mp4') || fileType.includes('.mp4')) {
|
|
1230
|
+
momentInfo.videoUrl = fileUrl
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
break
|
|
1234
|
+
}
|
|
1235
|
+
case PUPPET.types.Sayable.Url: {
|
|
1236
|
+
momentInfo.urlLink = item.payload
|
|
1237
|
+
break
|
|
1238
|
+
}
|
|
1239
|
+
case PUPPET.types.Sayable.Channel: {
|
|
1240
|
+
momentInfo.channel = item.payload
|
|
1241
|
+
break
|
|
1242
|
+
}
|
|
1243
|
+
case PUPPET.types.Sayable.MiniProgram: {
|
|
1244
|
+
momentInfo.miniInfo = item.payload
|
|
1245
|
+
break
|
|
1246
|
+
}
|
|
1247
|
+
default:
|
|
1248
|
+
throw new Error(`postPublish unsupported type ${item.type}`)
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
if (payload.rootId) momentInfo.rootId = payload.rootId
|
|
1252
|
+
if (payload.parentId) momentInfo.parentId = payload.parentId
|
|
1253
|
+
if (payload.location) momentInfo.location = payload.location
|
|
1254
|
+
|
|
1255
|
+
momentInfo.visibleList = payload.visibleList
|
|
1256
|
+
|
|
1257
|
+
const res = await this._client?.sendSnsMoment(this._self?.wxid || '', momentInfo)
|
|
1258
|
+
|
|
1259
|
+
return res
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
override async postUnpublish (id: string): Promise<void> {
|
|
1263
|
+
log.verbose(PRE, 'postUnpublish(%s)', id)
|
|
1264
|
+
|
|
1265
|
+
await this._client?.unSendMoment(id)
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
override async postRawPayload (id: string): Promise<PUPPET.payloads.Post | string> {
|
|
1269
|
+
log.verbose(PRE, 'postRawPayload(%s)', id)
|
|
1270
|
+
return id
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
override async postPayloadSayable (postId: string, sayableId: string): Promise<PUPPET.payloads.Sayable> {
|
|
1274
|
+
log.verbose(PRE, 'postPayloadSayable(%s, %s)', postId, sayableId)
|
|
1275
|
+
return postId as any
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
override async postRawPayloadParser (payload: PUPPET.payloads.Post): Promise<PUPPET.payloads.Post> {
|
|
1279
|
+
// log.silly('PuppetService', 'postRawPayloadParser({id:%s})', payload.id)
|
|
1280
|
+
// passthrough
|
|
1281
|
+
return payload
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
override async tap (postId: string, type: PUPPET.types.Tap, tap = true): Promise<boolean | void> {
|
|
1285
|
+
log.verbose(PRE, 'tap(%s, %s, %s)', postId, type, tap)
|
|
1286
|
+
|
|
1287
|
+
const res = await this._client?.sendMomentLike(postId, type)
|
|
1288
|
+
|
|
1289
|
+
return !!res
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1163
1292
|
/****************************************************************************
|
|
1164
1293
|
* extra methods section
|
|
1165
1294
|
***************************************************************************/
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FileBox,
|
|
3
|
+
} from 'file-box'
|
|
4
|
+
import {
|
|
5
|
+
FileBoxType,
|
|
6
|
+
FileBoxInterface,
|
|
7
|
+
} from 'file-box'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Huan(202110): for testing propose, use 20KB as the threshold
|
|
11
|
+
* after stable we should use a value between 64KB to 256KB as the threshold
|
|
12
|
+
*/
|
|
13
|
+
const PASS_THROUGH_THRESHOLD_BYTES = 20 * 1024 // 20KB
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 1. Green:
|
|
17
|
+
* Can be serialized directly
|
|
18
|
+
*/
|
|
19
|
+
const greenFileBoxTypes = [
|
|
20
|
+
FileBoxType.Url,
|
|
21
|
+
FileBoxType.Uuid,
|
|
22
|
+
FileBoxType.QRCode,
|
|
23
|
+
]
|
|
24
|
+
/**
|
|
25
|
+
* 2. Yellow:
|
|
26
|
+
* Can be serialized directly, if the size is less than a threshold
|
|
27
|
+
* if it's bigger than the threshold,
|
|
28
|
+
* then it should be convert to a UUID file box before send out
|
|
29
|
+
*/
|
|
30
|
+
const yellowFileBoxTypes: FileBoxType [] = [
|
|
31
|
+
// FileBoxType.Buffer,
|
|
32
|
+
// FileBoxType.Base64,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
const canPassthrough = (fileBox: FileBoxInterface) => {
|
|
36
|
+
/**
|
|
37
|
+
* 1. Green types: YES
|
|
38
|
+
*/
|
|
39
|
+
if (greenFileBoxTypes.includes(fileBox.type)) {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 2. Red types: NO
|
|
45
|
+
*/
|
|
46
|
+
if (!yellowFileBoxTypes.includes(fileBox.type)) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 3. Yellow types: CHECK size
|
|
52
|
+
*/
|
|
53
|
+
const size = fileBox.size
|
|
54
|
+
if (size < 0) {
|
|
55
|
+
// 1. Size unknown: NO
|
|
56
|
+
return false
|
|
57
|
+
} else if (size > PASS_THROUGH_THRESHOLD_BYTES) {
|
|
58
|
+
// 2. Size: bigger than threshold: NO
|
|
59
|
+
return false
|
|
60
|
+
} else {
|
|
61
|
+
// 3. Size: smaller than threshold: YES
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const normalizeFileBoxUuid = (FileBoxUuid: typeof FileBox) => async (fileBox: FileBoxInterface) => {
|
|
68
|
+
if (canPassthrough(fileBox)) {
|
|
69
|
+
return fileBox
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const stream = await fileBox.toStream()
|
|
73
|
+
|
|
74
|
+
const uuid = await FileBoxUuid
|
|
75
|
+
.fromStream(stream, fileBox.name)
|
|
76
|
+
.toUuid()
|
|
77
|
+
|
|
78
|
+
const uuidFileBox = FileBoxUuid.fromUuid(uuid, {
|
|
79
|
+
md5 : fileBox.md5,
|
|
80
|
+
name : fileBox.name,
|
|
81
|
+
size : fileBox.size,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
return uuidFileBox
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
canPassthrough,
|
|
89
|
+
normalizeFileBoxUuid,
|
|
90
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
type Media = {
|
|
2
|
+
fileId: string
|
|
3
|
+
fileSize: number
|
|
4
|
+
fileType: number
|
|
5
|
+
videoDuration: number
|
|
6
|
+
url: string
|
|
7
|
+
width: number
|
|
8
|
+
height: number
|
|
9
|
+
fileUrl: string
|
|
10
|
+
fileKey: string
|
|
11
|
+
thumbUrl: string
|
|
12
|
+
thumbWidth: number
|
|
13
|
+
thumbHeight: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const genTextSnsXml = (wxid: string, content: string): string => {
|
|
17
|
+
const xmlTemplate = `
|
|
18
|
+
<TimelineObject>
|
|
19
|
+
<id><![CDATA[0]]></id>
|
|
20
|
+
<username><![CDATA[${wxid}]]></username>
|
|
21
|
+
<createTime><![CDATA[${Math.floor(Date.now() / 1000)}]]></createTime>
|
|
22
|
+
<contentDescShowType>0</contentDescShowType>
|
|
23
|
+
<contentDescScene>0</contentDescScene>
|
|
24
|
+
<private><![CDATA[0]]></private>
|
|
25
|
+
<contentDesc><![CDATA[${content}]]></contentDesc>
|
|
26
|
+
<contentattr><![CDATA[0]]></contentattr>
|
|
27
|
+
<sourceUserName></sourceUserName>
|
|
28
|
+
<sourceNickName></sourceNickName>
|
|
29
|
+
<statisticsData></statisticsData>
|
|
30
|
+
<weappInfo>
|
|
31
|
+
<appUserName></appUserName>
|
|
32
|
+
<pagePath></pagePath>
|
|
33
|
+
<version><![CDATA[0]]></version>
|
|
34
|
+
<isHidden>0</isHidden>
|
|
35
|
+
<debugMode><![CDATA[0]]></debugMode>
|
|
36
|
+
<shareActionId></shareActionId>
|
|
37
|
+
<isGame><![CDATA[0]]></isGame>
|
|
38
|
+
<messageExtraData></messageExtraData>
|
|
39
|
+
<subType><![CDATA[0]]></subType>
|
|
40
|
+
<preloadResources></preloadResources>
|
|
41
|
+
</weappInfo>
|
|
42
|
+
<canvasInfoXml></canvasInfoXml>
|
|
43
|
+
<ContentObject>
|
|
44
|
+
<contentStyle><![CDATA[2]]></contentStyle>
|
|
45
|
+
<contentSubStyle><![CDATA[0]]></contentSubStyle>
|
|
46
|
+
<title></title>
|
|
47
|
+
<description></description>
|
|
48
|
+
<contentUrl></contentUrl>
|
|
49
|
+
</ContentObject>
|
|
50
|
+
<actionInfo>
|
|
51
|
+
<appMsg>
|
|
52
|
+
<mediaTagName></mediaTagName>
|
|
53
|
+
<messageExt></messageExt>
|
|
54
|
+
<messageAction></messageAction>
|
|
55
|
+
</appMsg>
|
|
56
|
+
</actionInfo>
|
|
57
|
+
<appInfo><id></id></appInfo>
|
|
58
|
+
<publicUserName></publicUserName>
|
|
59
|
+
<streamvideo>
|
|
60
|
+
<streamvideourl></streamvideourl>
|
|
61
|
+
<streamvideothumburl></streamvideothumburl>
|
|
62
|
+
<streamvideoweburl></streamvideoweburl>
|
|
63
|
+
</streamvideo>
|
|
64
|
+
</TimelineObject>`.replace(/\s+/g, '')
|
|
65
|
+
return xmlTemplate
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const genVideoSnsXml = (wxid: string, content: string, media: Media): string => {
|
|
69
|
+
const xmlTemplate = `
|
|
70
|
+
<TimelineObject>
|
|
71
|
+
<id>0</id>
|
|
72
|
+
<username>${wxid}</username>
|
|
73
|
+
<createTime>${Math.floor(Date.now() / 1000)}</createTime>
|
|
74
|
+
<contentDesc>${content}</contentDesc>
|
|
75
|
+
<contentDescShowType>0</contentDescShowType>
|
|
76
|
+
<contentDescScene>0</contentDescScene>
|
|
77
|
+
<private>0</private>
|
|
78
|
+
<sightFolded>0</sightFolded>
|
|
79
|
+
<showFlag>0</showFlag>
|
|
80
|
+
<appInfo>
|
|
81
|
+
<id></id>
|
|
82
|
+
<version></version>
|
|
83
|
+
<appName></appName>
|
|
84
|
+
<installUrl></installUrl>
|
|
85
|
+
<fromUrl></fromUrl>
|
|
86
|
+
<isForceUpdate>0</isForceUpdate>
|
|
87
|
+
<isHidden>0</isHidden>
|
|
88
|
+
</appInfo>
|
|
89
|
+
<sourceUserName></sourceUserName>
|
|
90
|
+
<sourceNickName></sourceNickName>
|
|
91
|
+
<statisticsData></statisticsData>
|
|
92
|
+
<statExtStr></statExtStr>
|
|
93
|
+
<ContentObject>
|
|
94
|
+
<contentStyle>15</contentStyle>
|
|
95
|
+
<title></title>
|
|
96
|
+
<description>Sight</description>
|
|
97
|
+
<mediaList>
|
|
98
|
+
<media>
|
|
99
|
+
<id>0</id>
|
|
100
|
+
<type>6</type>
|
|
101
|
+
<title></title>
|
|
102
|
+
<description>测试</description>
|
|
103
|
+
<private>0</private>
|
|
104
|
+
<userData></userData>
|
|
105
|
+
<subType>0</subType>
|
|
106
|
+
<videoSize width="${media.width}" height="${media.height}"/>
|
|
107
|
+
<url type="1" md5="951a7d7864d685a92fd2624155794bf9" videomd5="577f55635faf44f595a69ded26d87bcc">${media.fileUrl}</url>
|
|
108
|
+
<thumb type="1">${media.thumbUrl}</thumb>
|
|
109
|
+
<size width="${media.thumbWidth}.000000" height="${media.thumbHeight}.000000" totalSize="${media.fileSize}"/>
|
|
110
|
+
<videoDuration>${media.videoDuration}.000000</videoDuration>
|
|
111
|
+
</media>
|
|
112
|
+
</mediaList>
|
|
113
|
+
</ContentObject>
|
|
114
|
+
</TimelineObject>`.replace(/\s+/g, '')
|
|
115
|
+
return xmlTemplate
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const genImageSnsXml = (wxid: string, contentDesc: string, mediaList: Media[]): string => {
|
|
119
|
+
const mediaTemplate = (media: Media) => `
|
|
120
|
+
<media>
|
|
121
|
+
<id><![CDATA[0]]></id>
|
|
122
|
+
<type><![CDATA[2]]></type>
|
|
123
|
+
<title></title>
|
|
124
|
+
<description></description>
|
|
125
|
+
<private><![CDATA[0]]></private>
|
|
126
|
+
<url type="1" md5="951a7d7864d685a92fd2624155794bf9"><![CDATA[${media.fileUrl}]]></url>
|
|
127
|
+
<thumb type="1"><![CDATA[${media.thumbUrl}]]></thumb>
|
|
128
|
+
<videoDuration><![CDATA[0.0]]></videoDuration>
|
|
129
|
+
<size totalSize="${media.fileSize}" width="${media.width}" height="${media.height}"></size>
|
|
130
|
+
</media>`.replace(/\s+/g, '')
|
|
131
|
+
|
|
132
|
+
const mediaString = mediaList.map(media => mediaTemplate(media)).join('')
|
|
133
|
+
|
|
134
|
+
const xmlTemplate = `
|
|
135
|
+
<TimelineObject>
|
|
136
|
+
<id><![CDATA[0]]></id>
|
|
137
|
+
<username><![CDATA[${wxid}]]></username>
|
|
138
|
+
<createTime><![CDATA[${Math.floor(Date.now() / 1000)}]]></createTime>
|
|
139
|
+
<contentDescShowType>0</contentDescShowType>
|
|
140
|
+
<contentDescScene>0</contentDescScene>
|
|
141
|
+
<private><![CDATA[0]]></private>
|
|
142
|
+
<contentDesc><![CDATA[${contentDesc}]]></contentDesc>
|
|
143
|
+
<contentattr><![CDATA[0]]></contentattr>
|
|
144
|
+
<sourceUserName></sourceUserName>
|
|
145
|
+
<sourceNickName></sourceNickName>
|
|
146
|
+
<statisticsData></statisticsData>
|
|
147
|
+
<weappInfo>
|
|
148
|
+
<appUserName></appUserName>
|
|
149
|
+
<pagePath></pagePath>
|
|
150
|
+
<version><![CDATA[0]]></version>
|
|
151
|
+
<isHidden>0</isHidden>
|
|
152
|
+
<debugMode><![CDATA[0]]></debugMode>
|
|
153
|
+
<shareActionId></shareActionId>
|
|
154
|
+
<isGame><![CDATA[0]]></isGame>
|
|
155
|
+
<messageExtraData></messageExtraData>
|
|
156
|
+
<subType><![CDATA[0]]></subType>
|
|
157
|
+
<preloadResources></preloadResources>
|
|
158
|
+
</weappInfo>
|
|
159
|
+
<canvasInfoXml></canvasInfoXml>
|
|
160
|
+
<ContentObject>
|
|
161
|
+
<contentStyle><![CDATA[1]]></contentStyle>
|
|
162
|
+
<contentSubStyle><![CDATA[0]]></contentSubStyle>
|
|
163
|
+
<title></title>
|
|
164
|
+
<description></description>
|
|
165
|
+
<contentUrl></contentUrl>
|
|
166
|
+
<mediaList>${mediaString}</mediaList>
|
|
167
|
+
</ContentObject>
|
|
168
|
+
<actionInfo>
|
|
169
|
+
<appMsg>
|
|
170
|
+
<mediaTagName></mediaTagName>
|
|
171
|
+
<messageExt></messageExt>
|
|
172
|
+
<messageAction></messageAction>
|
|
173
|
+
</appMsg>
|
|
174
|
+
</actionInfo>
|
|
175
|
+
<appInfo><id></id></appInfo>
|
|
176
|
+
<publicUserName></publicUserName>
|
|
177
|
+
<streamvideo>
|
|
178
|
+
<streamvideourl></streamvideourl>
|
|
179
|
+
<streamvideothumburl></streamvideothumburl>
|
|
180
|
+
<streamvideoweburl></streamvideoweburl>
|
|
181
|
+
</streamvideo>
|
|
182
|
+
</TimelineObject>`.replace(/\s+/g, '')
|
|
183
|
+
return xmlTemplate
|
|
184
|
+
}
|