@dongdev/fca-unofficial 3.0.27 → 3.0.28

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.
@@ -1,377 +1,368 @@
1
- "use strict";
2
- const { formatDeltaEvent, formatMessage, _formatAttachment, formatDeltaMessage, formatDeltaReadReceipt, formatID, getType, decodeClientPayload, getMentionsFromDeltaMessage } = require("../../../utils/format");
3
- const logger = require("../../../../func/logger");
4
- module.exports = function createParseDelta(deps) {
5
- const { markDelivery, parseAndCheckLogin } = deps;
6
- return function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
7
- if (delta.class === "NewMessage") {
8
- const resolveAttachmentUrl = i => {
9
- if (!delta.attachments || i === delta.attachments.length || getType(delta.attachments) !== "Array") {
10
- let fmtMsg;
11
- try {
12
- fmtMsg = formatDeltaMessage(delta);
13
- } catch (err) {
14
- return;
15
- }
16
- if (fmtMsg) {
17
- if (ctx.globalOptions.autoMarkDelivery) {
18
- markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
19
- }
20
- if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) return;
21
- globalCallback(null, fmtMsg);
22
- }
23
- } else {
24
- const attachment = delta.attachments[i];
25
- if (attachment && attachment.mercury && attachment.mercury.attach_type === "photo") {
26
- api.resolvePhotoUrl(attachment.fbid, (err, url) => {
27
- if (!err && attachment.mercury && attachment.mercury.metadata) {
28
- attachment.mercury.metadata.url = url;
29
- }
30
- resolveAttachmentUrl(i + 1);
31
- });
32
- } else {
33
- resolveAttachmentUrl(i + 1);
34
- }
35
- }
36
- };
37
- resolveAttachmentUrl(0);
38
- } else if (delta.class === "ClientPayload") {
39
- const clientPayload = decodeClientPayload(delta.payload);
40
- if (clientPayload && clientPayload.deltas) {
41
- for (const d of clientPayload.deltas) {
42
- if (d.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
43
- const messageReaction = {
44
- type: "message_reaction",
45
- threadID: (d.deltaMessageReaction.threadKey.threadFbId ? d.deltaMessageReaction.threadKey.threadFbId : d.deltaMessageReaction.threadKey.otherUserFbId).toString(),
46
- messageID: d.deltaMessageReaction.messageId,
47
- reaction: d.deltaMessageReaction.reaction,
48
- senderID: d.deltaMessageReaction.senderId.toString(),
49
- userID: d.deltaMessageReaction.userId.toString()
50
- };
51
- globalCallback(null, messageReaction);
52
- } else if (d.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
53
- const messageUnsend = {
54
- type: "message_unsend",
55
- threadID: (d.deltaRecallMessageData.threadKey.threadFbId ? d.deltaRecallMessageData.threadKey.threadFbId : d.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
56
- messageID: d.deltaRecallMessageData.messageID,
57
- senderID: d.deltaRecallMessageData.senderID.toString(),
58
- deletionTimestamp: d.deltaRecallMessageData.deletionTimestamp,
59
- timestamp: d.deltaRecallMessageData.timestamp
60
- };
61
- globalCallback(null, messageUnsend);
62
- } else if (d.deltaMessageReply) {
63
- let callbackToReturn;
64
- try {
65
- const msg = d.deltaMessageReply.message;
66
- if (!msg || !msg.messageMetadata) {
67
- logger("parseDelta: deltaMessageReply.message or messageMetadata is missing", "warn");
68
- return;
69
- }
70
- const mentions = getMentionsFromDeltaMessage(msg);
71
- const msgMetadata = msg.messageMetadata;
72
- const threadKey = msgMetadata.threadKey || {};
73
- callbackToReturn = {
74
- type: "message_reply",
75
- threadID: (threadKey.threadFbId ? threadKey.threadFbId : threadKey.otherUserFbId || "").toString(),
76
- messageID: msgMetadata.messageId || "",
77
- senderID: (msgMetadata.actorFbId || "").toString(),
78
- attachments: (msg.attachments || []).map(att => {
79
- try {
80
- const mercury = JSON.parse(att.mercuryJSON);
81
- Object.assign(att, mercury);
82
- } catch (ex) {
83
- // Ignore parsing errors
84
- }
85
- return att;
86
- }).map(att => {
87
- let x;
88
- try {
89
- x = _formatAttachment(att);
90
- } catch (ex) {
91
- x = att;
92
- x.error = ex;
93
- x.type = "unknown";
94
- }
95
- return x;
96
- }),
97
- args: (msg.body || "").trim().split(/\s+/),
98
- body: msg.body || "",
99
- isGroup: !!threadKey.threadFbId,
100
- mentions,
101
- timestamp: parseInt(msgMetadata.timestamp || 0),
102
- participantIDs: (msg.participants || []).map(e => e.toString())
103
- };
104
- if (d.deltaMessageReply.repliedToMessage) {
105
- try {
106
- const repliedTo = d.deltaMessageReply.repliedToMessage;
107
- const rmentions = getMentionsFromDeltaMessage(repliedTo);
108
- const msgMetadata = repliedTo.messageMetadata;
109
- if (msgMetadata && msgMetadata.threadKey) {
110
- callbackToReturn.messageReply = {
111
- threadID: (msgMetadata.threadKey.threadFbId ? msgMetadata.threadKey.threadFbId : msgMetadata.threadKey.otherUserFbId || "").toString(),
112
- messageID: msgMetadata.messageId || "",
113
- senderID: (msgMetadata.actorFbId || "").toString(),
114
- attachments: (repliedTo.attachments || []).map(att => {
115
- let mercury;
116
- try {
117
- mercury = JSON.parse(att.mercuryJSON);
118
- Object.assign(att, mercury);
119
- } catch (ex) {
120
- mercury = {};
121
- }
122
- return att;
123
- }).map(att => {
124
- let x;
125
- try {
126
- x = _formatAttachment(att);
127
- } catch (ex) {
128
- x = att;
129
- x.error = ex;
130
- x.type = "unknown";
131
- }
132
- return x;
133
- }),
134
- args: (repliedTo.body || "").trim().split(/\s+/),
135
- body: repliedTo.body || "",
136
- isGroup: !!msgMetadata.threadKey.threadFbId,
137
- mentions: rmentions,
138
- timestamp: parseInt(msgMetadata.timestamp || 0),
139
- participantIDs: (repliedTo.participants || []).map(e => e.toString())
140
- };
141
- }
142
- } catch (err) {
143
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
144
- logger(`parseDelta message_reply repliedToMessage error: ${errMsg}`, "warn");
145
- }
146
- } else if (d.deltaMessageReply.replyToMessageId) {
147
- return defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
148
- av: ctx.globalOptions.pageID,
149
- queries: JSON.stringify({
150
- o0: {
151
- doc_id: "2848441488556444",
152
- query_params: {
153
- thread_and_message_id: {
154
- thread_id: callbackToReturn.threadID,
155
- message_id: d.deltaMessageReply.replyToMessageId.id
156
- }
157
- }
158
- }
159
- })
160
- }).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
161
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
162
- if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
163
- const fetchData = resData[0].o0.data.message;
164
- const mobj = {};
165
- for (const n in fetchData.message.ranges) {
166
- mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
167
- }
168
- callbackToReturn.messageReply = {
169
- type: "Message",
170
- threadID: callbackToReturn.threadID,
171
- messageID: fetchData.message_id,
172
- senderID: fetchData.message_sender.id.toString(),
173
- attachments: fetchData.message.blob_attachment.map(att => _formatAttachment({ blob_attachment: att })),
174
- args: (fetchData.message.text || "").trim().split(/\s+/) || [],
175
- body: fetchData.message.text || "",
176
- isGroup: callbackToReturn.isGroup,
177
- mentions: mobj,
178
- timestamp: parseInt(fetchData.timestamp_precise)
179
- };
180
- }).catch(err => {
181
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
182
- logger(`parseDelta message_reply fetch error: ${errMsg}`, "warn");
183
- }).finally(() => {
184
- if (callbackToReturn) {
185
- if (ctx.globalOptions.autoMarkDelivery) {
186
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
187
- }
188
- if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
189
- globalCallback(null, callbackToReturn);
190
- }
191
- });
192
- } else {
193
- if (callbackToReturn) callbackToReturn.delta = d;
194
- }
195
- } catch (err) {
196
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
197
- logger(`parseDelta message_reply error: ${errMsg}`, "warn");
198
- return;
199
- }
200
- if (callbackToReturn) {
201
- if (ctx.globalOptions.autoMarkDelivery) {
202
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
203
- }
204
- if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
205
- globalCallback(null, callbackToReturn);
206
- }
207
- }
208
- }
209
- return;
210
- }
211
- }
212
- switch (delta.class) {
213
- case "ReadReceipt": {
214
- let fmtMsg;
215
- try {
216
- fmtMsg = formatDeltaReadReceipt(delta);
217
- } catch (err) {
218
- return;
219
- }
220
- globalCallback(null, fmtMsg);
221
- break;
222
- }
223
- case "AdminTextMessage": {
224
- switch (delta.type) {
225
- case "instant_game_dynamic_custom_update":
226
- case "accept_pending_thread":
227
- case "confirm_friend_request":
228
- case "shared_album_delete":
229
- case "shared_album_addition":
230
- case "pin_messages_v2":
231
- case "unpin_messages_v2":
232
- case "change_thread_theme":
233
- case "change_thread_nickname":
234
- case "change_thread_icon":
235
- case "change_thread_quick_reaction":
236
- case "change_thread_admins":
237
- case "group_poll":
238
- case "joinable_group_link_mode_change":
239
- case "magic_words":
240
- case "change_thread_approval_mode":
241
- case "messenger_call_log":
242
- case "participant_joined_group_call":
243
- case "rtc_call_log":
244
- case "update_vote": {
245
- let fmtMsg;
246
- try {
247
- fmtMsg = formatDeltaEvent(delta);
248
- } catch (err) {
249
- return;
250
- }
251
- globalCallback(null, fmtMsg);
252
- break;
253
- }
254
- }
255
- break;
256
- }
257
- case "ForcedFetch": {
258
- if (!delta.threadKey) return;
259
- const mid = delta.messageId;
260
- const tid = delta.threadKey.threadFbId;
261
- if (mid && tid) {
262
- const form = {
263
- av: ctx.globalOptions.pageID,
264
- queries: JSON.stringify({
265
- o0: {
266
- doc_id: "2848441488556444",
267
- query_params: {
268
- thread_and_message_id: {
269
- thread_id: tid.toString(),
270
- message_id: mid
271
- }
272
- }
273
- }
274
- })
275
- };
276
- defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
277
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
278
- if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
279
- const fetchData = resData[0].o0.data.message;
280
- if (getType(fetchData) === "Object") {
281
- switch (fetchData.__typename) {
282
- case "ThreadImageMessage":
283
- if ((!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) || !ctx.loggedIn) {} else {
284
- globalCallback(null, {
285
- type: "event",
286
- threadID: formatID(tid.toString()),
287
- logMessageType: "log:thread-image",
288
- logMessageData: {
289
- image: {
290
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
291
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
292
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
293
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
294
- }
295
- },
296
- logMessageBody: fetchData.snippet,
297
- timestamp: fetchData.timestamp_precise,
298
- author: fetchData.message_sender.id
299
- });
300
- }
301
- break;
302
- case "UserMessage": {
303
- const event = {
304
- type: "message",
305
- senderID: formatID(fetchData.message_sender.id),
306
- body: fetchData.message.text || "",
307
- threadID: formatID(tid.toString()),
308
- messageID: fetchData.message_id,
309
- attachments: [
310
- {
311
- type: "share",
312
- ID: fetchData.extensible_attachment.legacy_attachment_id,
313
- url: fetchData.extensible_attachment.story_attachment.url,
314
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
315
- description: fetchData.extensible_attachment.story_attachment.description.text,
316
- source: fetchData.extensible_attachment.story_attachment.source,
317
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
318
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
319
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
320
- playable: ((fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false),
321
- duration: ((fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0),
322
- subattachments: fetchData.extensible_attachment.subattachments,
323
- properties: fetchData.extensible_attachment.story_attachment.properties
324
- }
325
- ],
326
- mentions: {},
327
- timestamp: parseInt(fetchData.timestamp_precise),
328
- isGroup: fetchData.message_sender.id !== tid.toString()
329
- };
330
- globalCallback(null, event);
331
- break;
332
- }
333
- default:
334
- break;
335
- }
336
- } else {
337
- return;
338
- }
339
- }).catch(err => {
340
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
341
- logger(`parseDelta ForcedFetch error: ${errMsg}`, "warn");
342
- });
343
- }
344
- break;
345
- }
346
- case "ThreadName":
347
- case "ParticipantsAddedToGroupThread":
348
- case "ParticipantLeftGroupThread": {
349
- let formattedEvent;
350
- try {
351
- formattedEvent = formatDeltaEvent(delta);
352
- } catch (err) {
353
- return;
354
- }
355
- if (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) return;
356
- if (!ctx.loggedIn) return;
357
- globalCallback(null, formattedEvent);
358
- break;
359
- }
360
- case "NewMessage": {
361
- const hasLiveLocation = d => {
362
- const attachment = d.attachments && d.attachments[0] && d.attachments[0].mercury && d.attachments[0].mercury.extensible_attachment;
363
- const storyAttachment = attachment && attachment.story_attachment;
364
- return storyAttachment && storyAttachment.style_list && storyAttachment.style_list.includes("message_live_location");
365
- };
366
- if (delta.attachments && delta.attachments.length === 1 && hasLiveLocation(delta)) {
367
- delta.class = "UserLocation";
368
- try {
369
- const fmtMsg = formatDeltaEvent(delta);
370
- globalCallback(null, fmtMsg);
371
- } catch (err) {}
372
- }
373
- break;
374
- }
375
- }
376
- };
377
- };
1
+ "use strict";
2
+ const { formatDeltaEvent, formatMessage, _formatAttachment, formatDeltaMessage, formatDeltaReadReceipt, formatID, getType, decodeClientPayload, getMentionsFromDeltaMessage } = require("../../../utils/format");
3
+ const logger = require("../../../../func/logger");
4
+ module.exports = function createParseDelta(deps) {
5
+ const { parseAndCheckLogin } = deps;
6
+ return function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
7
+ if (delta.class === "NewMessage") {
8
+ const resolveAttachmentUrl = i => {
9
+ if (!delta.attachments || i === delta.attachments.length || getType(delta.attachments) !== "Array") {
10
+ let fmtMsg;
11
+ try {
12
+ fmtMsg = formatDeltaMessage(delta);
13
+ } catch (err) {
14
+ return;
15
+ }
16
+ if (fmtMsg) {
17
+ if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) return;
18
+ globalCallback(null, fmtMsg);
19
+ }
20
+ } else {
21
+ const attachment = delta.attachments[i];
22
+ if (attachment && attachment.mercury && attachment.mercury.attach_type === "photo") {
23
+ api.resolvePhotoUrl(attachment.fbid, (err, url) => {
24
+ if (!err && attachment.mercury && attachment.mercury.metadata) {
25
+ attachment.mercury.metadata.url = url;
26
+ }
27
+ resolveAttachmentUrl(i + 1);
28
+ });
29
+ } else {
30
+ resolveAttachmentUrl(i + 1);
31
+ }
32
+ }
33
+ };
34
+ resolveAttachmentUrl(0);
35
+ } else if (delta.class === "ClientPayload") {
36
+ const clientPayload = decodeClientPayload(delta.payload);
37
+ if (clientPayload && clientPayload.deltas) {
38
+ for (const d of clientPayload.deltas) {
39
+ if (d.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
40
+ const messageReaction = {
41
+ type: "message_reaction",
42
+ threadID: (d.deltaMessageReaction.threadKey.threadFbId ? d.deltaMessageReaction.threadKey.threadFbId : d.deltaMessageReaction.threadKey.otherUserFbId).toString(),
43
+ messageID: d.deltaMessageReaction.messageId,
44
+ reaction: d.deltaMessageReaction.reaction,
45
+ senderID: d.deltaMessageReaction.senderId.toString(),
46
+ userID: d.deltaMessageReaction.userId.toString()
47
+ };
48
+ globalCallback(null, messageReaction);
49
+ } else if (d.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
50
+ const messageUnsend = {
51
+ type: "message_unsend",
52
+ threadID: (d.deltaRecallMessageData.threadKey.threadFbId ? d.deltaRecallMessageData.threadKey.threadFbId : d.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
53
+ messageID: d.deltaRecallMessageData.messageID,
54
+ senderID: d.deltaRecallMessageData.senderID.toString(),
55
+ deletionTimestamp: d.deltaRecallMessageData.deletionTimestamp,
56
+ timestamp: d.deltaRecallMessageData.timestamp
57
+ };
58
+ globalCallback(null, messageUnsend);
59
+ } else if (d.deltaMessageReply) {
60
+ let callbackToReturn;
61
+ try {
62
+ const msg = d.deltaMessageReply.message;
63
+ if (!msg || !msg.messageMetadata) {
64
+ logger("parseDelta: deltaMessageReply.message or messageMetadata is missing", "warn");
65
+ return;
66
+ }
67
+ const mentions = getMentionsFromDeltaMessage(msg);
68
+ const msgMetadata = msg.messageMetadata;
69
+ const threadKey = msgMetadata.threadKey || {};
70
+ callbackToReturn = {
71
+ type: "message_reply",
72
+ threadID: (threadKey.threadFbId ? threadKey.threadFbId : threadKey.otherUserFbId || "").toString(),
73
+ messageID: msgMetadata.messageId || "",
74
+ senderID: (msgMetadata.actorFbId || "").toString(),
75
+ attachments: (msg.attachments || []).map(att => {
76
+ try {
77
+ const mercury = JSON.parse(att.mercuryJSON);
78
+ Object.assign(att, mercury);
79
+ } catch (ex) {
80
+ // Ignore parsing errors
81
+ }
82
+ return att;
83
+ }).map(att => {
84
+ let x;
85
+ try {
86
+ x = _formatAttachment(att);
87
+ } catch (ex) {
88
+ x = att;
89
+ x.error = ex;
90
+ x.type = "unknown";
91
+ }
92
+ return x;
93
+ }),
94
+ args: (msg.body || "").trim().split(/\s+/),
95
+ body: msg.body || "",
96
+ isGroup: !!threadKey.threadFbId,
97
+ mentions,
98
+ timestamp: parseInt(msgMetadata.timestamp || 0),
99
+ participantIDs: (msg.participants || []).map(e => e.toString())
100
+ };
101
+ if (d.deltaMessageReply.repliedToMessage) {
102
+ try {
103
+ const repliedTo = d.deltaMessageReply.repliedToMessage;
104
+ const rmentions = getMentionsFromDeltaMessage(repliedTo);
105
+ const msgMetadata = repliedTo.messageMetadata;
106
+ if (msgMetadata && msgMetadata.threadKey) {
107
+ callbackToReturn.messageReply = {
108
+ threadID: (msgMetadata.threadKey.threadFbId ? msgMetadata.threadKey.threadFbId : msgMetadata.threadKey.otherUserFbId || "").toString(),
109
+ messageID: msgMetadata.messageId || "",
110
+ senderID: (msgMetadata.actorFbId || "").toString(),
111
+ attachments: (repliedTo.attachments || []).map(att => {
112
+ let mercury;
113
+ try {
114
+ mercury = JSON.parse(att.mercuryJSON);
115
+ Object.assign(att, mercury);
116
+ } catch (ex) {
117
+ mercury = {};
118
+ }
119
+ return att;
120
+ }).map(att => {
121
+ let x;
122
+ try {
123
+ x = _formatAttachment(att);
124
+ } catch (ex) {
125
+ x = att;
126
+ x.error = ex;
127
+ x.type = "unknown";
128
+ }
129
+ return x;
130
+ }),
131
+ args: (repliedTo.body || "").trim().split(/\s+/),
132
+ body: repliedTo.body || "",
133
+ isGroup: !!msgMetadata.threadKey.threadFbId,
134
+ mentions: rmentions,
135
+ timestamp: parseInt(msgMetadata.timestamp || 0),
136
+ participantIDs: (repliedTo.participants || []).map(e => e.toString())
137
+ };
138
+ }
139
+ } catch (err) {
140
+ const errMsg = err && err.message ? err.message : String(err || "Unknown error");
141
+ logger(`parseDelta message_reply repliedToMessage error: ${errMsg}`, "warn");
142
+ }
143
+ } else if (d.deltaMessageReply.replyToMessageId) {
144
+ return defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
145
+ av: ctx.globalOptions.pageID,
146
+ queries: JSON.stringify({
147
+ o0: {
148
+ doc_id: "2848441488556444",
149
+ query_params: {
150
+ thread_and_message_id: {
151
+ thread_id: callbackToReturn.threadID,
152
+ message_id: d.deltaMessageReply.replyToMessageId.id
153
+ }
154
+ }
155
+ }
156
+ })
157
+ }).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
158
+ if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
159
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
160
+ const fetchData = resData[0].o0.data.message;
161
+ const mobj = {};
162
+ for (const n in fetchData.message.ranges) {
163
+ mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
164
+ }
165
+ callbackToReturn.messageReply = {
166
+ type: "Message",
167
+ threadID: callbackToReturn.threadID,
168
+ messageID: fetchData.message_id,
169
+ senderID: fetchData.message_sender.id.toString(),
170
+ attachments: fetchData.message.blob_attachment.map(att => _formatAttachment({ blob_attachment: att })),
171
+ args: (fetchData.message.text || "").trim().split(/\s+/) || [],
172
+ body: fetchData.message.text || "",
173
+ isGroup: callbackToReturn.isGroup,
174
+ mentions: mobj,
175
+ timestamp: parseInt(fetchData.timestamp_precise)
176
+ };
177
+ }).catch(err => {
178
+ const errMsg = err && err.message ? err.message : String(err || "Unknown error");
179
+ logger(`parseDelta message_reply fetch error: ${errMsg}`, "warn");
180
+ }).finally(() => {
181
+ if (callbackToReturn) {
182
+ if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
183
+ globalCallback(null, callbackToReturn);
184
+ }
185
+ });
186
+ } else {
187
+ if (callbackToReturn) callbackToReturn.delta = d;
188
+ }
189
+ } catch (err) {
190
+ const errMsg = err && err.message ? err.message : String(err || "Unknown error");
191
+ logger(`parseDelta message_reply error: ${errMsg}`, "warn");
192
+ return;
193
+ }
194
+ if (callbackToReturn) {
195
+ if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
196
+ globalCallback(null, callbackToReturn);
197
+ }
198
+ }
199
+ }
200
+ return;
201
+ }
202
+ }
203
+ switch (delta.class) {
204
+ case "ReadReceipt": {
205
+ let fmtMsg;
206
+ try {
207
+ fmtMsg = formatDeltaReadReceipt(delta);
208
+ } catch (err) {
209
+ return;
210
+ }
211
+ globalCallback(null, fmtMsg);
212
+ break;
213
+ }
214
+ case "AdminTextMessage": {
215
+ switch (delta.type) {
216
+ case "instant_game_dynamic_custom_update":
217
+ case "accept_pending_thread":
218
+ case "confirm_friend_request":
219
+ case "shared_album_delete":
220
+ case "shared_album_addition":
221
+ case "pin_messages_v2":
222
+ case "unpin_messages_v2":
223
+ case "change_thread_theme":
224
+ case "change_thread_nickname":
225
+ case "change_thread_icon":
226
+ case "change_thread_quick_reaction":
227
+ case "change_thread_admins":
228
+ case "group_poll":
229
+ case "joinable_group_link_mode_change":
230
+ case "magic_words":
231
+ case "change_thread_approval_mode":
232
+ case "messenger_call_log":
233
+ case "participant_joined_group_call":
234
+ case "rtc_call_log":
235
+ case "update_vote": {
236
+ let fmtMsg;
237
+ try {
238
+ fmtMsg = formatDeltaEvent(delta);
239
+ } catch (err) {
240
+ return;
241
+ }
242
+ globalCallback(null, fmtMsg);
243
+ break;
244
+ }
245
+ }
246
+ break;
247
+ }
248
+ case "ForcedFetch": {
249
+ if (!delta.threadKey) return;
250
+ const mid = delta.messageId;
251
+ const tid = delta.threadKey.threadFbId;
252
+ if (mid && tid) {
253
+ const form = {
254
+ av: ctx.globalOptions.pageID,
255
+ queries: JSON.stringify({
256
+ o0: {
257
+ doc_id: "2848441488556444",
258
+ query_params: {
259
+ thread_and_message_id: {
260
+ thread_id: tid.toString(),
261
+ message_id: mid
262
+ }
263
+ }
264
+ }
265
+ })
266
+ };
267
+ defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
268
+ if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
269
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
270
+ const fetchData = resData[0].o0.data.message;
271
+ if (getType(fetchData) === "Object") {
272
+ switch (fetchData.__typename) {
273
+ case "ThreadImageMessage":
274
+ if ((!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) || !ctx.loggedIn) {} else {
275
+ globalCallback(null, {
276
+ type: "event",
277
+ threadID: formatID(tid.toString()),
278
+ logMessageType: "log:thread-image",
279
+ logMessageData: {
280
+ image: {
281
+ attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
282
+ width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
283
+ height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
284
+ url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
285
+ }
286
+ },
287
+ logMessageBody: fetchData.snippet,
288
+ timestamp: fetchData.timestamp_precise,
289
+ author: fetchData.message_sender.id
290
+ });
291
+ }
292
+ break;
293
+ case "UserMessage": {
294
+ const event = {
295
+ type: "message",
296
+ senderID: formatID(fetchData.message_sender.id),
297
+ body: fetchData.message.text || "",
298
+ threadID: formatID(tid.toString()),
299
+ messageID: fetchData.message_id,
300
+ attachments: [
301
+ {
302
+ type: "share",
303
+ ID: fetchData.extensible_attachment.legacy_attachment_id,
304
+ url: fetchData.extensible_attachment.story_attachment.url,
305
+ title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
306
+ description: fetchData.extensible_attachment.story_attachment.description.text,
307
+ source: fetchData.extensible_attachment.story_attachment.source,
308
+ image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
309
+ width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
310
+ height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
311
+ playable: ((fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false),
312
+ duration: ((fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0),
313
+ subattachments: fetchData.extensible_attachment.subattachments,
314
+ properties: fetchData.extensible_attachment.story_attachment.properties
315
+ }
316
+ ],
317
+ mentions: {},
318
+ timestamp: parseInt(fetchData.timestamp_precise),
319
+ isGroup: fetchData.message_sender.id !== tid.toString()
320
+ };
321
+ globalCallback(null, event);
322
+ break;
323
+ }
324
+ default:
325
+ break;
326
+ }
327
+ } else {
328
+ return;
329
+ }
330
+ }).catch(err => {
331
+ const errMsg = err && err.message ? err.message : String(err || "Unknown error");
332
+ logger(`parseDelta ForcedFetch error: ${errMsg}`, "warn");
333
+ });
334
+ }
335
+ break;
336
+ }
337
+ case "ThreadName":
338
+ case "ParticipantsAddedToGroupThread":
339
+ case "ParticipantLeftGroupThread": {
340
+ let formattedEvent;
341
+ try {
342
+ formattedEvent = formatDeltaEvent(delta);
343
+ } catch (err) {
344
+ return;
345
+ }
346
+ if (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) return;
347
+ if (!ctx.loggedIn) return;
348
+ globalCallback(null, formattedEvent);
349
+ break;
350
+ }
351
+ case "NewMessage": {
352
+ const hasLiveLocation = d => {
353
+ const attachment = d.attachments && d.attachments[0] && d.attachments[0].mercury && d.attachments[0].mercury.extensible_attachment;
354
+ const storyAttachment = attachment && attachment.story_attachment;
355
+ return storyAttachment && storyAttachment.style_list && storyAttachment.style_list.includes("message_live_location");
356
+ };
357
+ if (delta.attachments && delta.attachments.length === 1 && hasLiveLocation(delta)) {
358
+ delta.class = "UserLocation";
359
+ try {
360
+ const fmtMsg = formatDeltaEvent(delta);
361
+ globalCallback(null, fmtMsg);
362
+ } catch (err) {}
363
+ }
364
+ break;
365
+ }
366
+ }
367
+ };
368
+ };