@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
@@ -1,168 +1,233 @@
1
1
  "use strict";
2
2
 
3
3
  const utils = require("../utils");
4
+ const log = require("npmlog");
4
5
 
5
- // চ্যাট ইভেন্ট রিমাইন্ডার মেটাডাটা ফরম্যাট করার ফাংশন
6
- function formatEventReminders(reminder) {
7
- return {
8
- reminderID: reminder.id,
9
- eventCreatorID: reminder.lightweight_event_creator?.id,
10
- time: reminder.time,
11
- eventType: reminder.lightweight_event_type?.toLowerCase(),
12
- locationName: reminder.location_name,
13
- locationCoordinates: reminder.location_coordinates,
14
- locationPage: reminder.location_page,
15
- eventStatus: reminder.lightweight_event_status?.toLowerCase(),
16
- note: reminder.note,
17
- repeatMode: reminder.repeat_mode?.toLowerCase(),
18
- eventTitle: reminder.event_title,
19
- triggerMessage: reminder.trigger_message,
20
- secondsToNotifyBefore: reminder.seconds_to_notify_before,
21
- allowsRsvp: reminder.allows_rsvp,
22
- relatedEvent: reminder.related_event,
23
- members: (reminder.event_reminder_members?.edges || []).map(member => ({
24
- memberID: member.node?.id,
25
- state: member.guest_list_state?.toLowerCase(),
26
- })),
27
- };
6
+ function createProfileUrl(url, username, id) {
7
+ if (url) return url;
8
+ return (
9
+ "https://www.facebook.com/" + (username || utils.formatID(id.toString()))
10
+ );
28
11
  }
29
12
 
30
- // গ্রাফকিউএল থ্রেড রেসপন্স ক্লিন অবজেক্টে রূপান্তর করার ফাংশন
31
- function formatThreadGraphQLResponse(messageThread) {
32
- const threadID = messageThread.thread_key?.thread_fbid || messageThread.thread_key?.other_user_id;
33
-
34
- const lastM = messageThread.last_message;
35
- const snippetID = lastM?.nodes?.[0]?.message_sender?.messaging_actor?.id || null;
36
- const snippetText = lastM?.nodes?.[0]?.snippet || null;
37
- const lastR = messageThread.last_read_receipt;
38
- const lastReadTimestamp = lastR?.nodes?.[0]?.timestamp_precise || null;
39
-
40
- return {
41
- threadID: threadID,
42
- threadName: messageThread.name,
43
- participantIDs: (messageThread.all_participants?.edges || []).map(
44
- d => d.node?.messaging_actor?.id
45
- ),
46
- userInfo: (messageThread.all_participants?.edges || []).map(d => ({
47
- id: d.node?.messaging_actor?.id,
48
- name: d.node?.messaging_actor?.name,
49
- firstName: d.node?.messaging_actor?.short_name,
50
- vanity: d.node?.messaging_actor?.username,
51
- url: d.node?.messaging_actor?.url,
52
- thumbSrc: d.node?.messaging_actor?.big_image_src?.uri,
53
- profileUrl: d.node?.messaging_actor?.big_image_src?.uri,
54
- gender: d.node?.messaging_actor?.gender,
55
- type: d.node?.messaging_actor?.__typename,
56
- isFriend: d.node?.messaging_actor?.is_viewer_friend,
57
- isBirthday: !!d.node?.messaging_actor?.is_birthday,
58
- })),
59
- unreadCount: messageThread.unread_count,
60
- messageCount: messageThread.messages_count,
61
- timestamp: messageThread.updated_time_precise,
62
- muteUntil: messageThread.mute_until,
63
- isGroup: messageThread.thread_type === "GROUP",
64
- isSubscribed: messageThread.is_viewer_subscribed,
65
- isArchived: messageThread.has_viewer_archived,
66
- folder: messageThread.folder,
67
- cannotReplyReason: messageThread.cannot_reply_reason,
68
- eventReminders: messageThread.event_reminders
69
- ? messageThread.event_reminders.nodes.map(formatEventReminders)
70
- : null,
71
- emoji: messageThread.customization_info?.emoji || null,
72
- color: messageThread.customization_info?.outgoing_bubble_color
73
- ? messageThread.customization_info.outgoing_bubble_color.slice(2)
74
- : null,
75
- threadTheme: messageThread.thread_theme,
76
- nicknames: messageThread.customization_info?.participant_customizations
77
- ? messageThread.customization_info.participant_customizations.reduce((res, val) => {
78
- if (val.nickname) res[val.participant_id] = val.nickname;
79
- return res;
80
- }, {})
81
- : {},
82
- adminIDs: messageThread.thread_admins,
83
- approvalMode: Boolean(messageThread.approval_mode),
84
- approvalQueue: (messageThread.group_approval_queue?.nodes || []).map(a => ({
85
- inviterID: a.inviter?.id,
86
- requesterID: a.requester?.id,
87
- timestamp: a.request_timestamp,
88
- request_source: a.request_source,
89
- })),
90
- reactionsMuteMode: messageThread.reactions_mute_mode?.toLowerCase(),
91
- mentionsMuteMode: messageThread.mentions_mute_mode?.toLowerCase(),
92
- isPinProtected: messageThread.is_pin_protected,
93
- relatedPageThread: messageThread.related_page_thread,
94
- name: messageThread.name,
95
- snippet: snippetText,
96
- snippetSender: snippetID,
97
- snippetAttachments: [],
98
- serverTimestamp: messageThread.updated_time_precise,
99
- imageSrc: messageThread.image?.uri || null,
100
- isCanonicalUser: messageThread.is_canonical_neo_user,
101
- isCanonical: messageThread.thread_type !== "GROUP",
102
- recipientsLoadable: true,
103
- hasEmailParticipant: false,
104
- readOnly: false,
105
- canReply: messageThread.cannot_reply_reason == null,
106
- lastMessageTimestamp: messageThread.last_message?.timestamp_precise || null,
107
- lastMessageType: "message",
108
- lastReadTimestamp: lastReadTimestamp,
109
- threadType: messageThread.thread_type === "GROUP" ? 2 : 1,
110
- inviteLink: {
111
- enable: messageThread.joinable_mode ? messageThread.joinable_mode.mode === 1 : false,
112
- link: messageThread.joinable_mode ? messageThread.joinable_mode.link : null,
113
- },
114
- };
13
+ function formatParticipants(participants) {
14
+ return participants.edges.map((p) => {
15
+ p = p.node.messaging_actor;
16
+ switch (p["__typename"]) {
17
+ case "User":
18
+ return {
19
+ accountType: p["__typename"],
20
+ userID: utils.formatID(p.id.toString()), // do we need .toString()? when it is not a string?
21
+ name: p.name,
22
+ shortName: p.short_name,
23
+ gender: p.gender,
24
+ url: p.url, // how about making it profileURL
25
+ profilePicture: p.big_image_src.uri,
26
+ username: p.username || null,
27
+ // TODO: maybe better names for these?
28
+ isViewerFriend: p.is_viewer_friend, // true/false
29
+ isMessengerUser: p.is_messenger_user, // true/false
30
+ isVerified: p.is_verified, // true/false
31
+ isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
32
+ isViewerCoworker: p.is_viewer_coworker, // true/false
33
+ isEmployee: p.is_employee, // null? when it is something other? can someone check?
34
+ };
35
+ case "Page":
36
+ return {
37
+ accountType: p["__typename"],
38
+ userID: utils.formatID(p.id.toString()), // or maybe... pageID?
39
+ name: p.name,
40
+ url: p.url,
41
+ profilePicture: p.big_image_src.uri,
42
+ username: p.username || null,
43
+ // uhm... better names maybe?
44
+ acceptsMessengerUserFeedback: p.accepts_messenger_user_feedback, // true/false
45
+ isMessengerUser: p.is_messenger_user, // true/false
46
+ isVerified: p.is_verified, // true/false
47
+ isMessengerPlatformBot: p.is_messenger_platform_bot, // true/false
48
+ isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
49
+ };
50
+ case "ReducedMessagingActor":
51
+ return {
52
+ accountType: p["__typename"],
53
+ userID: utils.formatID(p.id.toString()),
54
+ name: p.name,
55
+ url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
56
+ profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
57
+ username: p.username || null, // maybe we could use it to generate profile URL?
58
+ isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
59
+ };
60
+ case "UnavailableMessagingActor":
61
+ return {
62
+ accountType: p["__typename"],
63
+ userID: utils.formatID(p.id.toString()),
64
+ name: p.name, // "Facebook User" in user's language
65
+ url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
66
+ profilePicture: p.big_image_src.uri, // default male facebook photo
67
+ username: p.username || null, // maybe we could use it to generate profile URL?
68
+ isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
69
+ };
70
+ default:
71
+ log.warn(
72
+ "getThreadList",
73
+ "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/fca-unofficial/issues\n" +
74
+ JSON.stringify(p, null, 2),
75
+ );
76
+ return {
77
+ accountType: p["__typename"],
78
+ userID: utils.formatID(p.id.toString()),
79
+ name: p.name || `[unknown ${p["__typename"]}]`, // probably it will always be something... but fallback to [unknown], just in case
80
+ };
81
+ }
82
+ });
83
+ }
84
+
85
+ // "FF8C0077" -> "8C0077"
86
+ function formatColor(color) {
87
+ if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g)) {
88
+ return color.slice(2);
89
+ }
90
+ return color;
91
+ }
92
+
93
+ function getThreadName(t) {
94
+ if (t.name || t.thread_key.thread_fbid) return t.name;
95
+
96
+ for (let po of t.all_participants.edges) {
97
+ let p = po.node;
98
+ if (p.messaging_actor.id === t.thread_key.other_user_id)
99
+ return p.messaging_actor.name;
100
+ }
101
+ }
102
+
103
+ function mapNicknames(customizationInfo) {
104
+ return customizationInfo && customizationInfo.participant_customizations
105
+ ? customizationInfo.participant_customizations.map((u) => {
106
+ return {
107
+ userID: u.participant_id,
108
+ nickname: u.nickname,
109
+ };
110
+ })
111
+ : [];
115
112
  }
116
113
 
117
114
  function formatThreadList(data) {
118
- return data.map(t => formatThreadGraphQLResponse(t));
115
+ return data.map((t) => {
116
+ let lastMessageNode =
117
+ t.last_message && t.last_message.nodes && t.last_message.nodes.length > 0
118
+ ? t.last_message.nodes[0]
119
+ : null;
120
+ return {
121
+ threadID: t.thread_key
122
+ ? utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id)
123
+ : null, // shall never be null
124
+ name: getThreadName(t),
125
+ unreadCount: t.unread_count,
126
+ messageCount: t.messages_count,
127
+ imageSrc: t.image ? t.image.uri : null,
128
+ emoji: t.customization_info ? t.customization_info.emoji : null,
129
+ color: formatColor(
130
+ t.customization_info
131
+ ? t.customization_info.outgoing_bubble_color
132
+ : null,
133
+ ),
134
+ nicknames: mapNicknames(t.customization_info),
135
+ muteUntil: t.mute_until,
136
+ participants: formatParticipants(t.all_participants),
137
+ adminIDs: t.thread_admins.map((a) => a.id),
138
+ folder: t.folder,
139
+ isGroup: t.thread_type === "GROUP",
140
+ // rtc_call_data: t.rtc_call_data, // TODO: format and document this
141
+ // isPinProtected: t.is_pin_protected, // feature from future? always false (2018-04-04)
142
+ customizationEnabled: t.customization_enabled, // false for ONE_TO_ONE with Page or ReducedMessagingActor
143
+ participantAddMode: t.participant_add_mode_as_string, // "ADD" if "GROUP" and null if "ONE_TO_ONE"
144
+ montageThread: t.montage_thread
145
+ ? Buffer.from(t.montage_thread.id, "base64").toString()
146
+ : null, // base64 encoded string "message_thread:0000000000000000"
147
+ // it is not userID nor any other ID known to me...
148
+ // can somebody inspect it? where is it used?
149
+ // probably Messenger Day uses it
150
+ reactionsMuteMode: t.reactions_mute_mode,
151
+ mentionsMuteMode: t.mentions_mute_mode,
152
+ isArchived: t.has_viewer_archived,
153
+ isSubscribed: t.is_viewer_subscribed,
154
+ timestamp: t.updated_time_precise, // in miliseconds
155
+ // isCanonicalUser: t.is_canonical_neo_user, // is it always false?
156
+ // TODO: how about putting snippet in another object? current implementation does not handle every possibile message type etc.
157
+ snippet: lastMessageNode ? lastMessageNode.snippet : null,
158
+ snippetAttachments: lastMessageNode
159
+ ? lastMessageNode.extensible_attachment
160
+ : null, // TODO: not sure if it works
161
+ snippetSender: lastMessageNode
162
+ ? utils.formatID(
163
+ (
164
+ lastMessageNode.message_sender.messaging_actor.id || ""
165
+ ).toString(),
166
+ )
167
+ : null,
168
+ lastMessageTimestamp: lastMessageNode
169
+ ? lastMessageNode.timestamp_precise
170
+ : null, // timestamp in miliseconds
171
+ lastReadTimestamp:
172
+ t.last_read_receipt && t.last_read_receipt.nodes.length > 0
173
+ ? t.last_read_receipt.nodes[0]
174
+ ? t.last_read_receipt.nodes[0].timestamp_precise
175
+ : null
176
+ : null, // timestamp in miliseconds
177
+ cannotReplyReason: t.cannot_reply_reason, // TODO: inspect possible values
178
+ approvalMode: Boolean(t.approval_mode),
179
+
180
+ // @Legacy
181
+ participantIDs: formatParticipants(t.all_participants).map(
182
+ (participant) => participant.userID,
183
+ ),
184
+ threadType: t.thread_type === "GROUP" ? 2 : 1, // "GROUP" or "ONE_TO_ONE"
185
+ };
186
+ });
119
187
  }
120
188
 
121
189
  module.exports = function (defaultFuncs, api, ctx) {
122
190
  return function getThreadList(limit, timestamp, tags, callback) {
123
191
  if (
124
192
  !callback &&
125
- (utils.getType(tags) === "Function" || utils.getType(tags) === "AsyncFunction")
193
+ (utils.getType(tags) === "Function" ||
194
+ utils.getType(tags) === "AsyncFunction")
126
195
  ) {
127
196
  callback = tags;
128
197
  tags = [""];
129
198
  }
130
-
131
- if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0) {
132
- throw new utils.CustomError({
133
- error: "getThreadList: limit must be a positive integer",
134
- });
199
+ if (
200
+ utils.getType(limit) !== "Number" ||
201
+ !Number.isInteger(limit) ||
202
+ limit <= 0
203
+ ) {
204
+ throw { error: "getThreadList: limit must be a positive integer" };
135
205
  }
136
-
137
206
  if (
138
207
  utils.getType(timestamp) !== "Null" &&
139
208
  (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
140
209
  ) {
141
- throw new utils.CustomError({
142
- error: "getThreadList: timestamp must be an integer or null",
143
- });
210
+ throw { error: "getThreadList: timestamp must be an integer or null" };
144
211
  }
145
-
146
212
  if (utils.getType(tags) === "String") {
147
213
  tags = [tags];
148
214
  }
149
-
150
215
  if (utils.getType(tags) !== "Array") {
151
- throw new utils.CustomError({
152
- error: "getThreadList: tags must be an array",
153
- message: "getThreadList: tags must be an array",
154
- });
216
+ throw { error: "getThreadList: tags must be an array" };
155
217
  }
156
218
 
157
- let resolveFunc = () => {};
158
- let rejectFunc = () => {};
159
- const returnPromise = new Promise((resolve, reject) => {
219
+ var resolveFunc = function () {};
220
+ var rejectFunc = function () {};
221
+ var returnPromise = new Promise(function (resolve, reject) {
160
222
  resolveFunc = resolve;
161
223
  rejectFunc = reject;
162
224
  });
163
225
 
164
- if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
165
- callback = (err, data) => {
226
+ if (
227
+ utils.getType(callback) !== "Function" &&
228
+ utils.getType(callback) !== "AsyncFunction"
229
+ ) {
230
+ callback = function (err, data) {
166
231
  if (err) {
167
232
  return rejectFunc(err);
168
233
  }
@@ -171,10 +236,11 @@ module.exports = function (defaultFuncs, api, ctx) {
171
236
  }
172
237
 
173
238
  const form = {
174
- av: ctx.i_userID || ctx.userID,
239
+ av: ctx.globalOptions.pageID,
175
240
  queries: JSON.stringify({
176
241
  o0: {
177
- doc_id: "3426149104143726",
242
+ // This doc_id was valid on 2020-07-20
243
+ doc_id: "3336396659757871",
178
244
  query_params: {
179
245
  limit: limit + (timestamp ? 1 : 0),
180
246
  before: timestamp,
@@ -190,27 +256,34 @@ module.exports = function (defaultFuncs, api, ctx) {
190
256
  defaultFuncs
191
257
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
192
258
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
193
- .then(resData => {
259
+ .then((resData) => {
194
260
  if (resData[resData.length - 1].error_results > 0) {
195
- throw new utils.CustomError(resData[0].o0.errors);
261
+ throw resData[0].o0.errors;
196
262
  }
197
263
 
198
264
  if (resData[resData.length - 1].successful_results === 0) {
199
- throw new utils.CustomError({
265
+ throw {
200
266
  error: "getThreadList: there was no successful_results",
201
267
  res: resData,
202
- });
268
+ };
203
269
  }
204
270
 
205
- const threads = resData[0].o0.data.viewer.message_threads.nodes;
206
- if (timestamp && threads.length > 0) {
207
- threads.shift();
271
+ // When we ask for threads using timestamp from the previous request,
272
+ // we are getting the last thread repeated as the first thread in this response.
273
+ // .shift() gets rid of it
274
+ // It is also the reason for increasing limit by 1 when timestamp is set
275
+ // this way user asks for 10 threads, we are asking for 11,
276
+ // but after removing the duplicated one, it is again 10
277
+ if (timestamp) {
278
+ resData[0].o0.data.viewer.message_threads.nodes.shift();
208
279
  }
209
-
210
- callback(null, formatThreadList(threads));
280
+ callback(
281
+ null,
282
+ formatThreadList(resData[0].o0.data.viewer.message_threads.nodes),
283
+ );
211
284
  })
212
- .catch(err => {
213
- utils.error("getThreadList", err);
285
+ .catch((err) => {
286
+ log.error("getThreadList", err);
214
287
  return callback(err);
215
288
  });
216
289
 
@@ -1,18 +1,19 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../utils");
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
4
5
 
5
6
  module.exports = function (defaultFuncs, api, ctx) {
6
7
  return function getThreadPictures(threadID, offset, limit, callback) {
7
- let resolveFunc = () => {};
8
- let rejectFunc = () => {};
9
- const returnPromise = new Promise((resolve, reject) => {
8
+ var resolveFunc = function () {};
9
+ var rejectFunc = function () {};
10
+ var returnPromise = new Promise(function (resolve, reject) {
10
11
  resolveFunc = resolve;
11
12
  rejectFunc = reject;
12
13
  });
13
14
 
14
15
  if (!callback) {
15
- callback = (err, friendList) => {
16
+ callback = function (err, friendList) {
16
17
  if (err) {
17
18
  return rejectFunc(err);
18
19
  }
@@ -20,7 +21,7 @@ module.exports = function (defaultFuncs, api, ctx) {
20
21
  };
21
22
  }
22
23
 
23
- const initialForm = {
24
+ var form = {
24
25
  thread_id: threadID,
25
26
  offset: offset,
26
27
  limit: limit,
@@ -30,56 +31,49 @@ module.exports = function (defaultFuncs, api, ctx) {
30
31
  .post(
31
32
  "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
32
33
  ctx.jar,
33
- initialForm,
34
+ form,
34
35
  )
35
36
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
36
- .then(resData => {
37
+ .then(function (resData) {
37
38
  if (resData.error) {
38
39
  throw resData;
39
40
  }
40
-
41
- // প্রতিটি ইমেজের জন্য আলাদা আলাদা রিকোয়েস্ট পাঠানো হচ্ছে
42
41
  return Promise.all(
43
- (resData.payload?.imagesData || []).map(image => {
44
- // বাগ ফিক্স: ভেতরের ফর্মকে লোকাল কনস্ট্যান্ট করা হলো যেন ডাটা ওভাররাইট না হয়
45
- const innerForm = {
42
+ resData.payload.imagesData.map(function (image) {
43
+ form = {
46
44
  thread_id: threadID,
47
45
  image_id: image.fbid,
48
46
  };
49
-
50
47
  return defaultFuncs
51
48
  .post(
52
49
  "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
53
50
  ctx.jar,
54
- innerForm,
51
+ form,
55
52
  )
56
53
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
57
- .then(innerResData => {
58
- if (innerResData.error) {
59
- throw innerResData;
54
+ .then(function (resData) {
55
+ if (resData.error) {
56
+ throw resData;
60
57
  }
61
-
62
- // অপশনাল চেইনিং ব্যবহার করে ক্র্যাশ সেফটি নিশ্চিত করা হলো
63
- const requireData = innerResData.jsmods?.require?.[0]?.[3]?.[1];
64
- if (!requireData) return null;
65
-
66
- const queryThreadID = requireData.query_metadata?.query_path?.[0]?.message_thread;
67
- const imageData = requireData.query_results?.[queryThreadID]?.message_images?.edges?.[0]?.node?.image2;
68
-
58
+ // the response is pretty messy
59
+ var queryThreadID =
60
+ resData.jsmods.require[0][3][1].query_metadata.query_path[0]
61
+ .message_thread;
62
+ var imageData =
63
+ resData.jsmods.require[0][3][1].query_results[queryThreadID]
64
+ .message_images.edges[0].node.image2;
69
65
  return imageData;
70
66
  });
71
67
  }),
72
68
  );
73
69
  })
74
- .then(resData => {
75
- // নাল ভ্যালুগুলো ফিল্টার করে শুধু ভ্যালিড ইমেজ ডাটা পাঠানো হচ্ছে
76
- callback(null, resData.filter(img => img !== null));
70
+ .then(function (resData) {
71
+ callback(null, resData);
77
72
  })
78
- .catch(err => {
79
- utils.error("Error in getThreadPictures", err);
73
+ .catch(function (err) {
74
+ log.error("Error in getThreadPictures", err);
80
75
  callback(err);
81
76
  });
82
-
83
77
  return returnPromise;
84
78
  };
85
79
  };
package/src/getUserID.js CHANGED
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../utils");
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
4
5
 
5
- // সার্চ রেজাল্টের ডাটা ফরম্যাট করার হেল্পার ফাংশন
6
6
  function formatData(data) {
7
7
  return {
8
- userID: data.uid ? utils.formatID(data.uid.toString()) : null,
8
+ userID: utils.formatID(data.uid.toString()),
9
9
  photoUrl: data.photo,
10
10
  indexRank: data.index_rank,
11
11
  name: data.text,
@@ -19,15 +19,15 @@ function formatData(data) {
19
19
 
20
20
  module.exports = function (defaultFuncs, api, ctx) {
21
21
  return function getUserID(name, callback) {
22
- let resolveFunc = () => {};
23
- let rejectFunc = () => {};
24
- const returnPromise = new Promise((resolve, reject) => {
22
+ var resolveFunc = function () {};
23
+ var rejectFunc = function () {};
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 = (err, friendList) => {
30
+ callback = function (err, friendList) {
31
31
  if (err) {
32
32
  return rejectFunc(err);
33
33
  }
@@ -35,7 +35,7 @@ module.exports = function (defaultFuncs, api, ctx) {
35
35
  };
36
36
  }
37
37
 
38
- const form = {
38
+ var form = {
39
39
  value: name.toLowerCase(),
40
40
  viewer: ctx.userID,
41
41
  rsp: "search",
@@ -47,18 +47,17 @@ module.exports = function (defaultFuncs, api, ctx) {
47
47
  defaultFuncs
48
48
  .get("https://www.facebook.com/ajax/typeahead/search.php", ctx.jar, form)
49
49
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
50
- .then(resData => {
50
+ .then(function (resData) {
51
51
  if (resData.error) {
52
52
  throw resData;
53
53
  }
54
54
 
55
- // অপশনাল চেইনিং ব্যবহার করে ক্র্যাশ সেফটি নিশ্চিত করা হলো
56
- const entries = resData.payload?.entries || [];
55
+ var data = resData.payload.entries;
57
56
 
58
- callback(null, entries.map(formatData));
57
+ callback(null, data.map(formatData));
59
58
  })
60
- .catch(err => {
61
- utils.error("getUserID", err);
59
+ .catch(function (err) {
60
+ log.error("getUserID", err);
62
61
  return callback(err);
63
62
  });
64
63