fca-priyansh 19.0.1 → 20.0.0
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/.gitlab-ci.yml +22 -0
- package/CountTime.json +1 -0
- package/Extra/Balancer.js +49 -49
- package/Extra/BroadcastSystem.js +1 -0
- package/Extra/Bypass/956/index.js +233 -233
- package/Extra/Bypass/test/aaaa.json +169 -169
- package/Extra/Bypass/test/index.js +187 -187
- package/Extra/Database/index.js +468 -468
- package/Extra/ExtraAddons.js +82 -82
- package/Extra/ExtraFindUID.js +61 -61
- package/Extra/ExtraGetThread.js +365 -365
- package/Extra/ExtraScreenShot.js +430 -430
- package/Extra/ExtraUptimeRobot.js +142 -38
- package/Extra/Html/Classic/script.js +118 -118
- package/Extra/Html/Classic/style.css +7 -7
- package/Extra/Security/Base/Step_1.js +5 -5
- package/Extra/Security/Base/Step_2.js +22 -22
- package/Extra/Security/Base/Step_3.js +22 -22
- package/Extra/Security/Base/index.js +190 -190
- package/Extra/Security/Index.js +4 -4
- package/Extra/Security/Step_1.js +5 -5
- package/Extra/Security/Step_2.js +22 -22
- package/Extra/Security/Step_3.js +22 -22
- package/Extra/Src/Change_Environment.js +24 -24
- package/Extra/Src/Check_Update.js +66 -66
- package/Extra/Src/History.js +114 -114
- package/Extra/Src/Instant_Update.js +64 -64
- package/Extra/Src/Last-Run.js +64 -64
- package/Extra/Src/Premium.js +81 -81
- package/Extra/Src/Websocket.js +212 -212
- package/Extra/Src/uuid.js +137 -137
- package/Func/AcceptAgreement.js +31 -31
- package/Func/ClearCache.js +64 -64
- package/Func/ReportV1.js +54 -54
- package/LICENSE +21 -21
- package/Language/index.json +228 -228
- package/Main.js +1 -1290
- package/README.md +198 -198
- package/broadcast.js +1 -44
- package/errorHandler.js +151 -0
- package/index.js +1 -448
- package/logger.js +69 -66
- package/package.json +99 -98
- package/src/Dev_Horizon_Data.js +124 -124
- package/src/Dev_getThreadInfoOLD.js +421 -421
- package/src/Dev_shareTest2.js +68 -68
- package/src/Dev_shareTest3.js +71 -71
- package/src/Premium.js +24 -24
- package/src/Screenshot.js +82 -82
- package/src/addExternalModule.js +16 -16
- package/src/addUserToGroup.js +79 -79
- package/src/changeAdminStatus.js +79 -79
- package/src/changeArchivedStatus.js +41 -41
- package/src/changeAvt.js +84 -84
- package/src/changeBio.js +65 -65
- package/src/changeBlockedStatus.js +36 -36
- package/src/changeGroupImage.js +106 -106
- package/src/changeNickname.js +45 -45
- package/src/changeThreadColor.js +62 -62
- package/src/changeThreadEmoji.js +42 -42
- package/src/changeThreadTheme.js +263 -0
- package/src/comment.js +244 -0
- package/src/createNewGroup.js +70 -70
- package/src/createPoll.js +60 -60
- package/src/deleteMessage.js +45 -45
- package/src/deleteThread.js +43 -43
- package/src/editMessage.js +71 -71
- package/src/follow.js +119 -0
- package/src/forwardAttachment.js +48 -48
- package/src/friend.js +383 -0
- package/src/getAccessToken.js +27 -27
- package/src/getCurrentUserID.js +7 -7
- package/src/getEmojiUrl.js +27 -27
- package/src/getFriendsList.js +73 -73
- package/src/getMessage.js +102 -102
- package/src/getPendingFriendRequests.js +45 -0
- package/src/getThreadHistory.js +537 -537
- package/src/getThreadInfo.js +424 -423
- package/src/getThreadInfoOLD.js +421 -421
- package/src/getThreadList.js +213 -213
- package/src/getThreadMain.js +219 -219
- package/src/getThreadPictures.js +59 -59
- package/src/getUID.js +58 -58
- package/src/getUserID.js +62 -62
- package/src/getUserInfo.js +112 -112
- package/src/getUserInfoMain.js +64 -64
- package/src/getUserInfoV2.js +31 -31
- package/src/getUserInfoV3.js +62 -62
- package/src/getUserInfoV4.js +54 -54
- package/src/getUserInfoV5.js +60 -60
- package/src/handleFriendRequest.js +46 -46
- package/src/handleMessageRequest.js +49 -49
- package/src/httpGet.js +49 -49
- package/src/httpPost.js +48 -48
- package/src/httpPostFormData.js +40 -40
- package/src/listenMqtt.js +1 -956
- package/src/listenMqttV1.js +832 -846
- package/src/logout.js +68 -68
- package/src/markAsDelivered.js +48 -48
- package/src/markAsRead.js +70 -70
- package/src/markAsReadAll.js +42 -42
- package/src/markAsSeen.js +51 -51
- package/src/muteThread.js +47 -47
- package/src/notes.js +279 -0
- package/src/removeUserFromGroup.js +49 -49
- package/src/resolvePhotoUrl.js +37 -37
- package/src/searchForThread.js +43 -43
- package/src/sendMention.js +325 -0
- package/src/sendMessage.js +1 -386
- package/src/sendMqttMessage.js +70 -70
- package/src/sendTypingIndicator.js +79 -80
- package/src/setMessageReaction.js +109 -109
- package/src/setPostReaction.js +101 -101
- package/src/setTitle.js +74 -74
- package/src/share.js +98 -0
- package/src/shareContact.js +55 -55
- package/src/shareLink.js +58 -58
- package/src/stickers.js +525 -0
- package/src/story.js +267 -0
- package/src/threadColors.js +38 -38
- package/src/unfriend.js +43 -43
- package/src/unsendMessage.js +47 -47
- package/src/unsendMqttMessage.js +65 -65
- package/test/data/shareAttach.js +146 -146
- package/test/data/test.txt +7 -7
- package/test/example-config.json +18 -18
- package/test/test-page.js +140 -140
- package/test/test.js +385 -385
- package/test/testv2.js +2 -2
- package/userAgentManager.js +129 -0
- package/utils.js +1 -3077
- package/.github/workflows/publish.yml +0 -20
- package/Extra/Src/Release_Memory.js +0 -160
- package/Extra/Src/test.js +0 -28
- package/SECURITY.md +0 -17
package/src/changeThreadEmoji.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
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 changeThreadEmoji(emoji, 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) {
|
|
17
|
-
if (err) return rejectFunc(err);
|
|
18
|
-
resolveFunc();
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
var form = {
|
|
22
|
-
emoji_choice: emoji,
|
|
23
|
-
thread_or_other_fbid: threadID
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
defaultFuncs
|
|
27
|
-
.post("https://www.facebook.com/messaging/save_thread_emoji/?source=thread_settings&__pc=EXP1%3Amessengerdotcom_pkg", ctx.jar, form)
|
|
28
|
-
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
29
|
-
.then(function (resData) {
|
|
30
|
-
if (resData.error === 1357031) throw { error: "Trying to change emoji of a chat that doesn't exist. Have at least one message in the thread before trying to change the emoji." };
|
|
31
|
-
if (resData.error) throw resData;
|
|
32
|
-
|
|
33
|
-
return callback();
|
|
34
|
-
})
|
|
35
|
-
.catch(function (err) {
|
|
36
|
-
log.error("changeThreadEmoji", err);
|
|
37
|
-
return callback(err);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return returnPromise;
|
|
41
|
-
};
|
|
42
|
-
};
|
|
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 changeThreadEmoji(emoji, 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) {
|
|
17
|
+
if (err) return rejectFunc(err);
|
|
18
|
+
resolveFunc();
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
var form = {
|
|
22
|
+
emoji_choice: emoji,
|
|
23
|
+
thread_or_other_fbid: threadID
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
defaultFuncs
|
|
27
|
+
.post("https://www.facebook.com/messaging/save_thread_emoji/?source=thread_settings&__pc=EXP1%3Amessengerdotcom_pkg", ctx.jar, form)
|
|
28
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
29
|
+
.then(function (resData) {
|
|
30
|
+
if (resData.error === 1357031) throw { error: "Trying to change emoji of a chat that doesn't exist. Have at least one message in the thread before trying to change the emoji." };
|
|
31
|
+
if (resData.error) throw resData;
|
|
32
|
+
|
|
33
|
+
return callback();
|
|
34
|
+
})
|
|
35
|
+
.catch(function (err) {
|
|
36
|
+
log.error("changeThreadEmoji", err);
|
|
37
|
+
return callback(err);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return returnPromise;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = require("../utils");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
/**
|
|
8
|
+
* Change thread theme using MQTT (more reliable than HTTP)
|
|
9
|
+
* Made by Choru Official - Ported to fca-updated format
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - List all available themes: api.changeThreadTheme("list", threadID)
|
|
13
|
+
* - Set theme by name: api.changeThreadTheme("love", threadID)
|
|
14
|
+
* - Set theme by ID: api.changeThreadTheme("168332145275126", threadID)
|
|
15
|
+
* - Partial name match: api.changeThreadTheme("dark", threadID) -> finds "Dark Mode"
|
|
16
|
+
*
|
|
17
|
+
* @param {string} themeName - Theme name, theme ID, or "list" to show all themes
|
|
18
|
+
* @param {string} threadID - Thread ID to change theme
|
|
19
|
+
* @param {function} callback - Optional callback(err, result)
|
|
20
|
+
* @returns {Promise} Promise that resolves with theme data or list
|
|
21
|
+
*/
|
|
22
|
+
return function changeThreadTheme(themeName, threadID, callback) {
|
|
23
|
+
var resolveFunc = function () {};
|
|
24
|
+
var rejectFunc = function () {};
|
|
25
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
26
|
+
resolveFunc = resolve;
|
|
27
|
+
rejectFunc = reject;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!callback) {
|
|
31
|
+
callback = function (err, data) {
|
|
32
|
+
if (err) return rejectFunc(err);
|
|
33
|
+
resolveFunc(data);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate parameters
|
|
38
|
+
if (!threadID) {
|
|
39
|
+
return callback({ error: "threadID is required to change theme." });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!themeName) {
|
|
43
|
+
return callback({ error: "themeName (or 'list') is required." });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check MQTT connection (required for theme change)
|
|
47
|
+
if (!ctx.mqttClient || !ctx.mqttClient.connected) {
|
|
48
|
+
return callback({
|
|
49
|
+
error: "MQTT not connected. Theme changes require MQTT connection. Make sure bot is fully started with listenMqtt active."
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fetch all available themes from Facebook GraphQL
|
|
55
|
+
*/
|
|
56
|
+
function fetchAllThemes(cb) {
|
|
57
|
+
log.info("changeThreadTheme", "Fetching available themes from Facebook...");
|
|
58
|
+
|
|
59
|
+
var form = {
|
|
60
|
+
fb_api_caller_class: "RelayModern",
|
|
61
|
+
fb_api_req_friendly_name: "MWPThreadThemeQuery_AllThemesQuery",
|
|
62
|
+
variables: JSON.stringify({ version: "default" }),
|
|
63
|
+
server_timestamps: true,
|
|
64
|
+
doc_id: "24474714052117636"
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
defaultFuncs
|
|
68
|
+
.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
|
|
69
|
+
"x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
|
|
70
|
+
"x-fb-lsd": ctx.lsd || ctx.fb_dtsg,
|
|
71
|
+
"referer": "https://www.facebook.com/messages/t/" + threadID
|
|
72
|
+
})
|
|
73
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
74
|
+
.then(function (resData) {
|
|
75
|
+
if (resData.errors) {
|
|
76
|
+
return cb({ error: "GraphQL error: " + JSON.stringify(resData.errors) });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!resData.data || !resData.data.messenger_thread_themes) {
|
|
80
|
+
return cb({ error: "Could not retrieve themes from Facebook." });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var themes = resData.data.messenger_thread_themes
|
|
84
|
+
.map(function (themeData) {
|
|
85
|
+
if (!themeData || !themeData.id) return null;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
id: themeData.id,
|
|
89
|
+
name: themeData.accessibility_label,
|
|
90
|
+
description: themeData.description,
|
|
91
|
+
appColorMode: themeData.app_color_mode,
|
|
92
|
+
fallbackColor: themeData.fallback_color,
|
|
93
|
+
gradientColors: themeData.gradient_colors,
|
|
94
|
+
backgroundImage: themeData.background_asset?.image?.uri,
|
|
95
|
+
iconAsset: themeData.icon_asset?.image?.uri,
|
|
96
|
+
// Color details
|
|
97
|
+
composerBackgroundColor: themeData.composer_background_color,
|
|
98
|
+
composerTintColor: themeData.composer_tint_color,
|
|
99
|
+
titleBarBackgroundColor: themeData.title_bar_background_color,
|
|
100
|
+
titleBarTextColor: themeData.title_bar_text_color,
|
|
101
|
+
hotLikeColor: themeData.hot_like_color,
|
|
102
|
+
inboundMessageGradientColors: themeData.inbound_message_gradient_colors,
|
|
103
|
+
messageTextColor: themeData.message_text_color
|
|
104
|
+
};
|
|
105
|
+
})
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
|
|
108
|
+
log.info("changeThreadTheme", "Successfully fetched " + themes.length + " themes");
|
|
109
|
+
cb(null, themes);
|
|
110
|
+
})
|
|
111
|
+
.catch(function (err) {
|
|
112
|
+
log.error("changeThreadTheme", "Failed to fetch themes:", err);
|
|
113
|
+
cb({ error: "Failed to fetch theme list: " + (err.message || err) });
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Set thread theme using MQTT publish
|
|
119
|
+
*/
|
|
120
|
+
function setThemeViaMqtt(themeID, actualThemeName, cb) {
|
|
121
|
+
log.info("changeThreadTheme", "Setting theme '" + actualThemeName + "' (ID: " + themeID + ") for thread " + threadID);
|
|
122
|
+
|
|
123
|
+
var currentEpochId = parseInt(utils.generateOfflineThreadingID());
|
|
124
|
+
var publishedCount = 0;
|
|
125
|
+
var errors = [];
|
|
126
|
+
|
|
127
|
+
// Helper to create and publish MQTT message
|
|
128
|
+
function createAndPublish(label, queueName, payload, done) {
|
|
129
|
+
currentEpochId = parseInt(utils.generateOfflineThreadingID());
|
|
130
|
+
ctx.wsReqNumber += 1;
|
|
131
|
+
ctx.wsTaskNumber += 1;
|
|
132
|
+
|
|
133
|
+
var requestId = ctx.wsReqNumber;
|
|
134
|
+
|
|
135
|
+
var queryPayload = {
|
|
136
|
+
thread_key: threadID.toString(),
|
|
137
|
+
theme_fbid: themeID.toString(),
|
|
138
|
+
sync_group: 1
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Merge additional payload
|
|
142
|
+
Object.keys(payload).forEach(function(key) {
|
|
143
|
+
queryPayload[key] = payload[key];
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
var query = {
|
|
147
|
+
failure_count: null,
|
|
148
|
+
label: label,
|
|
149
|
+
payload: JSON.stringify(queryPayload),
|
|
150
|
+
queue_name: queueName,
|
|
151
|
+
task_id: ctx.wsTaskNumber
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
var context = {
|
|
155
|
+
app_id: ctx.appID || "2220391788200892",
|
|
156
|
+
payload: {
|
|
157
|
+
epoch_id: currentEpochId,
|
|
158
|
+
tasks: [query],
|
|
159
|
+
version_id: "24631415369801570"
|
|
160
|
+
},
|
|
161
|
+
request_id: requestId,
|
|
162
|
+
type: 3
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
context.payload = JSON.stringify(context.payload);
|
|
166
|
+
|
|
167
|
+
log.info("changeThreadTheme", "Publishing MQTT message: label=" + label + ", queueName=" + queueName);
|
|
168
|
+
|
|
169
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(context), { qos: 1, retain: false }, function (err) {
|
|
170
|
+
if (err) {
|
|
171
|
+
log.error("changeThreadTheme", "MQTT publish failed for " + queueName + ":", err);
|
|
172
|
+
errors.push("Failed to publish " + queueName + ": " + err.message);
|
|
173
|
+
} else {
|
|
174
|
+
publishedCount++;
|
|
175
|
+
log.info("changeThreadTheme", "Successfully published " + queueName);
|
|
176
|
+
}
|
|
177
|
+
done();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Publish all required MQTT messages in parallel
|
|
182
|
+
var pending = 4;
|
|
183
|
+
function checkComplete() {
|
|
184
|
+
pending--;
|
|
185
|
+
if (pending === 0) {
|
|
186
|
+
if (errors.length > 0) {
|
|
187
|
+
return cb({ error: "Some MQTT publishes failed: " + errors.join(", ") });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
var eventData = {
|
|
191
|
+
type: "thread_theme_update",
|
|
192
|
+
threadID: threadID,
|
|
193
|
+
themeID: themeID,
|
|
194
|
+
themeName: actualThemeName,
|
|
195
|
+
senderID: ctx.userID,
|
|
196
|
+
timestamp: Date.now()
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
log.info("changeThreadTheme", "✅ Theme changed successfully!");
|
|
200
|
+
cb(null, eventData);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Publish 4 different MQTT messages (required by Facebook)
|
|
205
|
+
createAndPublish("1013", "ai_generated_theme", {}, checkComplete);
|
|
206
|
+
createAndPublish("1037", "msgr_custom_thread_theme", {}, checkComplete);
|
|
207
|
+
createAndPublish("1028", "thread_theme_writer", {}, checkComplete);
|
|
208
|
+
createAndPublish("43", "thread_theme", { source: null, payload: null }, checkComplete);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Main logic
|
|
213
|
+
*/
|
|
214
|
+
fetchAllThemes(function (err, themes) {
|
|
215
|
+
if (err) {
|
|
216
|
+
return callback(err);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// If user wants to list themes
|
|
220
|
+
if (themeName.toLowerCase() === "list") {
|
|
221
|
+
log.info("changeThreadTheme", "Returning list of " + themes.length + " available themes");
|
|
222
|
+
return callback(null, themes);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Find matching theme
|
|
226
|
+
var normalizedThemeName = themeName.toLowerCase();
|
|
227
|
+
var matchedTheme = null;
|
|
228
|
+
|
|
229
|
+
// 1. Try exact ID match
|
|
230
|
+
if (!isNaN(normalizedThemeName)) {
|
|
231
|
+
matchedTheme = themes.find(function (t) {
|
|
232
|
+
return t.id === normalizedThemeName;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 2. Try exact name match
|
|
237
|
+
if (!matchedTheme) {
|
|
238
|
+
matchedTheme = themes.find(function (t) {
|
|
239
|
+
return t.name.toLowerCase() === normalizedThemeName;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 3. Try partial name match
|
|
244
|
+
if (!matchedTheme) {
|
|
245
|
+
matchedTheme = themes.find(function (t) {
|
|
246
|
+
return t.name.toLowerCase().includes(normalizedThemeName);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!matchedTheme) {
|
|
251
|
+
log.warn("changeThreadTheme", "Theme '" + themeName + "' not found");
|
|
252
|
+
return callback({
|
|
253
|
+
error: "Theme \"" + themeName + "\" not found. Use api.changeThreadTheme('list', threadID) to see available themes."
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Set the theme
|
|
258
|
+
setThemeViaMqtt(matchedTheme.id, matchedTheme.name, callback);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return returnPromise;
|
|
262
|
+
};
|
|
263
|
+
};
|
package/src/comment.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comment API Module
|
|
5
|
+
* Create comments on Facebook posts with support for attachments, mentions, stickers, and URLs
|
|
6
|
+
*
|
|
7
|
+
* @author Priyansh Rajput
|
|
8
|
+
* @github https://github.com/priyanshufsdev
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
var utils = require("../utils");
|
|
13
|
+
var log = require("npmlog");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Handle upload of attachments (images/videos) for comment
|
|
17
|
+
* @param {object} defaultFuncs - Default functions for API requests
|
|
18
|
+
* @param {object} ctx - Context object
|
|
19
|
+
* @param {object} msg - Message object containing attachments
|
|
20
|
+
* @param {object} form - Form object to populate
|
|
21
|
+
* @returns {Promise<void>}
|
|
22
|
+
*/
|
|
23
|
+
async function handleUpload(defaultFuncs, ctx, msg, form) {
|
|
24
|
+
if (!msg.attachments || msg.attachments.length === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var uploads = msg.attachments.map(function(item) {
|
|
29
|
+
if (!utils.isReadableStream(item)) {
|
|
30
|
+
throw new Error('Attachments must be a readable stream.');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return defaultFuncs
|
|
34
|
+
.postFormData('https://www.facebook.com/ajax/ufi/upload/', ctx.jar, {
|
|
35
|
+
profile_id: ctx.userID,
|
|
36
|
+
source: 19,
|
|
37
|
+
target_id: ctx.userID,
|
|
38
|
+
file: item
|
|
39
|
+
})
|
|
40
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
41
|
+
.then(function(res) {
|
|
42
|
+
if (res.error || !res.payload || !res.payload.fbid) {
|
|
43
|
+
throw res;
|
|
44
|
+
}
|
|
45
|
+
return { media: { id: res.payload.fbid } };
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
var results = await Promise.all(uploads);
|
|
50
|
+
results.forEach(function(result) {
|
|
51
|
+
form.input.attachments.push(result);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Handle URL attachment for comment
|
|
57
|
+
* @param {object} msg - Message object
|
|
58
|
+
* @param {object} form - Form object
|
|
59
|
+
*/
|
|
60
|
+
function handleURL(msg, form) {
|
|
61
|
+
if (typeof msg.url === 'string') {
|
|
62
|
+
form.input.attachments.push({
|
|
63
|
+
link: {
|
|
64
|
+
external: {
|
|
65
|
+
url: msg.url
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Handle mentions in comment body
|
|
74
|
+
* @param {object} msg - Message object
|
|
75
|
+
* @param {object} form - Form object
|
|
76
|
+
*/
|
|
77
|
+
function handleMentions(msg, form) {
|
|
78
|
+
if (!msg.mentions) return;
|
|
79
|
+
|
|
80
|
+
for (var i = 0; i < msg.mentions.length; i++) {
|
|
81
|
+
var item = msg.mentions[i];
|
|
82
|
+
var tag = item.tag;
|
|
83
|
+
var id = item.id;
|
|
84
|
+
var fromIndex = item.fromIndex;
|
|
85
|
+
|
|
86
|
+
if (typeof tag !== 'string' || !id) {
|
|
87
|
+
log.warn('comment', 'Mentions must have a string "tag" and an "id".');
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var offset = msg.body.indexOf(tag, fromIndex || 0);
|
|
92
|
+
if (offset < 0) {
|
|
93
|
+
log.warn('comment', 'Mention for "' + tag + '" not found in message string.');
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
form.input.message.ranges.push({
|
|
98
|
+
entity: { id: id },
|
|
99
|
+
length: tag.length,
|
|
100
|
+
offset: offset
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Handle sticker attachment for comment
|
|
107
|
+
* @param {object} msg - Message object
|
|
108
|
+
* @param {object} form - Form object
|
|
109
|
+
*/
|
|
110
|
+
function handleSticker(msg, form) {
|
|
111
|
+
if (msg.sticker) {
|
|
112
|
+
form.input.attachments.push({
|
|
113
|
+
media: {
|
|
114
|
+
id: String(msg.sticker)
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Submit final comment form to GraphQL endpoint
|
|
122
|
+
* @param {object} defaultFuncs - Default functions
|
|
123
|
+
* @param {object} ctx - Context object
|
|
124
|
+
* @param {object} form - Fully constructed form object
|
|
125
|
+
* @returns {Promise<object>}
|
|
126
|
+
*/
|
|
127
|
+
async function createContent(defaultFuncs, ctx, form) {
|
|
128
|
+
var res = await defaultFuncs
|
|
129
|
+
.post('https://www.facebook.com/api/graphql/', ctx.jar, {
|
|
130
|
+
fb_api_caller_class: 'RelayModern',
|
|
131
|
+
fb_api_req_friendly_name: 'useCometUFICreateCommentMutation',
|
|
132
|
+
variables: JSON.stringify(form),
|
|
133
|
+
server_timestamps: true,
|
|
134
|
+
doc_id: 6993516810709754
|
|
135
|
+
})
|
|
136
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
137
|
+
|
|
138
|
+
if (res.errors) {
|
|
139
|
+
throw res;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var commentEdge = res.data.comment_create.feedback_comment_edge;
|
|
143
|
+
return {
|
|
144
|
+
id: commentEdge.node.id,
|
|
145
|
+
url: commentEdge.node.feedback.url,
|
|
146
|
+
count: res.data.comment_create.feedback.total_comment_count
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
151
|
+
/**
|
|
152
|
+
* Create a comment on a Facebook post
|
|
153
|
+
* Can also reply to an existing comment
|
|
154
|
+
*
|
|
155
|
+
* @param {string|object} msg - Message to post (string or object with body, attachments, mentions, etc.)
|
|
156
|
+
* @param {string} postID - ID of the post to comment on
|
|
157
|
+
* @param {string} replyCommentID - Optional: ID of comment to reply to
|
|
158
|
+
* @param {function} callback - Optional callback function
|
|
159
|
+
* @returns {Promise<object>}
|
|
160
|
+
*/
|
|
161
|
+
return function createCommentPost(msg, postID, replyCommentID, callback) {
|
|
162
|
+
var resolveFunc = function() {};
|
|
163
|
+
var rejectFunc = function() {};
|
|
164
|
+
var returnPromise = new Promise(function(resolve, reject) {
|
|
165
|
+
resolveFunc = resolve;
|
|
166
|
+
rejectFunc = reject;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Handle optional parameters
|
|
170
|
+
if (typeof replyCommentID === 'function') {
|
|
171
|
+
callback = replyCommentID;
|
|
172
|
+
replyCommentID = null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!callback) {
|
|
176
|
+
callback = function(err, data) {
|
|
177
|
+
if (err) return rejectFunc(err);
|
|
178
|
+
resolveFunc(data);
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Validation
|
|
183
|
+
if (typeof msg !== 'string' && typeof msg !== 'object') {
|
|
184
|
+
var error = 'Message must be a string or an object.';
|
|
185
|
+
log.error('comment', error);
|
|
186
|
+
return callback({ error: error });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (typeof postID !== 'string') {
|
|
190
|
+
var error2 = 'postID must be a string.';
|
|
191
|
+
log.error('comment', error2);
|
|
192
|
+
return callback({ error: error2 });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Prepare message object
|
|
196
|
+
var messageObject = typeof msg === 'string' ? { body: msg } : msg;
|
|
197
|
+
messageObject.mentions = messageObject.mentions || [];
|
|
198
|
+
messageObject.attachments = messageObject.attachments || [];
|
|
199
|
+
|
|
200
|
+
// Build form
|
|
201
|
+
var form = {
|
|
202
|
+
feedLocation: 'NEWSFEED',
|
|
203
|
+
feedbackSource: 1,
|
|
204
|
+
groupID: null,
|
|
205
|
+
input: {
|
|
206
|
+
client_mutation_id: Math.round(Math.random() * 19).toString(),
|
|
207
|
+
actor_id: ctx.userID,
|
|
208
|
+
attachments: [],
|
|
209
|
+
feedback_id: Buffer.from('feedback:' + postID).toString('base64'),
|
|
210
|
+
message: {
|
|
211
|
+
ranges: [],
|
|
212
|
+
text: messageObject.body || ''
|
|
213
|
+
},
|
|
214
|
+
reply_comment_parent_fbid: replyCommentID || null,
|
|
215
|
+
is_tracking_encrypted: true,
|
|
216
|
+
tracking: [],
|
|
217
|
+
feedback_source: 'NEWS_FEED',
|
|
218
|
+
idempotence_token: 'client:' + utils.getGUID(),
|
|
219
|
+
session_id: utils.getGUID()
|
|
220
|
+
},
|
|
221
|
+
scale: 1,
|
|
222
|
+
useDefaultActor: false
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Process all handlers and create comment
|
|
226
|
+
handleUpload(defaultFuncs, ctx, messageObject, form)
|
|
227
|
+
.then(function() {
|
|
228
|
+
handleURL(messageObject, form);
|
|
229
|
+
handleMentions(messageObject, form);
|
|
230
|
+
handleSticker(messageObject, form);
|
|
231
|
+
return createContent(defaultFuncs, ctx, form);
|
|
232
|
+
})
|
|
233
|
+
.then(function(info) {
|
|
234
|
+
log.info('comment', 'Comment created successfully: ' + info.id);
|
|
235
|
+
callback(null, info);
|
|
236
|
+
})
|
|
237
|
+
.catch(function(err) {
|
|
238
|
+
log.error('comment', err);
|
|
239
|
+
callback(err);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return returnPromise;
|
|
243
|
+
};
|
|
244
|
+
};
|