ayman-fca 1.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/README.md +81 -0
- package/func/checkUpdate.js +13 -0
- package/func/logAdapter.js +30 -0
- package/func/logger.js +66 -0
- package/index.d.ts +751 -0
- package/index.js +15 -0
- package/module/config.js +38 -0
- package/module/login.js +111 -0
- package/module/loginHelper.js +1296 -0
- package/module/options.js +37 -0
- package/package.json +78 -0
- package/src/api/action/addExternalModule.js +19 -0
- package/src/api/action/changeAvatar.js +137 -0
- package/src/api/action/changeBio.js +48 -0
- package/src/api/action/enableAutoSaveAppState.js +72 -0
- package/src/api/action/getCurrentUserID.js +11 -0
- package/src/api/action/handleFriendRequest.js +33 -0
- package/src/api/action/logout.js +76 -0
- package/src/api/action/refreshFb_dtsg.js +62 -0
- package/src/api/action/setPostReaction.js +106 -0
- package/src/api/action/story.js +118 -0
- package/src/api/action/unfriend.js +30 -0
- package/src/api/http/httpGet.js +28 -0
- package/src/api/http/httpPost.js +32 -0
- package/src/api/http/postFormData.js +23 -0
- package/src/api/messaging/J +1 -0
- package/src/api/messaging/addUserToGroup.js +70 -0
- package/src/api/messaging/changeAdminStatus.js +72 -0
- package/src/api/messaging/changeArchivedStatus.js +31 -0
- package/src/api/messaging/changeBlockedStatus.js +27 -0
- package/src/api/messaging/changeGroupImage.js +91 -0
- package/src/api/messaging/changeNickname.js +70 -0
- package/src/api/messaging/changeThreadColor.js +44 -0
- package/src/api/messaging/changeThreadEmoji.js +111 -0
- package/src/api/messaging/createNewGroup.js +50 -0
- package/src/api/messaging/createPoll.js +52 -0
- package/src/api/messaging/createThemeAI.js +98 -0
- package/src/api/messaging/deleteMessage.js +73 -0
- package/src/api/messaging/deleteThread.js +29 -0
- package/src/api/messaging/editMessage.js +67 -0
- package/src/api/messaging/forwardAttachment.js +55 -0
- package/src/api/messaging/forwardMessage.js +73 -0
- package/src/api/messaging/getEmojiUrl.js +29 -0
- package/src/api/messaging/getFriendsList.js +82 -0
- package/src/api/messaging/getMessage.js +829 -0
- package/src/api/messaging/getThemePictures.js +62 -0
- package/src/api/messaging/groupActions.js +119 -0
- package/src/api/messaging/handleMessageRequest.js +31 -0
- package/src/api/messaging/markAsDelivered.js +31 -0
- package/src/api/messaging/markAsRead.js +88 -0
- package/src/api/messaging/markAsReadAll.js +28 -0
- package/src/api/messaging/markAsSeen.js +30 -0
- package/src/api/messaging/muteThread.js +27 -0
- package/src/api/messaging/notes.js +101 -0
- package/src/api/messaging/removeUserFromGroup.js +51 -0
- package/src/api/messaging/resolvePhotoUrl.js +29 -0
- package/src/api/messaging/scheduler.js +100 -0
- package/src/api/messaging/searchForThread.js +32 -0
- package/src/api/messaging/sendMessage.js +270 -0
- package/src/api/messaging/sendTypingIndicator.js +62 -0
- package/src/api/messaging/setMessageReaction.js +91 -0
- package/src/api/messaging/setTitle.js +86 -0
- package/src/api/messaging/shareContact.js +47 -0
- package/src/api/messaging/threadColors.js +128 -0
- package/src/api/messaging/unsendMessage.js +73 -0
- package/src/api/messaging/uploadAttachment.js +492 -0
- package/src/api/socket/core/connectMqtt.js +259 -0
- package/src/api/socket/core/emitAuth.js +79 -0
- package/src/api/socket/core/getSeqID.js +170 -0
- package/src/api/socket/core/getTaskResponseData.js +27 -0
- package/src/api/socket/core/parseDelta.js +377 -0
- package/src/api/socket/detail/buildStream.js +215 -0
- package/src/api/socket/detail/constants.js +29 -0
- package/src/api/socket/listenMqtt.js +377 -0
- package/src/api/socket/middleware/index.js +80 -0
- package/src/api/threads/getThreadHistory.js +664 -0
- package/src/api/threads/getThreadInfo.js +296 -0
- package/src/api/threads/getThreadList.js +293 -0
- package/src/api/threads/getThreadPictures.js +43 -0
- package/src/api/user/J +1 -0
- package/src/api/user/getUserID.js +48 -0
- package/src/api/user/getUserInfo.js +402 -0
- package/src/api/user/getUserInfoV2.js +134 -0
- package/src/core/sendReqMqtt.js +69 -0
- package/src/database/helpers.js +36 -0
- package/src/database/models/index.js +55 -0
- package/src/database/models/thread.js +44 -0
- package/src/database/models/user.js +39 -0
- package/src/database/threadData.js +92 -0
- package/src/database/userData.js +88 -0
- package/src/remote/remoteClient.js +71 -0
- package/src/utils/broadcast.js +62 -0
- package/src/utils/client.js +10 -0
- package/src/utils/constants.js +53 -0
- package/src/utils/cookies.js +73 -0
- package/src/utils/format/attachment.js +357 -0
- package/src/utils/format/cookie.js +9 -0
- package/src/utils/format/date.js +50 -0
- package/src/utils/format/decode.js +44 -0
- package/src/utils/format/delta.js +194 -0
- package/src/utils/format/ids.js +64 -0
- package/src/utils/format/index.js +64 -0
- package/src/utils/format/message.js +88 -0
- package/src/utils/format/presence.js +132 -0
- package/src/utils/format/readTyp.js +44 -0
- package/src/utils/format/thread.js +42 -0
- package/src/utils/format/utils.js +141 -0
- package/src/utils/headers.js +96 -0
- package/src/utils/loginParser/autoLogin.js +125 -0
- package/src/utils/loginParser/helpers.js +43 -0
- package/src/utils/loginParser/index.js +10 -0
- package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
- package/src/utils/loginParser/textUtils.js +28 -0
- package/src/utils/request/H +1 -0
- package/src/utils/request/client.js +33 -0
- package/src/utils/request/config.js +25 -0
- package/src/utils/request/defaults.js +40 -0
- package/src/utils/request/helpers.js +31 -0
- package/src/utils/request/index.js +12 -0
- package/src/utils/request/methods.js +92 -0
- package/src/utils/request/proxy.js +23 -0
- package/src/utils/request/retry.js +87 -0
- package/src/utils/request/sanitize.js +41 -0
- package/src/utils/sessionKeeper.js +275 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Story API
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// مستوحى من: ws3-fca | مطوَّر بواسطة أيمن
|
|
5
|
+
//
|
|
6
|
+
// api.story.create(text, font, background)
|
|
7
|
+
// api.story.react(storyID, emoji)
|
|
8
|
+
// api.story.msg(storyID, message)
|
|
9
|
+
// ============================================================
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
13
|
+
|
|
14
|
+
const FONTS = {
|
|
15
|
+
headline: "1919119914775364",
|
|
16
|
+
classic: "516266749248495",
|
|
17
|
+
fancy: "1790435664339626",
|
|
18
|
+
casual: "516266749248495"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const BACKGROUNDS = {
|
|
22
|
+
orange: "2163607613910521",
|
|
23
|
+
blue: "401372137331149",
|
|
24
|
+
green: "367314917184744",
|
|
25
|
+
modern: "554617635055752",
|
|
26
|
+
red: "1234567890123456"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ALLOWED_REACTIONS = ["❤️","👍","🤗","😆","😡","😢","😮"];
|
|
30
|
+
|
|
31
|
+
function getStoryID(urlOrID) {
|
|
32
|
+
try {
|
|
33
|
+
const u = new URL(urlOrID);
|
|
34
|
+
const parts = u.pathname.split("/");
|
|
35
|
+
const idx = parts.indexOf("stories");
|
|
36
|
+
if (idx !== -1 && parts.length > idx + 2) return parts[idx + 2];
|
|
37
|
+
} catch (_) {}
|
|
38
|
+
return urlOrID;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ✅ إنشاء Story نصية
|
|
42
|
+
async function create(message, fontName = "classic", backgroundName = "blue") {
|
|
43
|
+
const fontId = FONTS[fontName.toLowerCase()] || FONTS.classic;
|
|
44
|
+
const bgId = BACKGROUNDS[backgroundName.toLowerCase()] || BACKGROUNDS.blue;
|
|
45
|
+
|
|
46
|
+
const variables = {
|
|
47
|
+
input: {
|
|
48
|
+
audiences: [{ stories: { self: { target_id: ctx.userID } } }],
|
|
49
|
+
audiences_is_complete: true,
|
|
50
|
+
logging: { composer_session_id: "ayman-story-" + Date.now() },
|
|
51
|
+
navigation_data: { attribution_id_v2: "StoriesCreateRoot.react,comet.stories.create" },
|
|
52
|
+
source: "WWW",
|
|
53
|
+
message: { ranges: [], text: message },
|
|
54
|
+
text_format_metadata: { inspirations_custom_font_id: fontId },
|
|
55
|
+
text_format_preset_id: bgId,
|
|
56
|
+
tracking: [null],
|
|
57
|
+
actor_id: ctx.userID,
|
|
58
|
+
client_mutation_id: "1"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const form = {
|
|
63
|
+
fb_api_caller_class: "RelayModern",
|
|
64
|
+
fb_api_req_friendly_name: "StoriesCreateMutation",
|
|
65
|
+
variables: JSON.stringify(variables),
|
|
66
|
+
doc_id: "24226878183562473"
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form);
|
|
70
|
+
const data = res?.data || res;
|
|
71
|
+
if (data?.errors) throw new Error(JSON.stringify(data.errors));
|
|
72
|
+
const storyID = data?.data?.story_create?.viewer?.actor?.story_bucket?.nodes?.[0]?.first_story_to_show?.id;
|
|
73
|
+
if (!storyID) throw new Error("AYMAN-FCA: لم يُعثر على storyID");
|
|
74
|
+
return { success: true, storyID };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ✅ رد أو تفاعل مع Story
|
|
78
|
+
async function sendStoryReply(storyIdOrUrl, message, isReaction) {
|
|
79
|
+
if (!storyIdOrUrl) throw new Error("AYMAN-FCA: storyID مطلوب");
|
|
80
|
+
if (!message) throw new Error("AYMAN-FCA: message مطلوب");
|
|
81
|
+
|
|
82
|
+
const storyID = getStoryID(storyIdOrUrl);
|
|
83
|
+
const variables = {
|
|
84
|
+
input: {
|
|
85
|
+
attribution_id_v2: "StoriesCometSuspenseRoot.react,comet.stories.viewer,via_cold_start",
|
|
86
|
+
message,
|
|
87
|
+
story_id: storyID,
|
|
88
|
+
story_reply_type: isReaction ? "LIGHT_WEIGHT" : "TEXT",
|
|
89
|
+
actor_id: ctx.userID,
|
|
90
|
+
client_mutation_id: String(Math.floor(Math.random() * 10 + 1))
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (isReaction) {
|
|
95
|
+
if (!ALLOWED_REACTIONS.includes(message))
|
|
96
|
+
throw new Error(`AYMAN-FCA: تفاعل غير صالح. استخدم: ${ALLOWED_REACTIONS.join(" ")}`);
|
|
97
|
+
variables.input.lightweight_reaction_actions = { offsets: [0], reaction: message };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const form = {
|
|
101
|
+
fb_api_caller_class: "RelayModern",
|
|
102
|
+
fb_api_req_friendly_name: "useStoriesSendReplyMutation",
|
|
103
|
+
variables: JSON.stringify(variables),
|
|
104
|
+
doc_id: "9697491553691692"
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form);
|
|
108
|
+
const data = res?.data || res;
|
|
109
|
+
if (data?.errors) throw new Error(JSON.stringify(data.errors));
|
|
110
|
+
return { success: true, result: data?.data?.direct_message_reply };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
create,
|
|
115
|
+
react: (storyIdOrUrl, reaction) => sendStoryReply(storyIdOrUrl, reaction, true),
|
|
116
|
+
msg: (storyIdOrUrl, message) => sendStoryReply(storyIdOrUrl, message, false)
|
|
117
|
+
};
|
|
118
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Unfriend
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const log = require("../../../func/logAdapter");
|
|
8
|
+
const { parseAndCheckLogin } = require("../../utils/client");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function unfriend(userID, callback) {
|
|
12
|
+
let resolve, reject;
|
|
13
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
14
|
+
callback = callback || (err => err ? reject(err) : resolve());
|
|
15
|
+
|
|
16
|
+
const form = {
|
|
17
|
+
uid: userID,
|
|
18
|
+
unref: "bd_friends_tab",
|
|
19
|
+
floc: "friends_tab",
|
|
20
|
+
"nctr[_mod]": `pagelet_timeline_app_collection_${ctx.userID}:2356318349:2`
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
defaultFuncs.post("https://www.facebook.com/ajax/profile/removefriendconfirm.php", ctx.jar, form)
|
|
24
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
25
|
+
.then(res => { if (res.error) throw res; callback(null, true); })
|
|
26
|
+
.catch(err => { log.error("unfriend", err); callback(err); });
|
|
27
|
+
|
|
28
|
+
return p;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — HTTP GET
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { getType } = require("../../utils/format");
|
|
8
|
+
const { get } = require("../../utils/request");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function httpGet(url, form, callback, notAPI) {
|
|
12
|
+
let resolve, reject;
|
|
13
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
14
|
+
|
|
15
|
+
if (!callback && (getType(form) === "Function" || getType(form) === "AsyncFunction")) {
|
|
16
|
+
callback = form; form = {};
|
|
17
|
+
}
|
|
18
|
+
form = form || {};
|
|
19
|
+
callback = callback || ((err, data) => err ? reject(err) : resolve(data));
|
|
20
|
+
|
|
21
|
+
const executor = notAPI ? get : defaultFuncs.get;
|
|
22
|
+
executor(url, ctx.jar, form)
|
|
23
|
+
.then(res => callback(null, res?.data ?? res))
|
|
24
|
+
.catch(err => callback(err));
|
|
25
|
+
|
|
26
|
+
return p;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — HTTP POST
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { post } = require("../../utils/request");
|
|
8
|
+
const { getType } = require("../../utils/format");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function httpPost(url, form, callback, notAPI) {
|
|
12
|
+
let resolve, reject;
|
|
13
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
14
|
+
|
|
15
|
+
if (!callback && (getType(form) === "Function" || getType(form) === "AsyncFunction")) {
|
|
16
|
+
callback = form; form = {};
|
|
17
|
+
}
|
|
18
|
+
form = form || {};
|
|
19
|
+
callback = callback || ((err, data) => err ? reject(err) : resolve(data));
|
|
20
|
+
|
|
21
|
+
const executor = notAPI ? post : defaultFuncs.post;
|
|
22
|
+
executor(url, ctx.jar, form, ctx.globalOptions)
|
|
23
|
+
.then(res => {
|
|
24
|
+
let data = res?.data ?? res;
|
|
25
|
+
if (data && typeof data === "object") data = JSON.stringify(data, null, 2);
|
|
26
|
+
callback(null, data);
|
|
27
|
+
})
|
|
28
|
+
.catch(err => callback(err));
|
|
29
|
+
|
|
30
|
+
return p;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — HTTP POST Form Data
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { postFormData } = require("../../utils/request");
|
|
8
|
+
const { getType } = require("../../utils/format");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function httpPostFormData(url, form, callback) {
|
|
12
|
+
let resolve, reject;
|
|
13
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
14
|
+
|
|
15
|
+
callback = callback || ((err, data) => err ? reject(err) : resolve(data));
|
|
16
|
+
|
|
17
|
+
postFormData(url, ctx.jar, form || {}, {}, ctx.globalOptions, ctx)
|
|
18
|
+
.then(res => callback(null, res?.data ?? res))
|
|
19
|
+
.catch(err => callback(err));
|
|
20
|
+
|
|
21
|
+
return p;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Add User To Group
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { generateOfflineThreadingID, getType } = require("../../utils/format");
|
|
8
|
+
|
|
9
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
10
|
+
return function addUserToGroup(userID, threadID, callback) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
if (!ctx.mqttClient) {
|
|
13
|
+
const err = new Error("AYMAN-FCA: MQTT غير متصل");
|
|
14
|
+
callback?.(err); return reject(err);
|
|
15
|
+
}
|
|
16
|
+
if (getType(threadID) !== "Number" && getType(threadID) !== "String") {
|
|
17
|
+
const err = new Error("threadID يجب أن يكون Number أو String");
|
|
18
|
+
callback?.(err); return reject(err);
|
|
19
|
+
}
|
|
20
|
+
if (getType(userID) !== "Array") userID = [userID];
|
|
21
|
+
|
|
22
|
+
const reqID = ++ctx.wsReqNumber;
|
|
23
|
+
const taskID = ++ctx.wsTaskNumber;
|
|
24
|
+
|
|
25
|
+
const content = {
|
|
26
|
+
app_id: "772021112871879",
|
|
27
|
+
payload: JSON.stringify({
|
|
28
|
+
epoch_id: generateOfflineThreadingID(),
|
|
29
|
+
tasks: [{
|
|
30
|
+
failure_count: null,
|
|
31
|
+
label: "23",
|
|
32
|
+
payload: JSON.stringify({ thread_key: threadID, contact_ids: userID, sync_group: 1 }),
|
|
33
|
+
queue_name: String(threadID),
|
|
34
|
+
task_id: taskID
|
|
35
|
+
}],
|
|
36
|
+
version_id: "24502707779384158"
|
|
37
|
+
}),
|
|
38
|
+
request_id: reqID,
|
|
39
|
+
type: 3
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let done = false;
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
if (done) return; done = true;
|
|
45
|
+
ctx.mqttClient?.removeListener("message", handleRes);
|
|
46
|
+
callback?.(null, { success: true }); resolve({ success: true });
|
|
47
|
+
}, 10000);
|
|
48
|
+
|
|
49
|
+
const handleRes = (topic, message) => {
|
|
50
|
+
if (topic !== "/ls_resp") return;
|
|
51
|
+
let msg;
|
|
52
|
+
try { msg = JSON.parse(message.toString()); msg.payload = JSON.parse(msg.payload); } catch { return; }
|
|
53
|
+
if (msg.request_id !== reqID) return;
|
|
54
|
+
if (done) return; done = true;
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
ctx.mqttClient?.removeListener("message", handleRes);
|
|
57
|
+
callback?.(null, { success: true }); resolve({ success: true });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
ctx.mqttClient.on("message", handleRes);
|
|
61
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, err => {
|
|
62
|
+
if (err) {
|
|
63
|
+
if (done) return; done = true;
|
|
64
|
+
clearTimeout(timer); ctx.mqttClient?.removeListener("message", handleRes);
|
|
65
|
+
callback?.(err); reject(err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Change Admin Status
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { generateOfflineThreadingID, getType } = require("../../utils/format");
|
|
8
|
+
|
|
9
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
10
|
+
|
|
11
|
+
function buildTasks(threadID, adminID, adminStatus) {
|
|
12
|
+
const ids = getType(adminID) === "Array" ? adminID : [adminID];
|
|
13
|
+
const isAdm = adminStatus ? 1 : 0;
|
|
14
|
+
return ids.map((id, i) => ({
|
|
15
|
+
failure_count: null,
|
|
16
|
+
label: "25",
|
|
17
|
+
payload: JSON.stringify({ thread_key: threadID, contact_id: id, is_admin: isAdm }),
|
|
18
|
+
queue_name: "admin_status",
|
|
19
|
+
task_id: i + 1
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function viaMqtt(threadID, adminID, adminStatus) {
|
|
24
|
+
if (!ctx.mqttClient) throw new Error("AYMAN-FCA: MQTT غير متصل");
|
|
25
|
+
if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
|
|
26
|
+
const reqID = ++ctx.wsReqNumber;
|
|
27
|
+
const form = JSON.stringify({
|
|
28
|
+
app_id: "2220391788200892",
|
|
29
|
+
payload: JSON.stringify({
|
|
30
|
+
epoch_id: generateOfflineThreadingID(),
|
|
31
|
+
tasks: buildTasks(threadID, adminID, adminStatus),
|
|
32
|
+
version_id: "8798795233522156"
|
|
33
|
+
}),
|
|
34
|
+
request_id: reqID,
|
|
35
|
+
type: 3
|
|
36
|
+
});
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
ctx.mqttClient.publish("/ls_req", form, { qos: 1, retain: false }, err =>
|
|
39
|
+
err ? reject(err) : resolve({ success: true })
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function viaHttp(threadID, adminID, adminStatus) {
|
|
45
|
+
if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
|
|
46
|
+
const reqID = ++ctx.wsReqNumber;
|
|
47
|
+
const form = JSON.stringify({
|
|
48
|
+
app_id: "772021112871879",
|
|
49
|
+
payload: JSON.stringify({
|
|
50
|
+
epoch_id: generateOfflineThreadingID(),
|
|
51
|
+
tasks: buildTasks(threadID, adminID, adminStatus),
|
|
52
|
+
data_trace_id: null
|
|
53
|
+
}),
|
|
54
|
+
request_id: reqID,
|
|
55
|
+
type: 3
|
|
56
|
+
});
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
if (!ctx.mqttClient) return reject(new Error("AYMAN-FCA: MQTT غير متصل"));
|
|
59
|
+
ctx.mqttClient.publish("/ls_req", form, {}, err =>
|
|
60
|
+
err ? reject(err) : resolve()
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return function changeAdminStatus(threadID, adminID, adminStatus) {
|
|
66
|
+
if (ctx.mqttClient) {
|
|
67
|
+
try { return viaMqtt(threadID, adminID, adminStatus); }
|
|
68
|
+
catch (_) { return viaHttp(threadID, adminID, adminStatus); }
|
|
69
|
+
}
|
|
70
|
+
return viaHttp(threadID, adminID, adminStatus);
|
|
71
|
+
};
|
|
72
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Change Archived Status
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const log = require("../../../func/logAdapter");
|
|
8
|
+
const { parseAndCheckLogin } = require("../../utils/client");
|
|
9
|
+
const { formatID } = require("../../utils/format");
|
|
10
|
+
|
|
11
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
12
|
+
return function changeArchivedStatus(threadOrThreads, archive, callback) {
|
|
13
|
+
let resolve, reject;
|
|
14
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
15
|
+
callback = callback || (err => err ? reject(err) : resolve());
|
|
16
|
+
|
|
17
|
+
const form = {};
|
|
18
|
+
const threads = Array.isArray(threadOrThreads) ? threadOrThreads : [threadOrThreads];
|
|
19
|
+
threads.forEach(t => { form[`ids[${formatID(t)}]`] = archive; });
|
|
20
|
+
|
|
21
|
+
defaultFuncs.post(
|
|
22
|
+
"https://www.facebook.com/ajax/mercury/change_archived_status.php",
|
|
23
|
+
ctx.jar, form
|
|
24
|
+
)
|
|
25
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
26
|
+
.then(res => { if (res.error) throw res; callback(); })
|
|
27
|
+
.catch(err => { log.error("changeArchivedStatus", err); callback(err); });
|
|
28
|
+
|
|
29
|
+
return p;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Change Blocked Status
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const log = require("../../../func/logAdapter");
|
|
8
|
+
const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function changeBlockedStatus(userID, block, callback) {
|
|
12
|
+
let resolve, reject;
|
|
13
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
14
|
+
callback = callback || (err => err ? reject(err) : resolve());
|
|
15
|
+
|
|
16
|
+
defaultFuncs.post(
|
|
17
|
+
`https://www.facebook.com/messaging/${block ? "" : "un"}block_messages/`,
|
|
18
|
+
ctx.jar, { fbid: userID }
|
|
19
|
+
)
|
|
20
|
+
.then(saveCookies(ctx.jar))
|
|
21
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
22
|
+
.then(res => { if (res.error) throw res; callback(); })
|
|
23
|
+
.catch(err => { log.error("changeBlockedStatus", err); callback(err); });
|
|
24
|
+
|
|
25
|
+
return p;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
|
+
const log = require("../../../func/logAdapter");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
function handleUpload(image) {
|
|
8
|
+
const form = {
|
|
9
|
+
images_only: "true",
|
|
10
|
+
fb_dtsg: ctx.fb_dtsg,
|
|
11
|
+
"attachment[]": image
|
|
12
|
+
};
|
|
13
|
+
return defaultFuncs
|
|
14
|
+
.postFormData("https://www.facebook.com/ajax/mercury/upload.php", ctx.jar, form, {})
|
|
15
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
16
|
+
.then(resData => {
|
|
17
|
+
if (resData.error) throw resData;
|
|
18
|
+
return resData.payload.metadata[0];
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return function changeGroupImage(image, threadID, callback) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
if (!ctx.mqttClient) {
|
|
24
|
+
const err = new Error("Not connected to MQTT");
|
|
25
|
+
callback?.(err);
|
|
26
|
+
return reject(err);
|
|
27
|
+
}
|
|
28
|
+
if (!threadID || typeof threadID !== "string") {
|
|
29
|
+
const err = new Error("Invalid threadID");
|
|
30
|
+
callback?.(err);
|
|
31
|
+
return reject(err);
|
|
32
|
+
}
|
|
33
|
+
const reqID = ++ctx.wsReqNumber;
|
|
34
|
+
const taskID = ++ctx.wsTaskNumber;
|
|
35
|
+
const onResponse = (topic, message) => {
|
|
36
|
+
if (topic !== "/ls_resp") return;
|
|
37
|
+
let jsonMsg;
|
|
38
|
+
try {
|
|
39
|
+
jsonMsg = JSON.parse(message.toString());
|
|
40
|
+
jsonMsg.payload = JSON.parse(jsonMsg.payload);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (jsonMsg.request_id !== reqID) return;
|
|
45
|
+
ctx.mqttClient.removeListener("message", onResponse);
|
|
46
|
+
callback?.(null, { success: true, response: jsonMsg.payload });
|
|
47
|
+
return resolve({ success: true, response: jsonMsg.payload });
|
|
48
|
+
};
|
|
49
|
+
ctx.mqttClient.on("message", onResponse);
|
|
50
|
+
handleUpload(image)
|
|
51
|
+
.then(payload => {
|
|
52
|
+
const imageID = payload.image_id;
|
|
53
|
+
const taskPayload = {
|
|
54
|
+
thread_key: threadID,
|
|
55
|
+
image_id: imageID,
|
|
56
|
+
sync_group: 1
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const mqttPayload = {
|
|
60
|
+
epoch_id: generateOfflineThreadingID(),
|
|
61
|
+
tasks: [
|
|
62
|
+
{
|
|
63
|
+
failure_count: null,
|
|
64
|
+
label: "37",
|
|
65
|
+
payload: JSON.stringify(taskPayload),
|
|
66
|
+
queue_name: "thread_image",
|
|
67
|
+
task_id: taskID
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
version_id: "8798795233522156"
|
|
71
|
+
};
|
|
72
|
+
const request = {
|
|
73
|
+
app_id: "2220391788200892",
|
|
74
|
+
payload: JSON.stringify(mqttPayload),
|
|
75
|
+
request_id: reqID,
|
|
76
|
+
type: 3
|
|
77
|
+
};
|
|
78
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(request), {
|
|
79
|
+
qos: 1,
|
|
80
|
+
retain: false
|
|
81
|
+
});
|
|
82
|
+
})
|
|
83
|
+
.catch(err => {
|
|
84
|
+
ctx.mqttClient.removeListener("message", onResponse);
|
|
85
|
+
log.error("changeGroupImageMqtt", err);
|
|
86
|
+
callback?.(err);
|
|
87
|
+
reject(err);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Change Nickname
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
8
|
+
const log = require("../../../func/logAdapter");
|
|
9
|
+
|
|
10
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
11
|
+
return function changeNickname(nickname, threadID, participantID, callback) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
if (!ctx.mqttClient) {
|
|
14
|
+
const err = new Error("AYMAN-FCA: MQTT غير متصل");
|
|
15
|
+
callback?.(err); return reject(err);
|
|
16
|
+
}
|
|
17
|
+
if (!threadID || !participantID) {
|
|
18
|
+
const err = new Error("threadID و participantID مطلوبان");
|
|
19
|
+
callback?.(err); return reject(err);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const reqID = ++ctx.wsReqNumber;
|
|
23
|
+
const taskID = ++ctx.wsTaskNumber;
|
|
24
|
+
|
|
25
|
+
const content = {
|
|
26
|
+
app_id: "2220391788200892",
|
|
27
|
+
payload: JSON.stringify({
|
|
28
|
+
epoch_id: generateOfflineThreadingID(),
|
|
29
|
+
tasks: [{
|
|
30
|
+
failure_count: null,
|
|
31
|
+
label: "44",
|
|
32
|
+
payload: JSON.stringify({ thread_key: threadID, contact_id: participantID, nickname: nickname || "", sync_group: 1 }),
|
|
33
|
+
queue_name: "thread_participant_nickname",
|
|
34
|
+
task_id: taskID
|
|
35
|
+
}],
|
|
36
|
+
version_id: "8798795233522156"
|
|
37
|
+
}),
|
|
38
|
+
request_id: reqID,
|
|
39
|
+
type: 3
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let done = false;
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
if (done) return; done = true;
|
|
45
|
+
ctx.mqttClient?.removeListener("message", handleRes);
|
|
46
|
+
callback?.(null, { success: true }); resolve({ success: true });
|
|
47
|
+
}, 10000);
|
|
48
|
+
|
|
49
|
+
const handleRes = (topic, message) => {
|
|
50
|
+
if (topic !== "/ls_resp") return;
|
|
51
|
+
let msg;
|
|
52
|
+
try { msg = JSON.parse(message.toString()); msg.payload = JSON.parse(msg.payload); } catch { return; }
|
|
53
|
+
if (msg.request_id !== reqID) return;
|
|
54
|
+
if (done) return; done = true;
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
ctx.mqttClient?.removeListener("message", handleRes);
|
|
57
|
+
callback?.(null, { success: true }); resolve({ success: true });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
ctx.mqttClient.on("message", handleRes);
|
|
61
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, err => {
|
|
62
|
+
if (err) {
|
|
63
|
+
if (done) return; done = true;
|
|
64
|
+
clearTimeout(timer); ctx.mqttClient?.removeListener("message", handleRes);
|
|
65
|
+
log.error("changeNickname", err); callback?.(err); reject(err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Change Thread Color
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
8
|
+
|
|
9
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
10
|
+
return function changeThreadColor(color, threadID, callback) {
|
|
11
|
+
let resolve, reject;
|
|
12
|
+
const p = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
13
|
+
callback = callback || ((err, data) => err ? reject(err) : resolve(data));
|
|
14
|
+
|
|
15
|
+
if (!ctx.mqttClient) return callback(new Error("AYMAN-FCA: MQTT غير متصل"));
|
|
16
|
+
|
|
17
|
+
const reqID = ++ctx.wsReqNumber;
|
|
18
|
+
const content = {
|
|
19
|
+
app_id: "2220391788200892",
|
|
20
|
+
payload: JSON.stringify({
|
|
21
|
+
data_trace_id: null,
|
|
22
|
+
epoch_id: parseInt(generateOfflineThreadingID()),
|
|
23
|
+
tasks: [{
|
|
24
|
+
failure_count: null,
|
|
25
|
+
label: "43",
|
|
26
|
+
payload: JSON.stringify({ thread_key: threadID, theme_fbid: color, source: null, sync_group: 1, payload: null }),
|
|
27
|
+
queue_name: "thread_theme",
|
|
28
|
+
task_id: ++ctx.wsTaskNumber
|
|
29
|
+
}],
|
|
30
|
+
version_id: "8798795233522156"
|
|
31
|
+
}),
|
|
32
|
+
request_id: reqID,
|
|
33
|
+
type: 3
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, err => {
|
|
37
|
+
if (err) return callback(err);
|
|
38
|
+
callback(null, { success: true, color, threadID });
|
|
39
|
+
resolve({ success: true });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return p;
|
|
43
|
+
};
|
|
44
|
+
};
|