alicezetion 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) 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 +488 -560
  4. package/package.json +25 -25
  5. package/replit.nix +5 -0
  6. package/src/addExternalModule.js +15 -0
  7. package/{alice → src}/addUserToGroup.js +16 -52
  8. package/src/changeAdminStatus.js +47 -0
  9. package/src/changeArchivedStatus.js +41 -0
  10. package/{alice → src}/changeBio.js +6 -19
  11. package/{alice → src}/changeBlockedStatus.js +3 -14
  12. package/{alice → src}/changeGroupImage.js +16 -40
  13. package/src/changeNickname.js +43 -0
  14. package/{alice → src}/changeThreadColor.js +10 -20
  15. package/src/changeThreadEmoji.js +41 -0
  16. package/src/chat.js +315 -0
  17. package/{alice → src}/createNewGroup.js +12 -28
  18. package/{alice → src}/createPoll.js +13 -25
  19. package/src/deleteMessage.js +44 -0
  20. package/src/deleteThread.js +42 -0
  21. package/src/forwardAttachment.js +47 -0
  22. package/src/forwardMessage.js +0 -0
  23. package/{alice → src}/getCurrentUserID.js +1 -1
  24. package/{alice → src}/getEmojiUrl.js +2 -4
  25. package/{alice → src}/getFriendsList.js +10 -21
  26. package/{alice → src}/getThreadHistory.js +58 -166
  27. package/{alice → src}/getThreadHistoryDeprecated.js +20 -42
  28. package/{alice → src}/getThreadInfo.js +25 -60
  29. package/src/getThreadInfoDeprecated.js +56 -0
  30. package/{alice → src}/getThreadList.js +41 -66
  31. package/src/getThreadListDeprecated.js +46 -0
  32. package/src/getThreadPictures.js +59 -0
  33. package/{alice → src}/getUserID.js +9 -14
  34. package/{alice → src}/getUserInfo.js +13 -19
  35. package/src/handleFriendRequest.js +46 -0
  36. package/src/handleMessageRequest.js +47 -0
  37. package/{alice → src}/httpGet.js +12 -17
  38. package/{alice → src}/httpPost.js +12 -17
  39. package/src/listen.js +553 -0
  40. package/src/listenMqtt-Test.js +687 -0
  41. package/src/listenMqtt.js +677 -0
  42. package/{alice → src}/logout.js +13 -20
  43. package/{alice → src}/markAsDelivered.js +11 -22
  44. package/{alice → src}/markAsRead.js +11 -21
  45. package/{alice → src}/markAsReadAll.js +10 -20
  46. package/{alice → src}/markAsSeen.js +7 -18
  47. package/{alice → src}/muteThread.js +11 -18
  48. package/src/removeUserFromGroup.js +45 -0
  49. package/{alice → src}/resolvePhotoUrl.js +8 -17
  50. package/{alice → src}/searchForThread.js +10 -21
  51. package/{alice → src}/sendTypingIndicator.js +14 -47
  52. package/{alice → src}/setMessageReaction.js +12 -26
  53. package/{alice → src}/setPostReaction.js +13 -26
  54. package/{alice → src}/setTitle.js +13 -29
  55. package/src/threadColors.js +41 -0
  56. package/{alice → src}/unfriend.js +9 -19
  57. package/{alice → src}/unsendMessage.js +9 -19
  58. package/utils.js +1021 -1190
  59. package/alice/addExternalModule.js +0 -19
  60. package/alice/changeAdminStatus.js +0 -79
  61. package/alice/changeArchivedStatus.js +0 -55
  62. package/alice/changeNickname.js +0 -59
  63. package/alice/changeThreadEmoji.js +0 -55
  64. package/alice/deleteMessage.js +0 -56
  65. package/alice/deleteThread.js +0 -56
  66. package/alice/forwardAttachment.js +0 -60
  67. package/alice/getThreadInfoDeprecated.js +0 -80
  68. package/alice/getThreadListDeprecated.js +0 -75
  69. package/alice/getThreadPictures.js +0 -79
  70. package/alice/handleFriendRequest.js +0 -61
  71. package/alice/handleMessageRequest.js +0 -65
  72. package/alice/listenMqtt.js +0 -789
  73. package/alice/removeUserFromGroup.js +0 -79
  74. package/alice/sendMessage.js +0 -459
  75. package/alice/threadColors.js +0 -57
@@ -21,7 +21,7 @@ function formatEventReminders(reminder) {
21
21
  secondsToNotifyBefore: reminder.seconds_to_notify_before,
22
22
  allowsRsvp: reminder.allows_rsvp,
23
23
  relatedEvent: reminder.related_event,
24
- members: reminder.event_reminder_members.edges.map(function(member) {
24
+ members: reminder.event_reminder_members.edges.map(function (member) {
25
25
  return {
26
26
  memberID: member.node.id,
27
27
  state: member.guest_list_state.toLowerCase()
@@ -31,33 +31,15 @@ function formatEventReminders(reminder) {
31
31
  }
32
32
 
33
33
  function formatThreadGraphQLResponse(data) {
34
- try{
35
- var messageThread = data.o0.data.message_thread;
36
- } catch (err){
37
- console.error("GetThreadInfoGraphQL", "Can't get this thread info!");
38
- return {err: err};
39
- }
40
- var threadID = messageThread.thread_key.thread_fbid
41
- ? messageThread.thread_key.thread_fbid
42
- : messageThread.thread_key.other_user_id;
34
+ var messageThread = data.o0.data.message_thread;
35
+ var threadID = messageThread.thread_key.thread_fbid ? messageThread.thread_key.thread_fbid : messageThread.thread_key.other_user_id;
43
36
 
44
37
  // Remove me
45
38
  var lastM = messageThread.last_message;
46
- var snippetID =
47
- lastM &&
48
- lastM.nodes &&
49
- lastM.nodes[0] &&
50
- lastM.nodes[0].message_sender &&
51
- lastM.nodes[0].message_sender.messaging_actor
52
- ? lastM.nodes[0].message_sender.messaging_actor.id
53
- : null;
54
- var snippetText =
55
- lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
39
+ var snippetID = lastM && lastM.nodes && lastM.nodes[0] && lastM.nodes[0].message_sender && lastM.nodes[0].message_sender.messaging_actor ? lastM.nodes[0].message_sender.messaging_actor.id : null;
40
+ var snippetText = lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
56
41
  var lastR = messageThread.last_read_receipt;
57
- var lastReadTimestamp =
58
- lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
59
- ? lastR.nodes[0].timestamp_precise
60
- : null;
42
+ var lastReadTimestamp = lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise ? lastR.nodes[0].timestamp_precise : null;
61
43
 
62
44
  return {
63
45
  threadID: threadID,
@@ -84,27 +66,16 @@ function formatThreadGraphQLResponse(data) {
84
66
  isArchived: messageThread.has_viewer_archived,
85
67
  folder: messageThread.folder,
86
68
  cannotReplyReason: messageThread.cannot_reply_reason,
87
- eventReminders: messageThread.event_reminders
88
- ? messageThread.event_reminders.nodes.map(formatEventReminders)
89
- : null,
90
- emoji: messageThread.customization_info
91
- ? messageThread.customization_info.emoji
92
- : null,
93
- color:
94
- messageThread.customization_info &&
95
- messageThread.customization_info.outgoing_bubble_color
96
- ? messageThread.customization_info.outgoing_bubble_color.slice(2)
97
- : null,
69
+ eventReminders: messageThread.event_reminders ? messageThread.event_reminders.nodes.map(formatEventReminders) : null,
70
+ emoji: messageThread.customization_info ? messageThread.customization_info.emoji : null,
71
+ color: messageThread.customization_info && messageThread.customization_info.outgoing_bubble_color ? messageThread.customization_info.outgoing_bubble_color.slice(2) : null,
98
72
  nicknames:
99
73
  messageThread.customization_info &&
100
- messageThread.customization_info.participant_customizations
101
- ? messageThread.customization_info.participant_customizations.reduce(
102
- function(res, val) {
103
- if (val.nickname) res[val.participant_id] = val.nickname;
104
- return res;
105
- },
106
- {}
107
- )
74
+ messageThread.customization_info.participant_customizations
75
+ ? messageThread.customization_info.participant_customizations.reduce(function (res, val) {
76
+ if (val.nickname) res[val.participant_id] = val.nickname;
77
+ return res;
78
+ }, {})
108
79
  : {},
109
80
  adminIDs: messageThread.thread_admins,
110
81
  approvalMode: Boolean(messageThread.approval_mode),
@@ -134,19 +105,17 @@ function formatThreadGraphQLResponse(data) {
134
105
  hasEmailParticipant: false,
135
106
  readOnly: false,
136
107
  canReply: messageThread.cannot_reply_reason == null,
137
- lastMessageTimestamp: messageThread.last_message
138
- ? messageThread.last_message.timestamp_precise
139
- : null,
108
+ lastMessageTimestamp: messageThread.last_message ? messageThread.last_message.timestamp_precise : null,
140
109
  lastMessageType: "message",
141
110
  lastReadTimestamp: lastReadTimestamp,
142
111
  threadType: messageThread.thread_type == "GROUP" ? 2 : 1
143
112
  };
144
113
  }
145
114
 
146
- module.exports = function(defaultFuncs, api, ctx) {
115
+ module.exports = function (defaultFuncs, api, ctx) {
147
116
  return function getThreadInfoGraphQL(threadID, callback) {
148
- var resolveFunc = function(){};
149
- var rejectFunc = function(){};
117
+ var resolveFunc = function () { };
118
+ var rejectFunc = function () { };
150
119
  var returnPromise = new Promise(function (resolve, reject) {
151
120
  resolveFunc = resolve;
152
121
  rejectFunc = reject;
@@ -154,9 +123,7 @@ module.exports = function(defaultFuncs, api, ctx) {
154
123
 
155
124
  if (utils.getType(callback) != "Function" && utils.getType(callback) != "AsyncFunction") {
156
125
  callback = function (err, data) {
157
- if (err) {
158
- return rejectFunc(err);
159
- }
126
+ if (err) return rejectFunc(err);
160
127
  resolveFunc(data);
161
128
  };
162
129
  }
@@ -183,21 +150,19 @@ module.exports = function(defaultFuncs, api, ctx) {
183
150
  defaultFuncs
184
151
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
185
152
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
186
- .then(function(resData) {
187
- if (resData.error) {
188
- throw resData;
189
- }
153
+ .then(function (resData) {
154
+ if (resData.error) throw resData;
190
155
  // This returns us an array of things. The last one is the success /
191
156
  // failure one.
192
157
  // @TODO What do we do in this case?
193
158
  if (resData[resData.length - 1].error_results !== 0) {
194
- console.error("GetThreadInfo", "Well darn there was an error_result");
159
+ console.log(resData); //Log more info
160
+ throw new Error("well darn there was an error_result");
195
161
  }
196
-
197
162
  callback(null, formatThreadGraphQLResponse(resData[0]));
198
163
  })
199
- .catch(function(err) {
200
- log.error("getThreadInfoGraphQL", err);
164
+ .catch(function (err) {
165
+ log.error("getThreadInfoGraphQL", "Can't get thread info");
201
166
  return callback(err);
202
167
  });
203
168
 
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ return function getThreadInfo(threadID, callback) {
8
+ var resolveFunc = function () { };
9
+ var rejectFunc = function () { };
10
+ var returnPromise = new Promise(function (resolve, reject) {
11
+ resolveFunc = resolve;
12
+ rejectFunc = reject;
13
+ });
14
+
15
+ if (!callback) {
16
+ callback = function (err, data) {
17
+ if (err) return rejectFunc(err);
18
+ resolveFunc(data);
19
+ };
20
+ }
21
+
22
+ var form = {
23
+ client: "mercury"
24
+ };
25
+
26
+ api.getUserInfo(threadID, function (err, userRes) {
27
+ if (err) return callback(err);
28
+ var key = Object.keys(userRes).length > 0 ? "user_ids" : "thread_fbids";
29
+ form["threads[" + key + "][0]"] = threadID;
30
+
31
+ if (ctx.globalOptions.pageId) form.request_user_id = ctx.globalOptions.pageId;
32
+
33
+ defaultFuncs
34
+ .post("https://www.facebook.com/ajax/mercury/thread_info.php", ctx.jar, form)
35
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(function (resData) {
37
+ if (resData.error) throw resData;
38
+ else if (!resData.payload) throw { error: "Could not retrieve thread Info." };
39
+
40
+ var threadData = resData.payload.threads[0];
41
+ var userData = userRes[threadID];
42
+
43
+ if (threadData == null) throw { error: "ThreadData is null" };
44
+
45
+ threadData.name = userData != null && userData.name != null ? userData.name : threadData.name;
46
+ threadData.image_src = userData != null && userData.thumbSrc != null ? userData.thumbSrc : threadData.image_src;
47
+ callback(null, utils.formatThread(threadData));
48
+ })
49
+ .catch(function (err) {
50
+ log.error("getThreadInfo", err);
51
+ return callback(err);
52
+ });
53
+ });
54
+ return returnPromise;
55
+ };
56
+ };
@@ -9,7 +9,7 @@ function createProfileUrl(url, username, id) {
9
9
  }
10
10
 
11
11
  function formatParticipants(participants) {
12
- return participants.edges.map((p)=>{
12
+ return participants.edges.map((p) => {
13
13
  p = p.node.messaging_actor;
14
14
  switch (p["__typename"]) {
15
15
  case "User":
@@ -21,7 +21,7 @@ function formatParticipants(participants) {
21
21
  gender: p.gender,
22
22
  url: p.url, // how about making it profileURL
23
23
  profilePicture: p.big_image_src.uri,
24
- username: (p.username||null),
24
+ username: (p.username || null),
25
25
  // TODO: maybe better names for these?
26
26
  isViewerFriend: p.is_viewer_friend, // true/false
27
27
  isMessengerUser: p.is_messenger_user, // true/false
@@ -37,7 +37,7 @@ function formatParticipants(participants) {
37
37
  name: p.name,
38
38
  url: p.url,
39
39
  profilePicture: p.big_image_src.uri,
40
- username: (p.username||null),
40
+ username: (p.username || null),
41
41
  // uhm... better names maybe?
42
42
  acceptsMessengerUserFeedback: p.accepts_messenger_user_feedback, // true/false
43
43
  isMessengerUser: p.is_messenger_user, // true/false
@@ -46,27 +46,18 @@ function formatParticipants(participants) {
46
46
  isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
47
47
  };
48
48
  case "ReducedMessagingActor":
49
+ case "UnavailableMessagingActor":
49
50
  return {
50
51
  accountType: p["__typename"],
51
52
  userID: utils.formatID(p.id.toString()),
52
53
  name: p.name,
53
54
  url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
54
55
  profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
55
- username: (p.username||null), // maybe we could use it to generate profile URL?
56
- isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
57
- };
58
- case "UnavailableMessagingActor":
59
- return {
60
- accountType: p["__typename"],
61
- userID: utils.formatID(p.id.toString()),
62
- name: p.name, // "Facebook User" in user's language
63
- url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
64
- profilePicture: p.big_image_src.uri, // default male facebook photo
65
- username: (p.username||null), // maybe we could use it to generate profile URL?
56
+ username: (p.username || null), // maybe we could use it to generate profile URL?
66
57
  isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
67
58
  };
68
59
  default:
69
- log.warn("getThreadList", "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/fca-unofficial/issues\n" + JSON.stringify(p, null, 2));
60
+ log.warn("getThreadList", "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues\n" + JSON.stringify(p, null, 2));
70
61
  return {
71
62
  accountType: p["__typename"],
72
63
  userID: utils.formatID(p.id.toString()),
@@ -78,9 +69,7 @@ function formatParticipants(participants) {
78
69
 
79
70
  // "FF8C0077" -> "8C0077"
80
71
  function formatColor(color) {
81
- if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g)) {
82
- return color.slice(2);
83
- }
72
+ if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g)) return color.slice(2);
84
73
  return color;
85
74
  }
86
75
 
@@ -95,24 +84,24 @@ function getThreadName(t) {
95
84
 
96
85
  function mapNicknames(customizationInfo) {
97
86
  return (customizationInfo && customizationInfo.participant_customizations) ? customizationInfo.participant_customizations.map(u => {
98
- return {
99
- "userID": u.participant_id,
100
- "nickname": u.nickname
101
- };
102
- }):[];
87
+ return {
88
+ "userID": u.participant_id,
89
+ "nickname": u.nickname
90
+ };
91
+ }) : [];
103
92
  }
104
93
 
105
94
  function formatThreadList(data) {
106
95
  return data.map(t => {
107
- let lastMessageNode = (t.last_message&&t.last_message.nodes&&t.last_message.nodes.length>0)?t.last_message.nodes[0]:null;
96
+ let lastMessageNode = (t.last_message && t.last_message.nodes && t.last_message.nodes.length > 0) ? t.last_message.nodes[0] : null;
108
97
  return {
109
- threadID: t.thread_key?utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id):null, // shall never be null
98
+ threadID: t.thread_key ? utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id) : null, // shall never be null
110
99
  name: getThreadName(t),
111
100
  unreadCount: t.unread_count,
112
101
  messageCount: t.messages_count,
113
- imageSrc: t.image?t.image.uri:null,
114
- emoji: t.customization_info?t.customization_info.emoji:null,
115
- color: formatColor(t.customization_info?t.customization_info.outgoing_bubble_color:null),
102
+ imageSrc: t.image ? t.image.uri : null,
103
+ emoji: t.customization_info ? t.customization_info.emoji : null,
104
+ color: formatColor(t.customization_info ? t.customization_info.outgoing_bubble_color : null),
116
105
  nicknames: mapNicknames(t.customization_info),
117
106
  muteUntil: t.mute_until,
118
107
  participants: formatParticipants(t.all_participants),
@@ -123,7 +112,7 @@ function formatThreadList(data) {
123
112
  // isPinProtected: t.is_pin_protected, // feature from future? always false (2018-04-04)
124
113
  customizationEnabled: t.customization_enabled, // false for ONE_TO_ONE with Page or ReducedMessagingActor
125
114
  participantAddMode: t.participant_add_mode_as_string, // "ADD" if "GROUP" and null if "ONE_TO_ONE"
126
- montageThread: t.montage_thread?Buffer.from(t.montage_thread.id,"base64").toString():null, // base64 encoded string "message_thread:0000000000000000"
115
+ montageThread: t.montage_thread ? Buffer.from(t.montage_thread.id, "base64").toString() : null, // base64 encoded string "message_thread:0000000000000000"
127
116
  // it is not userID nor any other ID known to me...
128
117
  // can somebody inspect it? where is it used?
129
118
  // probably Messenger Day uses it
@@ -134,13 +123,13 @@ function formatThreadList(data) {
134
123
  timestamp: t.updated_time_precise, // in miliseconds
135
124
  // isCanonicalUser: t.is_canonical_neo_user, // is it always false?
136
125
  // TODO: how about putting snippet in another object? current implementation does not handle every possibile message type etc.
137
- snippet: lastMessageNode?lastMessageNode.snippet:null,
138
- snippetAttachments: lastMessageNode?lastMessageNode.extensible_attachment:null, // TODO: not sure if it works
139
- snippetSender: lastMessageNode?utils.formatID((lastMessageNode.message_sender.messaging_actor.id || "").toString()):null,
140
- lastMessageTimestamp: lastMessageNode?lastMessageNode.timestamp_precise:null, // timestamp in miliseconds
141
- lastReadTimestamp: (t.last_read_receipt&&t.last_read_receipt.nodes.length>0)
142
- ? (t.last_read_receipt.nodes[0]?t.last_read_receipt.nodes[0].timestamp_precise:null)
143
- : null, // timestamp in miliseconds
126
+ snippet: lastMessageNode ? lastMessageNode.snippet : null,
127
+ snippetAttachments: lastMessageNode ? lastMessageNode.extensible_attachment : null, // TODO: not sure if it works
128
+ snippetSender: lastMessageNode ? utils.formatID((lastMessageNode.message_sender.messaging_actor.id || "").toString()) : null,
129
+ lastMessageTimestamp: lastMessageNode ? lastMessageNode.timestamp_precise : null, // timestamp in miliseconds
130
+ lastReadTimestamp: (t.last_read_receipt && t.last_read_receipt.nodes.length > 0)
131
+ ? (t.last_read_receipt.nodes[0] ? t.last_read_receipt.nodes[0].timestamp_precise : null)
132
+ : null, // timestamp in miliseconds
144
133
  cannotReplyReason: t.cannot_reply_reason, // TODO: inspect possible values
145
134
  approvalMode: Boolean(t.approval_mode),
146
135
 
@@ -151,28 +140,21 @@ function formatThreadList(data) {
151
140
  });
152
141
  }
153
142
 
154
- module.exports = function(defaultFuncs, api, ctx) {
143
+ module.exports = function (defaultFuncs, api, ctx) {
155
144
  return function getThreadList(limit, timestamp, tags, callback) {
156
145
  if (!callback && (utils.getType(tags) === "Function" || utils.getType(tags) === "AsyncFunction")) {
157
146
  callback = tags;
158
147
  tags = [""];
159
148
  }
160
- if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0) {
161
- throw {error: "getThreadList: limit must be a positive integer"};
162
- }
163
- if (utils.getType(timestamp) !== "Null" &&
164
- (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))) {
165
- throw {error: "getThreadList: timestamp must be an integer or null"};
166
- }
167
- if (utils.getType(tags) === "String") {
168
- tags = [tags];
169
- }
170
- if (utils.getType(tags) !== "Array") {
171
- throw {error: "getThreadList: tags must be an array"};
172
- }
149
+ if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0) throw { error: "getThreadList: limit must be a positive integer" };
150
+
151
+ if (utils.getType(timestamp) !== "Null" && (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))) throw { error: "getThreadList: timestamp must be an integer or null" };
152
+
153
+ if (utils.getType(tags) === "String") tags = [tags];
154
+ if (utils.getType(tags) !== "Array") throw { error: "getThreadList: tags must be an array" };
173
155
 
174
- var resolveFunc = function(){};
175
- var rejectFunc = function(){};
156
+ var resolveFunc = function () { };
157
+ var rejectFunc = function () { };
176
158
  var returnPromise = new Promise(function (resolve, reject) {
177
159
  resolveFunc = resolve;
178
160
  rejectFunc = reject;
@@ -180,9 +162,7 @@ module.exports = function(defaultFuncs, api, ctx) {
180
162
 
181
163
  if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
182
164
  callback = function (err, data) {
183
- if (err) {
184
- return rejectFunc(err);
185
- }
165
+ if (err) return rejectFunc(err);
186
166
  resolveFunc(data);
187
167
  };
188
168
  }
@@ -194,7 +174,7 @@ module.exports = function(defaultFuncs, api, ctx) {
194
174
  // This doc_id was valid on 2020-07-20
195
175
  "doc_id": "3336396659757871",
196
176
  "query_params": {
197
- "limit": limit+(timestamp?1:0),
177
+ "limit": limit + (timestamp ? 1 : 0),
198
178
  "before": timestamp,
199
179
  "tags": tags,
200
180
  "includeDeliveryReceipts": true,
@@ -209,13 +189,9 @@ module.exports = function(defaultFuncs, api, ctx) {
209
189
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
210
190
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
211
191
  .then((resData) => {
212
- if (resData[resData.length - 1].error_results > 0) {
213
- throw resData[0].o0.errors;
214
- }
192
+ if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
215
193
 
216
- if (resData[resData.length - 1].successful_results === 0) {
217
- throw {error: "getThreadList: there was no successful_results", res: resData};
218
- }
194
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "getThreadList: there was no successful_results", res: resData };
219
195
 
220
196
  // When we ask for threads using timestamp from the previous request,
221
197
  // we are getting the last thread repeated as the first thread in this response.
@@ -223,13 +199,12 @@ module.exports = function(defaultFuncs, api, ctx) {
223
199
  // It is also the reason for increasing limit by 1 when timestamp is set
224
200
  // this way user asks for 10 threads, we are asking for 11,
225
201
  // but after removing the duplicated one, it is again 10
226
- if (timestamp) {
227
- resData[0].o0.data.viewer.message_threads.nodes.shift();
228
- }
202
+ if (timestamp) resData[0].o0.data.viewer.message_threads.nodes.shift();
203
+
229
204
  callback(null, formatThreadList(resData[0].o0.data.viewer.message_threads.nodes));
230
205
  })
231
206
  .catch((err) => {
232
- log.error("getThreadList", err);
207
+ log.error("getThreadList", "ParseAndCheckLogin got status code: 404. Bailing out of trying to parse response.");
233
208
  return callback(err);
234
209
  });
235
210
 
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ return function getThreadList(start, end, type, callback) {
8
+ if (utils.getType(callback) === "Undefined") {
9
+ if (utils.getType(end) !== "Number") throw { error: "Please pass a number as a second argument." };
10
+ else if (utils.getType(type) === "Function" || utils.getType(type) === "AsyncFunction") {
11
+ callback = type;
12
+ type = "inbox"; //default to inbox
13
+ }
14
+ else if (utils.getType(type) !== "String") throw { error: "Please pass a String as a third argument. Your options are: inbox, pending, and archived" };
15
+ else throw { error: "getThreadList: need callback" };
16
+ }
17
+
18
+ if (type === "archived") type = "action:archived";
19
+ else if (type !== "inbox" && type !== "pending" && type !== "other") throw { error: "type can only be one of the following: inbox, pending, archived, other" };
20
+
21
+
22
+ if (end <= start) end = start + 20;
23
+
24
+ var form = {
25
+ client: "mercury"
26
+ };
27
+
28
+ form[type + "[offset]"] = start;
29
+ form[type + "[limit]"] = end - start;
30
+
31
+ if (ctx.globalOptions.pageID) form.request_user_id = ctx.globalOptions.pageID;
32
+
33
+ defaultFuncs
34
+ .post("https://www.facebook.com/ajax/mercury/threadlist_info.php", ctx.jar, form)
35
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(function (resData) {
37
+ if (resData.error) throw resData;
38
+ log.verbose("getThreadList", JSON.stringify(resData.payload.threads));
39
+ return callback(null, (resData.payload.threads || []).map(utils.formatThread));
40
+ })
41
+ .catch(function (err) {
42
+ log.error("getThreadList", err);
43
+ return callback(err);
44
+ });
45
+ };
46
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ return function getThreadPictures(threadID, offset, limit, callback) {
8
+ var resolveFunc = function () { };
9
+ var rejectFunc = function () { };
10
+ var returnPromise = new Promise(function (resolve, reject) {
11
+ resolveFunc = resolve;
12
+ rejectFunc = reject;
13
+ });
14
+
15
+ if (!callback) {
16
+ callback = function (err, data) {
17
+ if (err) return rejectFunc(err);
18
+ resolveFunc(data);
19
+ };
20
+ }
21
+
22
+ var form = {
23
+ thread_id: threadID,
24
+ offset: offset,
25
+ limit: limit
26
+ };
27
+
28
+ defaultFuncs
29
+ .post("https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", ctx.jar, form)
30
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
31
+ .then(function (resData) {
32
+ if (resData.error) throw resData;
33
+ return Promise.all(
34
+ resData.payload.imagesData.map(function (image) {
35
+ form = {
36
+ thread_id: threadID,
37
+ image_id: image.fbid
38
+ };
39
+ return defaultFuncs
40
+ .post("https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", ctx.jar, form)
41
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
42
+ .then(function (resData) {
43
+ if (resData.error) throw resData;
44
+ // the response is pretty messy
45
+ var queryThreadID = resData.jsmods.require[0][3][1].query_metadata.query_path[0].message_thread;
46
+ var imageData = resData.jsmods.require[0][3][1].query_results[queryThreadID].message_images.edges[0].node.image2;
47
+ return imageData;
48
+ });
49
+ })
50
+ );
51
+ })
52
+ .then(resData => callback(null, resData))
53
+ .catch(function (err) {
54
+ log.error("Error in getThreadPictures", err);
55
+ callback(err);
56
+ });
57
+ return returnPromise;
58
+ };
59
+ };
@@ -17,21 +17,19 @@ function formatData(data) {
17
17
  };
18
18
  }
19
19
 
20
- module.exports = function(defaultFuncs, api, ctx) {
20
+ module.exports = function (defaultFuncs, api, ctx) {
21
21
  return function getUserID(name, callback) {
22
- var resolveFunc = function(){};
23
- var rejectFunc = function(){};
22
+ var resolveFunc = function () { };
23
+ var rejectFunc = function () { };
24
24
  var returnPromise = new Promise(function (resolve, reject) {
25
25
  resolveFunc = resolve;
26
26
  rejectFunc = reject;
27
27
  });
28
28
 
29
29
  if (!callback) {
30
- callback = function (err, friendList) {
31
- if (err) {
32
- return rejectFunc(err);
33
- }
34
- resolveFunc(friendList);
30
+ callback = function (err, data) {
31
+ if (err) return rejectFunc(err);
32
+ resolveFunc(data);
35
33
  };
36
34
  }
37
35
 
@@ -47,16 +45,13 @@ module.exports = function(defaultFuncs, api, ctx) {
47
45
  defaultFuncs
48
46
  .get("https://www.facebook.com/ajax/typeahead/search.php", ctx.jar, form)
49
47
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
50
- .then(function(resData) {
51
- if (resData.error) {
52
- throw resData;
53
- }
48
+ .then(function (resData) {
49
+ if (resData.error) throw resData;
54
50
 
55
51
  var data = resData.payload.entries;
56
-
57
52
  callback(null, data.map(formatData));
58
53
  })
59
- .catch(function(err) {
54
+ .catch(function (err) {
60
55
  log.error("getUserID", err);
61
56
  return callback(err);
62
57
  });
@@ -19,7 +19,7 @@ function formatData(data) {
19
19
  gender: innerObj.gender,
20
20
  type: innerObj.type,
21
21
  isFriend: innerObj.is_friend,
22
- isBirthday: innerObj.is_birthday
22
+ isBirthday: !!innerObj.is_birthday
23
23
  };
24
24
  }
25
25
  }
@@ -27,43 +27,37 @@ function formatData(data) {
27
27
  return retObj;
28
28
  }
29
29
 
30
- module.exports = function(defaultFuncs, api, ctx) {
30
+ module.exports = function (defaultFuncs, api, ctx) {
31
31
  return function getUserInfo(id, callback) {
32
- var resolveFunc = function(){};
33
- var rejectFunc = function(){};
32
+ var resolveFunc = function () { };
33
+ var rejectFunc = function () { };
34
34
  var returnPromise = new Promise(function (resolve, reject) {
35
35
  resolveFunc = resolve;
36
36
  rejectFunc = reject;
37
37
  });
38
38
 
39
39
  if (!callback) {
40
- callback = function (err, friendList) {
41
- if (err) {
42
- return rejectFunc(err);
43
- }
44
- resolveFunc(friendList);
40
+ callback = function (err, userInfo) {
41
+ if (err) return rejectFunc(err);
42
+ resolveFunc(userInfo);
45
43
  };
46
44
  }
47
45
 
48
- if (utils.getType(id) !== "Array") {
49
- id = [id];
50
- }
46
+ if (utils.getType(id) !== "Array") id = [id];
51
47
 
52
48
  var form = {};
53
- id.map(function(v, i) {
49
+ id.map(function (v, i) {
54
50
  form["ids[" + i + "]"] = v;
55
51
  });
56
52
  defaultFuncs
57
53
  .post("https://www.facebook.com/chat/user_info/", ctx.jar, form)
58
54
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
59
- .then(function(resData) {
60
- if (resData.error) {
61
- throw resData;
62
- }
55
+ .then(function (resData) {
56
+ if (resData.error) throw resData;
63
57
  return callback(null, formatData(resData.payload.profiles));
64
58
  })
65
- .catch(function(err) {
66
- log.error("getUserInfo", err);
59
+ .catch(function (err) {
60
+ log.error("getUserInfo", "Can't get user info");
67
61
  return callback(err);
68
62
  });
69
63