// ==UserScript==
// @name MS Rewards Auto Daily Set • 02:00 WITA
// @namespace io.eternal.msr.autodaily.0200
// @version 2.0.0
// @description Jalan otomatis tiap hari setelah 02:00 (Asia/Makassar). Auto-buka & tutup Daily Set tasks (tanpa klik).
// @author you
// @match https://bing.com/*
// @icon https://www.bing.com/sa/simg/favicon-2x.ico
// @run-at document-idle
// @grant GM_openInTab
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant GM_notification
// ==/UserScript==
(function () {
'use strict';
/*** KONFIGURASI ***/
const TZ_OFFSET_MINUTES = 8 * 60; // Asia/Makassar (UTC+8)
const TARGET_HOUR = 2; // 02:00
const TARGET_MIN = 0; // 02:00
const SAFETY_DELAY_MS = 60 * 1000; // buffer 1 menit setelah jam target
const DELAY_BETWEEN_OPENS_MS = 3000;
const TAB_LIFETIME_MS = 22000; // tahan tab 8 detik, tweak 10-15s jika perlu
const MAX_CARDS = 4; // Daily Set biasanya 3
const LS_KEY_LAST_RUN = 'msr-auto-daily-last-run-v2';
// ---------- Util waktu (force ke UTC+8 lokal) ----------
function nowLocal() {
// Kita pakai waktu lokal mesin; kalau OS kamu sudah UTC+8, ini tepat.
// Untuk berjaga-jaga, kita geser ke UTC+8 manual.
const now = new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 60000;
return new Date(utc + TZ_OFFSET_MINUTES * 60000);
}
function ymd(d) {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
}
function targetToday() {
const d = nowLocal();
d.setHours(TARGET_HOUR, TARGET_MIN, 0, 0);
return d;
}
function msUntilNextRun() {
const n = nowLocal();
const tgt = targetToday();
if (n.getTime() <= tgt.getTime() + SAFETY_DELAY_MS) {
// Belum lewat 02:01 => tunggu ke 02:01 hari ini
return tgt.getTime() + SAFETY_DELAY_MS - n.getTime();
}
// Sudah lewat => jadwalkan besok 02:01
const t2 = new Date(tgt.getTime() + 24 * 3600 * 1000 + SAFETY_DELAY_MS);
return t2.getTime() - n.getTime();
}
function alreadyRanToday() {
const last = GM_getValue(LS_KEY_LAST_RUN, '');
return last === ymd(nowLocal());
}
function markRanToday() {
GM_setValue(LS_KEY_LAST_RUN, ymd(nowLocal()));
}
// ---------- DOM / aksi ----------
function findDailySetLinks() {
// Cari anchor klik yang kamu kirimkan: a.ds-card-sec di dalam mee-rewards-daily-set-item-content
const anchors = Array.from(
document.querySelectorAll('mee-rewards-daily-set-item-content a.ds-card-sec[href]')
);
const seen = new Set();
const unique = [];
for (const a of anchors) {
const href = a.getAttribute('href');
if (!href) continue;
if (seen.has(href)) continue;
seen.add(href);
unique.push(a);
if (unique.length >= MAX_CARDS) break;
}
return unique;
}
function toast(msg) {
try {
GM_notification({ text: msg, title: 'MS Rewards', timeout: 3000 });
} catch {
const el = document.createElement('div');
el.textContent = msg;
Object.assign(el.style, {
position: 'fixed', bottom: '60px', right: '16px',
padding: '10px 12px', borderRadius: '10px',
background: 'rgba(0,0,0,0.85)', color: '#fff',
fontSize: '12px', zIndex: 999999
});
document.body.appendChild(el);
setTimeout(() => el.remove(), 2800);
}
}
async function openAndClose(href) {
const tab = GM_openInTab(href, { active: false, insert: true, setParent: true });
await new Promise(r => setTimeout(r, TAB_LIFETIME_MS));
if (tab && typeof tab.close === 'function') { try { tab.close(); } catch {} }
}
async function runDailySet() {
if (alreadyRanToday()) return;
// Pastikan kartu sudah render
let links = findDailySetLinks();
if (links.length < 2) {
// tunggu sebentar biar yang ke-3 ikut tampil
await new Promise(r => setTimeout(r, 1200));
links = findDailySetLinks();
}
if (links.length === 0) {
// Kadang dashboard butuh scroll / network; coba lagi sebentar
await new Promise(r => setTimeout(r, 2000));
links = findDailySetLinks();
}
if (links.length === 0) {
toast('Daily Set tidak ditemukan (DOM belum siap). Akan dicoba lagi otomatis.');
// Biarkan observer memicu nanti
return;
}
toast(`Membuka ${links.length} tugas Daily Set…`);
for (let i = 0; i < links.length; i++) {
const href = links[i].href;
if (!href || href.startsWith('javascript:')) continue;
openAndClose(href); // non-blocking
await new Promise(r => setTimeout(r, DELAY_BETWEEN_OPENS_MS));
}
markRanToday();
toast('Daily Set dibuka di background; tab akan tertutup otomatis.');
}
// ---------- Scheduler dalam halaman ----------
// 1) Kalau sekarang sudah lewat 02:01 & belum jalan → eksekusi segera (setelah kartu muncul)
// 2) Selain itu, set timer menuju 02:01 run berikutnya
function armTimeScheduler() {
const waitMs = msUntilNextRun();
setTimeout(() => {
// Pada saat timer pecah: kalau halaman terbuka, kita jalankan
// (Observer di bawah memastikan nunggu kartu render)
forceRunWhenReady = true;
maybeKick();
// Jadwalkan hari berikutnya juga
armTimeScheduler();
}, waitMs);
}
// Amati DOM agar jalan otomatis saat kartu muncul / reload
let autoTriggered = false;
let forceRunWhenReady = false;
const obs = new MutationObserver(() => {
if (alreadyRanToday()) return;
const ready = document.querySelector('mee-rewards-daily-set-item-content a.ds-card-sec[href]');
if (!ready) return;
// Jika waktu sudah lewat target (atau dipaksa oleh timer), jalankan sekali
const n = nowLocal();
const tgt = targetToday().getTime() + SAFETY_DELAY_MS;
if ((n.getTime() >= tgt || forceRunWhenReady) && !autoTriggered) {
autoTriggered = true;
setTimeout(runDailySet, 400); // beri jeda kecil
}
});
function maybeKick() {
// Coba trigger kalau DOM sudah siap
const hasCards = document.querySelector('mee-rewards-daily-set-item-content a.ds-card-sec[href]');
if (hasCards) {
const n = nowLocal().getTime();
const tgt = targetToday().getTime() + SAFETY_DELAY_MS;
if (!alreadyRanToday() && (n >= tgt || forceRunWhenReady)) {
autoTriggered = true;
runDailySet();
}
}
}
// Start
obs.observe(document.documentElement, { childList: true, subtree: true });
armTimeScheduler(); // pasang timer menuju 02:01 berikutnya
maybeKick(); // coba langsung kalau kondisi sudah memenuhi
// Menu manual (opsional)
try {
GM_registerMenuCommand('Jalankan sekarang', () => {
forceRunWhenReady = true;
autoTriggered = false;
maybeKick();
toast('Menjalankan Daily Set sekarang…');
});
} catch {}
})();