fca-neokex-fix 1.0.1
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.
- package/CHANGELOG.md +220 -0
- package/LICENSE +26 -0
- package/README.md +346 -0
- package/THEME_FEATURES.md +137 -0
- package/examples/README.md +131 -0
- package/examples/apply-ai-theme.js +127 -0
- package/examples/check-current-theme.js +74 -0
- package/examples/simple-bot.js +114 -0
- package/examples/test-bot.js +752 -0
- package/examples/test-logging.js +85 -0
- package/examples/theme-usage-example.js +53 -0
- package/index.js +2 -0
- package/package.json +105 -0
- package/src/apis/addExternalModule.js +24 -0
- package/src/apis/addUserToGroup.js +108 -0
- package/src/apis/changeAdminStatus.js +148 -0
- package/src/apis/changeArchivedStatus.js +61 -0
- package/src/apis/changeAvatar.js +103 -0
- package/src/apis/changeBio.js +69 -0
- package/src/apis/changeBlockedStatus.js +54 -0
- package/src/apis/changeGroupImage.js +136 -0
- package/src/apis/changeThreadColor.js +116 -0
- package/src/apis/comment.js +207 -0
- package/src/apis/createAITheme.js +129 -0
- package/src/apis/createNewGroup.js +79 -0
- package/src/apis/createPoll.js +73 -0
- package/src/apis/deleteMessage.js +44 -0
- package/src/apis/deleteThread.js +52 -0
- package/src/apis/editMessage.js +70 -0
- package/src/apis/emoji.js +124 -0
- package/src/apis/fetchThemeData.js +65 -0
- package/src/apis/follow.js +81 -0
- package/src/apis/forwardMessage.js +52 -0
- package/src/apis/friend.js +243 -0
- package/src/apis/gcmember.js +122 -0
- package/src/apis/gcname.js +123 -0
- package/src/apis/gcrule.js +119 -0
- package/src/apis/getAccess.js +111 -0
- package/src/apis/getBotInfo.js +88 -0
- package/src/apis/getBotInitialData.js +43 -0
- package/src/apis/getFriendsList.js +79 -0
- package/src/apis/getMessage.js +423 -0
- package/src/apis/getTheme.js +104 -0
- package/src/apis/getThemeInfo.js +96 -0
- package/src/apis/getThreadHistory.js +239 -0
- package/src/apis/getThreadInfo.js +257 -0
- package/src/apis/getThreadList.js +222 -0
- package/src/apis/getThreadPictures.js +58 -0
- package/src/apis/getUserID.js +83 -0
- package/src/apis/getUserInfo.js +495 -0
- package/src/apis/getUserInfoV2.js +146 -0
- package/src/apis/handleMessageRequest.js +50 -0
- package/src/apis/httpGet.js +63 -0
- package/src/apis/httpPost.js +89 -0
- package/src/apis/httpPostFormData.js +69 -0
- package/src/apis/listenMqtt.js +796 -0
- package/src/apis/listenSpeed.js +170 -0
- package/src/apis/logout.js +63 -0
- package/src/apis/markAsDelivered.js +47 -0
- package/src/apis/markAsRead.js +95 -0
- package/src/apis/markAsReadAll.js +41 -0
- package/src/apis/markAsSeen.js +70 -0
- package/src/apis/mqttDeltaValue.js +330 -0
- package/src/apis/muteThread.js +45 -0
- package/src/apis/nickname.js +132 -0
- package/src/apis/notes.js +163 -0
- package/src/apis/pinMessage.js +141 -0
- package/src/apis/produceMetaTheme.js +180 -0
- package/src/apis/realtime.js +161 -0
- package/src/apis/removeUserFromGroup.js +117 -0
- package/src/apis/resolvePhotoUrl.js +58 -0
- package/src/apis/searchForThread.js +154 -0
- package/src/apis/sendMessage.js +281 -0
- package/src/apis/sendMessageMqtt.js +188 -0
- package/src/apis/sendTypingIndicator.js +41 -0
- package/src/apis/setMessageReaction.js +27 -0
- package/src/apis/setMessageReactionMqtt.js +61 -0
- package/src/apis/setThreadTheme.js +260 -0
- package/src/apis/setThreadThemeMqtt.js +94 -0
- package/src/apis/share.js +107 -0
- package/src/apis/shareContact.js +66 -0
- package/src/apis/stickers.js +257 -0
- package/src/apis/story.js +181 -0
- package/src/apis/theme.js +233 -0
- package/src/apis/unfriend.js +47 -0
- package/src/apis/unsendMessage.js +17 -0
- package/src/database/appStateBackup.js +189 -0
- package/src/database/models/index.js +56 -0
- package/src/database/models/thread.js +31 -0
- package/src/database/models/user.js +32 -0
- package/src/database/threadData.js +101 -0
- package/src/database/userData.js +90 -0
- package/src/engine/client.js +91 -0
- package/src/engine/models/buildAPI.js +109 -0
- package/src/engine/models/loginHelper.js +326 -0
- package/src/engine/models/setOptions.js +53 -0
- package/src/utils/auth-helpers.js +149 -0
- package/src/utils/autoReLogin.js +169 -0
- package/src/utils/axios.js +290 -0
- package/src/utils/clients.js +270 -0
- package/src/utils/constants.js +396 -0
- package/src/utils/formatters/data/formatAttachment.js +370 -0
- package/src/utils/formatters/data/formatDelta.js +153 -0
- package/src/utils/formatters/index.js +159 -0
- package/src/utils/formatters/value/formatCookie.js +91 -0
- package/src/utils/formatters/value/formatDate.js +36 -0
- package/src/utils/formatters/value/formatID.js +16 -0
- package/src/utils/formatters.js +1067 -0
- package/src/utils/headers.js +199 -0
- package/src/utils/index.js +151 -0
- package/src/utils/monitoring.js +358 -0
- package/src/utils/rateLimiter.js +380 -0
- package/src/utils/tokenRefresh.js +311 -0
- package/src/utils/user-agents.js +238 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
7
|
+
if (v.delta.class == "NewMessage") {
|
|
8
|
+
|
|
9
|
+
if (ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue) return;
|
|
10
|
+
(function resolveAttachmentUrl(i) {
|
|
11
|
+
if (!v.delta.attachments || i == v.delta.attachments.length || utils.getType(v.delta.attachments) !== "Array") {
|
|
12
|
+
var fmtMsg;
|
|
13
|
+
try {
|
|
14
|
+
fmtMsg = utils.formatDeltaMessage(v);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (fmtMsg) {
|
|
19
|
+
if (ctx.globalOptions.autoMarkDelivery) {
|
|
20
|
+
api.markAsDelivered(fmtMsg.threadID, fmtMsg.messageID);
|
|
21
|
+
}
|
|
22
|
+
if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
return globalCallback(null, fmtMsg);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
var attachment = v.delta.attachments[i];
|
|
29
|
+
if (attachment && attachment.mercury && attachment.mercury.attach_type == "photo") {
|
|
30
|
+
api.resolvePhotoUrl(attachment.fbid, (err, url) => {
|
|
31
|
+
if (!err) attachment.mercury.metadata.url = url;
|
|
32
|
+
return resolveAttachmentUrl(i + 1);
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
return resolveAttachmentUrl(i + 1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (v.delta.class == "ClientPayload") {
|
|
42
|
+
var clientPayload = utils.decodeClientPayload(v.delta.payload);
|
|
43
|
+
if (clientPayload && clientPayload.deltas) {
|
|
44
|
+
for (var i in clientPayload.deltas) {
|
|
45
|
+
var delta = clientPayload.deltas[i];
|
|
46
|
+
|
|
47
|
+
if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
|
|
48
|
+
const reactionEvent = {
|
|
49
|
+
type: "message_reaction",
|
|
50
|
+
threadID: (delta.deltaMessageReaction.threadKey.threadFbId || delta.deltaMessageReaction.threadKey.otherUserFbId).toString(),
|
|
51
|
+
messageID: delta.deltaMessageReaction.messageId,
|
|
52
|
+
reaction: delta.deltaMessageReaction.reaction,
|
|
53
|
+
senderID: delta.deltaMessageReaction.userId.toString(),
|
|
54
|
+
userID: delta.deltaMessageReaction.userId.toString()
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (!ctx.globalOptions.selfListen && reactionEvent.senderID === ctx.userID) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
globalCallback(null, reactionEvent);
|
|
62
|
+
} else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
|
|
63
|
+
globalCallback(null, {
|
|
64
|
+
type: "message_unsend",
|
|
65
|
+
threadID: (delta.deltaRecallMessageData.threadKey.threadFbId || delta.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
|
|
66
|
+
messageID: delta.deltaRecallMessageData.messageID,
|
|
67
|
+
senderID: delta.deltaRecallMessageData.senderID.toString(),
|
|
68
|
+
deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
|
|
69
|
+
timestamp: delta.deltaRecallMessageData.timestamp
|
|
70
|
+
});
|
|
71
|
+
} else if (delta.deltaMessageReply) {
|
|
72
|
+
// Parse mentions from multiple possible sources
|
|
73
|
+
var mdata = [];
|
|
74
|
+
var msg = delta.deltaMessageReply.message;
|
|
75
|
+
var msgBody = msg.body || "";
|
|
76
|
+
|
|
77
|
+
// Method 1: data.prng (old format)
|
|
78
|
+
if (msg?.data?.prng) {
|
|
79
|
+
try { mdata = JSON.parse(msg.data.prng); } catch (e) {}
|
|
80
|
+
}
|
|
81
|
+
// Method 2: data.mentions (newer format)
|
|
82
|
+
if (mdata.length === 0 && msg?.data?.mentions) {
|
|
83
|
+
try { mdata = JSON.parse(msg.data.mentions); } catch (e) {}
|
|
84
|
+
}
|
|
85
|
+
// Method 3: messageMetadata.ranges (latest format)
|
|
86
|
+
if (mdata.length === 0 && msg?.messageMetadata?.ranges) {
|
|
87
|
+
try {
|
|
88
|
+
mdata = msg.messageMetadata.ranges.map(r => ({
|
|
89
|
+
i: r.entity?.id || r.mentionID || r.id,
|
|
90
|
+
o: r.offset,
|
|
91
|
+
l: r.length
|
|
92
|
+
}));
|
|
93
|
+
} catch (e) {}
|
|
94
|
+
}
|
|
95
|
+
// Method 4: message.mentions directly
|
|
96
|
+
if (mdata.length === 0 && msg?.mentions) {
|
|
97
|
+
try {
|
|
98
|
+
if (Array.isArray(msg.mentions)) {
|
|
99
|
+
mdata = msg.mentions.map(mention => ({
|
|
100
|
+
i: mention.id || mention.i,
|
|
101
|
+
o: mention.offset || mention.o,
|
|
102
|
+
l: mention.length || mention.l
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
} catch (e) {}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var mentions = {};
|
|
109
|
+
if (mdata) {
|
|
110
|
+
mdata.forEach(m => {
|
|
111
|
+
if (m.i && msgBody) {
|
|
112
|
+
mentions[m.i] = msgBody.substring(m.o, m.o + m.l);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
var callbackToReturn = {
|
|
118
|
+
type: "message_reply",
|
|
119
|
+
threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId || delta.deltaMessageReply.message.messageMetadata.threadKey.otherUserFbId).toString(),
|
|
120
|
+
messageID: delta.deltaMessageReply.message.messageMetadata.messageId,
|
|
121
|
+
senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
|
|
122
|
+
attachments: delta.deltaMessageReply.message.attachments.map(att => {
|
|
123
|
+
try {
|
|
124
|
+
var mercury = JSON.parse(att.mercuryJSON);
|
|
125
|
+
Object.assign(att, mercury);
|
|
126
|
+
return utils._formatAttachment(att);
|
|
127
|
+
} catch (ex) {
|
|
128
|
+
return { ...att, error: ex, type: "unknown" };
|
|
129
|
+
}
|
|
130
|
+
}),
|
|
131
|
+
body: (delta.deltaMessageReply.message.body || ""),
|
|
132
|
+
isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
|
|
133
|
+
mentions: mentions,
|
|
134
|
+
timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
|
|
135
|
+
participantIDs: (delta.deltaMessageReply.message.participants || []).map(e => e.toString())
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
if (delta.deltaMessageReply.repliedToMessage) {
|
|
139
|
+
var rmdata = [];
|
|
140
|
+
var replyMsg = delta.deltaMessageReply.repliedToMessage;
|
|
141
|
+
var replyBody = replyMsg.body || "";
|
|
142
|
+
|
|
143
|
+
// Method 1: data.prng (old format)
|
|
144
|
+
if (replyMsg?.data?.prng) {
|
|
145
|
+
try { rmdata = JSON.parse(replyMsg.data.prng); } catch (e) {}
|
|
146
|
+
}
|
|
147
|
+
// Method 2: data.mentions (newer format)
|
|
148
|
+
if (rmdata.length === 0 && replyMsg?.data?.mentions) {
|
|
149
|
+
try { rmdata = JSON.parse(replyMsg.data.mentions); } catch (e) {}
|
|
150
|
+
}
|
|
151
|
+
// Method 3: messageMetadata.ranges (latest format)
|
|
152
|
+
if (rmdata.length === 0 && replyMsg?.messageMetadata?.ranges) {
|
|
153
|
+
try {
|
|
154
|
+
rmdata = replyMsg.messageMetadata.ranges.map(r => ({
|
|
155
|
+
i: r.entity?.id || r.mentionID || r.id,
|
|
156
|
+
o: r.offset,
|
|
157
|
+
l: r.length
|
|
158
|
+
}));
|
|
159
|
+
} catch (e) {}
|
|
160
|
+
}
|
|
161
|
+
// Method 4: mentions directly
|
|
162
|
+
if (rmdata.length === 0 && replyMsg?.mentions) {
|
|
163
|
+
try {
|
|
164
|
+
if (Array.isArray(replyMsg.mentions)) {
|
|
165
|
+
rmdata = replyMsg.mentions.map(mention => ({
|
|
166
|
+
i: mention.id || mention.i,
|
|
167
|
+
o: mention.offset || mention.o,
|
|
168
|
+
l: mention.length || mention.l
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
} catch (e) {}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
var rmentions = {};
|
|
175
|
+
if (rmdata) {
|
|
176
|
+
rmdata.forEach(m => {
|
|
177
|
+
if (m.i && replyBody) {
|
|
178
|
+
rmentions[m.i] = replyBody.substring(m.o, m.o + m.l);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
callbackToReturn.messageReply = {
|
|
184
|
+
threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId || delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.otherUserFbId).toString(),
|
|
185
|
+
messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
|
|
186
|
+
senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
|
|
187
|
+
attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(att => {
|
|
188
|
+
try {
|
|
189
|
+
var mercury = JSON.parse(att.mercuryJSON);
|
|
190
|
+
Object.assign(att, mercury);
|
|
191
|
+
return utils._formatAttachment(att);
|
|
192
|
+
} catch (ex) {
|
|
193
|
+
return { ...att, error: ex, type: "unknown" };
|
|
194
|
+
}
|
|
195
|
+
}),
|
|
196
|
+
body: delta.deltaMessageReply.repliedToMessage.body || "",
|
|
197
|
+
isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId,
|
|
198
|
+
mentions: rmentions,
|
|
199
|
+
timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp,
|
|
200
|
+
participantIDs: (delta.deltaMessageReply.repliedToMessage.participants || []).map(e => e.toString())
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (ctx.globalOptions.autoMarkDelivery) api.markAsDelivered(callbackToReturn.threadID, callbackToReturn.messageID);
|
|
204
|
+
if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
|
|
205
|
+
return globalCallback(null, callbackToReturn);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents) return;
|
|
213
|
+
switch (v.delta.class) {
|
|
214
|
+
case "ReadReceipt":
|
|
215
|
+
var fmtMsg;
|
|
216
|
+
try {
|
|
217
|
+
fmtMsg = utils.formatDeltaReadReceipt(v.delta);
|
|
218
|
+
} catch (err) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (fmtMsg) globalCallback(null, fmtMsg);
|
|
222
|
+
break;
|
|
223
|
+
case "AdminTextMessage":
|
|
224
|
+
switch (v.delta.type) {
|
|
225
|
+
case "instant_game_dynamic_custom_update":
|
|
226
|
+
case "accept_pending_thread":
|
|
227
|
+
case "confirm_friend_request":
|
|
228
|
+
case "shared_album_delete":
|
|
229
|
+
case "shared_album_addition":
|
|
230
|
+
case "pin_messages_v2":
|
|
231
|
+
case "unpin_messages_v2":
|
|
232
|
+
case "change_thread_theme":
|
|
233
|
+
case "change_thread_nickname":
|
|
234
|
+
case "change_thread_icon":
|
|
235
|
+
case "change_thread_quick_reaction":
|
|
236
|
+
case "change_thread_admins":
|
|
237
|
+
case "group_poll":
|
|
238
|
+
case "joinable_group_link_mode_change":
|
|
239
|
+
case "magic_words":
|
|
240
|
+
case "change_thread_approval_mode":
|
|
241
|
+
case "messenger_call_log":
|
|
242
|
+
case "participant_joined_group_call":
|
|
243
|
+
case "rtc_call_log":
|
|
244
|
+
case "update_vote":
|
|
245
|
+
var fmtEvent;
|
|
246
|
+
try {
|
|
247
|
+
fmtEvent = utils.formatDeltaEvent(v.delta);
|
|
248
|
+
} catch (err) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (fmtEvent) globalCallback(null, fmtEvent);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
case "ThreadName":
|
|
256
|
+
case "ParticipantsAddedToGroupThread":
|
|
257
|
+
case "ParticipantLeftGroupThread":
|
|
258
|
+
var fmtEvent2;
|
|
259
|
+
try {
|
|
260
|
+
fmtEvent2 = utils.formatDeltaEvent(v.delta);
|
|
261
|
+
} catch (err) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (!ctx.globalOptions.selfListen && fmtEvent2 && fmtEvent2.author && fmtEvent2.author.toString() === ctx.userID) return;
|
|
265
|
+
if (!ctx.loggedIn) return;
|
|
266
|
+
if (fmtEvent2) globalCallback(null, fmtEvent2);
|
|
267
|
+
break;
|
|
268
|
+
case "ForcedFetch":
|
|
269
|
+
if (!v.delta.threadKey) return;
|
|
270
|
+
var mid = v.delta.messageId;
|
|
271
|
+
var tid = v.delta.threadKey.threadFbId;
|
|
272
|
+
if (mid && tid) {
|
|
273
|
+
var form = {
|
|
274
|
+
av: ctx.globalOptions.pageID,
|
|
275
|
+
queries: JSON.stringify({
|
|
276
|
+
o0: {
|
|
277
|
+
doc_id: "2848441488556444",
|
|
278
|
+
query_params: {
|
|
279
|
+
thread_and_message_id: {
|
|
280
|
+
thread_id: tid.toString(),
|
|
281
|
+
message_id: mid
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
};
|
|
287
|
+
defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
|
288
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
289
|
+
.then(resData => {
|
|
290
|
+
if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
|
|
291
|
+
if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: no successful_results" };
|
|
292
|
+
var fetchData = resData[0].o0.data.message;
|
|
293
|
+
if (utils.getType(fetchData) === "Object") {
|
|
294
|
+
if (fetchData.__typename === "UserMessage" && fetchData.extensible_attachment) {
|
|
295
|
+
var event = {
|
|
296
|
+
type: "message",
|
|
297
|
+
senderID: utils.formatID(fetchData.message_sender.id),
|
|
298
|
+
body: fetchData.message.text || "",
|
|
299
|
+
threadID: utils.formatID(tid.toString()),
|
|
300
|
+
messageID: fetchData.message_id,
|
|
301
|
+
attachments: [{
|
|
302
|
+
type: "share",
|
|
303
|
+
ID: fetchData.extensible_attachment.legacy_attachment_id,
|
|
304
|
+
url: fetchData.extensible_attachment.story_attachment.url,
|
|
305
|
+
title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
|
|
306
|
+
description: fetchData.extensible_attachment.story_attachment.description ? fetchData.extensible_attachment.story_attachment.description.text : "",
|
|
307
|
+
source: fetchData.extensible_attachment.story_attachment.source,
|
|
308
|
+
image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
|
|
309
|
+
width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
|
|
310
|
+
height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
|
|
311
|
+
playable: ((fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false),
|
|
312
|
+
duration: ((fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0)
|
|
313
|
+
}],
|
|
314
|
+
mentions: {},
|
|
315
|
+
timestamp: parseInt(fetchData.timestamp_precise),
|
|
316
|
+
isGroup: fetchData.message_sender.id !== tid.toString()
|
|
317
|
+
};
|
|
318
|
+
globalCallback(null, event);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
.catch(err => {});
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
module.exports = {
|
|
329
|
+
parseDelta
|
|
330
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = (defaultFuncs, api, ctx) => {
|
|
6
|
+
return async function muteThread(threadID, muteSeconds, callback) {
|
|
7
|
+
let resolveFunc = () => {};
|
|
8
|
+
let rejectFunc = () => {};
|
|
9
|
+
const returnPromise = new Promise((resolve, reject) => {
|
|
10
|
+
resolveFunc = resolve;
|
|
11
|
+
rejectFunc = reject;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (!callback) {
|
|
15
|
+
callback = (err, result) => {
|
|
16
|
+
if (err) return rejectFunc(err);
|
|
17
|
+
resolveFunc(result);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const form = {
|
|
23
|
+
thread_fbid: threadID,
|
|
24
|
+
mute_settings: muteSeconds
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const res = await defaultFuncs.post(
|
|
28
|
+
"https://www.facebook.com/ajax/mercury/change_mute_thread.php",
|
|
29
|
+
ctx.jar,
|
|
30
|
+
form
|
|
31
|
+
).then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
32
|
+
|
|
33
|
+
if (res && res.error) {
|
|
34
|
+
throw res;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
callback(null, { success: true });
|
|
38
|
+
} catch (err) {
|
|
39
|
+
utils.error("muteThread", err);
|
|
40
|
+
callback(err);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return returnPromise;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
6
|
+
/**
|
|
7
|
+
* Made by Choru Official
|
|
8
|
+
* Mqtt
|
|
9
|
+
* Sets a nickname for a participant in a Facebook thread via MQTT.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} nickname The new nickname to set.
|
|
12
|
+
* @param {string} threadID The ID of the thread.
|
|
13
|
+
* @param {string} participantID The ID of the participant whose nickname will be changed. Defaults to the current user's ID if not provided or a function.
|
|
14
|
+
* @param {Function} [callback] Optional callback function to be invoked upon completion.
|
|
15
|
+
* @param {string} [initiatorID] The ID of the user who initiated the nickname change (e.g., from event.senderID).
|
|
16
|
+
* @returns {Promise<object>} A promise that resolves with a structured event object on success or rejects on error.
|
|
17
|
+
*/
|
|
18
|
+
return function setNickname(nickname, threadID, participantID, callback, initiatorID) {
|
|
19
|
+
let _callback;
|
|
20
|
+
let _initiatorID;
|
|
21
|
+
|
|
22
|
+
let _resolvePromise;
|
|
23
|
+
let _rejectPromise;
|
|
24
|
+
const returnPromise = new Promise((resolve, reject) => {
|
|
25
|
+
_resolvePromise = resolve;
|
|
26
|
+
_rejectPromise = reject;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (utils.getType(callback) === "Function" || utils.getType(callback) === "AsyncFunction") {
|
|
30
|
+
_callback = callback;
|
|
31
|
+
_initiatorID = initiatorID;
|
|
32
|
+
} else if (utils.getType(threadID) === "Function" || utils.getType(threadID) === "AsyncFunction") {
|
|
33
|
+
_callback = threadID;
|
|
34
|
+
threadID = null;
|
|
35
|
+
_initiatorID = callback;
|
|
36
|
+
} else if (utils.getType(participantID) === "Function" || utils.getType(participantID) === "AsyncFunction") {
|
|
37
|
+
_callback = participantID;
|
|
38
|
+
participantID = ctx.userID;
|
|
39
|
+
_initiatorID = callback;
|
|
40
|
+
}
|
|
41
|
+
else if (utils.getType(callback) === "string") {
|
|
42
|
+
_initiatorID = callback;
|
|
43
|
+
_callback = undefined;
|
|
44
|
+
} else {
|
|
45
|
+
_callback = undefined;
|
|
46
|
+
_initiatorID = undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!_callback) {
|
|
50
|
+
_callback = function (__err, __data) {
|
|
51
|
+
if (__err) _rejectPromise(__err);
|
|
52
|
+
else _resolvePromise(__data);
|
|
53
|
+
};
|
|
54
|
+
} else {
|
|
55
|
+
const originalCallback = _callback;
|
|
56
|
+
_callback = function(__err, __data) {
|
|
57
|
+
if (__err) {
|
|
58
|
+
originalCallback(__err);
|
|
59
|
+
_rejectPromise(__err);
|
|
60
|
+
} else {
|
|
61
|
+
originalCallback(null, __data);
|
|
62
|
+
_resolvePromise(__data);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_initiatorID = _initiatorID || ctx.userID;
|
|
68
|
+
|
|
69
|
+
threadID = threadID || ctx.threadID;
|
|
70
|
+
participantID = participantID || ctx.userID;
|
|
71
|
+
|
|
72
|
+
if (!threadID) {
|
|
73
|
+
return _callback(new Error("threadID is required to set a nickname."));
|
|
74
|
+
}
|
|
75
|
+
if (typeof nickname !== 'string') {
|
|
76
|
+
return _callback(new Error("nickname must be a string."));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!ctx.mqttClient) {
|
|
80
|
+
return _callback(new Error("Not connected to MQTT"));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ctx.wsReqNumber += 1;
|
|
84
|
+
ctx.wsTaskNumber += 1;
|
|
85
|
+
|
|
86
|
+
const queryPayload = {
|
|
87
|
+
thread_key: threadID.toString(),
|
|
88
|
+
contact_id: participantID.toString(),
|
|
89
|
+
nickname: nickname,
|
|
90
|
+
sync_group: 1,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const query = {
|
|
94
|
+
failure_count: null,
|
|
95
|
+
label: '44',
|
|
96
|
+
payload: JSON.stringify(queryPayload),
|
|
97
|
+
queue_name: 'thread_participant_nickname',
|
|
98
|
+
task_id: ctx.wsTaskNumber,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const context = {
|
|
102
|
+
app_id: ctx.appID,
|
|
103
|
+
payload: {
|
|
104
|
+
epoch_id: parseInt(utils.generateOfflineThreadingID()),
|
|
105
|
+
tasks: [query],
|
|
106
|
+
version_id: '24631415369801570',
|
|
107
|
+
},
|
|
108
|
+
request_id: ctx.wsReqNumber,
|
|
109
|
+
type: 3,
|
|
110
|
+
};
|
|
111
|
+
context.payload = JSON.stringify(context.payload);
|
|
112
|
+
|
|
113
|
+
ctx.mqttClient.publish('/ls_req', JSON.stringify(context), { qos: 1, retain: false }, (err) => {
|
|
114
|
+
if (err) {
|
|
115
|
+
return _callback(new Error(`MQTT publish failed for setNickname: ${err.message || err}`));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const nicknameChangeEvent = {
|
|
119
|
+
type: "thread_nickname_update",
|
|
120
|
+
threadID: threadID,
|
|
121
|
+
participantID: participantID,
|
|
122
|
+
newNickname: nickname,
|
|
123
|
+
senderID: _initiatorID,
|
|
124
|
+
BotID: ctx.userID,
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
};
|
|
127
|
+
_callback(null, nicknameChangeEvent);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return returnPromise;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @ChoruOfficial
|
|
7
|
+
* @description A module for interacting with Facebook Messenger Notes. This is not for creating notes on a user's profile page, but rather the temporary status-like notes in Messenger.
|
|
8
|
+
* @param {Object} defaultFuncs The default functions provided by the API wrapper.
|
|
9
|
+
* @param {Object} api The full API object.
|
|
10
|
+
* @param {Object} ctx The context object containing the user's session state (e.g., userID, jar).
|
|
11
|
+
* @returns {Object} An object containing methods to create, delete, recreate, and check notes.
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @callback notesCallback
|
|
17
|
+
* @param {Error|null} error An error object if the request fails, otherwise null.
|
|
18
|
+
* @param {Object} [data] The data returned from the API.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Checks for the currently active note for the logged-in user.
|
|
23
|
+
* @param {notesCallback} callback A callback function that is executed after the request. It receives an error object (if any) and an object representing the current note.
|
|
24
|
+
*/
|
|
25
|
+
function checkNote(callback) {
|
|
26
|
+
if (typeof callback !== 'function') {
|
|
27
|
+
callback = () => {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const form = {
|
|
31
|
+
fb_api_caller_class: "RelayModern",
|
|
32
|
+
fb_api_req_friendly_name: "MWInboxTrayNoteCreationDialogQuery",
|
|
33
|
+
variables: JSON.stringify({ scale: 2 }),
|
|
34
|
+
doc_id: "30899655739648624",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
defaultFuncs
|
|
38
|
+
.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
|
|
39
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
40
|
+
.then(resData => {
|
|
41
|
+
if (resData && resData.errors) throw resData.errors[0];
|
|
42
|
+
const currentNote = resData?.data?.viewer?.actor?.msgr_user_rich_status;
|
|
43
|
+
callback(null, currentNote);
|
|
44
|
+
})
|
|
45
|
+
.catch(err => {
|
|
46
|
+
utils.error("notes.checkNote", err);
|
|
47
|
+
callback(err);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new note with the provided text. The note lasts for 24 hours (86400 seconds).
|
|
53
|
+
* @param {string} text The content of the note.
|
|
54
|
+
* @param {notesCallback} callback A callback function that is executed after the request. It receives an error object (if any) and an object confirming the note's creation status.
|
|
55
|
+
*/
|
|
56
|
+
function createNote(text, privacy = "EVERYONE", callback) {
|
|
57
|
+
if (typeof callback !== 'function') {
|
|
58
|
+
callback = () => {};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const variables = {
|
|
62
|
+
input: {
|
|
63
|
+
client_mutation_id: Math.round(Math.random() * 10).toString(),
|
|
64
|
+
actor_id: ctx.userID,
|
|
65
|
+
description: text,
|
|
66
|
+
duration: 86400,
|
|
67
|
+
note_type: "TEXT_NOTE",
|
|
68
|
+
privacy,
|
|
69
|
+
session_id: utils.getGUID(),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const form = {
|
|
73
|
+
fb_api_caller_class: "RelayModern",
|
|
74
|
+
fb_api_req_friendly_name: "MWInboxTrayNoteCreationDialogCreationStepContentMutation",
|
|
75
|
+
variables: JSON.stringify(variables),
|
|
76
|
+
doc_id: "24060573783603122",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
defaultFuncs
|
|
80
|
+
.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
|
|
81
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
82
|
+
.then(resData => {
|
|
83
|
+
if (resData && resData.errors) throw resData.errors[0];
|
|
84
|
+
const status = resData?.data?.xfb_rich_status_create?.status;
|
|
85
|
+
if (!status) throw new Error("Could not find note status in the server response.");
|
|
86
|
+
callback(null, status);
|
|
87
|
+
})
|
|
88
|
+
.catch(err => {
|
|
89
|
+
utils.error("notes.createNote", err);
|
|
90
|
+
callback(err);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Deletes a specific note by its ID.
|
|
96
|
+
* @param {string} noteID The ID of the note to be deleted.
|
|
97
|
+
* @param {notesCallback} callback A callback function that is executed after the request. It receives an error object (if any) and an object confirming the deletion.
|
|
98
|
+
*/
|
|
99
|
+
function deleteNote(noteID, callback) {
|
|
100
|
+
if (typeof callback !== 'function') {
|
|
101
|
+
callback = () => {};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const variables = {
|
|
105
|
+
input: {
|
|
106
|
+
client_mutation_id: Math.round(Math.random() * 10).toString(),
|
|
107
|
+
actor_id: ctx.userID,
|
|
108
|
+
rich_status_id: noteID,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
const form = {
|
|
112
|
+
fb_api_caller_class: "RelayModern",
|
|
113
|
+
fb_api_req_friendly_name: "useMWInboxTrayDeleteNoteMutation",
|
|
114
|
+
variables: JSON.stringify(variables),
|
|
115
|
+
doc_id: "9532619970198958",
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
defaultFuncs
|
|
119
|
+
.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
|
|
120
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
121
|
+
.then(resData => {
|
|
122
|
+
if (resData && resData.errors) throw resData.errors[0];
|
|
123
|
+
const deletedStatus = resData?.data?.xfb_rich_status_delete;
|
|
124
|
+
if (!deletedStatus) throw new Error("Could not find deletion status in the server response.");
|
|
125
|
+
callback(null, deletedStatus);
|
|
126
|
+
})
|
|
127
|
+
.catch(err => {
|
|
128
|
+
utils.error("notes.deleteNote", err);
|
|
129
|
+
callback(err);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A convenience function that first deletes an old note and then creates a new one.
|
|
135
|
+
* @param {string} oldNoteID The ID of the note to delete.
|
|
136
|
+
* @param {string} newText The text for the new note.
|
|
137
|
+
* @param {notesCallback} callback A callback function that is executed after the request. It receives an error object (if any) and an object containing the deletion and creation statuses.
|
|
138
|
+
*/
|
|
139
|
+
function recreateNote(oldNoteID, newText, callback) {
|
|
140
|
+
if (typeof callback !== 'function') {
|
|
141
|
+
callback = () => {};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
deleteNote(oldNoteID, (err, deleted) => {
|
|
145
|
+
if (err) {
|
|
146
|
+
return callback(err);
|
|
147
|
+
}
|
|
148
|
+
createNote(newText, (err, created) => {
|
|
149
|
+
if (err) {
|
|
150
|
+
return callback(err);
|
|
151
|
+
}
|
|
152
|
+
callback(null, { deleted, created });
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
create: createNote,
|
|
159
|
+
delete: deleteNote,
|
|
160
|
+
recreate: recreateNote,
|
|
161
|
+
check: checkNote,
|
|
162
|
+
};
|
|
163
|
+
};
|