Skip to content

Commit e424bb0

Browse files
committed
fb mess count (done) + mess history (wip)
1 parent d91e7e0 commit e424bb0

File tree

12 files changed

+326
-33
lines changed

12 files changed

+326
-33
lines changed

popup/popup.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ <h3 class="modal-title">Modal Title</h3>
5454
<div class="loader"></div>
5555
</div>
5656

57+
<script src="../scripts/content-scripts/scripts/ufs_global_webpage_context.js"></script>
5758
<!-- <script type="module" src="./index.js"></script> -->
5859
<script src="main.js"></script>
5960
</body>

popup/tabs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ const tabs = [
9999
s.fb_moreReactionStory,
100100
s.fb_whoIsTyping,
101101
s.fb_messengerHistory,
102+
s.fb_messengerCount,
102103
createTitle("--- UI ---", "--- Giao diện ---"),
103104
s.fb_toggleLight,
104105
s.fb_toggleNewFeed,

scripts/changeAudioOutput.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ export default {
88
en: "Pick a default audio output device, customizable for each browser tab.",
99
vi: "Thay đổi đầu ra âm thanh của trang web đang mở.\nMỗi tab có thể chọn đầu ra khác nhau (tai nghe/loa).",
1010
},
11+
infoLink: "https://www.facebook.com/groups/j2team.community/posts/1362716140727169/",
1112

12-
// Fb Post: https://www.facebook.com/groups/j2team.community/posts/1362716140727169
1313
// Source: https://gist.github.com/monokaijs/44ef4bd0770f83272b83c038a2769c90
1414
onClick: async () => {
1515
let key = "ufs-audio-output-switcher";

scripts/content-scripts/scripts/ufs_global_webpage_context.js

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ const UsefulScriptGlobalPageContext = {
2121
});
2222
},
2323
getURL: async function (filePath) {
24-
return await UsefulScriptGlobalPageContext.Extension.sendToContentScript(
25-
"getURL",
26-
filePath
27-
);
24+
if (typeof chrome?.runtime?.getURL === "function") {
25+
return await chrome.runtime.getURL(filePath);
26+
} else {
27+
return await UsefulScriptGlobalPageContext.Extension.sendToContentScript(
28+
"getURL",
29+
filePath
30+
);
31+
}
2832
},
2933
},
3034
DOM: {
@@ -132,8 +136,8 @@ const UsefulScriptGlobalPageContext = {
132136
},
133137
},
134138
Facebook: {
135-
async fetchGraphQl(str, token) {
136-
var fb_dtsg = "fb_dtsg=" + encodeURIComponent(token);
139+
async fetchGraphQl(str, fb_dtsg) {
140+
var fb_dtsg = "fb_dtsg=" + encodeURIComponent(fb_dtsg);
137141
fb_dtsg += str.includes("variables")
138142
? "&" + str
139143
: "&q=" + encodeURIComponent(str);
@@ -163,7 +167,10 @@ const UsefulScriptGlobalPageContext = {
163167
scale: 1.5,
164168
};
165169
let f = new URLSearchParams();
166-
f.append("fb_dtsg", require("DTSGInitialData").token);
170+
f.append(
171+
"fb_dtsg",
172+
await UsefulScriptGlobalPageContext.Facebook.getFbdtsg()
173+
);
167174
f.append("fb_api_req_friendly_name", "ProfileCometHeaderQuery");
168175
f.append("variables", JSON.stringify(variables));
169176
f.append("doc_id", "4159355184147969");
@@ -234,38 +241,47 @@ const UsefulScriptGlobalPageContext = {
234241
);
235242
return htmlStory[htmlStory.length - 1].getAttribute("data-id");
236243
},
237-
getFbdtsg() {
244+
async getFbdtsg() {
238245
let methods = [
239246
() => require("DTSGInitData").token,
240247
() => require("DTSG").getToken(),
241248
() => {
242-
const regex = /"DTSGInitialData",\[],{"token":"(.+?)"/gm;
243-
const resp = regex.exec(document.documentElement.innerHTML);
244-
return resp[1];
249+
return document.documentElement.innerHTML.match(
250+
/"DTSGInitialData",\[],{"token":"(.+?)"/gm
251+
)[1];
252+
},
253+
async () => {
254+
let res = await fetch("https://mbasic.facebook.com/photos/upload/");
255+
let text = await res.text();
256+
return text.match(/name="fb_dtsg" value="(.*?)"/)[1];
245257
},
246258
() => require("DTSG_ASYNC").getToken(), // TODO: trace xem tại sao method này trả về cấu trúc khác 2 method trên
247259
];
248260
for (let m of methods) {
249261
try {
250-
return m();
262+
let d = await m();
263+
if (d) return d;
251264
} catch (e) {}
252265
}
253266
return null;
254267
},
255-
getYourUserId() {
268+
async getYourUserId() {
256269
let methods = [
257270
() => require("CurrentUserInitialData").USER_ID,
258271
() => require("RelayAPIConfigDefaults").actorID,
259272
() => document.cookie.match(/c_user=(\d+)/)[1],
260-
() => {
261-
const regex = /c_user=(\d+);/gm;
262-
const resp = regex.exec(document.cookie);
263-
return resp[1];
264-
},
273+
async () =>
274+
(
275+
await chrome.cookies.get({
276+
url: "https://www.facebook.com",
277+
name: "c_user",
278+
})
279+
).value,
265280
];
266281
for (let m of methods) {
267282
try {
268-
return m();
283+
let d = await m();
284+
if (d) return d;
269285
} catch (e) {}
270286
}
271287
return null;
@@ -433,12 +449,11 @@ const UsefulScriptGlobalPageContext = {
433449
}
434450
);
435451
},
436-
async messagesCount(token) {
437-
let res = await UsefulScriptGlobalPageContext.Facebook.fetchGraphQl(
452+
async messagesCount(fb_dtsg) {
453+
return await UsefulScriptGlobalPageContext.Facebook.fetchGraphQl(
438454
"viewer(){message_threads{count,nodes{customization_info{emoji,outgoing_bubble_color,participant_customizations{participant_id,nickname}},all_participants{nodes{messaging_actor{name,id,profile_picture}}},thread_type,name,messages_count,image,id}}}",
439-
token
455+
fb_dtsg
440456
);
441-
return await res.json();
442457
},
443458
},
444459
};

scripts/fb_messengerCount.html

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<title>Đếm tin nhắn Useful-script</title>
9+
10+
<style>
11+
body {
12+
margin: auto;
13+
max-width: 700px;
14+
}
15+
16+
table {
17+
font-family: arial, sans-serif;
18+
border-collapse: collapse;
19+
width: 100%;
20+
font-size: 1.2em;
21+
margin: auto;
22+
}
23+
24+
td,
25+
th {
26+
border: 1px solid #dddddd;
27+
padding: 8px;
28+
}
29+
30+
tr:nth-child(even) {
31+
background-color: #dddddd;
32+
}
33+
34+
tr.hidden {
35+
display: none;
36+
}
37+
38+
table a {
39+
text-decoration: none;
40+
}
41+
42+
input#search-inp {
43+
width: 50%;
44+
margin: auto;
45+
margin-bottom: 10px;
46+
}
47+
48+
.avatar {
49+
width: 50px;
50+
height: 50px;
51+
border-radius: 50%;
52+
margin-right: 5px;
53+
vertical-align: middle;
54+
}
55+
56+
.avatar-list {
57+
display: inline-block;
58+
}
59+
60+
.avatar-list .avatar {
61+
width: 40px;
62+
height: 40px;
63+
}
64+
65+
.avatar-list .avatar:not(:first-child) {
66+
margin-left: -20px;
67+
}
68+
</style>
69+
70+
</head>
71+
72+
<body>
73+
<h1>Facebook Messenger Count - Đếm tin nhắn Facebook</h1>
74+
<input id="search-inp" type="text" placeholder="Tìm theo tên, rank, count, group...">
75+
<span>Gợi ý: Nhập ✅ để tìm tất cả tin nhắn group</span>
76+
<table></table>
77+
<script src="./fb_messengerCount_main.js"></script>
78+
</body>
79+
80+
</html>

scripts/fb_messengerCount.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { showLoading } from "./helpers/utils.js";
2+
3+
export default {
4+
icon: '<i class="fa-solid fa-comments fa-lg"></i>',
5+
name: {
6+
en: "Facebook - Messenger count",
7+
vi: "Facebook - Đếm tin nhắn",
8+
},
9+
description: {
10+
en: "Counts the number of messages sent from your Facebook Messenger account.",
11+
vi: "Đếm tin nhắn từ tài khoản Facebook Messenger của bạn.",
12+
},
13+
infoLink: "",
14+
whiteList: ["https://*.facebook.com/*", "https://*.messenger.com/*"],
15+
16+
onClickExtension: async () => {
17+
let { closeLoading, setLoadingText } = showLoading("Đang chuẩn bị...");
18+
try {
19+
setLoadingText("Đang lấy token...");
20+
let dtsg = await UsefulScriptGlobalPageContext.Facebook.getFbdtsg();
21+
let uid = await UsefulScriptGlobalPageContext.Facebook.getYourUserId();
22+
23+
setLoadingText("Đang lấy dữ liệu tin nhắn...");
24+
let msgData = await UsefulScriptGlobalPageContext.Facebook.messagesCount(
25+
dtsg
26+
);
27+
28+
let { count: threadCount, nodes } = msgData.viewer.message_threads;
29+
let ranking = nodes
30+
.map((node, i) => ({ ...node, recent: i })) // inject recent rank
31+
.sort((a, b) => b.messages_count - a.messages_count) // calculate count rank
32+
.map((node) => {
33+
let participants = node.all_participants.nodes
34+
.filter((p) => p.messaging_actor.id !== uid)
35+
.map((p) => ({
36+
id: p.messaging_actor.id,
37+
name: p.messaging_actor.name,
38+
avatar: p.messaging_actor.profile_picture.uri,
39+
}));
40+
41+
return {
42+
type: node.thread_type,
43+
id: atob(node.id)?.split(":")?.[1],
44+
count: node.messages_count,
45+
name: node.name || participants[0]?.name || "-no data-",
46+
participants: participants,
47+
};
48+
});
49+
50+
localStorage.ufs_fb_msg_kount = JSON.stringify(ranking);
51+
52+
window.open(
53+
await UsefulScriptGlobalPageContext.Extension.getURL(
54+
"scripts/fb_messengerCount.html"
55+
)
56+
);
57+
} catch (e) {
58+
alert("ERROR: " + e);
59+
} finally {
60+
closeLoading();
61+
}
62+
},
63+
};

scripts/fb_messengerCount_main.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const inputSearch = document.querySelector("#search-inp");
2+
const tableDiv = document.querySelector("table");
3+
4+
function main() {
5+
try {
6+
let data = JSON.parse(localStorage.ufs_fb_msg_kount);
7+
8+
tableDiv.innerHTML = `
9+
<tr>
10+
<th>Rank</th>
11+
<th>Group</th>
12+
<th>Name</th>
13+
<th>Count</th>
14+
</tr>
15+
${data
16+
.map((c, i) => {
17+
let link = `https://www.facebook.com/messages/t/${c.id}`;
18+
let isGroup = c.type === "GROUP";
19+
let group = isGroup ? "✅" : "";
20+
let participants_name = c.participants
21+
.map((_) => _.name)
22+
.filter((_) => _)
23+
.join(", ");
24+
let name = isGroup
25+
? `${c.name}<br/>(${participants_name})`
26+
: c.name;
27+
let avatar = isGroup
28+
? `<div class="avatar-list">
29+
${c.participants
30+
.map((p) => `<img class="avatar" src="${p?.avatar}" />`)
31+
.join("")}
32+
</div>`
33+
: `<img class="avatar" src="${c.participants[0]?.avatar}" />`;
34+
35+
return `<tr>
36+
<td>${i + 1}</td>
37+
<td>${group}</td>
38+
<td>
39+
${avatar}
40+
<a href="${link}" target="_blank">${name}</a>
41+
</td>
42+
<td>${c.count}</td>
43+
</tr>`;
44+
})
45+
.join("")}
46+
`;
47+
48+
inputSearch.oninput = (e) => {
49+
search(inputSearch.value);
50+
};
51+
} catch (e) {
52+
alert("ERROR: " + e);
53+
}
54+
}
55+
56+
function search(text) {
57+
[...tableDiv.querySelectorAll("tr")].forEach((tr) => {
58+
let html = tr.innerHTML;
59+
if (!html.toLowerCase().includes(text.toLowerCase())) {
60+
tr.classList.add("hidden");
61+
} else {
62+
tr.classList.remove("hidden");
63+
}
64+
});
65+
}
66+
67+
main();

0 commit comments

Comments
 (0)