alicezetion 1.0.9 → 1.1.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/.cache/replit/__replit_disk_meta.json +1 -1
- package/.cache/replit/nix/env.json +1 -1
- package/index.js +558 -490
- package/leiamnash/addExternalModule.js +19 -0
- package/{src → leiamnash}/addUserToGroup.js +52 -16
- package/leiamnash/changeAdminStatus.js +79 -0
- package/leiamnash/changeArchivedStatus.js +55 -0
- package/{src → leiamnash}/changeBio.js +19 -6
- package/{src → leiamnash}/changeBlockedStatus.js +14 -3
- package/{src → leiamnash}/changeGroupImage.js +40 -16
- package/leiamnash/changeNickname.js +59 -0
- package/{src → leiamnash}/changeThreadColor.js +20 -10
- package/leiamnash/changeThreadEmoji.js +55 -0
- package/leiamnash/chat.js +459 -0
- package/{src → leiamnash}/createNewGroup.js +28 -12
- package/{src → leiamnash}/createPoll.js +25 -13
- package/leiamnash/deleteMessage.js +56 -0
- package/leiamnash/deleteThread.js +56 -0
- package/leiamnash/forwardAttachment.js +60 -0
- package/{src → leiamnash}/getCurrentUserID.js +1 -1
- package/{src → leiamnash}/getEmojiUrl.js +4 -2
- package/{src → leiamnash}/getFriendsList.js +21 -10
- package/{src → leiamnash}/getThreadHistory.js +166 -58
- package/{src → leiamnash}/getThreadHistoryDeprecated.js +42 -20
- package/{src → leiamnash}/getThreadInfo.js +60 -25
- package/leiamnash/getThreadInfoDeprecated.js +80 -0
- package/{src → leiamnash}/getThreadList.js +66 -41
- package/leiamnash/getThreadListDeprecated.js +75 -0
- package/leiamnash/getThreadPictures.js +79 -0
- package/{src → leiamnash}/getUserID.js +14 -9
- package/{src → leiamnash}/getUserInfo.js +18 -12
- package/leiamnash/handleFriendRequest.js +61 -0
- package/leiamnash/handleMessageRequest.js +65 -0
- package/{src → leiamnash}/httpGet.js +17 -12
- package/{src → leiamnash}/httpPost.js +17 -12
- package/leiamnash/listenMqtt.js +687 -0
- package/{src → leiamnash}/logout.js +20 -13
- package/{src → leiamnash}/markAsDelivered.js +22 -11
- package/{src → leiamnash}/markAsRead.js +21 -11
- package/{src → leiamnash}/markAsReadAll.js +20 -10
- package/{src → leiamnash}/markAsSeen.js +18 -7
- package/{src → leiamnash}/muteThread.js +18 -11
- package/leiamnash/removeUserFromGroup.js +79 -0
- package/{src → leiamnash}/resolvePhotoUrl.js +17 -8
- package/{src → leiamnash}/searchForThread.js +21 -10
- package/{src → leiamnash}/sendTypingIndicator.js +47 -14
- package/{src → leiamnash}/setMessageReaction.js +26 -12
- package/{src → leiamnash}/setPostReaction.js +26 -13
- package/{src → leiamnash}/setTitle.js +29 -13
- package/leiamnash/threadColors.js +57 -0
- package/{src → leiamnash}/unfriend.js +19 -9
- package/{src → leiamnash}/unsendMessage.js +19 -9
- package/package.json +9 -14
- package/replit.nix +0 -1
- package/utils.js +1193 -1023
- package/src/addExternalModule.js +0 -15
- package/src/changeAdminStatus.js +0 -47
- package/src/changeArchivedStatus.js +0 -41
- package/src/changeNickname.js +0 -43
- package/src/changeThreadEmoji.js +0 -41
- package/src/chat.js +0 -315
- package/src/deleteMessage.js +0 -44
- package/src/deleteThread.js +0 -42
- package/src/forwardAttachment.js +0 -47
- package/src/forwardMessage.js +0 -0
- package/src/getThreadInfoDeprecated.js +0 -56
- package/src/getThreadListDeprecated.js +0 -46
- package/src/getThreadPictures.js +0 -59
- package/src/handleFriendRequest.js +0 -46
- package/src/handleMessageRequest.js +0 -47
- package/src/listen.js +0 -553
- package/src/listenMqtt-Test.js +0 -687
- package/src/listenMqtt.js +0 -677
- package/src/removeUserFromGroup.js +0 -45
- package/src/threadColors.js +0 -41
@@ -3,54 +3,73 @@
|
|
3
3
|
var utils = require("../utils");
|
4
4
|
var log = require("npmlog");
|
5
5
|
|
6
|
-
module.exports = function
|
6
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
7
7
|
return function getThreadHistory(threadID, amount, timestamp, callback) {
|
8
|
-
var resolveFunc = function
|
9
|
-
var rejectFunc = function
|
8
|
+
var resolveFunc = function(){};
|
9
|
+
var rejectFunc = function(){};
|
10
10
|
var returnPromise = new Promise(function (resolve, reject) {
|
11
11
|
resolveFunc = resolve;
|
12
12
|
rejectFunc = reject;
|
13
13
|
});
|
14
14
|
|
15
15
|
if (!callback) {
|
16
|
-
callback = function (err,
|
17
|
-
if (err)
|
18
|
-
|
16
|
+
callback = function (err, friendList) {
|
17
|
+
if (err) {
|
18
|
+
return rejectFunc(err);
|
19
|
+
}
|
20
|
+
resolveFunc(friendList);
|
19
21
|
};
|
20
22
|
}
|
21
23
|
|
22
|
-
if (!callback)
|
24
|
+
if (!callback) {
|
25
|
+
throw { error: "getThreadHistory: need callback" };
|
26
|
+
}
|
27
|
+
|
23
28
|
var form = {
|
24
29
|
client: "mercury"
|
25
30
|
};
|
26
31
|
|
27
|
-
api.getUserInfo(threadID, function
|
28
|
-
if (err)
|
32
|
+
api.getUserInfo(threadID, function(err, res) {
|
33
|
+
if (err) {
|
34
|
+
return callback(err);
|
35
|
+
}
|
29
36
|
var key = Object.keys(res).length > 0 ? "user_ids" : "thread_fbids";
|
30
37
|
form["messages[" + key + "][" + threadID + "][offset]"] = 0;
|
31
38
|
form["messages[" + key + "][" + threadID + "][timestamp]"] = timestamp;
|
32
39
|
form["messages[" + key + "][" + threadID + "][limit]"] = amount;
|
33
40
|
|
34
|
-
if (ctx.globalOptions.pageID)
|
41
|
+
if (ctx.globalOptions.pageID)
|
42
|
+
form.request_user_id = ctx.globalOptions.pageID;
|
35
43
|
|
36
44
|
defaultFuncs
|
37
|
-
.post(
|
45
|
+
.post(
|
46
|
+
"https://www.facebook.com/ajax/mercury/thread_info.php",
|
47
|
+
ctx.jar,
|
48
|
+
form
|
49
|
+
)
|
38
50
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
39
|
-
.then(function
|
40
|
-
if (resData.error)
|
41
|
-
|
51
|
+
.then(function(resData) {
|
52
|
+
if (resData.error) {
|
53
|
+
throw resData;
|
54
|
+
} else if (!resData.payload) {
|
55
|
+
throw { error: "Could not retrieve thread history." };
|
56
|
+
}
|
42
57
|
|
43
58
|
// Asking for message history from a thread with no message history
|
44
59
|
// will return undefined for actions here
|
45
|
-
if (!resData.payload.actions)
|
60
|
+
if (!resData.payload.actions) {
|
61
|
+
resData.payload.actions = [];
|
62
|
+
}
|
46
63
|
|
47
64
|
var userIDs = {};
|
48
|
-
resData.payload.actions.forEach(v
|
65
|
+
resData.payload.actions.forEach(function(v) {
|
66
|
+
userIDs[v.author.split(":").pop()] = "";
|
67
|
+
});
|
49
68
|
|
50
|
-
api.getUserInfo(Object.keys(userIDs), function
|
69
|
+
api.getUserInfo(Object.keys(userIDs), function(err, data) {
|
51
70
|
if (err) return callback(err); //callback({error: "Could not retrieve user information in getThreadHistory."});
|
52
71
|
|
53
|
-
resData.payload.actions.forEach(function
|
72
|
+
resData.payload.actions.forEach(function(v) {
|
54
73
|
var sender = data[v.author.split(":").pop()];
|
55
74
|
if (sender) v.sender_name = sender.name;
|
56
75
|
else v.sender_name = "Facebook User";
|
@@ -58,10 +77,13 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
58
77
|
delete v.author;
|
59
78
|
});
|
60
79
|
|
61
|
-
callback(
|
80
|
+
callback(
|
81
|
+
null,
|
82
|
+
resData.payload.actions.map(utils.formatHistoryMessage)
|
83
|
+
);
|
62
84
|
});
|
63
85
|
})
|
64
|
-
.catch(function
|
86
|
+
.catch(function(err) {
|
65
87
|
log.error("getThreadHistory", err);
|
66
88
|
return callback(err);
|
67
89
|
});
|
@@ -21,7 +21,7 @@ function formatEventReminders(reminder) {
|
|
21
21
|
secondsToNotifyBefore: reminder.seconds_to_notify_before,
|
22
22
|
allowsRsvp: reminder.allows_rsvp,
|
23
23
|
relatedEvent: reminder.related_event,
|
24
|
-
members: reminder.event_reminder_members.edges.map(function
|
24
|
+
members: reminder.event_reminder_members.edges.map(function(member) {
|
25
25
|
return {
|
26
26
|
memberID: member.node.id,
|
27
27
|
state: member.guest_list_state.toLowerCase()
|
@@ -31,15 +31,33 @@ function formatEventReminders(reminder) {
|
|
31
31
|
}
|
32
32
|
|
33
33
|
function formatThreadGraphQLResponse(data) {
|
34
|
-
|
35
|
-
|
34
|
+
try{
|
35
|
+
var messageThread = data.o0.data.message_thread;
|
36
|
+
} catch (err){
|
37
|
+
console.error("GetThreadInfoGraphQL", "Can't get this thread info!");
|
38
|
+
return {err: err};
|
39
|
+
}
|
40
|
+
var threadID = messageThread.thread_key.thread_fbid
|
41
|
+
? messageThread.thread_key.thread_fbid
|
42
|
+
: messageThread.thread_key.other_user_id;
|
36
43
|
|
37
44
|
// Remove me
|
38
45
|
var lastM = messageThread.last_message;
|
39
|
-
var snippetID =
|
40
|
-
|
46
|
+
var snippetID =
|
47
|
+
lastM &&
|
48
|
+
lastM.nodes &&
|
49
|
+
lastM.nodes[0] &&
|
50
|
+
lastM.nodes[0].message_sender &&
|
51
|
+
lastM.nodes[0].message_sender.messaging_actor
|
52
|
+
? lastM.nodes[0].message_sender.messaging_actor.id
|
53
|
+
: null;
|
54
|
+
var snippetText =
|
55
|
+
lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
|
41
56
|
var lastR = messageThread.last_read_receipt;
|
42
|
-
var lastReadTimestamp =
|
57
|
+
var lastReadTimestamp =
|
58
|
+
lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
|
59
|
+
? lastR.nodes[0].timestamp_precise
|
60
|
+
: null;
|
43
61
|
|
44
62
|
return {
|
45
63
|
threadID: threadID,
|
@@ -66,16 +84,27 @@ function formatThreadGraphQLResponse(data) {
|
|
66
84
|
isArchived: messageThread.has_viewer_archived,
|
67
85
|
folder: messageThread.folder,
|
68
86
|
cannotReplyReason: messageThread.cannot_reply_reason,
|
69
|
-
eventReminders: messageThread.event_reminders
|
70
|
-
|
71
|
-
|
87
|
+
eventReminders: messageThread.event_reminders
|
88
|
+
? messageThread.event_reminders.nodes.map(formatEventReminders)
|
89
|
+
: null,
|
90
|
+
emoji: messageThread.customization_info
|
91
|
+
? messageThread.customization_info.emoji
|
92
|
+
: null,
|
93
|
+
color:
|
94
|
+
messageThread.customization_info &&
|
95
|
+
messageThread.customization_info.outgoing_bubble_color
|
96
|
+
? messageThread.customization_info.outgoing_bubble_color.slice(2)
|
97
|
+
: null,
|
72
98
|
nicknames:
|
73
99
|
messageThread.customization_info &&
|
74
|
-
|
75
|
-
? messageThread.customization_info.participant_customizations.reduce(
|
76
|
-
|
77
|
-
|
78
|
-
|
100
|
+
messageThread.customization_info.participant_customizations
|
101
|
+
? messageThread.customization_info.participant_customizations.reduce(
|
102
|
+
function(res, val) {
|
103
|
+
if (val.nickname) res[val.participant_id] = val.nickname;
|
104
|
+
return res;
|
105
|
+
},
|
106
|
+
{}
|
107
|
+
)
|
79
108
|
: {},
|
80
109
|
adminIDs: messageThread.thread_admins,
|
81
110
|
approvalMode: Boolean(messageThread.approval_mode),
|
@@ -105,17 +134,19 @@ function formatThreadGraphQLResponse(data) {
|
|
105
134
|
hasEmailParticipant: false,
|
106
135
|
readOnly: false,
|
107
136
|
canReply: messageThread.cannot_reply_reason == null,
|
108
|
-
lastMessageTimestamp: messageThread.last_message
|
137
|
+
lastMessageTimestamp: messageThread.last_message
|
138
|
+
? messageThread.last_message.timestamp_precise
|
139
|
+
: null,
|
109
140
|
lastMessageType: "message",
|
110
141
|
lastReadTimestamp: lastReadTimestamp,
|
111
142
|
threadType: messageThread.thread_type == "GROUP" ? 2 : 1
|
112
143
|
};
|
113
144
|
}
|
114
145
|
|
115
|
-
module.exports = function
|
146
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
116
147
|
return function getThreadInfoGraphQL(threadID, callback) {
|
117
|
-
var resolveFunc = function
|
118
|
-
var rejectFunc = function
|
148
|
+
var resolveFunc = function(){};
|
149
|
+
var rejectFunc = function(){};
|
119
150
|
var returnPromise = new Promise(function (resolve, reject) {
|
120
151
|
resolveFunc = resolve;
|
121
152
|
rejectFunc = reject;
|
@@ -123,7 +154,9 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
123
154
|
|
124
155
|
if (utils.getType(callback) != "Function" && utils.getType(callback) != "AsyncFunction") {
|
125
156
|
callback = function (err, data) {
|
126
|
-
if (err)
|
157
|
+
if (err) {
|
158
|
+
return rejectFunc(err);
|
159
|
+
}
|
127
160
|
resolveFunc(data);
|
128
161
|
};
|
129
162
|
}
|
@@ -150,19 +183,21 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
150
183
|
defaultFuncs
|
151
184
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
152
185
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
153
|
-
.then(function
|
154
|
-
if (resData.error)
|
186
|
+
.then(function(resData) {
|
187
|
+
if (resData.error) {
|
188
|
+
throw resData;
|
189
|
+
}
|
155
190
|
// This returns us an array of things. The last one is the success /
|
156
191
|
// failure one.
|
157
192
|
// @TODO What do we do in this case?
|
158
193
|
if (resData[resData.length - 1].error_results !== 0) {
|
159
|
-
console.
|
160
|
-
throw new Error("well darn there was an error_result");
|
194
|
+
console.error("GetThreadInfo", "Well darn there was an error_result");
|
161
195
|
}
|
196
|
+
|
162
197
|
callback(null, formatThreadGraphQLResponse(resData[0]));
|
163
198
|
})
|
164
|
-
.catch(function
|
165
|
-
log.error("getThreadInfoGraphQL",
|
199
|
+
.catch(function(err) {
|
200
|
+
log.error("getThreadInfoGraphQL", err);
|
166
201
|
return callback(err);
|
167
202
|
});
|
168
203
|
|
@@ -0,0 +1,80 @@
|
|
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 getThreadInfo(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, friendList) {
|
17
|
+
if (err) {
|
18
|
+
return rejectFunc(err);
|
19
|
+
}
|
20
|
+
resolveFunc(friendList);
|
21
|
+
};
|
22
|
+
}
|
23
|
+
|
24
|
+
var form = {
|
25
|
+
client: "mercury"
|
26
|
+
};
|
27
|
+
|
28
|
+
api.getUserInfo(threadID, function(err, userRes) {
|
29
|
+
if (err) {
|
30
|
+
return callback(err);
|
31
|
+
}
|
32
|
+
var key = Object.keys(userRes).length > 0 ? "user_ids" : "thread_fbids";
|
33
|
+
form["threads[" + key + "][0]"] = threadID;
|
34
|
+
|
35
|
+
if (ctx.globalOptions.pageId)
|
36
|
+
form.request_user_id = ctx.globalOptions.pageId;
|
37
|
+
|
38
|
+
defaultFuncs
|
39
|
+
.post(
|
40
|
+
"https://www.facebook.com/ajax/mercury/thread_info.php",
|
41
|
+
ctx.jar,
|
42
|
+
form
|
43
|
+
)
|
44
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
45
|
+
.then(function(resData) {
|
46
|
+
if (resData.error) {
|
47
|
+
throw resData;
|
48
|
+
} else if (!resData.payload) {
|
49
|
+
throw {
|
50
|
+
error: "Could not retrieve thread Info."
|
51
|
+
};
|
52
|
+
}
|
53
|
+
var threadData = resData.payload.threads[0];
|
54
|
+
var userData = userRes[threadID];
|
55
|
+
|
56
|
+
if (threadData == null) {
|
57
|
+
throw {
|
58
|
+
error: "ThreadData is null"
|
59
|
+
};
|
60
|
+
}
|
61
|
+
|
62
|
+
threadData.name =
|
63
|
+
userData != null && userData.name != null
|
64
|
+
? userData.name
|
65
|
+
: threadData.name;
|
66
|
+
threadData.image_src =
|
67
|
+
userData != null && userData.thumbSrc != null
|
68
|
+
? userData.thumbSrc
|
69
|
+
: threadData.image_src;
|
70
|
+
|
71
|
+
callback(null, utils.formatThread(threadData));
|
72
|
+
})
|
73
|
+
.catch(function(err) {
|
74
|
+
log.error("getThreadInfo", err);
|
75
|
+
return callback(err);
|
76
|
+
});
|
77
|
+
});
|
78
|
+
return returnPromise;
|
79
|
+
};
|
80
|
+
};
|
@@ -9,7 +9,7 @@ function createProfileUrl(url, username, id) {
|
|
9
9
|
}
|
10
10
|
|
11
11
|
function formatParticipants(participants) {
|
12
|
-
return participants.edges.map((p)
|
12
|
+
return participants.edges.map((p)=>{
|
13
13
|
p = p.node.messaging_actor;
|
14
14
|
switch (p["__typename"]) {
|
15
15
|
case "User":
|
@@ -21,7 +21,7 @@ function formatParticipants(participants) {
|
|
21
21
|
gender: p.gender,
|
22
22
|
url: p.url, // how about making it profileURL
|
23
23
|
profilePicture: p.big_image_src.uri,
|
24
|
-
username: (p.username
|
24
|
+
username: (p.username||null),
|
25
25
|
// TODO: maybe better names for these?
|
26
26
|
isViewerFriend: p.is_viewer_friend, // true/false
|
27
27
|
isMessengerUser: p.is_messenger_user, // true/false
|
@@ -37,7 +37,7 @@ function formatParticipants(participants) {
|
|
37
37
|
name: p.name,
|
38
38
|
url: p.url,
|
39
39
|
profilePicture: p.big_image_src.uri,
|
40
|
-
username: (p.username
|
40
|
+
username: (p.username||null),
|
41
41
|
// uhm... better names maybe?
|
42
42
|
acceptsMessengerUserFeedback: p.accepts_messenger_user_feedback, // true/false
|
43
43
|
isMessengerUser: p.is_messenger_user, // true/false
|
@@ -46,18 +46,27 @@ function formatParticipants(participants) {
|
|
46
46
|
isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
|
47
47
|
};
|
48
48
|
case "ReducedMessagingActor":
|
49
|
-
case "UnavailableMessagingActor":
|
50
49
|
return {
|
51
50
|
accountType: p["__typename"],
|
52
51
|
userID: utils.formatID(p.id.toString()),
|
53
52
|
name: p.name,
|
54
53
|
url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
|
55
54
|
profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
|
56
|
-
username: (p.username
|
55
|
+
username: (p.username||null), // maybe we could use it to generate profile URL?
|
56
|
+
isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
|
57
|
+
};
|
58
|
+
case "UnavailableMessagingActor":
|
59
|
+
return {
|
60
|
+
accountType: p["__typename"],
|
61
|
+
userID: utils.formatID(p.id.toString()),
|
62
|
+
name: p.name, // "Facebook User" in user's language
|
63
|
+
url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
|
64
|
+
profilePicture: p.big_image_src.uri, // default male facebook photo
|
65
|
+
username: (p.username||null), // maybe we could use it to generate profile URL?
|
57
66
|
isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
|
58
67
|
};
|
59
68
|
default:
|
60
|
-
log.warn("getThreadList", "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/
|
69
|
+
log.warn("getThreadList", "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/fca-unofficial/issues\n" + JSON.stringify(p, null, 2));
|
61
70
|
return {
|
62
71
|
accountType: p["__typename"],
|
63
72
|
userID: utils.formatID(p.id.toString()),
|
@@ -69,7 +78,9 @@ function formatParticipants(participants) {
|
|
69
78
|
|
70
79
|
// "FF8C0077" -> "8C0077"
|
71
80
|
function formatColor(color) {
|
72
|
-
if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g))
|
81
|
+
if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g)) {
|
82
|
+
return color.slice(2);
|
83
|
+
}
|
73
84
|
return color;
|
74
85
|
}
|
75
86
|
|
@@ -84,24 +95,24 @@ function getThreadName(t) {
|
|
84
95
|
|
85
96
|
function mapNicknames(customizationInfo) {
|
86
97
|
return (customizationInfo && customizationInfo.participant_customizations) ? customizationInfo.participant_customizations.map(u => {
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
})
|
98
|
+
return {
|
99
|
+
"userID": u.participant_id,
|
100
|
+
"nickname": u.nickname
|
101
|
+
};
|
102
|
+
}):[];
|
92
103
|
}
|
93
104
|
|
94
105
|
function formatThreadList(data) {
|
95
106
|
return data.map(t => {
|
96
|
-
let lastMessageNode = (t.last_message
|
107
|
+
let lastMessageNode = (t.last_message&&t.last_message.nodes&&t.last_message.nodes.length>0)?t.last_message.nodes[0]:null;
|
97
108
|
return {
|
98
|
-
threadID: t.thread_key
|
109
|
+
threadID: t.thread_key?utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id):null, // shall never be null
|
99
110
|
name: getThreadName(t),
|
100
111
|
unreadCount: t.unread_count,
|
101
112
|
messageCount: t.messages_count,
|
102
|
-
imageSrc: t.image
|
103
|
-
emoji: t.customization_info
|
104
|
-
color: formatColor(t.customization_info
|
113
|
+
imageSrc: t.image?t.image.uri:null,
|
114
|
+
emoji: t.customization_info?t.customization_info.emoji:null,
|
115
|
+
color: formatColor(t.customization_info?t.customization_info.outgoing_bubble_color:null),
|
105
116
|
nicknames: mapNicknames(t.customization_info),
|
106
117
|
muteUntil: t.mute_until,
|
107
118
|
participants: formatParticipants(t.all_participants),
|
@@ -112,7 +123,7 @@ function formatThreadList(data) {
|
|
112
123
|
// isPinProtected: t.is_pin_protected, // feature from future? always false (2018-04-04)
|
113
124
|
customizationEnabled: t.customization_enabled, // false for ONE_TO_ONE with Page or ReducedMessagingActor
|
114
125
|
participantAddMode: t.participant_add_mode_as_string, // "ADD" if "GROUP" and null if "ONE_TO_ONE"
|
115
|
-
montageThread: t.montage_thread
|
126
|
+
montageThread: t.montage_thread?Buffer.from(t.montage_thread.id,"base64").toString():null, // base64 encoded string "message_thread:0000000000000000"
|
116
127
|
// it is not userID nor any other ID known to me...
|
117
128
|
// can somebody inspect it? where is it used?
|
118
129
|
// probably Messenger Day uses it
|
@@ -123,13 +134,13 @@ function formatThreadList(data) {
|
|
123
134
|
timestamp: t.updated_time_precise, // in miliseconds
|
124
135
|
// isCanonicalUser: t.is_canonical_neo_user, // is it always false?
|
125
136
|
// TODO: how about putting snippet in another object? current implementation does not handle every possibile message type etc.
|
126
|
-
snippet: lastMessageNode
|
127
|
-
snippetAttachments: lastMessageNode
|
128
|
-
snippetSender: lastMessageNode
|
129
|
-
lastMessageTimestamp: lastMessageNode
|
130
|
-
lastReadTimestamp: (t.last_read_receipt
|
131
|
-
|
132
|
-
|
137
|
+
snippet: lastMessageNode?lastMessageNode.snippet:null,
|
138
|
+
snippetAttachments: lastMessageNode?lastMessageNode.extensible_attachment:null, // TODO: not sure if it works
|
139
|
+
snippetSender: lastMessageNode?utils.formatID((lastMessageNode.message_sender.messaging_actor.id || "").toString()):null,
|
140
|
+
lastMessageTimestamp: lastMessageNode?lastMessageNode.timestamp_precise:null, // timestamp in miliseconds
|
141
|
+
lastReadTimestamp: (t.last_read_receipt&&t.last_read_receipt.nodes.length>0)
|
142
|
+
? (t.last_read_receipt.nodes[0]?t.last_read_receipt.nodes[0].timestamp_precise:null)
|
143
|
+
: null, // timestamp in miliseconds
|
133
144
|
cannotReplyReason: t.cannot_reply_reason, // TODO: inspect possible values
|
134
145
|
approvalMode: Boolean(t.approval_mode),
|
135
146
|
|
@@ -140,21 +151,28 @@ function formatThreadList(data) {
|
|
140
151
|
});
|
141
152
|
}
|
142
153
|
|
143
|
-
module.exports = function
|
154
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
144
155
|
return function getThreadList(limit, timestamp, tags, callback) {
|
145
156
|
if (!callback && (utils.getType(tags) === "Function" || utils.getType(tags) === "AsyncFunction")) {
|
146
157
|
callback = tags;
|
147
158
|
tags = [""];
|
148
159
|
}
|
149
|
-
if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
160
|
+
if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0) {
|
161
|
+
throw {error: "getThreadList: limit must be a positive integer"};
|
162
|
+
}
|
163
|
+
if (utils.getType(timestamp) !== "Null" &&
|
164
|
+
(utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))) {
|
165
|
+
throw {error: "getThreadList: timestamp must be an integer or null"};
|
166
|
+
}
|
167
|
+
if (utils.getType(tags) === "String") {
|
168
|
+
tags = [tags];
|
169
|
+
}
|
170
|
+
if (utils.getType(tags) !== "Array") {
|
171
|
+
throw {error: "getThreadList: tags must be an array"};
|
172
|
+
}
|
155
173
|
|
156
|
-
var resolveFunc = function
|
157
|
-
var rejectFunc = function
|
174
|
+
var resolveFunc = function(){};
|
175
|
+
var rejectFunc = function(){};
|
158
176
|
var returnPromise = new Promise(function (resolve, reject) {
|
159
177
|
resolveFunc = resolve;
|
160
178
|
rejectFunc = reject;
|
@@ -162,7 +180,9 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
162
180
|
|
163
181
|
if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
|
164
182
|
callback = function (err, data) {
|
165
|
-
if (err)
|
183
|
+
if (err) {
|
184
|
+
return rejectFunc(err);
|
185
|
+
}
|
166
186
|
resolveFunc(data);
|
167
187
|
};
|
168
188
|
}
|
@@ -174,7 +194,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
174
194
|
// This doc_id was valid on 2020-07-20
|
175
195
|
"doc_id": "3336396659757871",
|
176
196
|
"query_params": {
|
177
|
-
"limit": limit
|
197
|
+
"limit": limit+(timestamp?1:0),
|
178
198
|
"before": timestamp,
|
179
199
|
"tags": tags,
|
180
200
|
"includeDeliveryReceipts": true,
|
@@ -189,9 +209,13 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
189
209
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
190
210
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
191
211
|
.then((resData) => {
|
192
|
-
if (resData[resData.length - 1].error_results > 0)
|
212
|
+
if (resData[resData.length - 1].error_results > 0) {
|
213
|
+
throw resData[0].o0.errors;
|
214
|
+
}
|
193
215
|
|
194
|
-
if (resData[resData.length - 1].successful_results === 0)
|
216
|
+
if (resData[resData.length - 1].successful_results === 0) {
|
217
|
+
throw {error: "getThreadList: there was no successful_results", res: resData};
|
218
|
+
}
|
195
219
|
|
196
220
|
// When we ask for threads using timestamp from the previous request,
|
197
221
|
// we are getting the last thread repeated as the first thread in this response.
|
@@ -199,12 +223,13 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
199
223
|
// It is also the reason for increasing limit by 1 when timestamp is set
|
200
224
|
// this way user asks for 10 threads, we are asking for 11,
|
201
225
|
// but after removing the duplicated one, it is again 10
|
202
|
-
if (timestamp)
|
203
|
-
|
226
|
+
if (timestamp) {
|
227
|
+
resData[0].o0.data.viewer.message_threads.nodes.shift();
|
228
|
+
}
|
204
229
|
callback(null, formatThreadList(resData[0].o0.data.viewer.message_threads.nodes));
|
205
230
|
})
|
206
231
|
.catch((err) => {
|
207
|
-
log.error("getThreadList",
|
232
|
+
log.error("getThreadList", err);
|
208
233
|
return callback(err);
|
209
234
|
});
|
210
235
|
|
@@ -0,0 +1,75 @@
|
|
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 getThreadList(start, end, type, callback) {
|
8
|
+
if (utils.getType(callback) === "Undefined") {
|
9
|
+
if (utils.getType(end) !== "Number") {
|
10
|
+
throw {
|
11
|
+
error: "Please pass a number as a second argument."
|
12
|
+
};
|
13
|
+
} else if (
|
14
|
+
utils.getType(type) === "Function" ||
|
15
|
+
utils.getType(type) === "AsyncFunction"
|
16
|
+
) {
|
17
|
+
callback = type;
|
18
|
+
type = "inbox"; //default to inbox
|
19
|
+
} else if (utils.getType(type) !== "String") {
|
20
|
+
throw {
|
21
|
+
error:
|
22
|
+
"Please pass a String as a third argument. Your options are: inbox, pending, and archived"
|
23
|
+
};
|
24
|
+
} else {
|
25
|
+
throw {
|
26
|
+
error: "getThreadList: need callback"
|
27
|
+
};
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
if (type === "archived") {
|
32
|
+
type = "action:archived";
|
33
|
+
} else if (type !== "inbox" && type !== "pending" && type !== "other") {
|
34
|
+
throw {
|
35
|
+
error:
|
36
|
+
"type can only be one of the following: inbox, pending, archived, other"
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
if (end <= start) end = start + 20;
|
41
|
+
|
42
|
+
var form = {
|
43
|
+
client: "mercury"
|
44
|
+
};
|
45
|
+
|
46
|
+
form[type + "[offset]"] = start;
|
47
|
+
form[type + "[limit]"] = end - start;
|
48
|
+
|
49
|
+
if (ctx.globalOptions.pageID) {
|
50
|
+
form.request_user_id = ctx.globalOptions.pageID;
|
51
|
+
}
|
52
|
+
|
53
|
+
defaultFuncs
|
54
|
+
.post(
|
55
|
+
"https://www.facebook.com/ajax/mercury/threadlist_info.php",
|
56
|
+
ctx.jar,
|
57
|
+
form
|
58
|
+
)
|
59
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
60
|
+
.then(function(resData) {
|
61
|
+
if (resData.error) {
|
62
|
+
throw resData;
|
63
|
+
}
|
64
|
+
log.verbose("getThreadList", JSON.stringify(resData.payload.threads));
|
65
|
+
return callback(
|
66
|
+
null,
|
67
|
+
(resData.payload.threads || []).map(utils.formatThread)
|
68
|
+
);
|
69
|
+
})
|
70
|
+
.catch(function(err) {
|
71
|
+
log.error("getThreadList", err);
|
72
|
+
return callback(err);
|
73
|
+
});
|
74
|
+
};
|
75
|
+
};
|