167 lines
5.1 KiB
JavaScript
167 lines
5.1 KiB
JavaScript
|
|
(() => {
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
window.alert = function(msg) {
|
|
console.warn("차단된 alert:", msg);
|
|
};
|
|
|
|
if (window.__zzimAutomationRunning) {
|
|
console.warn("이미 실행 중인 자동화 스크립트가 있습니다.");
|
|
return;
|
|
}
|
|
window.__zzimAutomationRunning = true;
|
|
|
|
let isRunning = true;
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
isRunning = false;
|
|
console.log("찜하기 자동화 중단됨 (ESC)");
|
|
}
|
|
});
|
|
|
|
function getStoreName() {
|
|
const el = document.querySelector('.KasFrJs3SA');
|
|
return el ? el.innerText.trim() : "스토어";
|
|
}
|
|
|
|
function waitForZzimButtons(callback) {
|
|
const check = () => {
|
|
const buttons = document.querySelectorAll('button.zzim_button[type="button"]');
|
|
if (buttons.length > 0) {
|
|
callback(buttons);
|
|
} else {
|
|
requestAnimationFrame(check);
|
|
}
|
|
};
|
|
requestAnimationFrame(check);
|
|
}
|
|
|
|
async function waitForButtonToChange(btn, timeout = 1000) {
|
|
const start = Date.now();
|
|
while (Date.now() - start < timeout) {
|
|
const pressed = btn.getAttribute("aria-pressed");
|
|
const label = btn.innerText?.trim();
|
|
if (pressed === "true" || (label && !label.includes("찜하기"))) {
|
|
return true;
|
|
}
|
|
await sleep(50);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function createProgressUI() {
|
|
const ui = document.createElement("div");
|
|
ui.id = "zzim-progress-ui";
|
|
ui.style.position = "fixed";
|
|
ui.style.bottom = "20px";
|
|
ui.style.right = "20px";
|
|
ui.style.background = "#222";
|
|
ui.style.color = "#fff";
|
|
ui.style.padding = "10px 15px";
|
|
ui.style.borderRadius = "8px";
|
|
ui.style.zIndex = "99999";
|
|
ui.style.fontSize = "14px";
|
|
ui.style.whiteSpace = "pre-line";
|
|
ui.style.boxShadow = "0 0 5px rgba(0,0,0,0.5)";
|
|
ui.innerText = "찜하기 자동화 시작...";
|
|
document.body.appendChild(ui);
|
|
return ui;
|
|
}
|
|
|
|
async function runAutomation(startPage, finalPage) {
|
|
const url = new URL(window.location.href);
|
|
const storeName = getStoreName();
|
|
let currentPage = parseInt(url.searchParams.get("page") || startPage);
|
|
let totalClicked = 0;
|
|
const progressUI = createProgressUI();
|
|
const today = new Date().toISOString().split("T")[0];
|
|
|
|
if (currentPage > finalPage) {
|
|
progressUI.innerText = `${storeName}
|
|
페이지 ${finalPage} / ${finalPage}
|
|
찜 완료: 0개
|
|
완료`;
|
|
alert(`${storeName} 작업 이미 완료됨`);
|
|
return;
|
|
}
|
|
|
|
while (isRunning && currentPage <= finalPage) {
|
|
progressUI.innerText = `${storeName}
|
|
페이지 ${currentPage} / ${finalPage}
|
|
찜 완료: ${totalClicked}개
|
|
진행중`;
|
|
|
|
await new Promise(resolve => waitForZzimButtons(resolve));
|
|
const buttons = Array.from(document.querySelectorAll('button.zzim_button[type="button"]'));
|
|
|
|
for (let i = 0; i < buttons.length; i++) {
|
|
const btn = buttons[i];
|
|
if (!isRunning) break;
|
|
|
|
const pressed = btn.getAttribute("aria-pressed");
|
|
const label = btn.innerText?.trim();
|
|
|
|
if (pressed === "false" && label.includes("찜하기")) {
|
|
try {
|
|
btn.click();
|
|
const changed = await waitForButtonToChange(btn);
|
|
if (changed) {
|
|
totalClicked++;
|
|
}
|
|
progressUI.innerText = `${storeName}
|
|
페이지 ${currentPage} / ${finalPage}
|
|
찜 완료: ${totalClicked}개
|
|
진행중`;
|
|
await sleep(200);
|
|
} catch (e) {
|
|
console.warn("❌ 클릭 실패:", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isRunning || currentPage >= finalPage) break;
|
|
|
|
const nextPage = currentPage + 1;
|
|
url.searchParams.set("page", nextPage);
|
|
await sleep(1000);
|
|
window.location.href = url.toString();
|
|
setTimeout(() => document.dispatchEvent(new KeyboardEvent("keydown", {key: "Enter"})), 1500);
|
|
return;
|
|
}
|
|
|
|
// 🔒 루프 종료 후 항상 최종 처리
|
|
const now = new Date();
|
|
const timestamp = now.getFullYear() + "-" +
|
|
String(now.getMonth()+1).padStart(2, '0') + "-" +
|
|
String(now.getDate()).padStart(2, '0') + " " +
|
|
String(now.getHours()).padStart(2, '0') + ":" +
|
|
String(now.getMinutes()).padStart(2, '0');
|
|
progressUI.innerText = `${storeName}
|
|
페이지 ${currentPage} / ${finalPage}
|
|
찜 완료: ${totalClicked}개
|
|
완료`;
|
|
alert(`${storeName}\n${timestamp}\n총 ${totalClicked}개 찜 완료`);
|
|
}
|
|
|
|
chrome.storage.local.get(["isZzimRun", "pageCount", "_zzimStartPage", "_zzimFinalPage"], (res) => {
|
|
if (!res.isZzimRun) return;
|
|
// 제거는 완료 시점에만 수행됨
|
|
const url = new URL(window.location.href);
|
|
const current = parseInt(url.searchParams.get("page") || "1");
|
|
|
|
if (!res._zzimStartPage || !res._zzimFinalPage) {
|
|
const startPage = current;
|
|
const finalPage = startPage + (res.pageCount || 1) - 1;
|
|
chrome.storage.local.set({ _zzimStartPage: startPage, _zzimFinalPage: finalPage }, () => {
|
|
runAutomation(startPage, finalPage);
|
|
});
|
|
} else {
|
|
runAutomation(res._zzimStartPage, res._zzimFinalPage);
|
|
}
|
|
});
|
|
})();
|