stfca 1.0.25 → 1.0.27
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 +46 -0
- package/package.json +22 -2
- package/src/listenMqtt.js +21 -1
- package/src/sendButtons.js +161 -0
- package/src/sendMessage.js +27 -0
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var log = require("npmlog");
|
|
|
6
6
|
var { checkForFCAUpdate } = require("./checkUpdate");
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const request = require('request');
|
|
9
10
|
/*var { getThemeColors } = require("../../func/utils/log.js");
|
|
10
11
|
var logger = require("../../func/utils/log.js");
|
|
11
12
|
var { cra, cv, cb, co } = getThemeColors();*/
|
|
@@ -279,6 +280,51 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
279
280
|
api.postFormData = function (url, body) {
|
|
280
281
|
return defaultFuncs.postFormData(url, ctx.jar, body);
|
|
281
282
|
};
|
|
283
|
+
|
|
284
|
+
const IMGBB_API_KEY = process.env.IMG_BB_KEY || '3e198e6ffe205d1c7968a92fd92177c9';
|
|
285
|
+
async function uploadImageToImgbb(image, expiration = 600) {
|
|
286
|
+
const formData = {};
|
|
287
|
+
if (Buffer.isBuffer(image)) {
|
|
288
|
+
formData.image = image.toString('base64');
|
|
289
|
+
} else if (typeof image === 'string') {
|
|
290
|
+
const dataUriMatch = image.match(/^data:image\/[a-zA-Z]+;base64,(.+)$/);
|
|
291
|
+
if (dataUriMatch) {
|
|
292
|
+
formData.image = dataUriMatch[1];
|
|
293
|
+
} else {
|
|
294
|
+
formData.image = image.trim();
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
throw new Error('Unsupported image type for ImgBB upload');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return new Promise((resolve, reject) => {
|
|
301
|
+
request.post(
|
|
302
|
+
{
|
|
303
|
+
url: 'https://api.imgbb.com/1/upload',
|
|
304
|
+
qs: {
|
|
305
|
+
expiration: expiration,
|
|
306
|
+
key: IMGBB_API_KEY
|
|
307
|
+
},
|
|
308
|
+
formData: formData,
|
|
309
|
+
timeout: 60000
|
|
310
|
+
},
|
|
311
|
+
function (error, response, body) {
|
|
312
|
+
if (error) return reject(error);
|
|
313
|
+
try {
|
|
314
|
+
const data = JSON.parse(body);
|
|
315
|
+
if (!data || !data.success) return reject(data || new Error('ImgBB upload failed'));
|
|
316
|
+
resolve(data);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
reject(err);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
api.uploadImageToImgbb = uploadImageToImgbb;
|
|
326
|
+
ctx.uploadImageToImgbb = uploadImageToImgbb;
|
|
327
|
+
|
|
282
328
|
api.getFreshDtsg = async function () {
|
|
283
329
|
try {
|
|
284
330
|
const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stfca",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "Unofficial Facebook Chat API for Node.js with Auto-Update System - Enhanced by ST | Sheikh Tamim",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -26,7 +26,27 @@
|
|
|
26
26
|
"unofficial",
|
|
27
27
|
"fca",
|
|
28
28
|
"st-fca",
|
|
29
|
-
"sheikh-tamim"
|
|
29
|
+
"sheikh-tamim",
|
|
30
|
+
"stfca",
|
|
31
|
+
"fbchatapi",
|
|
32
|
+
"fbchat",
|
|
33
|
+
"messenger-api",
|
|
34
|
+
"facebook-messenger",
|
|
35
|
+
"nodejs",
|
|
36
|
+
"javascript",
|
|
37
|
+
"auto-update",
|
|
38
|
+
"update-check",
|
|
39
|
+
"update-notifier",
|
|
40
|
+
"version-check",
|
|
41
|
+
"update-system",
|
|
42
|
+
"update-manager",
|
|
43
|
+
"update-handler",
|
|
44
|
+
"update-service",
|
|
45
|
+
"update-module",
|
|
46
|
+
"update-function",
|
|
47
|
+
"unofficial-facebook-chat-api",
|
|
48
|
+
"messengerwapper",
|
|
49
|
+
"e2ee"
|
|
30
50
|
],
|
|
31
51
|
"author": "ST | Sheikh Tamim",
|
|
32
52
|
"license": "MIT",
|
package/src/listenMqtt.js
CHANGED
|
@@ -118,7 +118,10 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
118
118
|
`📍 Region: ${ctx.region || 'PNB'}`,
|
|
119
119
|
`🔄 Auto-reconnect: ${ctx.globalOptions.autoReconnect ? 'Enabled' : 'Disabled'}${ctx.globalOptions.autoReconnect ? ' (reconnects every 3s on disconnect)' : ''}`,
|
|
120
120
|
`⏱️ MQTT Restart Interval: ${ctx.globalOptions.restartListenMqtt?.enable ? `${ctx.globalOptions.restartListenMqtt.timeRestart / 1000}s` : 'Disabled'}`,
|
|
121
|
-
'
|
|
121
|
+
'� This FCA is specially for ST BOT',
|
|
122
|
+
'🌐 GitHub: https://github.com/sheikhtamimlover/ST-BOT',
|
|
123
|
+
'📱 Owner IG: https://www.instagram.com/sheikh.tamim_lover',
|
|
124
|
+
'�🎨 Maintained & Enhanced by ST | Sheikh Tamim\n'
|
|
122
125
|
];
|
|
123
126
|
|
|
124
127
|
let index = 0;
|
|
@@ -236,6 +239,15 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
236
239
|
mqttClient.on('close', function () { });
|
|
237
240
|
}
|
|
238
241
|
|
|
242
|
+
function attachImgbbUrlToAttachment(api, attachment) {
|
|
243
|
+
if (!api || !api.uploadImageToImgbb || !attachment || attachment.type !== "photo" || !attachment.url) return;
|
|
244
|
+
api.uploadImageToImgbb(attachment.url).then((result) => {
|
|
245
|
+
if (result && result.data) {
|
|
246
|
+
attachment.imgbbUrl = result.data.url || result.data.display_url || (result.data.image && result.data.image.url);
|
|
247
|
+
}
|
|
248
|
+
}).catch(() => { });
|
|
249
|
+
}
|
|
250
|
+
|
|
239
251
|
function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
240
252
|
if (v.delta.class == "NewMessage") {
|
|
241
253
|
//Not tested for pages
|
|
@@ -257,6 +269,9 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
257
269
|
// Store thread type in context for sendMessage to use
|
|
258
270
|
if (!ctx.threadTypes) ctx.threadTypes = {};
|
|
259
271
|
ctx.threadTypes[fmtMsg.threadID] = fmtMsg.isSingleUser ? 'dm' : 'group';
|
|
272
|
+
if (fmtMsg.attachments && Array.isArray(fmtMsg.attachments)) {
|
|
273
|
+
fmtMsg.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
|
|
274
|
+
}
|
|
260
275
|
} catch (err) {
|
|
261
276
|
return globalCallback({
|
|
262
277
|
error: "Problem parsing message object.",
|
|
@@ -364,6 +379,9 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
364
379
|
timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
|
|
365
380
|
participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e => e.toString())
|
|
366
381
|
};
|
|
382
|
+
if (callbackToReturn.attachments && Array.isArray(callbackToReturn.attachments)) {
|
|
383
|
+
callbackToReturn.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
|
|
384
|
+
}
|
|
367
385
|
|
|
368
386
|
if (delta.deltaMessageReply.repliedToMessage) {
|
|
369
387
|
//Mention block - #2
|
|
@@ -397,6 +415,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
397
415
|
x.error = ex;
|
|
398
416
|
x.type = "unknown";
|
|
399
417
|
}
|
|
418
|
+
attachImgbbUrlToAttachment(api, x);
|
|
400
419
|
return x;
|
|
401
420
|
}),
|
|
402
421
|
args: (delta.deltaMessageReply.repliedToMessage.body || "").trim().split(/\s+/),
|
|
@@ -445,6 +464,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
445
464
|
x.error = ex;
|
|
446
465
|
x.type = "unknown";
|
|
447
466
|
}
|
|
467
|
+
attachImgbbUrlToAttachment(api, x);
|
|
448
468
|
return x;
|
|
449
469
|
}),
|
|
450
470
|
args: (fetchData.message.text || "").trim().split(/\s+/) || [],
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { generateOfflineThreadingID } = require('../utils');
|
|
4
|
+
|
|
5
|
+
function safeParseInt(value, fallback = 0) {
|
|
6
|
+
const parsed = parseInt(value);
|
|
7
|
+
return isNaN(parsed) ? fallback : parsed;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const SHUFFLE_SEED = 42;
|
|
11
|
+
|
|
12
|
+
function generateShufflePattern(length) {
|
|
13
|
+
const pattern = Array.from({ length }, (_, i) => i);
|
|
14
|
+
let seed = SHUFFLE_SEED;
|
|
15
|
+
for (let i = length - 1; i > 0; i--) {
|
|
16
|
+
seed = (seed * 9301 + 49297) % 233280;
|
|
17
|
+
const j = Math.floor((seed / 233280) * (i + 1));
|
|
18
|
+
[pattern[i], pattern[j]] = [pattern[j], pattern[i]];
|
|
19
|
+
}
|
|
20
|
+
return pattern;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function generateReversePattern(shufflePattern) {
|
|
24
|
+
const reversePattern = new Array(shufflePattern.length);
|
|
25
|
+
for (let i = 0; i < shufflePattern.length; i++) {
|
|
26
|
+
reversePattern[shufflePattern[i]] = i;
|
|
27
|
+
}
|
|
28
|
+
return reversePattern;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function unrearrange(rearrangedId) {
|
|
32
|
+
try {
|
|
33
|
+
if (!rearrangedId || typeof rearrangedId !== "string") {
|
|
34
|
+
console.error("Unrearrange: Invalid input");
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const pattern = generateShufflePattern(rearrangedId.length);
|
|
38
|
+
const reversePattern = generateReversePattern(pattern);
|
|
39
|
+
const original = new Array(rearrangedId.length);
|
|
40
|
+
for (let i = 0; i < rearrangedId.length; i++) {
|
|
41
|
+
original[reversePattern[i]] = rearrangedId[i];
|
|
42
|
+
}
|
|
43
|
+
return original.join("");
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error("Unrearrange error:", err.message);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
51
|
+
return function sendButtons(
|
|
52
|
+
call_to_actions,
|
|
53
|
+
text,
|
|
54
|
+
threadID,
|
|
55
|
+
messageID,
|
|
56
|
+
callback,
|
|
57
|
+
) {
|
|
58
|
+
let resolveFunc = () => {};
|
|
59
|
+
let rejectFunc = () => {};
|
|
60
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
61
|
+
resolveFunc = resolve;
|
|
62
|
+
rejectFunc = reject;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (!callback) {
|
|
66
|
+
callback = function (err, data) {
|
|
67
|
+
if (err) return rejectFunc(err);
|
|
68
|
+
resolveFunc(data);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!ctx.mqttClient) {
|
|
73
|
+
const err = new Error("Not connected to MQTT");
|
|
74
|
+
callback(err);
|
|
75
|
+
return returnPromise;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!ctx.reqCallbacks) ctx.reqCallbacks = {};
|
|
79
|
+
if (!ctx.callback_Task) ctx.callback_Task = {};
|
|
80
|
+
|
|
81
|
+
ctx.wsReqNumber += 1;
|
|
82
|
+
ctx.wsTaskNumber += 1;
|
|
83
|
+
|
|
84
|
+
const reqID = ctx.wsReqNumber;
|
|
85
|
+
const cta_id = unrearrange(call_to_actions);
|
|
86
|
+
|
|
87
|
+
if (!cta_id) {
|
|
88
|
+
const err = new Error("Failed to unrearrange messageID");
|
|
89
|
+
callback(err);
|
|
90
|
+
return returnPromise;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const taskPayload = {
|
|
94
|
+
thread_id: threadID,
|
|
95
|
+
otid: safeParseInt(generateOfflineThreadingID()),
|
|
96
|
+
source: 65544,
|
|
97
|
+
send_type: 5,
|
|
98
|
+
sync_group: 1,
|
|
99
|
+
forwarded_msg_id: cta_id,
|
|
100
|
+
strip_forwarded_msg_caption: 1,
|
|
101
|
+
skip_url_preview_gen: 0,
|
|
102
|
+
text: text || "",
|
|
103
|
+
initiating_source: 1,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (messageID != undefined && messageID != null) {
|
|
107
|
+
taskPayload.reply_metadata = {
|
|
108
|
+
reply_source_id: messageID,
|
|
109
|
+
reply_source_type: 1,
|
|
110
|
+
reply_type: 0,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const task = {
|
|
115
|
+
failure_count: null,
|
|
116
|
+
label: "46",
|
|
117
|
+
payload: JSON.stringify(taskPayload),
|
|
118
|
+
queue_name: `${threadID}`,
|
|
119
|
+
task_id: ctx.wsTaskNumber,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const content = {
|
|
123
|
+
app_id: "2220391788200892",
|
|
124
|
+
payload: JSON.stringify({
|
|
125
|
+
data_trace_id: null,
|
|
126
|
+
epoch_id: safeParseInt(generateOfflineThreadingID()),
|
|
127
|
+
tasks: [task],
|
|
128
|
+
version_id: "24180904141611263",
|
|
129
|
+
}),
|
|
130
|
+
request_id: reqID,
|
|
131
|
+
type: 3,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Setup the callback listener
|
|
135
|
+
ctx.callback_Task[reqID] = {
|
|
136
|
+
type: "call_to_actions",
|
|
137
|
+
callback: function (err, data) {
|
|
138
|
+
if (err) return callback(err);
|
|
139
|
+
|
|
140
|
+
const messageID =
|
|
141
|
+
JSON.parse(data)?.step?.[1]?.[2]?.[2]?.[1]?.[3] || null;
|
|
142
|
+
|
|
143
|
+
const result = {
|
|
144
|
+
messageID: cta_id,
|
|
145
|
+
senderID: ctx.userID,
|
|
146
|
+
threadID: threadID,
|
|
147
|
+
action: "cta_buttons",
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
callback(null, result);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(content), {
|
|
155
|
+
qos: 1,
|
|
156
|
+
retain: false,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return returnPromise;
|
|
160
|
+
};
|
|
161
|
+
};
|
package/src/sendMessage.js
CHANGED
|
@@ -42,6 +42,32 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
42
42
|
if (!resData || resData.error || !resData.payload){
|
|
43
43
|
throw new Error(resData);
|
|
44
44
|
}
|
|
45
|
+
return resData.payload;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function ensureImgbbUrl(msg) {
|
|
49
|
+
if (!api.uploadImageToImgbb) return;
|
|
50
|
+
try {
|
|
51
|
+
if (msg.attachment && typeof msg.attachment === 'string') {
|
|
52
|
+
const uploaded = await api.uploadImageToImgbb(msg.attachment).catch(() => null);
|
|
53
|
+
if (uploaded && uploaded.data) {
|
|
54
|
+
msg.url = uploaded.data.url || uploaded.data.display_url || (uploaded.data.image && uploaded.data.image.url);
|
|
55
|
+
delete msg.attachment;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (msg.url && typeof msg.url === 'string') {
|
|
59
|
+
const dataUri = /^data:image\/[a-zA-Z]+;base64,/.test(msg.url);
|
|
60
|
+
const base64String = /^[A-Za-z0-9+/=]+$/.test(msg.url.replace(/\s+/g, '')) && msg.url.length > 100;
|
|
61
|
+
if (dataUri || base64String) {
|
|
62
|
+
const uploaded = await api.uploadImageToImgbb(msg.url).catch(() => null);
|
|
63
|
+
if (uploaded && uploaded.data) {
|
|
64
|
+
msg.url = uploaded.data.url || uploaded.data.display_url || (uploaded.data.image && uploaded.data.image.url);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
45
71
|
}
|
|
46
72
|
|
|
47
73
|
async function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
|
|
@@ -122,6 +148,7 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
122
148
|
if (msgType === "String") {
|
|
123
149
|
msg = { body: msg };
|
|
124
150
|
}
|
|
151
|
+
await ensureImgbbUrl(msg);
|
|
125
152
|
|
|
126
153
|
// Auto-detect if this is a DM if not explicitly specified
|
|
127
154
|
if (isSingleUser === null && ctx.threadTypes && ctx.threadTypes[threadID]) {
|