@cexy/hoonfca 1.0.0 → 1.0.2

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