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