stfca 1.0.19 → 1.0.21
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/index.js +12 -0
- package/package.json +1 -1
- package/src/OldMessage.js +34 -10
- package/src/sendMessage.js +15 -4
- package/src/setThreadTheme.js +88 -261
- package/utils.js +6 -1
package/index.js
CHANGED
|
@@ -4,6 +4,8 @@ var utils = require("./utils");
|
|
|
4
4
|
var cheerio = require("cheerio");
|
|
5
5
|
var log = require("npmlog");
|
|
6
6
|
var { checkForFCAUpdate } = require("./checkUpdate");
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
7
9
|
/*var { getThemeColors } = require("../../func/utils/log.js");
|
|
8
10
|
var logger = require("../../func/utils/log.js");
|
|
9
11
|
var { cra, cv, cb, co } = getThemeColors();*/
|
|
@@ -188,6 +190,16 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
188
190
|
reqCallbacks: {},
|
|
189
191
|
threadTypes: {} // Store thread type (dm/group) for each thread
|
|
190
192
|
};
|
|
193
|
+
let config = { enableTypingIndicator: false, typingDuration: 4000 };
|
|
194
|
+
try {
|
|
195
|
+
const configPath = path.join(__dirname, 'config.json');
|
|
196
|
+
if (fs.existsSync(configPath)) {
|
|
197
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
198
|
+
}
|
|
199
|
+
} catch (e) {
|
|
200
|
+
console.log('Error loading config.json:', e);
|
|
201
|
+
}
|
|
202
|
+
ctx.config = config;
|
|
191
203
|
var api = {
|
|
192
204
|
setOptions: setOptions.bind(null, globalOptions),
|
|
193
205
|
getAppState: () => utils.getAppState(jar),
|
package/package.json
CHANGED
package/src/OldMessage.js
CHANGED
|
@@ -311,19 +311,43 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
311
311
|
};
|
|
312
312
|
// console.log(form)
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
314
|
+
if (isSingleUser && ctx.config.enableTypingIndicator) {
|
|
315
|
+
const stopTyping = api.sendTypingIndicator(threadID, () => {}, false);
|
|
316
|
+
const originalCallback = callback;
|
|
317
|
+
callback = (err, data) => {
|
|
318
|
+
stopTyping(() => {});
|
|
319
|
+
originalCallback(err, data);
|
|
320
|
+
};
|
|
321
|
+
setTimeout(() => {
|
|
322
|
+
handleLocation(msg, form, callback, () =>
|
|
323
|
+
handleSticker(msg, form, callback, () =>
|
|
324
|
+
handleAttachment(msg, form, callback, () =>
|
|
325
|
+
handleUrl(msg, form, callback, () =>
|
|
326
|
+
handleEmoji(msg, form, callback, () =>
|
|
327
|
+
handleMention(msg, form, callback, () =>
|
|
328
|
+
sendContent(form, threadID, isSingleUser, messageAndOTID, callback)
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
}, ctx.config.typingDuration);
|
|
336
|
+
} else {
|
|
337
|
+
handleLocation(msg, form, callback, () =>
|
|
338
|
+
handleSticker(msg, form, callback, () =>
|
|
339
|
+
handleAttachment(msg, form, callback, () =>
|
|
340
|
+
handleUrl(msg, form, callback, () =>
|
|
341
|
+
handleEmoji(msg, form, callback, () =>
|
|
342
|
+
handleMention(msg, form, callback, () =>
|
|
343
|
+
sendContent(form, threadID, isSingleUser, messageAndOTID, callback)
|
|
344
|
+
)
|
|
345
|
+
)
|
|
321
346
|
)
|
|
322
347
|
)
|
|
323
348
|
)
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
);
|
|
349
|
+
);
|
|
350
|
+
}
|
|
327
351
|
return returnPromise;
|
|
328
352
|
};
|
|
329
353
|
};
|
package/src/sendMessage.js
CHANGED
|
@@ -234,10 +234,21 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
234
234
|
form["profile_xmd[" + i + "][type]"] = "p";
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
if (isSingleUser && ctx.config.enableTypingIndicator) {
|
|
238
|
+
const stopTyping = api.sendTypingIndicator(threadID, () => {}, false);
|
|
239
|
+
await utils.delay(ctx.config.typingDuration);
|
|
240
|
+
const result = await sendContent(form, threadID, isSingleUser, messageAndOTID);
|
|
241
|
+
stopTyping(() => {});
|
|
242
|
+
if (callback && typeof callback === "function") {
|
|
243
|
+
callback(null, result);
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
} else {
|
|
247
|
+
const result = await sendContent(form, threadID, isSingleUser, messageAndOTID);
|
|
248
|
+
if (callback && typeof callback === "function") {
|
|
249
|
+
callback(null, result);
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
240
252
|
}
|
|
241
|
-
return result;
|
|
242
253
|
};
|
|
243
254
|
};
|
package/src/setThreadTheme.js
CHANGED
|
@@ -8,269 +8,96 @@
|
|
|
8
8
|
* 🕊️ Respect the creator & give proper credits if reused.
|
|
9
9
|
* ===========================================================
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
'use strict';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const utils = require('../utils');
|
|
14
|
+
const log = require('npmlog');
|
|
15
15
|
|
|
16
16
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
103
|
-
|
|
104
|
-
if (themeResult && themeResult.data && themeResult.data.messenger_thread_themes) {
|
|
105
|
-
availableThemes = themeResult.data.messenger_thread_themes;
|
|
106
|
-
}
|
|
107
|
-
} catch (e) {
|
|
108
|
-
log.warn("setThreadTheme", "Could not fetch available themes, proceeding with theme update");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Step 3: Determine theme ID based on input
|
|
112
|
-
let themeId = null;
|
|
113
|
-
let customEmoji = "👍";
|
|
114
|
-
|
|
115
|
-
if (typeof themeData === "string") {
|
|
116
|
-
// If it's a string, try to find matching theme
|
|
117
|
-
if (themeData.match(/^[0-9]+$/)) {
|
|
118
|
-
// Numeric theme ID
|
|
119
|
-
themeId = themeData;
|
|
120
|
-
} else {
|
|
121
|
-
// Search by theme name/description
|
|
122
|
-
const foundTheme = availableThemes.find(theme =>
|
|
123
|
-
theme.accessibility_label &&
|
|
124
|
-
theme.accessibility_label.toLowerCase().includes(themeData.toLowerCase())
|
|
125
|
-
);
|
|
126
|
-
if (foundTheme) {
|
|
127
|
-
themeId = foundTheme.id;
|
|
128
|
-
} else {
|
|
129
|
-
// Fallback color mapping
|
|
130
|
-
const colorMap = {
|
|
131
|
-
blue: "196241301102133",
|
|
132
|
-
purple: "370940413392601",
|
|
133
|
-
green: "169463077092846",
|
|
134
|
-
pink: "230032715012014",
|
|
135
|
-
orange: "175615189761153",
|
|
136
|
-
red: "2136751179887052",
|
|
137
|
-
yellow: "2058653964378557",
|
|
138
|
-
teal: "417639218648241",
|
|
139
|
-
black: "539927563794799",
|
|
140
|
-
white: "2873642392710980",
|
|
141
|
-
default: "196241301102133"
|
|
142
|
-
};
|
|
143
|
-
themeId = colorMap[themeData.toLowerCase()] || colorMap.default;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} else if (typeof themeData === "object" && themeData !== null) {
|
|
147
|
-
themeId = themeData.themeId || themeData.theme_id || themeData.id;
|
|
148
|
-
customEmoji = themeData.emoji || themeData.customEmoji || "👍";
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (!themeId) {
|
|
152
|
-
themeId = "196241301102133"; // Default blue theme
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Step 4: Use direct bootloader approach for theme update
|
|
156
|
-
try {
|
|
157
|
-
// First try with the legacy changeThreadColor approach
|
|
158
|
-
const legacyForm = {
|
|
159
|
-
dpr: 1,
|
|
160
|
-
queries: JSON.stringify({
|
|
161
|
-
o0: {
|
|
162
|
-
doc_id: "1727493033983591",
|
|
163
|
-
query_params: {
|
|
164
|
-
data: {
|
|
165
|
-
actor_id: ctx.userID,
|
|
166
|
-
client_mutation_id: "0",
|
|
167
|
-
source: "SETTINGS",
|
|
168
|
-
theme_id: themeId,
|
|
169
|
-
thread_id: threadID,
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
}),
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
const legacyResult = await defaultFuncs
|
|
177
|
-
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, legacyForm)
|
|
178
|
-
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
179
|
-
|
|
180
|
-
if (legacyResult && !legacyResult[0]?.o0?.errors) {
|
|
181
|
-
return callback(null, {
|
|
182
|
-
threadID: threadID,
|
|
183
|
-
themeId: themeId,
|
|
184
|
-
customEmoji: customEmoji,
|
|
185
|
-
timestamp: timestamp,
|
|
186
|
-
success: true,
|
|
187
|
-
method: "legacy",
|
|
188
|
-
availableThemes: availableThemes.length > 0 ? availableThemes.map(t => ({
|
|
189
|
-
id: t.id,
|
|
190
|
-
name: t.accessibility_label,
|
|
191
|
-
description: t.description
|
|
192
|
-
})) : null
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
} catch (legacyErr) {
|
|
196
|
-
log.warn("setThreadTheme", "Legacy method failed, trying alternative approach");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Step 5: Try alternative GraphQL mutation with updated doc_id
|
|
200
|
-
const alternativeForm = {
|
|
201
|
-
av: ctx.userID,
|
|
202
|
-
__aaid: 0,
|
|
203
|
-
__user: ctx.userID,
|
|
204
|
-
__a: 1,
|
|
205
|
-
__req: utils.getSignatureID(),
|
|
206
|
-
__hs: "20352.HYP:comet_pkg.2.1...0",
|
|
207
|
-
dpr: 1,
|
|
208
|
-
__ccg: "EXCELLENT",
|
|
209
|
-
__rev: "1027396270",
|
|
210
|
-
__s: utils.getSignatureID(),
|
|
211
|
-
__hsi: "7552524636527201016",
|
|
212
|
-
__comet_req: 15,
|
|
213
|
-
fb_dtsg: ctx.fb_dtsg,
|
|
214
|
-
jazoest: ctx.ttstamp,
|
|
215
|
-
lsd: ctx.fb_dtsg,
|
|
216
|
-
__spin_r: "1027396270",
|
|
217
|
-
__spin_b: "trunk",
|
|
218
|
-
__spin_t: timestamp,
|
|
219
|
-
__crn: "comet.fbweb.MWInboxHomeRoute",
|
|
220
|
-
fb_api_caller_class: "RelayModern",
|
|
221
|
-
fb_api_req_friendly_name: "MessengerThreadThemeUpdateMutation",
|
|
222
|
-
variables: JSON.stringify({
|
|
223
|
-
"input": {
|
|
224
|
-
"actor_id": ctx.userID,
|
|
225
|
-
"client_mutation_id": Math.floor(Math.random() * 10000).toString(),
|
|
226
|
-
"source": "SETTINGS",
|
|
227
|
-
"thread_id": threadID.toString(),
|
|
228
|
-
"theme_id": themeId.toString(),
|
|
229
|
-
"custom_emoji": customEmoji
|
|
230
|
-
}
|
|
231
|
-
}),
|
|
232
|
-
server_timestamps: true,
|
|
233
|
-
doc_id: "9734829906576883" // Updated doc_id based on working API
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const result = await defaultFuncs
|
|
237
|
-
.post("https://www.facebook.com/api/graphql/", ctx.jar, alternativeForm)
|
|
238
|
-
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
239
|
-
|
|
240
|
-
if (result && result.errors && result.errors.length > 0) {
|
|
241
|
-
throw new Error("GraphQL Error: " + JSON.stringify(result.errors));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Check if the mutation was successful
|
|
245
|
-
if (result && result.data && result.data.messenger_thread_theme_update) {
|
|
246
|
-
const updateResult = result.data.messenger_thread_theme_update;
|
|
247
|
-
if (updateResult.errors && updateResult.errors.length > 0) {
|
|
248
|
-
throw new Error("Theme Update Error: " + JSON.stringify(updateResult.errors));
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return callback(null, {
|
|
253
|
-
threadID: threadID,
|
|
254
|
-
themeId: themeId,
|
|
255
|
-
customEmoji: customEmoji,
|
|
256
|
-
timestamp: timestamp,
|
|
257
|
-
success: true,
|
|
258
|
-
method: "graphql",
|
|
259
|
-
availableThemes: availableThemes.length > 0 ? availableThemes.map(t => ({
|
|
260
|
-
id: t.id,
|
|
261
|
-
name: t.accessibility_label,
|
|
262
|
-
description: t.description
|
|
263
|
-
})) : null
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
} catch (err) {
|
|
267
|
-
log.error("setThreadTheme", err);
|
|
268
|
-
return callback(err);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
updateThreadTheme();
|
|
273
|
-
return returnPromise;
|
|
274
|
-
};
|
|
17
|
+
/** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Instagram: @sheikh.tamim_lover */
|
|
18
|
+
return function setThreadTheme(threadID, themeFBID, callback) {
|
|
19
|
+
var resolveFunc = function () { };
|
|
20
|
+
var rejectFunc = function () { };
|
|
21
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
22
|
+
resolveFunc = resolve;
|
|
23
|
+
rejectFunc = reject;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (!callback) {
|
|
27
|
+
callback = function (err, data) {
|
|
28
|
+
if (err) return rejectFunc(err);
|
|
29
|
+
resolveFunc(data);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!ctx.mqttClient) {
|
|
34
|
+
return callback(new Error('Not connected to MQTT'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ctx.wsReqNumber += 1;
|
|
38
|
+
let baseTaskNumber = ++ctx.wsTaskNumber;
|
|
39
|
+
|
|
40
|
+
const makeTask = (label, queueName, extraPayload = {}) => ({
|
|
41
|
+
failure_count: null,
|
|
42
|
+
label: String(label),
|
|
43
|
+
payload: JSON.stringify({
|
|
44
|
+
thread_key: threadID,
|
|
45
|
+
theme_fbid: themeFBID,
|
|
46
|
+
sync_group: 1,
|
|
47
|
+
...extraPayload,
|
|
48
|
+
}),
|
|
49
|
+
queue_name: typeof queueName === 'string' ? queueName : JSON.stringify(queueName),
|
|
50
|
+
task_id: baseTaskNumber++,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const messages = [
|
|
54
|
+
{
|
|
55
|
+
label: 1013,
|
|
56
|
+
queue: ['ai_generated_theme', String(threadID)],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: 1037,
|
|
60
|
+
queue: ['msgr_custom_thread_theme', String(threadID)],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: 1028,
|
|
64
|
+
queue: ['thread_theme_writer', String(threadID)],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
label: 43,
|
|
68
|
+
queue: 'thread_theme',
|
|
69
|
+
extra: { source: null, payload: null },
|
|
70
|
+
},
|
|
71
|
+
].map(({ label, queue, extra }) => {
|
|
72
|
+
ctx.wsReqNumber += 1;
|
|
73
|
+
return {
|
|
74
|
+
app_id: '772021112871879',
|
|
75
|
+
payload: JSON.stringify({
|
|
76
|
+
epoch_id: parseInt(utils.generateOfflineThreadingID()),
|
|
77
|
+
tasks: [makeTask(label, queue, extra)],
|
|
78
|
+
version_id: '24227364673632991',
|
|
79
|
+
}),
|
|
80
|
+
//pwa_version: '1',
|
|
81
|
+
request_id: ctx.wsReqNumber,
|
|
82
|
+
type: 3,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
messages.forEach((msg, idx) => {
|
|
88
|
+
ctx.mqttClient.publish(
|
|
89
|
+
'/ls_req',
|
|
90
|
+
JSON.stringify(msg),
|
|
91
|
+
{ qos: 1, retain: false },
|
|
92
|
+
idx === messages.length - 1 && callback ? callback : undefined
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (callback) callback(err);
|
|
97
|
+
else throw err;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return returnPromise;
|
|
101
|
+
};
|
|
275
102
|
};
|
|
276
103
|
/** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Please give credits if reused. */
|
package/utils.js
CHANGED
|
@@ -2878,6 +2878,10 @@ function cleanHTML(text) {
|
|
|
2878
2878
|
return text;
|
|
2879
2879
|
}
|
|
2880
2880
|
|
|
2881
|
+
function delay(ms) {
|
|
2882
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2881
2885
|
module.exports = {
|
|
2882
2886
|
cleanHTML,
|
|
2883
2887
|
isReadableStream: isReadableStream,
|
|
@@ -2926,5 +2930,6 @@ module.exports = {
|
|
|
2926
2930
|
getJazoest,
|
|
2927
2931
|
getEventTime,
|
|
2928
2932
|
getSessionID,
|
|
2929
|
-
getFormData
|
|
2933
|
+
getFormData,
|
|
2934
|
+
delay
|
|
2930
2935
|
};
|