alicezetion 1.6.7 → 1.6.9

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 (57) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/nix/env.json +1 -1
  3. package/index.js +804 -381
  4. package/leiamnash/addExternalModule.js +19 -19
  5. package/leiamnash/addUserToGroup.js +113 -113
  6. package/leiamnash/changeAdminStatus.js +79 -79
  7. package/leiamnash/changeApprovalMode.js +80 -0
  8. package/leiamnash/changeArchivedStatus.js +55 -55
  9. package/leiamnash/changeBio.js +77 -77
  10. package/leiamnash/changeBlockedStatus.js +47 -47
  11. package/leiamnash/changeGroupImage.js +129 -129
  12. package/leiamnash/changeNickname.js +59 -59
  13. package/leiamnash/changeThreadColor.js +71 -71
  14. package/leiamnash/changeThreadEmoji.js +55 -55
  15. package/leiamnash/chat.js +447 -459
  16. package/leiamnash/createNewGroup.js +86 -86
  17. package/leiamnash/createPoll.js +71 -71
  18. package/leiamnash/deleteMessage.js +56 -56
  19. package/leiamnash/deleteThread.js +56 -56
  20. package/leiamnash/forwardAttachment.js +60 -60
  21. package/leiamnash/getCurrentUserID.js +7 -7
  22. package/leiamnash/getEmojiUrl.js +29 -29
  23. package/leiamnash/getFriendsList.js +84 -84
  24. package/leiamnash/getThreadHistory.js +645 -645
  25. package/leiamnash/getThreadHistoryDeprecated.js +93 -93
  26. package/leiamnash/getThreadInfo.js +212 -206
  27. package/leiamnash/getThreadInfoDeprecated.js +80 -80
  28. package/leiamnash/getThreadList.js +238 -238
  29. package/leiamnash/getThreadListDeprecated.js +75 -75
  30. package/leiamnash/getThreadPictures.js +79 -79
  31. package/leiamnash/getUserID.js +66 -66
  32. package/leiamnash/getUserInfo.js +72 -72
  33. package/leiamnash/handleFriendRequest.js +61 -61
  34. package/leiamnash/handleMessageRequest.js +65 -65
  35. package/leiamnash/httpGet.js +52 -52
  36. package/leiamnash/httpPost.js +52 -52
  37. package/leiamnash/listenMqtt.js +1078 -509
  38. package/leiamnash/logout.js +75 -75
  39. package/leiamnash/markAsDelivered.js +58 -58
  40. package/leiamnash/markAsRead.js +80 -80
  41. package/leiamnash/markAsReadAll.js +49 -49
  42. package/leiamnash/markAsSeen.js +59 -59
  43. package/leiamnash/muteThread.js +52 -52
  44. package/leiamnash/removeUserFromGroup.js +79 -79
  45. package/leiamnash/resolvePhotoUrl.js +45 -45
  46. package/leiamnash/searchForThread.js +53 -53
  47. package/leiamnash/sendTypingIndicator.js +103 -103
  48. package/leiamnash/setMessageReaction.js +117 -117
  49. package/leiamnash/setPostReaction.js +76 -76
  50. package/leiamnash/setTitle.js +86 -86
  51. package/leiamnash/threadColors.js +57 -57
  52. package/leiamnash/unfriend.js +52 -52
  53. package/leiamnash/unsendMessage.js +49 -49
  54. package/package.json +72 -72
  55. package/replit.nix +3 -0
  56. package/utils.js +196 -71
  57. package/leiamnash/listen.js +0 -553
@@ -2,559 +2,1128 @@
2
2
  "use strict";
3
3
  var utils = require("../utils");
4
4
  var log = require("npmlog");
5
- var mqtt = require('mqtt');
6
- var websocket = require('websocket-stream');
5
+ var mqtt = require("mqtt");
6
+ var websocket = require("websocket-stream");
7
+ var HttpsProxyAgent = require("https-proxy-agent");
8
+ const EventEmitter = require("events");
7
9
 
8
- var identity = function () {};
9
-
10
- //Don't really know what this does but I think it's for the active state
11
- //TODO: Move to ctx when implemented
12
- var chatOn = true;
13
- var foreground = false;
10
+ var identity = function() {};
11
+ var form = {};
12
+ var getSeqID = function() {};
14
13
 
15
14
  var topics = [
16
- "/t_ms",
17
- "/thread_typing",
18
- "/orca_typing_notifications",
19
- "/orca_presence",
20
- "/legacy_web",
21
- "/br_sr",
22
- "/sr_res",
23
- "/webrtc",
24
- "/onevc",
25
- "/notify_disconnect",
26
- "/inbox",
27
- "/mercury",
28
- "/messaging_events",
29
- "/orca_message_notifications",
30
- "/pp",
31
- "/webrtc_response",
15
+ "/legacy_web",
16
+ "/webrtc",
17
+ "/rtc_multi",
18
+ "/onevc",
19
+ "/br_sr", //Notification
20
+ //Need to publish /br_sr right after this
21
+ "/sr_res",
22
+ "/t_ms",
23
+ "/thread_typing",
24
+ "/orca_typing_notifications",
25
+ "/notify_disconnect",
26
+ //Need to publish /messenger_sync_create_queue right after this
27
+ "/orca_presence",
28
+ //Will receive /sr_res right here.
29
+
30
+ "/inbox",
31
+ "/mercury",
32
+ "/messaging_events",
33
+ "/orca_message_notifications",
34
+ "/pp",
35
+ "/webrtc_response",
32
36
  ];
33
37
 
34
38
  function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
35
- var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
36
- var username = {
37
- u: ctx.userID,
38
- s: sessionID,
39
- chat_on: chatOn,
40
- fg: foreground,
41
- d: utils.getGUID(),
42
- ct: "websocket",
43
- //App id from facebook
44
- aid: "219994525426954",
45
- mqtt_sid: "",
46
- cp: 3,
47
- ecp: 10,
48
- st: topics,
49
- pm: [],
50
- dc: "",
51
- no_auto_fg: true,
52
- gas: null
53
- };
54
- var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
55
-
56
- //Region could be changed for better ping. (Region atn: Southeast Asia, region ash: West US, prob) (Don't really know if we need it).
57
- //// var host = 'wss://edge-chat.facebook.com/chat?region=atn&sid=' + sessionID;
58
- var host = 'wss://edge-chat.facebook.com/chat?sid=' + sessionID;
59
-
60
- var options = {
61
- clientId: "mqttwsclient",
62
- protocolId: 'MQIsdp',
63
- protocolVersion: 3,
64
- username: JSON.stringify(username),
65
- clean: true,
66
- wsOptions: {
67
- headers: {
68
- 'Cookie': cookies,
69
- 'Origin': 'https://www.facebook.com',
70
- 'User-Agent': ctx.globalOptions.userAgent,
71
- 'Referer': 'https://www.facebook.com',
72
- 'Host': 'edge-chat.facebook.com'
73
- },
74
- origin: 'https://www.facebook.com',
75
- protocolVersion: 13
76
- }
77
- };
78
-
79
- ctx.mqttClient = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
80
-
81
- var mqttClient = ctx.mqttClient;
82
-
83
- mqttClient.on('error', function(err) {
84
- log.error(err);
85
- mqttClient.end();
86
- globalCallback("Connection refused: Server unavailable", null);
87
- });
88
-
89
- mqttClient.on('connect', function() {
90
- var topic;
91
- var queue = {
92
- sync_api_version: 10,
93
- max_deltas_able_to_process: 1000,
94
- delta_batch_size: 500,
95
- encoding: "JSON",
96
- entity_fbid: ctx.userID,
39
+ //Don't really know what this does but I think it's for the active state?
40
+ //TODO: Move to ctx when implemented
41
+ var chatOn = ctx.globalOptions.online;
42
+ var foreground = false;
43
+
44
+ var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
45
+ var username = {
46
+ u: ctx.userID,
47
+ s: sessionID,
48
+ chat_on: chatOn,
49
+ fg: foreground,
50
+ d: utils.getGUID(),
51
+ ct: "websocket",
52
+ //App id from facebook
53
+ aid: "219994525426954",
54
+ mqtt_sid: "",
55
+ cp: 3,
56
+ ecp: 10,
57
+ st: [],
58
+ pm: [],
59
+ dc: "",
60
+ no_auto_fg: true,
61
+ gas: null,
62
+ pack: [],
97
63
  };
64
+ var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
98
65
 
99
- if(ctx.globalOptions.pageID) {
100
- queue.entity_fbid = ctx.globalOptions.pageID;
66
+ var host;
67
+ if (ctx.mqttEndpoint) {
68
+ host = `${ctx.mqttEndpoint}&sid=${sessionID}`;
69
+ } else if (ctx.region) {
70
+ host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLocaleLowerCase()}&sid=${sessionID}`;
71
+ } else {
72
+ host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}`;
101
73
  }
102
74
 
103
- if(ctx.syncToken) {
104
- topic = "/messenger_sync_get_diffs";
105
- queue.last_seq_id = ctx.lastSeqId;
106
- queue.sync_token = ctx.syncToken;
107
- } else {
108
- topic = "/messenger_sync_create_queue";
109
- queue.initial_titan_sequence_id = ctx.lastSeqId;
110
- queue.device_params = null;
75
+ var options = {
76
+ clientId: "mqttwsclient",
77
+ protocolId: "MQIsdp",
78
+ protocolVersion: 3,
79
+ username: JSON.stringify(username),
80
+ clean: true,
81
+ wsOptions: {
82
+ headers: {
83
+ Cookie: cookies,
84
+ Origin: "https://www.facebook.com",
85
+ "User-Agent": ctx.globalOptions.userAgent,
86
+ Referer: "https://www.facebook.com/",
87
+ Host: new URL(host).hostname, //'edge-chat.facebook.com'
88
+ },
89
+ origin: "https://www.facebook.com",
90
+ protocolVersion: 13,
91
+ },
92
+ keepalive: 10,
93
+ reschedulePings: false,
94
+ };
95
+
96
+ if (typeof ctx.globalOptions.proxy != "undefined") {
97
+ var agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
98
+ options.wsOptions.agent = agent;
111
99
  }
112
-
113
- mqttClient.publish(topic, JSON.stringify(queue), {qos: 1, retain: false});
114
- });
115
-
116
- mqttClient.on('message', function(topic, message, packet) {
117
- var jsonMessage = JSON.parse(message);
118
- if(topic === "/t_ms") {
119
- if(jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
120
- ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
121
- ctx.syncToken = jsonMessage.syncToken;
122
- }
123
-
124
- if(jsonMessage.lastIssuedSeqId) {
125
- ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
126
- }
127
-
128
- if(jsonMessage.queueEntityId && ctx.globalOptions.pageID &&
129
- ctx.globalOptions.pageID != jsonMessage.queueEntityId) {
130
- return;
131
- }
132
-
133
- //If it contains more than 1 delta
134
- for (var i in jsonMessage.deltas) {
135
- var delta = jsonMessage.deltas[i];
136
- parseDelta(defaultFuncs, api, ctx, globalCallback, { "delta": delta });
137
- }
138
- } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
139
- var typ = {
140
- type: "typ",
141
- isTyping: !!jsonMessage.state,
142
- from: jsonMessage.sender_fbid.toString(),
143
- threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
144
- };
145
- (function () { globalCallback(null, typ); })();
146
- } else if (topic === "/orca_presence") {
147
- if (!ctx.globalOptions.updatePresence) {
148
- for (var i in jsonMessage.list) {
149
- var data = jsonMessage.list[i];
150
- var userID = data["u"];
151
-
152
- var presence = {
153
- type: "presence",
154
- userID: userID.toString(),
155
- //Convert to ms
156
- timestamp: data["l"] * 1000,
157
- statuses: data["p"]
158
- };
159
- (function () { globalCallback(null, presence); })();
100
+
101
+ ctx.mqttClient = new mqtt.Client(
102
+ (_) => websocket(host, options.wsOptions),
103
+ options
104
+ );
105
+
106
+ var mqttClient = ctx.mqttClient;
107
+
108
+ mqttClient.on("error", function(err) {
109
+ log.error("listenMqtt", err);
110
+ mqttClient.end();
111
+ if (ctx.globalOptions.autoReconnect) {
112
+ getSeqID();
113
+ } else {
114
+ globalCallback(
115
+ {
116
+ type: "stop_listen",
117
+ error: "Connection refused: Server unavailable",
118
+ },
119
+ null
120
+ );
160
121
  }
161
- }
162
- }
122
+ });
163
123
 
164
- });
124
+ mqttClient.on("connect", function() {
125
+ topics.forEach(function(topicsub) {
126
+ mqttClient.subscribe(topicsub);
127
+ });
165
128
 
166
- mqttClient.on('close', function() {
167
- // client.end();
168
- });
169
- }
129
+ var topic;
130
+ var queue = {
131
+ sync_api_version: 10,
132
+ max_deltas_able_to_process: 1000,
133
+ delta_batch_size: 500,
134
+ encoding: "JSON",
135
+ entity_fbid: ctx.userID,
136
+ };
170
137
 
171
- function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
172
- if(v.delta.class == "NewMessage") {
173
- (function resolveAttachmentUrl(i) {
174
- // sometimes, with sticker message in group, delta does not contain 'attachments' property.
175
- if (v.delta.attachments && (i == v.delta.attachments.length)) {
176
- var fmtMsg;
177
- try {
178
- fmtMsg = utils.formatDeltaMessage(v);
179
- } catch (err) {
180
- return globalCallback({
181
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
182
- detail: err,
183
- res: v,
184
- type: "parse_error"
185
- });
138
+ if (ctx.syncToken) {
139
+ topic = "/messenger_sync_get_diffs";
140
+ queue.last_seq_id = ctx.lastSeqId;
141
+ queue.sync_token = ctx.syncToken;
142
+ } else {
143
+ topic = "/messenger_sync_create_queue";
144
+ queue.initial_titan_sequence_id = ctx.lastSeqId;
145
+ queue.device_params = null;
186
146
  }
187
- if (fmtMsg) {
188
- if (ctx.globalOptions.autoMarkDelivery) {
189
- markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
190
- }
147
+
148
+ mqttClient.publish(topic, JSON.stringify(queue), {
149
+ qos: 1,
150
+ retain: false,
151
+ });
152
+
153
+ var rTimeout = setTimeout(function() {
154
+ mqttClient.end();
155
+ getSeqID();
156
+ }, 5000);
157
+
158
+ ctx.tmsWait = function() {
159
+ clearTimeout(rTimeout);
160
+ ctx.globalOptions.emitReady
161
+ ? globalCallback({
162
+ type: "ready",
163
+ error: null,
164
+ })
165
+ : "";
166
+ delete ctx.tmsWait;
167
+ };
168
+ });
169
+
170
+ mqttClient.on("message", function(topic, message, _packet) {
171
+ try {
172
+ var jsonMessage = JSON.parse(message);
173
+ } catch (ex) {
174
+ return log.error("listenMqtt", ex);
191
175
  }
192
- return !ctx.globalOptions.selfListen &&
193
- fmtMsg.senderID === ctx.userID ?
194
- undefined :
195
- (function () { globalCallback(null, fmtMsg); })();
196
- } else {
197
- if (
198
- v.delta.attachments && (v.delta.attachments[i].mercury.attach_type == "photo")
176
+ if (topic === "/t_ms") {
177
+ if (ctx.tmsWait && typeof ctx.tmsWait == "function") {
178
+ ctx.tmsWait();
179
+ }
180
+
181
+ if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
182
+ ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
183
+ ctx.syncToken = jsonMessage.syncToken;
184
+ }
185
+
186
+ if (jsonMessage.lastIssuedSeqId) {
187
+ ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
188
+ }
189
+
190
+ //If it contains more than 1 delta
191
+ for (var i in jsonMessage.deltas) {
192
+ var delta = jsonMessage.deltas[i];
193
+ parseDelta(defaultFuncs, api, ctx, globalCallback, {
194
+ delta: delta,
195
+ });
196
+ }
197
+ } else if (
198
+ topic === "/thread_typing" ||
199
+ topic === "/orca_typing_notifications"
199
200
  ) {
200
- api.resolvePhotoUrl(
201
- v.delta.attachments[i].fbid,
202
- (err, url) => {
203
- if (!err)
204
- v.delta.attachments[
205
- i
206
- ].mercury.metadata.url = url;
207
- return resolveAttachmentUrl(i + 1);
201
+ var typ = {
202
+ type: "typ",
203
+ isTyping: !!jsonMessage.state,
204
+ from: jsonMessage.sender_fbid.toString(),
205
+ threadID: utils.formatID(
206
+ (jsonMessage.thread || jsonMessage.sender_fbid).toString()
207
+ ),
208
+ };
209
+ (function() {
210
+ globalCallback(null, typ);
211
+ })();
212
+ } else if (topic === "/orca_presence") {
213
+ if (!ctx.globalOptions.updatePresence) {
214
+ for (var i in jsonMessage.list) {
215
+ var data = jsonMessage.list[i];
216
+ var userID = data["u"];
217
+
218
+ var presence = {
219
+ type: "presence",
220
+ userID: userID.toString(),
221
+ //Convert to ms
222
+ timestamp: data["l"] * 1000,
223
+ statuses: data["p"],
224
+ };
225
+ (function() {
226
+ globalCallback(null, presence);
227
+ })();
228
+ }
208
229
  }
209
- );
210
- } else {
211
- return resolveAttachmentUrl(i + 1);
212
230
  }
213
- }
214
- })(0);
215
- }
231
+ });
216
232
 
217
- if (v.delta.class == "ClientPayload") {
218
- var clientPayload = utils.decodeClientPayload(
219
- v.delta.payload
220
- );
221
- if (clientPayload && clientPayload.deltas) {
222
- for (var i in clientPayload.deltas) {
223
- var delta = clientPayload.deltas[i];
224
- if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
225
- (function () { globalCallback(null, {
226
- type: "message_reaction",
227
- threadID: (delta.deltaMessageReaction.threadKey
228
- .threadFbId ?
229
- delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey
230
- .otherUserFbId).toString(),
231
- messageID: delta.deltaMessageReaction.messageId,
232
- reaction: delta.deltaMessageReaction.reaction,
233
- senderID: delta.deltaMessageReaction.senderId.toString(),
234
- userID: delta.deltaMessageReaction.userId.toString()
235
- }); })();
236
- } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
237
- (function () { globalCallback(null, {
238
- type: "message_unsend",
239
- threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ?
240
- delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey
241
- .otherUserFbId).toString(),
242
- messageID: delta.deltaRecallMessageData.messageID,
243
- senderID: delta.deltaRecallMessageData.senderID.toString(),
244
- deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
245
- timestamp: delta.deltaRecallMessageData.timestamp
246
- }); })();
247
- } else if (delta.deltaMessageReply) {
248
- //Mention block - #1
249
- var mdata =
250
- delta.deltaMessageReply.message === undefined ? [] :
251
- delta.deltaMessageReply.message.data === undefined ? [] :
252
- delta.deltaMessageReply.message.data.prng === undefined ? [] :
253
- JSON.parse(delta.deltaMessageReply.message.data.prng);
254
- var m_id = mdata.map(u => u.i);
255
- var m_offset = mdata.map(u => u.o);
256
- var m_length = mdata.map(u => u.l);
257
-
258
- var mentions = {};
259
-
260
- for (var i = 0; i < m_id.length; i++) {
261
- mentions[m_id[i]] = (delta.deltaMessageReply.message.body || "").substring(
262
- m_offset[i],
263
- m_offset[i] + m_length[i]
264
- );
265
- }
266
- //Mention block - 1#
267
- var callbackToReturn = {
268
- type: "message_reply",
269
- threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ?
270
- delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey
271
- .otherUserFbId).toString(),
272
- messageID: delta.deltaMessageReply.message.messageMetadata.messageId,
273
- senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
274
- attachments: delta.deltaMessageReply.message.attachments.map(function (att) {
275
- var mercury = JSON.parse(att.mercuryJSON);
276
- Object.assign(att, mercury);
277
- return att;
278
- }).map(att => {
279
- var x;
280
- try {
281
- x = utils._formatAttachment(att);
282
- } catch (ex) {
283
- x = att;
284
- x.error = ex;
285
- x.type = "unknown";
286
- }
287
- return x;
288
- }),
289
- body: delta.deltaMessageReply.message.body || "",
290
- isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
291
- mentions: mentions,
292
- timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
293
- };
294
-
295
- if (delta.deltaMessageReply.repliedToMessage) {
296
- //Mention block - #2
297
- mdata =
298
- delta.deltaMessageReply.repliedToMessage === undefined ? [] :
299
- delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
300
- delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
301
- JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
302
- m_id = mdata.map(u => u.i);
303
- m_offset = mdata.map(u => u.o);
304
- m_length = mdata.map(u => u.l);
305
-
306
- var rmentions = {};
307
-
308
- for (var i = 0; i < m_id.length; i++) {
309
- rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(
310
- m_offset[i],
311
- m_offset[i] + m_length[i]
312
- );
313
- }
314
- //Mention block - 2#
315
- callbackToReturn.messageReply = {
316
- threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ?
317
- delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey
318
- .otherUserFbId).toString(),
319
- messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
320
- senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
321
- attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) {
322
- var mercury = JSON.parse(att.mercuryJSON);
323
- Object.assign(att, mercury);
324
- return att;
325
- }).map(att => {
326
- var x;
233
+ mqttClient.on("close", function() {
234
+ //(function () { globalCallback("Connection closed."); })();
235
+ // client.end();
236
+ });
237
+ }
238
+
239
+ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
240
+ if (v.delta.class == "NewMessage") {
241
+ //Not tested for pages
242
+ if (ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue)
243
+ return;
244
+
245
+ (function resolveAttachmentUrl(i) {
246
+ if (v.delta.attachments && i == v.delta.attachments.length) {
247
+ var fmtMsg;
327
248
  try {
328
- x = utils._formatAttachment(att);
329
- } catch (ex) {
330
- x = att;
331
- x.error = ex;
332
- x.type = "unknown";
249
+ fmtMsg = utils.formatDeltaMessage(v);
250
+ } catch (err) {
251
+ return globalCallback({
252
+ error:
253
+ "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
254
+ detail: err,
255
+ res: v,
256
+ type: "parse_error",
257
+ });
333
258
  }
334
- return x;
335
- }),
336
- body: delta.deltaMessageReply.repliedToMessage.body || "",
337
- isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId,
338
- mentions: rmentions,
339
- timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp,
340
- };
341
- }
259
+ if (fmtMsg) {
260
+ if (ctx.globalOptions.autoMarkDelivery) {
261
+ markDelivery(
262
+ ctx,
263
+ api,
264
+ fmtMsg.threadID,
265
+ fmtMsg.messageID
266
+ );
267
+ }
268
+ }
269
+ return !ctx.globalOptions.selfListen &&
270
+ fmtMsg.senderID === ctx.userID
271
+ ? undefined
272
+ : (function() {
273
+ globalCallback(null, fmtMsg);
274
+ })();
275
+ } else {
276
+ if (v.delta.attachments[i].mercury.attach_type == "photo") {
277
+ api.resolvePhotoUrl(
278
+ v.delta.attachments[i].fbid,
279
+ (err, url) => {
280
+ if (!err)
281
+ v.delta.attachments[
282
+ i
283
+ ].mercury.metadata.url = url;
284
+ return resolveAttachmentUrl(i + 1);
285
+ }
286
+ );
287
+ } else {
288
+ return resolveAttachmentUrl(i + 1);
289
+ }
290
+ }
291
+ })(0);
292
+ }
342
293
 
343
- if (ctx.globalOptions.autoMarkDelivery) {
344
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
345
- }
294
+ if (v.delta.class == "ClientPayload") {
295
+ var clientPayload = utils.decodeClientPayload(v.delta.payload);
296
+ if (clientPayload && clientPayload.deltas) {
297
+ for (var i in clientPayload.deltas) {
298
+ var delta = clientPayload.deltas[i];
299
+ if (
300
+ delta.deltaMessageReaction &&
301
+ !!ctx.globalOptions.listenEvents
302
+ ) {
303
+ (function() {
304
+ globalCallback(null, {
305
+ type: "message_reaction",
306
+ threadID: (delta.deltaMessageReaction.threadKey
307
+ .threadFbId
308
+ ? delta.deltaMessageReaction.threadKey
309
+ .threadFbId
310
+ : delta.deltaMessageReaction.threadKey
311
+ .otherUserFbId
312
+ ).toString(),
313
+ messageID: delta.deltaMessageReaction.messageId,
314
+ reaction: delta.deltaMessageReaction.reaction,
315
+ senderID: delta.deltaMessageReaction.senderId.toString(),
316
+ userID: delta.deltaMessageReaction.userId.toString(),
317
+ });
318
+ })();
319
+ } else if (
320
+ delta.deltaRecallMessageData &&
321
+ !!ctx.globalOptions.listenEvents
322
+ ) {
323
+ (function() {
324
+ globalCallback(null, {
325
+ type: "message_unsend",
326
+ threadID: (delta.deltaRecallMessageData.threadKey
327
+ .threadFbId
328
+ ? delta.deltaRecallMessageData.threadKey
329
+ .threadFbId
330
+ : delta.deltaRecallMessageData.threadKey
331
+ .otherUserFbId
332
+ ).toString(),
333
+ messageID: delta.deltaRecallMessageData.messageID,
334
+ senderID: delta.deltaRecallMessageData.senderID.toString(),
335
+ deletionTimestamp:
336
+ delta.deltaRecallMessageData.deletionTimestamp,
337
+ timestamp: delta.deltaRecallMessageData.timestamp,
338
+ });
339
+ })();
340
+ } else if (delta.deltaMessageReply) {
341
+ //Mention block - #1
342
+ var mdata =
343
+ delta.deltaMessageReply.message === undefined
344
+ ? []
345
+ : delta.deltaMessageReply.message.data === undefined
346
+ ? []
347
+ : delta.deltaMessageReply.message.data.prng ===
348
+ undefined
349
+ ? []
350
+ : JSON.parse(
351
+ delta.deltaMessageReply.message.data.prng
352
+ );
353
+ var m_id = mdata.map((u) => u.i);
354
+ var m_offset = mdata.map((u) => u.o);
355
+ var m_length = mdata.map((u) => u.l);
346
356
 
347
- return !ctx.globalOptions.selfListen &&
348
- callbackToReturn.senderID === ctx.userID ?
349
- undefined :
350
- (function () { globalCallback(null, callbackToReturn); })();
351
- }
352
- }
353
- return;
354
- }
355
- }
356
-
357
- if (v.delta.class !== "NewMessage" &&
358
- !ctx.globalOptions.listenEvents
359
- )
360
- return;
361
-
362
- switch (v.delta.class) {
363
- case "ReadReceipt":
364
- var fmtMsg;
365
- try {
366
- fmtMsg = utils.formatDeltaReadReceipt(v.delta);
367
- } catch (err) {
368
- return globalCallback({
369
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
370
- detail: err,
371
- res: v.delta,
372
- type: "parse_error"
373
- });
374
- }
375
- return (function () { globalCallback(null, fmtMsg); })();
376
- case "AdminTextMessage":
377
- switch (v.delta.type) {
378
- case "change_thread_theme":
379
- case "change_thread_nickname":
380
- case "change_thread_icon":
381
- break;
382
- case "group_poll":
383
- var fmtMsg;
384
- try {
385
- fmtMsg = utils.formatDeltaEvent(v.delta);
386
- } catch (err) {
387
- return globalCallback({
388
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
389
- detail: err,
390
- res: v.delta,
391
- type: "parse_error"
392
- });
393
- }
394
- return (function () { globalCallback(null, fmtMsg); })();
395
- default:
396
- return;
397
- }
398
- break;
399
- //For group images
400
- case "ForcedFetch":
401
- if (!v.delta.threadKey) return;
402
- var mid = v.delta.messageId;
403
- var tid = v.delta.threadKey.threadFbId;
404
- if (mid && tid) {
405
- const form = {
406
- "av": ctx.globalOptions.pageID,
407
- "queries": JSON.stringify({
408
- "o0": {
409
- //This doc_id is valid as of ? (prob January 18, 2020)
410
- "doc_id": "1768656253222505",
411
- "query_params": {
412
- "thread_and_message_id": {
413
- "thread_id": tid.toString(),
414
- "message_id": mid.toString(),
357
+ var mentions = {};
358
+
359
+ for (var i = 0; i < m_id.length; i++) {
360
+ mentions[m_id[i]] = (
361
+ delta.deltaMessageReply.message.body || ""
362
+ ).substring(m_offset[i], m_offset[i] + m_length[i]);
363
+ }
364
+ //Mention block - 1#
365
+ var callbackToReturn = {
366
+ type: "message_reply",
367
+ threadID: (delta.deltaMessageReply.message
368
+ .messageMetadata.threadKey.threadFbId
369
+ ? delta.deltaMessageReply.message.messageMetadata
370
+ .threadKey.threadFbId
371
+ : delta.deltaMessageReply.message.messageMetadata
372
+ .threadKey.otherUserFbId
373
+ ).toString(),
374
+ messageID:
375
+ delta.deltaMessageReply.message.messageMetadata
376
+ .messageId,
377
+ senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
378
+ attachments: delta.deltaMessageReply.message.attachments
379
+ .map(function(att) {
380
+ var mercury = JSON.parse(att.mercuryJSON);
381
+ Object.assign(att, mercury);
382
+ return att;
383
+ })
384
+ .map((att) => {
385
+ var x;
386
+ try {
387
+ x = utils._formatAttachment(att);
388
+ } catch (ex) {
389
+ x = att;
390
+ x.error = ex;
391
+ x.type = "unknown";
392
+ }
393
+ return x;
394
+ }),
395
+ args: (delta.deltaMessageReply.message.body || "")
396
+ .trim()
397
+ .split(/\s+/),
398
+ body: delta.deltaMessageReply.message.body || "",
399
+ mentions: mentions,
400
+ timestamp:
401
+ delta.deltaMessageReply.message.messageMetadata
402
+ .timestamp,
403
+ isGroup: !!delta.deltaMessageReply.message
404
+ .messageMetadata.threadKey.threadFbId,
405
+ participantIDs: delta.deltaMessageReply.message.participants?.map(
406
+ (u) => u.toString()
407
+ ),
408
+ };
409
+
410
+ if (delta.deltaMessageReply.repliedToMessage) {
411
+ //Mention block - #2
412
+ mdata =
413
+ delta.deltaMessageReply.repliedToMessage ===
414
+ undefined
415
+ ? []
416
+ : delta.deltaMessageReply.repliedToMessage
417
+ .data === undefined
418
+ ? []
419
+ : delta.deltaMessageReply.repliedToMessage.data
420
+ .prng === undefined
421
+ ? []
422
+ : JSON.parse(
423
+ delta.deltaMessageReply.repliedToMessage
424
+ .data.prng
425
+ );
426
+ m_id = mdata.map((u) => u.i);
427
+ m_offset = mdata.map((u) => u.o);
428
+ m_length = mdata.map((u) => u.l);
429
+
430
+ var rmentions = {};
431
+
432
+ for (var i = 0; i < m_id.length; i++) {
433
+ rmentions[m_id[i]] = (
434
+ delta.deltaMessageReply.repliedToMessage.body ||
435
+ ""
436
+ ).substring(m_offset[i], m_offset[i] + m_length[i]);
437
+ }
438
+ //Mention block - 2#
439
+ callbackToReturn.messageReply = {
440
+ threadID: (delta.deltaMessageReply.repliedToMessage
441
+ .messageMetadata.threadKey.threadFbId
442
+ ? delta.deltaMessageReply.repliedToMessage
443
+ .messageMetadata.threadKey.threadFbId
444
+ : delta.deltaMessageReply.repliedToMessage
445
+ .messageMetadata.threadKey.otherUserFbId
446
+ ).toString(),
447
+ messageID:
448
+ delta.deltaMessageReply.repliedToMessage
449
+ .messageMetadata.messageId,
450
+ senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
451
+ attachments: delta.deltaMessageReply.repliedToMessage.attachments
452
+ .map(function(att) {
453
+ var mercury = JSON.parse(att.mercuryJSON);
454
+ Object.assign(att, mercury);
455
+ return att;
456
+ })
457
+ .map((att) => {
458
+ var x;
459
+ try {
460
+ x = utils._formatAttachment(att);
461
+ } catch (ex) {
462
+ x = att;
463
+ x.error = ex;
464
+ x.type = "unknown";
465
+ }
466
+ return x;
467
+ }),
468
+ args: (
469
+ delta.deltaMessageReply.repliedToMessage.body ||
470
+ ""
471
+ )
472
+ .trim()
473
+ .split(/\s+/),
474
+ body:
475
+ delta.deltaMessageReply.repliedToMessage.body ||
476
+ "",
477
+ isGroup: !!delta.deltaMessageReply.repliedToMessage
478
+ .messageMetadata.threadKey.threadFbId,
479
+ mentions: rmentions,
480
+ timestamp:
481
+ delta.deltaMessageReply.repliedToMessage
482
+ .messageMetadata.timestamp,
483
+ };
484
+ } else if (delta.deltaMessageReply.replyToMessageId) {
485
+ return defaultFuncs
486
+ .post(
487
+ "https://www.facebook.com/api/graphqlbatch/",
488
+ ctx.jar,
489
+ {
490
+ av: ctx.globalOptions.pageID,
491
+ queries: JSON.stringify({
492
+ o0: {
493
+ //Using the same doc_id as forcedFetch
494
+ doc_id: "2848441488556444",
495
+ query_params: {
496
+ thread_and_message_id: {
497
+ thread_id:
498
+ callbackToReturn.threadID,
499
+ message_id:
500
+ delta.deltaMessageReply
501
+ .replyToMessageId
502
+ .id,
503
+ },
504
+ },
505
+ },
506
+ }),
507
+ }
508
+ )
509
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
510
+ .then((resData) => {
511
+ if (
512
+ resData[resData.length - 1].error_results >
513
+ 0
514
+ ) {
515
+ throw resData[0].o0.errors;
516
+ }
517
+
518
+ if (
519
+ resData[resData.length - 1]
520
+ .successful_results === 0
521
+ ) {
522
+ throw {
523
+ error:
524
+ "forcedFetch: there was no successful_results",
525
+ res: resData,
526
+ };
527
+ }
528
+
529
+ var fetchData = resData[0].o0.data.message;
530
+
531
+ var mobj = {};
532
+ for (var n in fetchData.message.ranges) {
533
+ mobj[
534
+ fetchData.message.ranges[n].entity.id
535
+ ] = (fetchData.message.text || "").substr(
536
+ fetchData.message.ranges[n].offset,
537
+ fetchData.message.ranges[n].length
538
+ );
539
+ }
540
+
541
+ callbackToReturn.messageReply = {
542
+ threadID: callbackToReturn.threadID,
543
+ messageID: fetchData.message_id,
544
+ senderID: fetchData.message_sender.id.toString(),
545
+ attachments: fetchData.message.blob_attachment.map(
546
+ (att) => {
547
+ var x;
548
+ try {
549
+ x = utils._formatAttachment({
550
+ blob_attachment: att,
551
+ });
552
+ } catch (ex) {
553
+ x = att;
554
+ x.error = ex;
555
+ x.type = "unknown";
556
+ }
557
+ return x;
558
+ }
559
+ ),
560
+ args: (
561
+ delta.deltaMessageReply.repliedToMessage
562
+ .body || ""
563
+ )
564
+ .trim()
565
+ .split(/\s+/),
566
+ body: fetchData.message.text || "",
567
+ isGroup: callbackToReturn.isGroup,
568
+ mentions: mobj,
569
+ timestamp: parseInt(
570
+ fetchData.timestamp_precise
571
+ ),
572
+ };
573
+ })
574
+ .catch((err) => {
575
+ log.error("forcedFetch", err);
576
+ })
577
+ .finally(function() {
578
+ if (ctx.globalOptions.autoMarkDelivery) {
579
+ markDelivery(
580
+ ctx,
581
+ api,
582
+ callbackToReturn.threadID,
583
+ callbackToReturn.messageID
584
+ );
585
+ }
586
+ !ctx.globalOptions.selfListen &&
587
+ callbackToReturn.senderID === ctx.userID
588
+ ? undefined
589
+ : (function() {
590
+ globalCallback(
591
+ null,
592
+ callbackToReturn
593
+ );
594
+ })();
595
+ });
596
+ } else {
597
+ callbackToReturn.delta = delta;
598
+ }
599
+
600
+ if (ctx.globalOptions.autoMarkDelivery) {
601
+ markDelivery(
602
+ ctx,
603
+ api,
604
+ callbackToReturn.threadID,
605
+ callbackToReturn.messageID
606
+ );
607
+ }
608
+
609
+ return !ctx.globalOptions.selfListen &&
610
+ callbackToReturn.senderID === ctx.userID
611
+ ? undefined
612
+ : (function() {
613
+ globalCallback(null, callbackToReturn);
614
+ })();
415
615
  }
416
- }
417
616
  }
418
- })
419
- };
617
+ return;
618
+ }
619
+ }
420
620
 
421
- defaultFuncs
422
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
423
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
424
- .then((resData) => {
425
- if (resData[resData.length - 1].error_results > 0) {
426
- throw resData[0].o0.errors;
427
- }
621
+ if (v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents)
622
+ return;
428
623
 
429
- if (resData[resData.length - 1].successful_results === 0) {
430
- throw { error: "forcedFetch: there was no successful_results", res: resData };
624
+ switch (v.delta.class) {
625
+ case "ReadReceipt":
626
+ var fmtMsg;
627
+ try {
628
+ fmtMsg = utils.formatDeltaReadReceipt(v.delta);
629
+ } catch (err) {
630
+ return globalCallback({
631
+ error:
632
+ "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
633
+ detail: err,
634
+ res: v.delta,
635
+ type: "parse_error",
636
+ });
637
+ }
638
+ return (function() {
639
+ globalCallback(null, fmtMsg);
640
+ })();
641
+ case "AdminTextMessage":
642
+ switch (v.delta.type) {
643
+ case "change_thread_theme":
644
+ // case "change_thread_icon": deprecated
645
+ case "change_thread_quick_reaction":
646
+ case "change_thread_nickname":
647
+ case "change_thread_admins":
648
+ case "change_thread_approval_mode":
649
+ case "group_poll":
650
+ case "messenger_call_log":
651
+ case "participant_joined_group_call":
652
+ var fmtMsg;
653
+ try {
654
+ fmtMsg = utils.formatDeltaEvent(v.delta);
655
+ } catch (err) {
656
+ return globalCallback({
657
+ error:
658
+ "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
659
+ detail: err,
660
+ res: v.delta,
661
+ type: "parse_error",
662
+ });
663
+ }
664
+ return (function() {
665
+ globalCallback(null, fmtMsg);
666
+ })();
667
+ default:
668
+ return;
431
669
  }
670
+ break;
671
+ //For group images
672
+ case "ForcedFetch":
673
+ if (!v.delta.threadKey) return;
674
+ var mid = v.delta.messageId;
675
+ var tid = v.delta.threadKey.threadFbId;
676
+ if (mid && tid) {
677
+ const form = {
678
+ av: ctx.globalOptions.pageID,
679
+ queries: JSON.stringify({
680
+ o0: {
681
+ //This doc_id is valid as of March 25, 2020
682
+ doc_id: "2848441488556444",
683
+ query_params: {
684
+ thread_and_message_id: {
685
+ thread_id: tid.toString(),
686
+ message_id: mid,
687
+ },
688
+ },
689
+ },
690
+ }),
691
+ };
692
+
693
+ defaultFuncs
694
+ .post(
695
+ "https://www.facebook.com/api/graphqlbatch/",
696
+ ctx.jar,
697
+ form
698
+ )
699
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
700
+ .then((resData) => {
701
+ if (resData[resData.length - 1].error_results > 0) {
702
+ throw resData[0].o0.errors;
703
+ }
704
+
705
+ if (
706
+ resData[resData.length - 1].successful_results === 0
707
+ ) {
708
+ throw {
709
+ error:
710
+ "forcedFetch: there was no successful_results",
711
+ res: resData,
712
+ };
713
+ }
714
+
715
+ var fetchData = resData[0].o0.data.message;
716
+
717
+ if (utils.getType(fetchData) == "Object") {
718
+ log.info("forcedFetch", fetchData);
719
+ switch (fetchData.__typename) {
720
+ case "ThreadImageMessage":
721
+ (!ctx.globalOptions.selfListen &&
722
+ fetchData.message_sender.id.toString() ===
723
+ ctx.userID) ||
724
+ !ctx.loggedIn
725
+ ? undefined
726
+ : (function() {
727
+ globalCallback(null, {
728
+ type: "event",
729
+ threadID: utils.formatID(
730
+ tid.toString()
731
+ ),
732
+ logMessageType:
733
+ "log:thread-image",
734
+ logMessageData: {
735
+ image: {
736
+ attachmentID:
737
+ fetchData.image_with_metadata &&
738
+ fetchData
739
+ .image_with_metadata
740
+ .legacy_attachment_id,
741
+ width:
742
+ fetchData.image_with_metadata &&
743
+ fetchData
744
+ .image_with_metadata
745
+ .original_dimensions
746
+ .x,
747
+ height:
748
+ fetchData.image_with_metadata &&
749
+ fetchData
750
+ .image_with_metadata
751
+ .original_dimensions
752
+ .y,
753
+ url:
754
+ fetchData.image_with_metadata &&
755
+ fetchData
756
+ .image_with_metadata
757
+ .preview.uri,
758
+ },
759
+ },
760
+ logMessageBody:
761
+ fetchData.snippet,
762
+ timestamp:
763
+ fetchData.timestamp_precise,
764
+ author:
765
+ fetchData.message_sender
766
+ .id,
767
+ });
768
+ })();
769
+ break;
770
+ case "UserMessage":
771
+ log.info("ff-Return", {
772
+ type: "message",
773
+ senderID: utils.formatID(
774
+ fetchData.message_sender.id
775
+ ),
776
+ body: fetchData.message.text || "",
777
+ threadID: utils.formatID(
778
+ tid.toString()
779
+ ),
780
+ messageID: fetchData.message_id,
781
+ attachments: [
782
+ {
783
+ type: "share",
784
+ ID:
785
+ fetchData
786
+ .extensible_attachment
787
+ .legacy_attachment_id,
788
+ url:
789
+ fetchData
790
+ .extensible_attachment
791
+ .story_attachment.url,
432
792
 
433
- var fetchData = resData[0].o0.data.message;
434
- if (fetchData && fetchData.__typename === "ThreadImageMessage") {
435
- (!ctx.globalOptions.selfListen &&
436
- fetchData.message_sender.id.toString() === ctx.userID) ||
437
- !ctx.loggedIn ?
438
- undefined :
439
- (function () { globalCallback(null, {
440
- type: "change_thread_image",
441
- threadID: utils.formatID(tid.toString()),
442
- snippet: fetchData.snippet,
443
- timestamp: fetchData.timestamp_precise,
444
- author: fetchData.message_sender.id,
445
- image: {
446
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
447
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
448
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
449
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
450
- }
451
- }); })();
793
+ title:
794
+ fetchData
795
+ .extensible_attachment
796
+ .story_attachment
797
+ .title_with_entities
798
+ .text,
799
+ description:
800
+ fetchData
801
+ .extensible_attachment
802
+ .story_attachment
803
+ .description.text,
804
+ source:
805
+ fetchData
806
+ .extensible_attachment
807
+ .story_attachment
808
+ .source,
809
+
810
+ image: (
811
+ (
812
+ fetchData
813
+ .extensible_attachment
814
+ .story_attachment
815
+ .media || {}
816
+ ).image || {}
817
+ ).uri,
818
+ width: (
819
+ (
820
+ fetchData
821
+ .extensible_attachment
822
+ .story_attachment
823
+ .media || {}
824
+ ).image || {}
825
+ ).width,
826
+ height: (
827
+ (
828
+ fetchData
829
+ .extensible_attachment
830
+ .story_attachment
831
+ .media || {}
832
+ ).image || {}
833
+ ).height,
834
+ playable:
835
+ (
836
+ fetchData
837
+ .extensible_attachment
838
+ .story_attachment
839
+ .media || {}
840
+ ).is_playable || false,
841
+ duration:
842
+ (
843
+ fetchData
844
+ .extensible_attachment
845
+ .story_attachment
846
+ .media || {}
847
+ ).playable_duration_in_ms ||
848
+ 0,
849
+
850
+ subattachments:
851
+ fetchData
852
+ .extensible_attachment
853
+ .subattachments,
854
+ properties:
855
+ fetchData
856
+ .extensible_attachment
857
+ .story_attachment
858
+ .properties,
859
+ },
860
+ ],
861
+ mentions: {},
862
+ timestamp: parseInt(
863
+ fetchData.timestamp_precise
864
+ ),
865
+ isGroup:
866
+ fetchData.message_sender.id !=
867
+ tid.toString(),
868
+ });
869
+ globalCallback(null, {
870
+ type: "message",
871
+ senderID: utils.formatID(
872
+ fetchData.message_sender.id
873
+ ),
874
+ body: fetchData.message.text || "",
875
+ threadID: utils.formatID(
876
+ tid.toString()
877
+ ),
878
+ messageID: fetchData.message_id,
879
+ attachments: [
880
+ {
881
+ type: "share",
882
+ ID:
883
+ fetchData
884
+ .extensible_attachment
885
+ .legacy_attachment_id,
886
+ url:
887
+ fetchData
888
+ .extensible_attachment
889
+ .story_attachment.url,
890
+
891
+ title:
892
+ fetchData
893
+ .extensible_attachment
894
+ .story_attachment
895
+ .title_with_entities
896
+ .text,
897
+ description:
898
+ fetchData
899
+ .extensible_attachment
900
+ .story_attachment
901
+ .description.text,
902
+ source:
903
+ fetchData
904
+ .extensible_attachment
905
+ .story_attachment
906
+ .source,
907
+
908
+ image: (
909
+ (
910
+ fetchData
911
+ .extensible_attachment
912
+ .story_attachment
913
+ .media || {}
914
+ ).image || {}
915
+ ).uri,
916
+ width: (
917
+ (
918
+ fetchData
919
+ .extensible_attachment
920
+ .story_attachment
921
+ .media || {}
922
+ ).image || {}
923
+ ).width,
924
+ height: (
925
+ (
926
+ fetchData
927
+ .extensible_attachment
928
+ .story_attachment
929
+ .media || {}
930
+ ).image || {}
931
+ ).height,
932
+ playable:
933
+ (
934
+ fetchData
935
+ .extensible_attachment
936
+ .story_attachment
937
+ .media || {}
938
+ ).is_playable || false,
939
+ duration:
940
+ (
941
+ fetchData
942
+ .extensible_attachment
943
+ .story_attachment
944
+ .media || {}
945
+ ).playable_duration_in_ms ||
946
+ 0,
947
+
948
+ subattachments:
949
+ fetchData
950
+ .extensible_attachment
951
+ .subattachments,
952
+ properties:
953
+ fetchData
954
+ .extensible_attachment
955
+ .story_attachment
956
+ .properties,
957
+ },
958
+ ],
959
+ mentions: {},
960
+ timestamp: parseInt(
961
+ fetchData.timestamp_precise
962
+ ),
963
+ isGroup:
964
+ fetchData.message_sender.id !=
965
+ tid.toString(),
966
+ });
967
+ }
968
+ } else {
969
+ log.error("forcedFetch", fetchData);
970
+ }
971
+ })
972
+ .catch((err) => {
973
+ log.error("forcedFetch", err);
974
+ });
452
975
  }
453
- })
454
- .catch((err) => {
455
- log.error("forcedFetch", err);
456
- });
457
- }
458
- break;
459
- case "ThreadName":
460
- case "ParticipantsAddedToGroupThread":
461
- case "ParticipantLeftGroupThread":
462
- var formattedEvent;
463
- try {
464
- formattedEvent = utils.formatDeltaEvent(v.delta);
465
- } catch (err) {
466
- return globalCallback({
467
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
468
- detail: err,
469
- res: v.delta,
470
- type: "parse_error"
471
- });
472
- }
473
- return (!ctx.globalOptions.selfListen &&
474
- formattedEvent.author.toString() === ctx.userID) ||
475
- !ctx.loggedIn ?
476
- undefined :
477
- (function () { globalCallback(null, formattedEvent); })();
478
- }
976
+ break;
977
+ case "ThreadName":
978
+ case "ParticipantsAddedToGroupThread":
979
+ case "ParticipantLeftGroupThread":
980
+ var formattedEvent;
981
+ try {
982
+ formattedEvent = utils.formatDeltaEvent(v.delta);
983
+ } catch (err) {
984
+ return globalCallback({
985
+ error:
986
+ "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
987
+ detail: err,
988
+ res: v.delta,
989
+ type: "parse_error",
990
+ });
991
+ }
992
+ return (!ctx.globalOptions.selfListen &&
993
+ formattedEvent.author.toString() === ctx.userID) ||
994
+ !ctx.loggedIn
995
+ ? undefined
996
+ : (function() {
997
+ globalCallback(null, formattedEvent);
998
+ })();
999
+ }
479
1000
  }
480
1001
 
481
1002
  function markDelivery(ctx, api, threadID, messageID) {
482
- if (threadID && messageID) {
483
- api.markAsDelivered(threadID, messageID, (err) => {
484
- if (err) {
485
- log.error(err);
486
- } else {
487
- if (ctx.globalOptions.autoMarkRead) {
488
- api.markAsRead(threadID, (err) => {
1003
+ if (threadID && messageID) {
1004
+ api.markAsDelivered(threadID, messageID, (err) => {
489
1005
  if (err) {
490
- log.error(err);
1006
+ log.error("markAsDelivered", err);
1007
+ } else {
1008
+ if (ctx.globalOptions.autoMarkRead) {
1009
+ api.markAsRead(threadID, (err) => {
1010
+ if (err) {
1011
+ log.error("markAsDelivered", err);
1012
+ }
1013
+ });
1014
+ }
491
1015
  }
492
- });
493
- }
494
- }
495
- });
496
- }
1016
+ });
1017
+ }
497
1018
  }
498
1019
 
499
- module.exports = function (defaultFuncs, api, ctx) {
500
- var globalCallback = identity;
501
- return function (callback) {
502
- globalCallback = callback;
503
-
504
- //Reset some stuff
505
- ctx.lastSeqId = 0;
506
- ctx.syncToken = undefined;
507
-
508
- //Same request as getThreadList
509
- const form = {
510
- "av": ctx.globalOptions.pageID,
511
- "queries": JSON.stringify({
512
- "o0": {
513
- "doc_id": "1349387578499440",
514
- "query_params": {
515
- "limit": 1,
516
- "before": null,
517
- "tags": ["INBOX"],
518
- "includeDeliveryReceipts": false,
519
- "includeSeqID": true
520
- }
521
- }
522
- })
523
- };
1020
+ module.exports = function(defaultFuncs, api, ctx) {
1021
+ var globalCallback = identity;
1022
+ getSeqID = function getSeqID() {
1023
+ ctx.t_mqttCalled = false;
1024
+ defaultFuncs
1025
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
1026
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
1027
+ .then((resData) => {
1028
+ if (utils.getType(resData) != "Array") {
1029
+ throw {
1030
+ error: "Not logged in",
1031
+ res: resData,
1032
+ };
1033
+ }
524
1034
 
525
- defaultFuncs
526
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
527
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
528
- .then((resData) => {
529
- if (resData && resData.length > 0 && resData[resData.length - 1].error_results > 0) {
530
- throw resData[0].o0.errors;
531
- }
1035
+ if (resData && resData[resData.length - 1].error_results > 0) {
1036
+ throw resData[0].o0.errors;
1037
+ }
532
1038
 
533
- if (resData[resData.length - 1].successful_results === 0) {
534
- throw { error: "getSeqId: there was no successful_results", res: resData };
535
- }
1039
+ if (resData[resData.length - 1].successful_results === 0) {
1040
+ throw {
1041
+ error: "getSeqId: there was no successful_results",
1042
+ res: resData,
1043
+ };
1044
+ }
536
1045
 
537
- if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) {
538
- ctx.lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id;
539
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
1046
+ if (
1047
+ resData[0].o0.data.viewer.message_threads.sync_sequence_id
1048
+ ) {
1049
+ ctx.lastSeqId =
1050
+ resData[0].o0.data.viewer.message_threads.sync_sequence_id;
1051
+ listenMqtt(defaultFuncs, api, ctx, globalCallback);
1052
+ } else {
1053
+ throw {
1054
+ error: "getSeqId: no sync_sequence_id found.",
1055
+ res: resData,
1056
+ };
1057
+ }
1058
+ })
1059
+ .catch((err) => {
1060
+ log.error("getSeqId", err);
1061
+ if (
1062
+ utils.getType(err) == "Object" &&
1063
+ err.error === "Not logged in"
1064
+ ) {
1065
+ ctx.loggedIn = false;
1066
+ }
1067
+ return globalCallback(err);
1068
+ });
1069
+ };
1070
+
1071
+ return function(callback) {
1072
+ class MessageEmitter extends EventEmitter {
1073
+ stopListening(callback) {
1074
+ callback = callback || (() => {});
1075
+ globalCallback = identity;
1076
+ if (ctx.mqttClient) {
1077
+ ctx.mqttClient.unsubscribe("/webrtc");
1078
+ ctx.mqttClient.unsubscribe("/rtc_multi");
1079
+ ctx.mqttClient.unsubscribe("/onevc");
1080
+ ctx.mqttClient.publish("/browser_close", "{}");
1081
+ ctx.mqttClient.end(false, function(...data) {
1082
+ callback(data);
1083
+ ctx.mqttClient = undefined;
1084
+ });
1085
+ }
1086
+ }
540
1087
  }
541
1088
 
542
- })
543
- .catch((err) => {
544
- log.error("getSeqId", err);
545
- return callback(err);
546
- });
1089
+ var msgEmitter = new MessageEmitter();
1090
+ globalCallback =
1091
+ callback ||
1092
+ function(error, message) {
1093
+ if (error) {
1094
+ return msgEmitter.emit("error", error);
1095
+ }
1096
+ msgEmitter.emit("message", message);
1097
+ };
1098
+
1099
+ //Reset some stuff
1100
+ if (!ctx.firstListen) ctx.lastSeqId = null;
1101
+ ctx.syncToken = undefined;
1102
+ ctx.t_mqttCalled = false;
547
1103
 
548
- var stopListening = function () {
549
- globalCallback = identity;
1104
+ //Same request as getThreadList
1105
+ form = {
1106
+ av: ctx.globalOptions.pageID,
1107
+ queries: JSON.stringify({
1108
+ o0: {
1109
+ doc_id: "3336396659757871",
1110
+ query_params: {
1111
+ limit: 1,
1112
+ before: null,
1113
+ tags: ["INBOX"],
1114
+ includeDeliveryReceipts: false,
1115
+ includeSeqID: true,
1116
+ },
1117
+ },
1118
+ }),
1119
+ };
550
1120
 
551
- if(ctx.mqttClient)
552
- {
553
- ctx.mqttClient.end();
554
- ctx.mqttClient = undefined;
555
- }
1121
+ if (!ctx.firstListen || !ctx.lastSeqId) {
1122
+ getSeqID();
1123
+ } else {
1124
+ listenMqtt(defaultFuncs, api, ctx, globalCallback);
1125
+ }
1126
+ ctx.firstListen = false;
1127
+ return msgEmitter;
556
1128
  };
557
-
558
- return stopListening;
559
- };
560
- }
1129
+ };