// ==UserScript==
// @name AutoBot FBMP Enhanced
// @namespace http://tampermonkey.net/
// @version 4.5
// @description Gabungan auto perbarui & relist Marketplace FB dengan logika retry final, auto start, dan UI kontrol
// @author Behesty
// @match https://www.facebook.com/marketplace/selling/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// ⚙️ Konfigurasi yang bisa diubah:
let retryInterval = 500; // ms antar percobaan
let maxTriesPerRound = 60; // jumlah percobaan per round
let maxRetryRounds = 3; // jumlah maksimal round
let maxLoops = 100; // maksimal jumlah siklus utama
let running = true;
let loopCounter = 0;
let isLooping = false; // ✅ untuk mencegah mainLoop dipanggil ganda
// 📦 Log Box
const logBox = document.createElement('div');
Object.assign(logBox.style, {
position: 'fixed',
bottom: '10px',
right: '10px',
background: 'rgba(0,0,0,0.8)',
color: '#fff',
padding: '10px',
maxHeight: '300px',
overflowY: 'auto',
fontSize: '12px',
zIndex: '9999',
borderRadius: '8px',
whiteSpace: 'pre-line'
});
logBox.innerText = '📢 FB Marketplace Auto Bot\n';
document.body.appendChild(logBox);
function log(msg) {
const now = new Date();
const time = now.toLocaleTimeString('id-ID', { hour12: false });
const fullMsg = `[${time}] ${msg}`;
console.log('[FBMBot] ' + fullMsg);
logBox.innerText += fullMsg + '\n';
logBox.scrollTop = logBox.scrollHeight;
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function randomDelay(min = 500, max = 1500) {
return delay(Math.floor(Math.random() * (max - min + 1)) + min);
}
async function waitForElement(selector) {
for (let round = 1; round <= maxRetryRounds; round++) {
log(`🔄 Percobaan ${round}`);
for (let i = 1; i <= maxTriesPerRound; i++) {
//log(`🔄 Pengecekan tombol: "${selector}" (Round ${round}, Try ${i})`);
const el = document.querySelector(selector);
if (el && el.offsetHeight > 0) return el;
await delay(retryInterval);
}
}
return null;
}
async function waitForVisibleElements(selector) {
for (let round = 1; round <= maxRetryRounds; round++) {
log(`🔄 Percobaan ${round}`);
for (let i = 1; i <= maxTriesPerRound; i++) {
//log(`🔄 Pengecekan tombol: "${selector}" (Round ${round}, Try ${i})`);
const els = Array.from(document.querySelectorAll(selector)).filter(e => e.offsetHeight > 0);
if (els.length > 0) return els;
await delay(retryInterval);
}
}
return [];
}
async function findAndClickRelistButton() {
log('🔎 Mencari tombol "Untuk dihapus & ditawarkan ulang"...');
for (let round = 1; round <= maxRetryRounds; round++) {
log(`🔍 Percobaan ${round}`);
const links = Array.from(document.querySelectorAll('a[role="link"]')).filter(a => a.offsetHeight > 0);
for (const link of links) {
const text = link.innerText;
if (text.includes('Untuk dihapus & ditawarkan ulang')) {
const count = parseInt(text.match(/\d+/)?.[0] || '0');
log(`ℹ️ Ditemukan "Untuk dihapus & ditawarkan ulang" (${count} listing)`);
if (count < 2) {
log('✅ "Untuk dihapus & ditawarkan ulang" <= 1. Lewati.');
return false; // ⛔ Tidak perlu delay
}
log(`📌 Klik "Untuk dihapus & ditawarkan ulang" (${count} listing)`);
link.scrollIntoView({ behavior: 'smooth', block: 'center' });
link.click();
return true;
}
}
await delay(retryInterval); // ⏳ Tunggu tombol muncul di round berikutnya
}
log('❌ Tidak menemukan tombol "Untuk dihapus & ditawarkan ulang" setelah retry.');
return false;
}
async function findAndClickUpdateButton() {
log('🔎 Mencari tombol "Untuk diperbarui"...');
for (let round = 1; round <= maxRetryRounds; round++) {
log(`🔍 Percobaan ${round}`);
const links = Array.from(document.querySelectorAll('a[role="link"]')).filter(a => a.offsetHeight > 0);
for (const link of links) {
const text = link.innerText;
if (text.includes('Untuk diperbarui')) {
const count = parseInt(text.match(/\d+/)?.[0] || '0');
log(`ℹ️ Ditemukan "Untuk diperbarui" (${count} listing)`);
if (count < 2) {
log('✅ "Untuk diperbarui" <= 1. Lewati.');
return false;
}
log(`📌 Klik "Untuk diperbarui" (${count} listing)`);
link.scrollIntoView({ behavior: 'smooth', block: 'center' });
link.click();
return true;
}
}
await delay(retryInterval); // ⏳ Tunggu tombol muncul di round berikutnya
}
log('❌ Tidak menemukan tombol "Untuk diperbarui" setelah retry.');
return false;
}
async function clickRelistButtons() {
log('🔎 Menunggu tombol "Hapus & Tawarkan Ulang"...');
const buttons = await waitForVisibleElements('div[aria-label="Hapus & Tawarkan Ulang"]');
if (buttons.length === 0) {
log('❌ ERROR: Tidak menemukan tombol "Hapus & Tawarkan Ulang".');
return false;
}
log(`🔧 Menemukan ${buttons.length} tombol "Hapus & Tawarkan Ulang"`);
for (const btn of buttons) {
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
log('🔁 Klik tombol "Hapus & Tawarkan Ulang"...');
btn.click();
await randomDelay();
}
return true;
}
async function clickUpdateButtons() {
log('🔎 Menunggu tombol "Perbarui"...');
const buttons = await waitForVisibleElements('div[aria-label="Perbarui"]');
if (buttons.length === 0) {
log('❌ ERROR: Tidak menemukan tombol "Perbarui".');
return false;
}
log(`🔧 Menemukan ${buttons.length} tombol "Perbarui"`);
for (const btn of buttons) {
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
log('🔁 Klik tombol "Perbarui"...');
btn.click();
await randomDelay();
}
return true;
}
async function clickDoneButton() {
log('🔎 Mencari tombol "Selesai"...');
const btn = await waitForElement('div[aria-label="Selesai"]');
if (btn) {
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
log('✅ Klik tombol "Selesai"');
btn.click();
return true;
}
log('⚠️ Tombol "Selesai" tidak ditemukan.');
return false;
}
async function countdown(seconds) {
for (let i = seconds; i > 0; i--) {
if (!running) {
log('⏹ Dihentikan saat countdown.');
return;
}
log(`⏳ Menunggu ${i} detik...`);
await delay(1000);
}
}
async function checkErrorMessage(selector, expectedText, context) {
log(`🔎 Mencari pesan khusus untuk ${context}...`);
const el = Array.from(document.querySelectorAll(selector)).find(e => e.textContent.trim().includes(expectedText));
if (el) {
log(`⚠️ Ditemukan pesan error untuk ${context}: "${expectedText}"`);
await countdown(5);
window.location.href = 'https://www.facebook.com/marketplace/selling/';
return true;
}
log(`ℹ️ Tidak ditemukan pesan khusus untuk ${context}`);
return false;
}
async function runCycle() {
if (!running) return;
loopCounter++;
log(`🚀 Mulai siklus ${loopCounter}`);
let didSomething = false;
let relistClickCounter = 0;
let updateClickCounter = 0;
let shouldReload = false;
// 1. Proses relist dulu
const relistClicked = await findAndClickRelistButton();
if (relistClicked) {
await delay(2000);
const buttons = await waitForVisibleElements('div[aria-label="Hapus & Tawarkan Ulang"]');
if (buttons.length === 0) {
log('❌ ERROR: Tidak menemukan tombol "Hapus & Tawarkan Ulang".');
const found = await checkErrorMessage(
'span[dir="auto"]',
'Ini tidak bisa diperbarui lagi, tetapi Anda bisa menawarkan ulang dan menghapus tawaran asli.',
'Relist'
);
if (found) return;
} else {
log(`🔧 Menemukan ${buttons.length} tombol "Hapus & Tawarkan Ulang"`);
for (const btn of buttons) {
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
log('🔁 Klik tombol "Hapus & Tawarkan Ulang"...');
btn.click();
relistClickCounter++;
await randomDelay();
}
await clickDoneButton();
await delay(2000);
didSomething = true;
}
if (relistClickCounter < 20) {
log(`⚠️ Tombol "Hapus & Tawarkan Ulang" yang diklik (${relistClickCounter}). Akan reload.`);
shouldReload = true;
}
}
// 2. Proses update
const updateClicked = await findAndClickUpdateButton();
if (updateClicked) {
await delay(2000);
const buttons = await waitForVisibleElements('div[aria-label="Perbarui"]');
if (buttons.length === 0) {
log('❌ ERROR: Tidak menemukan tombol "Perbarui".');
const found = await checkErrorMessage(
'span[dir="auto"]',
'Anda tidak lagi memiliki tawaran yang memenuhi syarat untuk diperbarui.',
'Update'
);
if (found) return;
} else {
log(`🔧 Menemukan ${buttons.length} tombol "Perbarui"`);
for (const btn of buttons) {
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
log('🔁 Klik tombol "Perbarui"...');
btn.click();
updateClickCounter++;
await randomDelay();
}
await clickDoneButton();
didSomething = true;
}
if (updateClickCounter < 20) {
log(`⚠️ Tombol "Perbarui" yang diklik (${updateClickCounter}). Akan reload.`);
shouldReload = true;
}
}
log(`📊 Ringkasan siklus ${loopCounter} → Relist: ${relistClickCounter}x klik | Update: ${updateClickCounter}x klik`);
if (shouldReload) {
log('🔁 Kondisi reload terpenuhi (jumlah klik < 20). Countdown sebelum reload...');
await countdown(20); // atau countdown(20);
window.location.href = 'https://www.facebook.com/marketplace/selling/';
return;
}
if (!didSomething) {
log('✅ Tidak ada tombol tersisa. Proses selesai.');
running = false;
return;
}
}
async function mainLoop() {
if (isLooping) return; // ⛔ mencegah dua loop berjalan bersamaan
isLooping = true;
while (running && loopCounter < maxLoops) {
await runCycle();
await countdown(20);
}
isLooping = false;
if (loopCounter >= maxLoops) {
log(`🔄 Maksimum ${maxLoops} siklus tercapai. Reload halaman...`);
await delay(2000);
window.location.href = 'https://www.facebook.com/marketplace/selling/';
}
}
// 🔘 UI: Tombol Start/Stop + input maxLoops
function createUIControls() {
const wrapper = document.createElement('div');
Object.assign(wrapper.style, {
position: 'fixed',
bottom: '35px',
left: '20px',
zIndex: 10000,
display: 'flex',
gap: '10px',
alignItems: 'center'
});
const btn = document.createElement('button');
btn.innerText = '⏹ STOP';
Object.assign(btn.style, {
padding: '15px 80px',
background: '#333',
color: '#fff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer'
});
const input = document.createElement('input');
input.type = 'number';
input.value = maxLoops;
input.min = 1;
input.max = 1000;
input.style.fontSize = '15px';
input.style.width = '60px';
input.style.height = '35px';
input.title = 'Max Loop';
input.onchange = () => {
maxLoops = parseInt(input.value) || 100;
log(`🔧 maxLoops diubah menjadi ${maxLoops}`);
};
btn.onclick = () => {
running = !running;
btn.innerText = running ? '⏹ STOP' : '▶️ START';
if (running) mainLoop(); // ✅ hanya panggil mainLoop satu kali
};
wrapper.appendChild(btn);
wrapper.appendChild(input);
document.body.appendChild(wrapper);
}
// ▶️ Mulai otomatis
setTimeout(() => {
createUIControls();
mainLoop();
}, 2000);
})();