-
Thời gian chờ:
-
+
Duyệt tối đa bao nhiêu bài?
diff --git a/scripts/backup/ext/fb-group-ext/popup/main.js b/scripts/backup/ext/fb-group-ext/popup/main.js
index e5891053..3d053e0a 100644
--- a/scripts/backup/ext/fb-group-ext/popup/main.js
+++ b/scripts/backup/ext/fb-group-ext/popup/main.js
@@ -1,21 +1,27 @@
-const sliderWaitTime = document.getElementById("slider-wait-time");
-const spanWaitTime = document.getElementById("wait-time");
+const waitMinInp = document.getElementById("inputWaitMin");
+const waitMaxInp = document.getElementById("inputWaitMax");
const inputMaxPosts = document.getElementById("max-posts");
const radioAction = document.getElementsByName("action");
const startBtn = document.getElementById("start-btn");
-sliderWaitTime.value = localStorage.getItem("wait-time") || 3000;
-spanWaitTime.innerHTML = renderTime(sliderWaitTime.value);
-sliderWaitTime.oninput = function () {
- spanWaitTime.innerHTML = renderTime(this.value);
- localStorage.setItem("wait-time", this.value);
-};
+function initCacheInput(input, cacheName) {
+ if (localStorage.getItem(cacheName)) {
+ input.value = localStorage.getItem(cacheName);
+ }
+ input.addEventListener("input", () => {
+ localStorage.setItem(cacheName, input.value);
+ });
+}
-function renderTime(time) {
- return (time / 1000).toFixed(1) + "s";
+function renderTime(time, fixed = 1) {
+ return (time / 1000).toFixed(fixed) + "s";
}
async function main() {
+ initCacheInput(waitMinInp, "wait-min");
+ initCacheInput(waitMaxInp, "wait-max");
+ initCacheInput(inputMaxPosts, "max-posts");
+
const tab = await getCurrentTab();
if (!tab.url.includes("groups") || !tab.url.includes("spam")) {
@@ -26,44 +32,70 @@ async function main() {
}
startBtn.addEventListener("click", async () => {
+ const state = await getCurrentState(tab);
+ if (state?.running) {
+ return stop(tab);
+ }
+
let action = radioAction[0].checked ? 1 : 2;
- let max = parseInt(inputMaxPosts.value);
- let wait = parseInt(sliderWaitTime.value);
+ let maxPosts = parseInt(inputMaxPosts.value);
+ let waitMin = parseInt(waitMinInp.value) * 1000;
+ let waitMax = parseInt(waitMaxInp.value) * 1000;
+
+ if (waitMin > waitMax) {
+ return alert(
+ "Thời gian chờ không hợp lệ\nBên trái phải bé hơn hoặc bằng bên phải"
+ );
+ }
+
runScriptInTab({
target: { tabId: tab.id },
func: start,
- args: [action, max, wait],
+ args: [action, maxPosts, waitMin, waitMax],
});
});
// check is running
(async function checkIsRunning() {
- const isRunning = await runScriptInTab({
- target: { tabId: tab.id },
- func: () => window.fb_group_ext_running,
- });
- if (isRunning) {
- // disable button
- startBtn.disabled = true;
- startBtn.innerHTML = "Đang xử lý...";
- startBtn.classList.add("disabled");
+ const state = await getCurrentState(tab);
+ const { running, nextExecuteTime } = state || {};
+ if (running) {
+ startBtn.innerHTML =
+ "Đang xử lý... (chờ " +
+ renderTime(nextExecuteTime - Date.now(), 0) +
+ ")
(
Bấm để dừng)";
+ startBtn.classList.add("running");
} else {
- // enable button
- startBtn.disabled = false;
startBtn.innerHTML = "Bắt đầu";
- startBtn.classList.remove("disabled");
+ startBtn.classList.remove("running");
}
- setTimeout(checkIsRunning, 500);
+ setTimeout(checkIsRunning, 1000);
})();
}
-function start(action, max, wait) {
+function getCurrentState(tab) {
+ return runScriptInTab({
+ target: { tabId: tab.id },
+ func: () => window.fb_group_ext,
+ });
+}
+
+function stop(tab) {
+ runScriptInTab({
+ target: { tabId: tab.id },
+ func: () => {
+ window.fb_group_ext.stop = true;
+ },
+ });
+}
+
+function start(action, maxPosts, waitMin, waitMax) {
const selector =
action == 1
? '[role="main"] [aria-label="Đăng"]'
: '[role="main"] [aria-label="Từ chối"]';
- if (max == 0) max = Infinity;
+ if (maxPosts == 0) maxPosts = Infinity;
const btns = Array.from(document.querySelectorAll(selector));
@@ -80,14 +112,14 @@ function start(action, max, wait) {
});
async function main() {
- window.fb_group_ext_running = true;
-
- // for test
- // setTimeout(() => (window.fb_group_ext_running = false), 5000);
- // return;
+ window.fb_group_ext = {
+ running: true,
+ nextExecuteTime: 0,
+ stop: false,
+ };
let counter = 0;
- while (counter < max) {
+ while (counter < maxPosts && !window.fb_group_ext.stop) {
if (btns.length > 0) {
const btn = btns.shift();
@@ -96,18 +128,34 @@ function start(action, max, wait) {
btn.click();
counter++;
+ const waitTime = ranInt(waitMin, waitMax);
+ window.fb_group_ext.nextExecuteTime = Date.now() + waitTime;
+ await sleep(waitTime, () => window.fb_group_ext.stop);
+ } else {
+ // wait for load more
+ await sleep(1000);
}
-
- if (wait) await sleep(wait);
}
- window.fb_group_ext_running = false;
+
+ window.fb_group_ext.running = false;
alert("Duyệt xong " + counter + " bài");
}
main();
- function sleep(time) {
- return new Promise((resolve) => setTimeout(resolve, time));
+ function ranInt(min, max) {
+ return Math.floor(Math.random() * (max - min) + min);
+ }
+
+ function sleep(time, cancelFn) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time);
+ if (cancelFn) {
+ setInterval(() => {
+ if (cancelFn()) resolve();
+ }, 100);
+ }
+ });
}
function onElementsAdded(selector, callback, once) {
diff --git a/scripts/backup/ext/fb-group-ext/popup/style.css b/scripts/backup/ext/fb-group-ext/popup/style.css
index 1faef683..5b788e9e 100644
--- a/scripts/backup/ext/fb-group-ext/popup/style.css
+++ b/scripts/backup/ext/fb-group-ext/popup/style.css
@@ -79,41 +79,6 @@ h3 {
/* ======================= Range ====================== */
-.slidecontainer {
- width: 100%;
-}
-
-.slider {
- -webkit-appearance: none;
- width: 100%;
- height: 25px;
- background: #d3d3d3;
- outline: none;
- opacity: 0.7;
- -webkit-transition: .2s;
- transition: opacity .2s;
-}
-
-.slider:hover {
- opacity: 1;
-}
-
-.slider::-webkit-slider-thumb {
- -webkit-appearance: none;
- appearance: none;
- width: 25px;
- height: 25px;
- background: #04AA6D;
- cursor: pointer;
-}
-
-.slider::-moz-range-thumb {
- width: 25px;
- height: 25px;
- background: #04AA6D;
- cursor: pointer;
-}
-
input[type=number] {
padding: 5px;
font-size: large;
@@ -133,7 +98,19 @@ input[type=number] {
margin-top: 30px;
}
-.button.disabled {
+.button.running {
background-color: rgb(151, 12, 12);
- cursor: not-allowed;
+ /* cursor: not-allowed; */
+}
+
+.input-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-direction: row;
+ white-space: pre;
+}
+
+.input-row input[type=number] {
+ /* max-width: 80px; */
}
From 279716429f827010123dfd8c5e7af505ef58fcba Mon Sep 17 00:00:00 2001
From: "hoang.tran12" <99.hoangtran@gmail.com>
Date: Tue, 6 Aug 2024 18:28:40 +0700
Subject: [PATCH 21/43] .
---
scripts/backup/ext/fb-group-ext/popup/main.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/backup/ext/fb-group-ext/popup/main.js b/scripts/backup/ext/fb-group-ext/popup/main.js
index 3d053e0a..2a4dc55d 100644
--- a/scripts/backup/ext/fb-group-ext/popup/main.js
+++ b/scripts/backup/ext/fb-group-ext/popup/main.js
@@ -132,6 +132,8 @@ function start(action, maxPosts, waitMin, waitMax) {
window.fb_group_ext.nextExecuteTime = Date.now() + waitTime;
await sleep(waitTime, () => window.fb_group_ext.stop);
} else {
+ // scroll to end
+ window.scrollTo(0, document.body.scrollHeight);
// wait for load more
await sleep(1000);
}
From 745856cc572fb4312c3403a2ab7f67c47ee716df Mon Sep 17 00:00:00 2001
From: HoangTran <99.hoangtran@gmail.com>
Date: Tue, 6 Aug 2024 22:18:33 +0700
Subject: [PATCH 22/43] refactor insta
---
popup/recommend.js | 17 +++++++++++++++++
popup/tabs.js | 4 ++--
scripts/insta_GLOBAL.js | 2 ++
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/popup/recommend.js b/popup/recommend.js
index 4fc8e136..36992bed 100644
--- a/popup/recommend.js
+++ b/popup/recommend.js
@@ -886,4 +886,21 @@ export const Recommend = {
),
},
},
+ insta_bulkDownload: {
+ id: "recommend_fbAIOInstagram",
+ icon: "https://static.cdninstagram.com/rsrc.php/v3/yI/r/VsNE-OHk_8a.png",
+ name: {
+ en: "Instagram - Bulk download",
+ vi: "Instagram - Tải hàng loạt",
+ },
+ description: {
+ en: "Download all user's media on instagram (video/photo/reels/highlight)",
+ vi: "Tải mọi ảnh/video/reel/highlight của người dùng Instagram",
+ },
+ badges: [BADGES.new, BADGES.hot],
+ popupScript: {
+ onClick: () =>
+ window.open("https://facebook-all-in-one.com/dist/#/bulk-downloader"),
+ },
+ },
};
diff --git a/popup/tabs.js b/popup/tabs.js
index 4b8881fb..a13dff1c 100644
--- a/popup/tabs.js
+++ b/popup/tabs.js
@@ -168,11 +168,11 @@ const tabs = [
{
...CATEGORY.instagram,
scripts: [
+ R.insta_bulkDownload,
+ // s.insta_getAllUserMedia,
s.insta_getUserInfo,
s.insta_injectDownloadBtn,
s.insta_anonymousStoryViewer,
- createTitle("--- Bulk Download ---", "--- Tải hàng loạt ---"),
- s.insta_getAllUserMedia,
s.insta_getFollowForOther,
],
},
diff --git a/scripts/insta_GLOBAL.js b/scripts/insta_GLOBAL.js
index c7fc4d7b..dc07aee4 100644
--- a/scripts/insta_GLOBAL.js
+++ b/scripts/insta_GLOBAL.js
@@ -25,6 +25,8 @@ export function getUniversalCdnUrl(cdnLink) {
return cdnLink;
}
}
+
+// WARNING: not working anymore??
export async function getAllMedia({ uid, progressCallback, limit = 0 }) {
let all_urls = [];
let after = "";
From 13728196da0ffa76bbac4ffd5bc2e1d5766daa99 Mon Sep 17 00:00:00 2001
From: "hoang.tran12" <99.hoangtran@gmail.com>
Date: Wed, 7 Aug 2024 09:52:52 +0700
Subject: [PATCH 23/43] fix fb avatar expired
---
scripts/ufs_statistic.js | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/scripts/ufs_statistic.js b/scripts/ufs_statistic.js
index 8a5ff73f..f4f06ca8 100644
--- a/scripts/ufs_statistic.js
+++ b/scripts/ufs_statistic.js
@@ -533,6 +533,26 @@ async function onDocumentEnd() {
.querySelectorAll(`[data-profile-avatar="${uid}"]`)
.forEach((el) => {
el.src = info.avatar.replace(/\\\//g, "/") || el.src;
+
+ let tried = 0,
+ loading = false;
+
+ // in case cached avatqr expired
+ el.onerror = () => {
+ if (loading) return;
+ tried++;
+ if (tried > 3) el.src = getUserAvatarFromUid(uid);
+ else {
+ loading = true;
+ getFbProfile(uid, true)
+ .then((info) => {
+ el.src = info.avatar.replace(/\\\//g, "/") || el.src;
+ })
+ .finally(() => {
+ loading = false;
+ });
+ }
+ };
});
})
);
@@ -654,8 +674,8 @@ async function initCache() {
}
}
-async function getFbProfile(uid) {
- if (CACHED.fbProfile.has(uid)) return CACHED.fbProfile.get(uid);
+async function getFbProfile(uid, force = false) {
+ if (CACHED.fbProfile.has(uid) && !force) return CACHED.fbProfile.get(uid);
const variables = {
userID: uid,
From 619382c075ea0618b4aa4b30aeb6010673af08b2 Mon Sep 17 00:00:00 2001
From: HoangTran <99.hoangtran@gmail.com>
Date: Wed, 7 Aug 2024 13:05:21 +0700
Subject: [PATCH 24/43] hin
---
.../generated_indexed_rulesets/_ruleset1 | Bin 0 -> 1811 bytes
.../popup/auto_duyet_bai/index.html | 43 ++
.../popup/{ => auto_duyet_bai}/main.js | 474 +++++++++---------
.../popup/{ => auto_duyet_bai}/style.css | 232 ++++-----
.../backup/ext/fb-group-ext/popup/index.html | 52 +-
5 files changed, 418 insertions(+), 383 deletions(-)
create mode 100644 _metadata/generated_indexed_rulesets/_ruleset1
create mode 100644 scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/index.html
rename scripts/backup/ext/fb-group-ext/popup/{ => auto_duyet_bai}/main.js (96%)
rename scripts/backup/ext/fb-group-ext/popup/{ => auto_duyet_bai}/style.css (94%)
diff --git a/_metadata/generated_indexed_rulesets/_ruleset1 b/_metadata/generated_indexed_rulesets/_ruleset1
new file mode 100644
index 0000000000000000000000000000000000000000..9c3f4a785ad68c59c7777c17c2897f42c9697d7e
GIT binary patch
literal 1811
zcmbtUJ!=$E6uqOP8Dt3yuDXiF6k@TMnUJKAfTa+u771b@#7Ug&4$008Gn0>>U|}sH
z7AZw6EK*pc2x5_P%M>YsRSHWB3w1o_&3ihU4M==&_I=EG_n!Olc49)02Vs^+NqlE|
zsx2aSAI{$w8JD)$;z&c9(!x%}u|#GtH@OBHfEnkp*guCe;HfQQ1CwV(HqVG)l4rmi
zfMfamy(~dfb|&>1CS}vbd>x>U7C>M0Lw~$`h`YCboc_LxyQ}|k|1s_|o=3<<1E8jz
zn!PVtCnlwR5Az{#0PF)VfFY0q{MH3_fk}YzZUgUtx4>&)t1L^#pQlC9#|)R!Lh|10
zbAJ|J^!Yr54b3?}=<^-a;7Fg7Zuke_J5cGUI#+ovR-(ew_Zqn8K$ZF4#Ch(+FlG*F
zY2&AW?OousHQiR)T1o}Gjqw^=Ggvdn91d^;aDkJ1#8&)|-^vm+n|(=p#s)%CJ
{
zieoWv+_!*!QKb2-@8`jKxE?(T6K@dWSUzZOS995)qqu$;`{Z{K)41iT9-s!5EKHYy
zk@q@yE9h-}wi)|Ln(tK{YYTx;bKTy?#)el!D@C&6EhPhyb{z
zs@jlm{Bn5}Fu7zrQJfb+FAD}$__C+{qhu%gf2sX-wf{GI-`D;(x!3+_r|!Sr1N6Tf
zEQO1S$v)yo58#H)p8LC=zv8br)({-_Uq|nccoDb=m>BaoNKs!eNK@pdjXG8J0;M*7
z*NeLOX6fJP=DQhT&kq)tro6PDlFI*kN5;5>?xwPVrHzyvi-R?z&QDr5-{@_C%91SV
zMKKm~0XD{9vw@Ww7J1Z0FIl)8W??3mur}J(;=G?^MHqWg!3X8y#s5pZ%prA}c)7d@
WjI=ulqS)_+#lmV5_ZHT&Rgs^Sk{fXV
literal 0
HcmV?d00001
diff --git a/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/index.html b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/index.html
new file mode 100644
index 00000000..a3e6e118
--- /dev/null
+++ b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ Quản lý nhóm Facebook
+
+
+
+
+
+ Auto duyệt bài spam group fb
+
+ Chọn hành động
+
+
+
+
+
+ Duyệt tối đa bao nhiêu bài?
+ (nhập 0 để duyệt hết)
+
+
+
+
+
+
+
+
diff --git a/scripts/backup/ext/fb-group-ext/popup/main.js b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/main.js
similarity index 96%
rename from scripts/backup/ext/fb-group-ext/popup/main.js
rename to scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/main.js
index 2a4dc55d..4b58e5a9 100644
--- a/scripts/backup/ext/fb-group-ext/popup/main.js
+++ b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/main.js
@@ -1,237 +1,237 @@
-const waitMinInp = document.getElementById("inputWaitMin");
-const waitMaxInp = document.getElementById("inputWaitMax");
-const inputMaxPosts = document.getElementById("max-posts");
-const radioAction = document.getElementsByName("action");
-const startBtn = document.getElementById("start-btn");
-
-function initCacheInput(input, cacheName) {
- if (localStorage.getItem(cacheName)) {
- input.value = localStorage.getItem(cacheName);
- }
- input.addEventListener("input", () => {
- localStorage.setItem(cacheName, input.value);
- });
-}
-
-function renderTime(time, fixed = 1) {
- return (time / 1000).toFixed(fixed) + "s";
-}
-
-async function main() {
- initCacheInput(waitMinInp, "wait-min");
- initCacheInput(waitMaxInp, "wait-max");
- initCacheInput(inputMaxPosts, "max-posts");
-
- const tab = await getCurrentTab();
-
- if (!tab.url.includes("groups") || !tab.url.includes("spam")) {
- return prompt(
- "Bạn cần mở trang duyệt bài spam của group trước. Ví dụ:",
- "https://www.facebook.com/groups/gamecode/spam"
- );
- }
-
- startBtn.addEventListener("click", async () => {
- const state = await getCurrentState(tab);
- if (state?.running) {
- return stop(tab);
- }
-
- let action = radioAction[0].checked ? 1 : 2;
- let maxPosts = parseInt(inputMaxPosts.value);
- let waitMin = parseInt(waitMinInp.value) * 1000;
- let waitMax = parseInt(waitMaxInp.value) * 1000;
-
- if (waitMin > waitMax) {
- return alert(
- "Thời gian chờ không hợp lệ\nBên trái phải bé hơn hoặc bằng bên phải"
- );
- }
-
- runScriptInTab({
- target: { tabId: tab.id },
- func: start,
- args: [action, maxPosts, waitMin, waitMax],
- });
- });
-
- // check is running
- (async function checkIsRunning() {
- const state = await getCurrentState(tab);
- const { running, nextExecuteTime } = state || {};
- if (running) {
- startBtn.innerHTML =
- "Đang xử lý... (chờ " +
- renderTime(nextExecuteTime - Date.now(), 0) +
- ")
(Bấm để dừng)";
- startBtn.classList.add("running");
- } else {
- startBtn.innerHTML = "Bắt đầu";
- startBtn.classList.remove("running");
- }
- setTimeout(checkIsRunning, 1000);
- })();
-}
-
-function getCurrentState(tab) {
- return runScriptInTab({
- target: { tabId: tab.id },
- func: () => window.fb_group_ext,
- });
-}
-
-function stop(tab) {
- runScriptInTab({
- target: { tabId: tab.id },
- func: () => {
- window.fb_group_ext.stop = true;
- },
- });
-}
-
-function start(action, maxPosts, waitMin, waitMax) {
- const selector =
- action == 1
- ? '[role="main"] [aria-label="Đăng"]'
- : '[role="main"] [aria-label="Từ chối"]';
-
- if (maxPosts == 0) maxPosts = Infinity;
-
- const btns = Array.from(document.querySelectorAll(selector));
-
- if (!btns.length) {
- alert("Không tìm thấy bài nào");
- return;
- }
-
- onElementsAdded(selector, (nodes) => {
- for (let node of nodes) {
- if (btns.includes(node)) continue;
- btns.push(node);
- }
- });
-
- async function main() {
- window.fb_group_ext = {
- running: true,
- nextExecuteTime: 0,
- stop: false,
- };
-
- let counter = 0;
- while (counter < maxPosts && !window.fb_group_ext.stop) {
- if (btns.length > 0) {
- const btn = btns.shift();
-
- btn.scrollIntoView({ block: "center", behavior: "smooth" });
- console.log("click", btn);
- btn.click();
-
- counter++;
- const waitTime = ranInt(waitMin, waitMax);
- window.fb_group_ext.nextExecuteTime = Date.now() + waitTime;
- await sleep(waitTime, () => window.fb_group_ext.stop);
- } else {
- // scroll to end
- window.scrollTo(0, document.body.scrollHeight);
- // wait for load more
- await sleep(1000);
- }
- }
-
- window.fb_group_ext.running = false;
- alert("Duyệt xong " + counter + " bài");
- }
-
- main();
-
- function ranInt(min, max) {
- return Math.floor(Math.random() * (max - min) + min);
- }
-
- function sleep(time, cancelFn) {
- return new Promise((resolve) => {
- setTimeout(resolve, time);
- if (cancelFn) {
- setInterval(() => {
- if (cancelFn()) resolve();
- }, 100);
- }
- });
- }
-
- function onElementsAdded(selector, callback, once) {
- let nodes = document.querySelectorAll(selector);
- if (nodes?.length) {
- callback(nodes);
- if (once) return;
- }
-
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- if (!mutation.addedNodes) return;
-
- for (let node of mutation.addedNodes) {
- if (node.nodeType != 1) continue; // only process Node.ELEMENT_NODE
-
- let n = node.matches(selector)
- ? [node]
- : Array.from(node.querySelectorAll(selector));
-
- if (n?.length) {
- callback(n);
- if (once) observer.disconnect();
- }
- }
- });
- });
-
- observer.observe(document, {
- childList: true,
- subtree: true,
- attributes: false,
- characterData: false,
- });
-
- // return disconnect function
- return () => observer.disconnect();
- }
-}
-
-async function getCurrentTab() {
- let tabs = await chrome.tabs.query({
- active: true,
- currentWindow: true,
- });
- return tabs[0];
-}
-
-const runScriptInTab = async (config = {}) => {
- return new Promise((resolve, reject) => {
- chrome.scripting.executeScript(
- mergeObject(
- {
- world: "MAIN",
- injectImmediately: true,
- },
- config
- ),
- (injectionResults) => {
- if (chrome.runtime.lastError) {
- console.error(chrome.runtime.lastError);
- reject(chrome.runtime.lastError);
- }
- // https://developer.chrome.com/docs/extensions/reference/scripting/#handling-results
- else resolve(injectionResults?.find?.((_) => _.result)?.result);
- }
- );
- });
-};
-const mergeObject = (...objs) => {
- // merge without null value
- let res = {};
- for (let obj of objs) for (let key in obj) if (obj[key]) res[key] = obj[key];
- return res;
-};
-
-main();
+const waitMinInp = document.getElementById("inputWaitMin");
+const waitMaxInp = document.getElementById("inputWaitMax");
+const inputMaxPosts = document.getElementById("max-posts");
+const radioAction = document.getElementsByName("action");
+const startBtn = document.getElementById("start-btn");
+
+function initCacheInput(input, cacheName) {
+ if (localStorage.getItem(cacheName)) {
+ input.value = localStorage.getItem(cacheName);
+ }
+ input.addEventListener("input", () => {
+ localStorage.setItem(cacheName, input.value);
+ });
+}
+
+function renderTime(time, fixed = 1) {
+ return (time / 1000).toFixed(fixed) + "s";
+}
+
+async function main() {
+ initCacheInput(waitMinInp, "wait-min");
+ initCacheInput(waitMaxInp, "wait-max");
+ initCacheInput(inputMaxPosts, "max-posts");
+
+ const tab = await getCurrentTab();
+
+ if (!tab.url.includes("groups") || !tab.url.includes("spam")) {
+ return prompt(
+ "Bạn cần mở trang duyệt bài spam của group trước. Ví dụ:",
+ "https://www.facebook.com/groups/gamecode/spam"
+ );
+ }
+
+ startBtn.addEventListener("click", async () => {
+ const state = await getCurrentState(tab);
+ if (state?.running) {
+ return stop(tab);
+ }
+
+ let action = radioAction[0].checked ? 1 : 2;
+ let maxPosts = parseInt(inputMaxPosts.value);
+ let waitMin = parseInt(waitMinInp.value) * 1000;
+ let waitMax = parseInt(waitMaxInp.value) * 1000;
+
+ if (waitMin > waitMax) {
+ return alert(
+ "Thời gian chờ không hợp lệ\nBên trái phải bé hơn hoặc bằng bên phải"
+ );
+ }
+
+ runScriptInTab({
+ target: { tabId: tab.id },
+ func: start,
+ args: [action, maxPosts, waitMin, waitMax],
+ });
+ });
+
+ // check is running
+ (async function checkIsRunning() {
+ const state = await getCurrentState(tab);
+ const { running, nextExecuteTime } = state || {};
+ if (running) {
+ startBtn.innerHTML =
+ "Đang xử lý... (chờ " +
+ renderTime(nextExecuteTime - Date.now(), 0) +
+ ")
(Bấm để dừng)";
+ startBtn.classList.add("running");
+ } else {
+ startBtn.innerHTML = "Bắt đầu";
+ startBtn.classList.remove("running");
+ }
+ setTimeout(checkIsRunning, 1000);
+ })();
+}
+
+function getCurrentState(tab) {
+ return runScriptInTab({
+ target: { tabId: tab.id },
+ func: () => window.fb_group_ext,
+ });
+}
+
+function stop(tab) {
+ runScriptInTab({
+ target: { tabId: tab.id },
+ func: () => {
+ window.fb_group_ext.stop = true;
+ },
+ });
+}
+
+function start(action, maxPosts, waitMin, waitMax) {
+ const selector =
+ action == 1
+ ? '[role="main"] [aria-label="Đăng"]'
+ : '[role="main"] [aria-label="Từ chối"]';
+
+ if (maxPosts == 0) maxPosts = Infinity;
+
+ const btns = Array.from(document.querySelectorAll(selector));
+
+ if (!btns.length) {
+ alert("Không tìm thấy bài nào");
+ return;
+ }
+
+ onElementsAdded(selector, (nodes) => {
+ for (let node of nodes) {
+ if (btns.includes(node)) continue;
+ btns.push(node);
+ }
+ });
+
+ async function main() {
+ window.fb_group_ext = {
+ running: true,
+ nextExecuteTime: 0,
+ stop: false,
+ };
+
+ let counter = 0;
+ while (counter < maxPosts && !window.fb_group_ext.stop) {
+ if (btns.length > 0) {
+ const btn = btns.shift();
+
+ btn.scrollIntoView({ block: "center", behavior: "smooth" });
+ console.log("click", btn);
+ btn.click();
+
+ counter++;
+ const waitTime = ranInt(waitMin, waitMax);
+ window.fb_group_ext.nextExecuteTime = Date.now() + waitTime;
+ await sleep(waitTime, () => window.fb_group_ext.stop);
+ } else {
+ // scroll to end
+ window.scrollTo(0, document.body.scrollHeight);
+ // wait for load more
+ await sleep(1000);
+ }
+ }
+
+ window.fb_group_ext.running = false;
+ alert("Duyệt xong " + counter + " bài");
+ }
+
+ main();
+
+ function ranInt(min, max) {
+ return Math.floor(Math.random() * (max - min) + min);
+ }
+
+ function sleep(time, cancelFn) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time);
+ if (cancelFn) {
+ setInterval(() => {
+ if (cancelFn()) resolve();
+ }, 100);
+ }
+ });
+ }
+
+ function onElementsAdded(selector, callback, once) {
+ let nodes = document.querySelectorAll(selector);
+ if (nodes?.length) {
+ callback(nodes);
+ if (once) return;
+ }
+
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ if (!mutation.addedNodes) return;
+
+ for (let node of mutation.addedNodes) {
+ if (node.nodeType != 1) continue; // only process Node.ELEMENT_NODE
+
+ let n = node.matches(selector)
+ ? [node]
+ : Array.from(node.querySelectorAll(selector));
+
+ if (n?.length) {
+ callback(n);
+ if (once) observer.disconnect();
+ }
+ }
+ });
+ });
+
+ observer.observe(document, {
+ childList: true,
+ subtree: true,
+ attributes: false,
+ characterData: false,
+ });
+
+ // return disconnect function
+ return () => observer.disconnect();
+ }
+}
+
+async function getCurrentTab() {
+ let tabs = await chrome.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ return tabs[0];
+}
+
+const runScriptInTab = async (config = {}) => {
+ return new Promise((resolve, reject) => {
+ chrome.scripting.executeScript(
+ mergeObject(
+ {
+ world: "MAIN",
+ injectImmediately: true,
+ },
+ config
+ ),
+ (injectionResults) => {
+ if (chrome.runtime.lastError) {
+ console.error(chrome.runtime.lastError);
+ reject(chrome.runtime.lastError);
+ }
+ // https://developer.chrome.com/docs/extensions/reference/scripting/#handling-results
+ else resolve(injectionResults?.find?.((_) => _.result)?.result);
+ }
+ );
+ });
+};
+const mergeObject = (...objs) => {
+ // merge without null value
+ let res = {};
+ for (let obj of objs) for (let key in obj) if (obj[key]) res[key] = obj[key];
+ return res;
+};
+
+main();
diff --git a/scripts/backup/ext/fb-group-ext/popup/style.css b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/style.css
similarity index 94%
rename from scripts/backup/ext/fb-group-ext/popup/style.css
rename to scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/style.css
index 5b788e9e..ed4f3892 100644
--- a/scripts/backup/ext/fb-group-ext/popup/style.css
+++ b/scripts/backup/ext/fb-group-ext/popup/auto_duyet_bai/style.css
@@ -1,116 +1,116 @@
-body {
- min-width: 350px;
- min-height: 200px;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- font-size: 16px;
-}
-
-
-h3 {
- text-decoration: underline;
- margin-bottom: 8px;
-}
-
-
-/* The container */
-.container {
- display: block;
- position: relative;
- padding-left: 35px;
- margin-bottom: 12px;
- cursor: pointer;
- font-size: 22px;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-/* Hide the browser's default radio button */
-.container input {
- position: absolute;
- opacity: 0;
- cursor: pointer;
-}
-
-/* Create a custom radio button */
-.checkmark {
- position: absolute;
- top: 0;
- left: 0;
- height: 25px;
- width: 25px;
- background-color: #eee;
- border-radius: 50%;
-}
-
-/* On mouse-over, add a grey background color */
-.container:hover input~.checkmark {
- background-color: #ccc;
-}
-
-/* When the radio button is checked, add a blue background */
-.container input:checked~.checkmark {
- background-color: #2196F3;
-}
-
-/* Create the indicator (the dot/circle - hidden when not checked) */
-.checkmark:after {
- content: "";
- position: absolute;
- display: none;
-}
-
-/* Show the indicator (dot/circle) when checked */
-.container input:checked~.checkmark:after {
- display: block;
-}
-
-/* Style the indicator (dot/circle) */
-.container .checkmark:after {
- top: 9px;
- left: 9px;
- width: 8px;
- height: 8px;
- border-radius: 50%;
- background: white;
-}
-
-
-/* ======================= Range ====================== */
-
-input[type=number] {
- padding: 5px;
- font-size: large;
-}
-
-.button {
- background-color: #04AA6D;
- border: none;
- color: white;
- padding: 15px 32px;
- text-align: center;
- text-decoration: none;
- display: inline-block;
- font-size: 16px;
- cursor: pointer;
- width: 100%;
- margin-top: 30px;
-}
-
-.button.running {
- background-color: rgb(151, 12, 12);
- /* cursor: not-allowed; */
-}
-
-.input-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-direction: row;
- white-space: pre;
-}
-
-.input-row input[type=number] {
- /* max-width: 80px; */
-}
+body {
+ min-width: 350px;
+ min-height: 200px;
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-size: 16px;
+}
+
+
+h3 {
+ text-decoration: underline;
+ margin-bottom: 8px;
+}
+
+
+/* The container */
+.container {
+ display: block;
+ position: relative;
+ padding-left: 35px;
+ margin-bottom: 12px;
+ cursor: pointer;
+ font-size: 22px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+/* Hide the browser's default radio button */
+.container input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+}
+
+/* Create a custom radio button */
+.checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 25px;
+ width: 25px;
+ background-color: #eee;
+ border-radius: 50%;
+}
+
+/* On mouse-over, add a grey background color */
+.container:hover input~.checkmark {
+ background-color: #ccc;
+}
+
+/* When the radio button is checked, add a blue background */
+.container input:checked~.checkmark {
+ background-color: #2196F3;
+}
+
+/* Create the indicator (the dot/circle - hidden when not checked) */
+.checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+/* Show the indicator (dot/circle) when checked */
+.container input:checked~.checkmark:after {
+ display: block;
+}
+
+/* Style the indicator (dot/circle) */
+.container .checkmark:after {
+ top: 9px;
+ left: 9px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: white;
+}
+
+
+/* ======================= Range ====================== */
+
+input[type=number] {
+ padding: 5px;
+ font-size: large;
+}
+
+.button {
+ background-color: #04AA6D;
+ border: none;
+ color: white;
+ padding: 15px 32px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 16px;
+ cursor: pointer;
+ width: 100%;
+ margin-top: 30px;
+}
+
+.button.running {
+ background-color: rgb(151, 12, 12);
+ /* cursor: not-allowed; */
+}
+
+.input-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-direction: row;
+ white-space: pre;
+}
+
+.input-row input[type=number] {
+ /* max-width: 80px; */
+}
diff --git a/scripts/backup/ext/fb-group-ext/popup/index.html b/scripts/backup/ext/fb-group-ext/popup/index.html
index e8c4bd55..708c4784 100644
--- a/scripts/backup/ext/fb-group-ext/popup/index.html
+++ b/scripts/backup/ext/fb-group-ext/popup/index.html
@@ -4,40 +4,32 @@
- Quản lý nhóm Facebook
-
-
+ Document
+
+
- Facebook Tools
-
- Chọn hành động
-
-
-
-
-
- Duyệt tối đa bao nhiêu bài?
- (nhập 0 để duyệt hết)
-
-
-
+ Auto duyệt bài group
-