wechaty-puppet-matrix 0.0.9 → 0.0.12

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.
Files changed (39) hide show
  1. package/dist/cjs/src/matrix/cache-manager.js +1 -1
  2. package/dist/cjs/src/matrix/service/request.d.ts +63 -0
  3. package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
  4. package/dist/cjs/src/matrix/service/request.js +407 -4
  5. package/dist/cjs/src/matrix/utils/index.d.ts +3 -0
  6. package/dist/cjs/src/matrix/utils/index.d.ts.map +1 -1
  7. package/dist/cjs/src/matrix/utils/index.js +31 -0
  8. package/dist/cjs/src/puppet-matrix.d.ts +6 -0
  9. package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
  10. package/dist/cjs/src/puppet-matrix.js +84 -0
  11. package/dist/cjs/src/utils/normalize-filebox.d.ts +6 -0
  12. package/dist/cjs/src/utils/normalize-filebox.d.ts.map +1 -0
  13. package/dist/cjs/src/utils/normalize-filebox.js +46 -0
  14. package/dist/cjs/src/utils/sns-xml-generator.d.ts +19 -0
  15. package/dist/cjs/src/utils/sns-xml-generator.d.ts.map +1 -0
  16. package/dist/cjs/src/utils/sns-xml-generator.js +171 -0
  17. package/dist/esm/src/matrix/cache-manager.js +1 -1
  18. package/dist/esm/src/matrix/service/request.d.ts +63 -0
  19. package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
  20. package/dist/esm/src/matrix/service/request.js +407 -4
  21. package/dist/esm/src/matrix/utils/index.d.ts +3 -0
  22. package/dist/esm/src/matrix/utils/index.d.ts.map +1 -1
  23. package/dist/esm/src/matrix/utils/index.js +28 -0
  24. package/dist/esm/src/puppet-matrix.d.ts +6 -0
  25. package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
  26. package/dist/esm/src/puppet-matrix.js +85 -1
  27. package/dist/esm/src/utils/normalize-filebox.d.ts +6 -0
  28. package/dist/esm/src/utils/normalize-filebox.d.ts.map +1 -0
  29. package/dist/esm/src/utils/normalize-filebox.js +42 -0
  30. package/dist/esm/src/utils/sns-xml-generator.d.ts +19 -0
  31. package/dist/esm/src/utils/sns-xml-generator.d.ts.map +1 -0
  32. package/dist/esm/src/utils/sns-xml-generator.js +165 -0
  33. package/package.json +6 -5
  34. package/src/matrix/cache-manager.ts +1 -1
  35. package/src/matrix/service/request.ts +523 -8
  36. package/src/matrix/utils/index.ts +62 -0
  37. package/src/puppet-matrix.ts +112 -1
  38. package/src/utils/normalize-filebox.ts +90 -0
  39. package/src/utils/sns-xml-generator.ts +184 -0
@@ -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 { FileBox } from 'file-box'
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'
@@ -54,6 +57,11 @@ class PuppetMatrix extends PUPPET.Puppet {
54
57
  private _verifyInterval?: ReturnType<typeof setInterval> | null
55
58
  private _qrcodeStatuasInterval?: ReturnType<typeof setInterval> | null
56
59
  public static override readonly VERSION = VERSION
60
+ /**
61
+ * UUIDify:
62
+ * We need to clone a FileBox
63
+ * to set uuid loader/saver with this grpc client
64
+ */
57
65
 
58
66
  constructor (public override options: PuppetEngineOptions = {} as PuppetEngineOptions) {
59
67
  super(options)
@@ -1160,6 +1168,109 @@ class PuppetMatrix extends PUPPET.Puppet {
1160
1168
 
1161
1169
  return ret
1162
1170
  }
1171
+
1172
+ /****************************************************************************
1173
+ * moment section
1174
+ ***************************************************************************/
1175
+ /**
1176
+ * 发布朋友圈
1177
+ * @param payload
1178
+ */
1179
+ override async postPublish (payload: PUPPET.payloads.Post): Promise<void | string> {
1180
+ log.verbose(PRE, 'postPublish(%s)', payload)
1181
+ if (!PUPPET.payloads.isPostClient(payload)) {
1182
+ throw new Error('can only publish client post now')
1183
+ }
1184
+ const momentInfo:any = {
1185
+ content: '',
1186
+ mentionIdList: [],
1187
+ visibledList: [],
1188
+ imageUrls: [],
1189
+ videoUrl: '',
1190
+ urlLink: null,
1191
+ channel: null,
1192
+ miniInfo: null,
1193
+ location: null,
1194
+ rootId: '',
1195
+ parentId: '',
1196
+ }
1197
+ for (const item of payload.sayableList) {
1198
+ switch (item.type) {
1199
+ case PUPPET.types.Sayable.Text:
1200
+ momentInfo.content = `${momentInfo.content ? momentInfo.content + '\n' : ''}${item.payload.text}`
1201
+ momentInfo.mentionIdList = item.payload.mentions
1202
+ break
1203
+ case PUPPET.types.Sayable.Attachment: {
1204
+ const fileBox = item.payload.filebox as FileBoxInterface
1205
+ if (typeof item.payload.filebox !== 'string' && (fileBox as FileBoxInterface).type === FileBoxType.Url) {
1206
+ const fileType = fileBox.mediaType && fileBox.mediaType !== 'application/octet-stream' ? fileBox.mediaType : path.extname(fileBox.name)
1207
+ // @ts-ignore
1208
+ const fileUrl = fileBox.remoteUrl || ''
1209
+ if (fileBox.mediaType.startsWith('image/')) {
1210
+ momentInfo.imageUrls.push(fileUrl)
1211
+ } else if (fileType.includes('video/mp4') || fileType.includes('.mp4')) {
1212
+ momentInfo.videoInfo = fileUrl
1213
+ }
1214
+ }
1215
+ break
1216
+ }
1217
+ case PUPPET.types.Sayable.Url: {
1218
+ momentInfo.urlLink = item.payload
1219
+ break
1220
+ }
1221
+ case PUPPET.types.Sayable.Channel: {
1222
+ momentInfo.channel = item.payload
1223
+ break
1224
+ }
1225
+ case PUPPET.types.Sayable.MiniProgram: {
1226
+ momentInfo.miniInfo = item.payload
1227
+ break
1228
+ }
1229
+ default:
1230
+ throw new Error(`postPublish unsupported type ${item.type}`)
1231
+ }
1232
+ }
1233
+ if (payload.rootId) momentInfo.rootId = payload.rootId
1234
+ if (payload.parentId) momentInfo.parentId = payload.parentId
1235
+ if (payload.location) momentInfo.location = payload.location
1236
+
1237
+ momentInfo.visibleList = payload.visibleList
1238
+
1239
+ const res = await this._client?.sendSnsMoment(this._self?.wxid || '', momentInfo)
1240
+
1241
+ return res
1242
+ }
1243
+
1244
+ override async postUnpublish (id: string): Promise<void> {
1245
+ log.verbose(PRE, 'postUnpublish(%s)', id)
1246
+
1247
+ await this._client?.unSendMoment(id)
1248
+ }
1249
+
1250
+ override async postRawPayload (id: string): Promise<PUPPET.payloads.Post | string> {
1251
+ log.verbose(PRE, 'postRawPayload(%s)', id)
1252
+ return id
1253
+ }
1254
+
1255
+ override async postPayloadSayable (postId: string, sayableId: string): Promise<PUPPET.payloads.Sayable> {
1256
+ log.verbose(PRE, 'postPayloadSayable(%s, %s)', postId, sayableId)
1257
+ return postId as any
1258
+ }
1259
+
1260
+ override async postRawPayloadParser (payload: PUPPET.payloads.Post): Promise<PUPPET.payloads.Post> {
1261
+ // log.silly('PuppetService', 'postRawPayloadParser({id:%s})', payload.id)
1262
+ // passthrough
1263
+ return payload
1264
+ }
1265
+
1266
+ override async tap (postId: string, type: PUPPET.types.Tap, tap = true): Promise<boolean | void> {
1267
+ log.verbose(PRE, 'tap(%s, %s, %s)', postId, type, tap)
1268
+
1269
+ const res = await this._client?.sendMomentLike(postId, type)
1270
+
1271
+ return !!res
1272
+ }
1273
+
1163
1274
  /****************************************************************************
1164
1275
  * extra methods section
1165
1276
  ***************************************************************************/
@@ -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
+ }