Code đặt lịch cho via và tkqc có nút
(() => {
// ========================= CONFIG: SỬA TRỰC TIẾP Ở ĐÂY =========================
const CONFIG = {
program: "Accelerate Plus",
contact: {
name: "Linh Hạ",
phone_number: "7885565255",
business_name: "Linh Hạ",
email_address: "sonyaifulopetqi@hotmail.com"
},
// selected_timezone gửi lên API (IANA). Ảnh cho thấy GMT+07, mình để Asia/Ho_Chi_Minh.
selected_timezone: "Asia/Ho_Chi_Minh",
// OFFSET để tính epoch (theo ảnh: GMT+07:00). Nếu đổi múi giờ, sửa "+07:00".
TZ_OFFSET: "+07:00",
// Độ dài mỗi slot (phút). Theo UI: 45'.
SLOT_MINUTES: 45,
// Toàn bộ ngày/giờ như ảnh — có thể SỬA/BỚT/THÊM trước khi chạy.
TIMEPOOL: [
// 19/11/2025
{ date: "19/11/2025", times: ["09:00","09:45","10:30","11:15","12:00","12:45","13:30","14:15","15:30","16:15"] },
// 20/11/2025
{ date: "20/11/2025", times: ["09:00","09:45","10:30","11:15","12:00","12:45","13:30","14:15","15:30","16:15"] },
// 21/11/2025
{ date: "21/11/2025", times: ["09:00","09:45","10:30","11:15","12:00","12:45","13:30","14:15","15:30","16:15"] },
// 24/11/2025
{ date: "24/11/2025", times: ["09:00","09:45","10:30","11:15","12:00","12:45","13:30","14:15","15:30","16:15"] },
// 20/11/2025
{ date: "20/11/2025", times: ["09:00","09:45","10:30","11:15","12:00","12:45","13:30","14:15","15:30","16:15"] },
],
perIdDelayMs: 5200, // nghỉ giữa các ID để giảm rate-limit
autoLabel: true // tự tạo label dd/mm HH:MM theo timezone
};
// ========================= DOC_ID DỰ PHÒNG =========================
const DOCIDS = {
engagementDetailsQuery: ["24205266979145499"],
scheduleCallMutation: ["9512784282180280"]
};
// ========================= HELPERS =========================
const ensureAdsManager = () => {
if (!/(^|\.)adsmanager\.facebook\.com$/.test(location.host) ||
!/\/adsmanager\/manage\/campaigns/.test(location.pathname)) {
throw new Error("Hãy mở đúng Ads Manager: https://adsmanager.facebook.com/adsmanager/manage/campaigns?act=...");
}
};
const getCookie = (name) =>
document.cookie.split("; ").find(r => r.startsWith(name + "="))?.split("=")[1];
const getParam = (k, url = location.href) => new URL(url).searchParams.get(k);
const stripGuards = (t) =>
t.replace(/^for\s*\(\s*;;\s*\);\s*/, "").replace(/^[\uFEFF\xEF\xBB\xBF]+/, "");
const parseJSONSafe = (text) => {
try { return JSON.parse(text); } catch {
const a = text.indexOf("{"), b = text.lastIndexOf("}");
if (a !== -1 && b > a) { try { return JSON.parse(text.slice(a, b+1)); } catch {} }
return null;
}
};
const delay = (ms) => new Promise(r => setTimeout(r, ms));
const isValidTimeZone = (tz) => { try { Intl.DateTimeFormat(undefined, { timeZone: tz }); return true; } catch { return false; } };
const makeTimeslotLabel = (sec, tz) => {
const d = new Date(sec * 1000);
const fmt = (opts) => d.toLocaleString("en-GB", { timeZone: tz, ...opts });
const dd = fmt({ day: "2-digit" });
const mm = fmt({ month: "2-digit" });
const hm = fmt({ hour12: false, hour: "2-digit", minute: "2-digit" });
return `${dd}/${mm} ${hm}`;
};
const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
// Parse "dd/mm/yyyy" + "HH:MM" + offset ("+07:00") -> epoch seconds
function toEpochFromDMY_HM(dateStr, timeStr, offset) {
const [dd, mm, yyyy] = dateStr.split("/").map(s => s.trim());
const [HH, MM] = timeStr.split(":").map(s => s.trim());
const iso = `${yyyy}-${mm.padStart(2,"0")}-${dd.padStart(2,"0")}T${HH.padStart(2,"0")}:${MM.padStart(2,"0")}:00${offset}`;
const t = Date.parse(iso);
if (Number.isNaN(t)) throw new Error(`Không parse được thời gian: ${dateStr} ${timeStr} ${offset}`);
return Math.floor(t / 1000);
}
function chooseRandomSlot() {
const day = pickRandom(CONFIG.TIMEPOOL);
const time = pickRandom(day.times);
const start = toEpochFromDMY_HM(day.date, time, CONFIG.TZ_OFFSET);
const end = start + CONFIG.SLOT_MINUTES * 60;
return { start, end, tz: CONFIG.selected_timezone, labelTime: time, labelDate: day.date };
}
// ========================= LẤY TOKEN TỪ PHIÊN HIỆN TẠI =========================
function getTokens() {
let uid = "", fb_dtsg = "", lsd = "";
try { uid = typeof require === "function" ? (require("CurrentUserInitialData")?.USER_ID || "") : ""; } catch {}
if (!uid) uid = getCookie("c_user") || "";
try {
if (typeof require === "function") {
fb_dtsg = require("DTSGInitialData")?.token || require("DTSGInitData")?.token || "";
}
} catch {}
if (!fb_dtsg) {
fb_dtsg = document.querySelector('input[name="fb_dtsg"]')?.value ||
(window.fb_dtsg && (window.fb_dtsg.value || window.fb_dtsg.token)) || "";
}
try { const LSD = typeof require === "function" ? require("LSD") : null; lsd = LSD?.LSDToken || LSD?.token || ""; } catch {}
if (!lsd) lsd = document.querySelector('input[name="lsd"]')?.value || "";
if (!uid || !fb_dtsg || !lsd) {
throw new Error("Thiếu uid/fb_dtsg/lsd. Hãy đăng nhập và đứng trong tab Ads Manager.");
}
const jazoest = "2" + [...fb_dtsg].reduce((s,c)=>s+c.charCodeAt(0),0);
return { uid, fb_dtsg, lsd, jazoest };
}
// ========================= CALL GRAPHQL (FALLBACK DOC_ID) =========================
async function callGraphQLWithFallback({ url, friendlyName, variables, extraParams = {}, docIds = [] }) {
const { uid, fb_dtsg, lsd, jazoest } = getTokens();
const base = {
av: uid, __user: uid, __a: "1",
fb_dtsg, jazoest, lsd,
fb_api_caller_class: "RelayModern",
fb_api_req_friendly_name: friendlyName,
variables: JSON.stringify(variables),
__comet_req: "58",
server_timestamps: "true",
__ccg: "UNKNOWN",
dpr: String(window.devicePixelRatio || 1),
__hs: "20321.BP:ads_manager_comet_pkg.2.0...0",
...extraParams
};
let lastErr;
for (const doc_id of docIds) {
const body = new URLSearchParams({ ...base, doc_id });
try {
const resp = await fetch(url, {
method: "POST",
credentials: "include",
headers: {
"content-type": "application/x-www-form-urlencoded",
"x-fb-lsd": lsd,
"x-fb-friendly-name": friendlyName
},
body
});
const raw = await resp.text();
const cleaned = stripGuards(raw);
const json = parseJSONSafe(cleaned);
if (!resp.ok || /^\s*</.test(cleaned) || !json) {
lastErr = new Error(`doc_id ${doc_id}: Shell/JSON không hợp lệ`);
continue;
}
if (json?.error === 1357001 || /đăng nh\u1eadp|login/i.test(json?.errorSummary || "")) {
const loginHref = json?.payload?.__dialog?.buttons?.find(b => b?.name === "login")?.href;
if (loginHref) window.open(loginHref, "_blank");
throw new Error("Login required (1357001).");
}
return json;
} catch (e) {
lastErr = e;
}
}
throw lastErr || new Error("Không gọi được GraphQL với các doc_id dự phòng.");
}
// ========================= API CỤ THỂ =========================
async function getMEEngagementDetails(adAccountId) {
const variables = {
inputData: {
source_tracking: {
surface: "ADS_MANAGER",
entry_point: "ADS_MANAGER_MODAL",
lead_source: "IOS_AdsMngr_CampaignsOverView_EntryPoint"
},
advertiser_user_id: String(getTokens().uid),
ad_account_id: String(adAccountId)
},
fields: ["EMAIL","FULL_NAME","PHONE"],
advertiserContext: { ad_account_id: String(adAccountId) }
};
const url = `https://adsmanager.facebook.com/api/graphql/?_callFlowletID=0&_triggerFlowletID=5197&qpl_active_e2e_trace_ids=`;
return callGraphQLWithFallback({
url,
friendlyName: "AdsSBGMEEngagementDetailsDialogQuery",
variables,
extraParams: { __aaid: String(adAccountId) },
docIds: DOCIDS.engagementDetailsQuery
});
}
async function scheduleMarketingExpertCall(adAccountId, slot) {
const tz = slot.tz;
if (!isValidTimeZone(tz)) throw new Error(`Timezone không hợp lệ: ${tz}`);
const label = CONFIG.autoLabel ? makeTimeslotLabel(slot.start, tz) : `${slot.labelDate} ${slot.labelTime}`;
const { uid } = getTokens();
const variables = {
input: {
client_mutation_id: String(Date.now()),
actor_id: String(uid),
channel_type: "SCHEDULE_CALL",
program: CONFIG.program,
sub_program: null,
contact: CONFIG.contact,
source_tracking: {
surface: "ADS_MANAGER",
entry_point: "ADS_MANAGER_MODAL",
lead_source: "IOS_AdsMngr_CampaignsOverView_EntryPoint"
},
timeframe: { start_time: slot.start, end_time: slot.end, preferred: true },
advertiser_id: String(uid),
advertiser_context: null,
ad_account_id: String(adAccountId),
notes: "",
selected_timezone: tz,
chat_input: {},
selected_timeslot_label: label
}
};
const url = `https://adsmanager.facebook.com/api/graphql/?_callFlowletID=0&_triggerFlowletID=7918&qpl_active_e2e_trace_ids=`;
return callGraphQLWithFallback({
url,
friendlyName: "BizKitMarketingExpertScheduleCallButtonMutation",
variables,
extraParams: { __aaid: String(adAccountId) },
docIds: DOCIDS.scheduleCallMutation
});
}
// ========================= DRIVER =========================
(async () => {
try {
ensureAdsManager();
// Nhập nhiều ID
const urlAct = (getParam("act") || "").trim();
const prefill = urlAct ? `act_${urlAct}` : "";
const raw = prompt(
"Nhập NHIỀU ad_account_id (phân tách bằng dấu phẩy / khoảng trắng / xuống dòng).\nVD: 685464807853109, 788860910378872",
prefill
);
if (!raw) throw new Error("Bạn chưa nhập ID.");
const ids = raw.split(/[\s,;\n\r]+/)
.map(s => s.trim()).filter(Boolean)
.map(s => s.replace(/^act_/, "")).map(s => s.replace(/\D+/g, ""))
.filter(s => /^\d{6,}$/.test(s));
if (ids.length === 0) throw new Error("Không có ad_account_id hợp lệ.");
// Kiểm tra token session
const tok = getTokens();
console.log("🔐 Session OK cho UID: " + tok.uid, "LINH PHẠM");
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
// cập nhật ?act= cho rõ context (không reload)
try { const u = new URL(location.href); u.searchParams.set("act", id); history.replaceState(null, "", u.toString()); } catch {}
// bốc ngẫu nhiên 1 slot trong TIMEPOOL
const picked = (() => {
const d = pickRandom(CONFIG.TIMEPOOL);
const t = pickRandom(d.times);
const start = toEpochFromDMY_HM(d.date, t, CONFIG.TZ_OFFSET);
return { start, end: start + CONFIG.SLOT_MINUTES * 60, tz: CONFIG.selected_timezone, labelDate: d.date, labelTime: t };
})();
try {
// probe eligibility nhẹ (nếu fail sẽ throw)
await getMEEngagementDetails(id);
// đặt lịch
const resp = await scheduleMarketingExpertCall(id, picked);
const status =
resp?.data?.sbg_engagement_connection_create?.connection?.connection_details?.status ||
resp?.data?.sbg_engagement_connection_update?.connection?.connection_details?.status || "";
if (status === "SCHEDULED") {
console.log("%c✅ DONE [act_%s]: SCHEDULED @ %s %s", "color:#16a34a;font-weight:700", id, picked.labelDate, picked.labelTime);
} else {
console.log("ℹ️ HOÀN TẤT: Không trả SCHEDULED ", "ĐÃ BẤM LÊN LỊCH GỌI", id);
console.log("ℹ️ KÍCH XONG: KÍCH 3 OK -LINH PHẠM ");
}
} catch (e) {
console.log("%c⛔ LỖI [act_%s]: %s", "color:#dc2626;font-weight:700", id, e?.message || e);
}
if (i < ids.length - 1) {
console.log("➡️ Nghỉ giữa các ID...", "id");
await delay(CONFIG.perIdDelayMs);
}
}
alert("BẠN ƠI ĐÃ CHẠY XONG CODE RỒI");
} catch (e) {
console.error("❌ LỖI:", e?.message || e);
alert("ĐÃ GẶP LỖI: " + (e?.message || e));
}
})();
})();
Public Last updated: 2025-09-08 04:41:47 AM