feat: full migration to extension

This commit is contained in:
MiraclePatrickLumowa authored and GitHub committed 2025-09-15 02:44:12 +08:00
1 parent 266e2e8f97
commit 12e871ec26
19 files changed
+11363 -245

No files matched your search

+220 -52
View File
@@ -38,7 +38,7 @@ localStorage.removeItem("lp");
REPEAT_MINUTES: 5, // repeat reminder while threshold condition holds
},
OVERLAY: {
OPACITY_DEFAULT: 0.2,
OPACITY_DEFAULT: 0.6,
BLUE_MARBLE_DEFAULT: false,
ditheringEnabled: false,
}, // --- START: Color data from colour-converter.js ---
@@ -229,6 +229,7 @@ localStorage.removeItem("lp");
COORDINATE_SNAKE: true,
COORDINATE_BLOCK_WIDTH: 6,
COORDINATE_BLOCK_HEIGHT: 2,
autoSwap: true,
};
const getCurrentTheme = () => CONFIG.THEMES[CONFIG.currentTheme];
@@ -251,7 +252,7 @@ localStorage.removeItem("lp");
const theme = getCurrentTheme();
console.group('%c🎨 Applying Theme in Auto-Image Script', 'color: #8b5cf6; font-weight: bold;');
console.log(`%c🎯 Target theme: ${CONFIG.currentTheme}`, 'color: #8b5cf6;');
// Toggle theme class on documentElement so CSS vars cascade to our UI
document.documentElement.classList.remove(
'wplace-theme-classic',
@@ -262,7 +263,7 @@ localStorage.removeItem("lp");
let themeClass = 'wplace-theme-classic'; // default
let themeFileName = 'classic'; // corresponding file name
if (CONFIG.currentTheme === 'Neon Retro') {
themeClass = 'wplace-theme-neon';
themeFileName = 'neon';
@@ -320,7 +321,7 @@ localStorage.removeItem("lp");
setVar('--wplace-border-width', '' + (theme.borderWidth || '1px'));
setVar('--wplace-backdrop', '' + (theme.backdropFilter || 'blur(10px)'));
setVar('--wplace-border-color', 'rgba(255,255,255,0.1)');
console.log(`%c🎨 Theme application complete`, 'color: #8b5cf6; font-weight: bold;');
console.groupEnd();
}
@@ -377,11 +378,11 @@ localStorage.removeItem("lp");
// First try: Check if extension has loaded local resources
if (window.AUTOBOT_LANGUAGES && Object.keys(window.AUTOBOT_LANGUAGES).length > 0) {
console.log(`%c🔍 Checking extension local resources...`, 'color: #06b6d4;');
const langFile = language + '.json';
if (window.AUTOBOT_LANGUAGES[langFile]) {
const translations = window.AUTOBOT_LANGUAGES[langFile];
// Validate that translations is an object with keys
if (
typeof translations === 'object' &&
@@ -721,6 +722,7 @@ localStorage.removeItem("lp");
_lastSaveTime: 0,
_saveInProgress: false,
paintedMap: null,
accountIndex: -1,
};
let _updateResizePreview = () => { };
@@ -2976,34 +2978,49 @@ localStorage.removeItem("lp");
},
async getCharges() {
const defaultResult = {
charges: 0,
max: 1,
cooldown: CONFIG.COOLDOWN_DEFAULT,
};
try {
const res = await fetch('https://backend.wplace.live/me', {
credentials: 'include',
});
if (!res.ok) {
console.error(`Failed to get charges: HTTP ${res.status}`);
return defaultResult;
}
const data = await res.json();
const res = await fetch("https://backend.wplace.live/me", {
credentials: "include",
})
const data = await res.json()
return {
charges: data.charges?.count ?? 0,
max: data.charges?.max ?? 1,
cooldown: data.charges?.cooldownMs ?? CONFIG.COOLDOWN_DEFAULT,
};
id: data.id,
charges: data.charges?.count || 0,
max: data.charges?.max || 1,
cooldown: data.charges?.next || CONFIG.COOLDOWN_DEFAULT,
droplets: data.droplets || 0,
}
} catch (e) {
console.error('Failed to get charges:', e);
return defaultResult;
console.error("Failed to get charges:", e)
return {
id: null,
charges: 0,
max: 1,
cooldown: CONFIG.COOLDOWN_DEFAULT,
droplets: 0,
}
}
},
async fetchCheck() {
try {
const res = await fetch("https://backend.wplace.live/me", {
credentials: "include",
})
const data = await res.json()
return {
ID: data.id,
Charges: data.charges.count,
Max: data.charges.max,
Droplets: data.droplets
}
} catch (e) {
console.error("Failed to get ID:", e)
return {
}
}
}
};
// Desktop Notification Manager
@@ -3515,13 +3532,13 @@ localStorage.removeItem("lp");
// Load auto-image-styles.css - prioritize extension local resources
console.group('%c🎨 Loading Auto-Image Styles', 'color: #8b5cf6; font-weight: bold;');
let stylesLoaded = false;
// First try: Check if extension has loaded local CSS resources
if (window.AUTOBOT_THEMES && window.AUTOBOT_THEMES['auto-image-styles.css']) {
console.log('%c🔍 Found auto-image-styles.css in extension local resources!', 'color: #10b981; font-weight: bold;');
// Check if it's already injected by the extension
const existingStyle = document.getElementById('autobot-auto-image-styles');
if (existingStyle) {
@@ -3536,7 +3553,7 @@ localStorage.removeItem("lp");
styleElement.setAttribute('data-wplace-theme', 'true');
styleElement.textContent = window.AUTOBOT_THEMES['auto-image-styles.css'];
document.head.appendChild(styleElement);
console.log('%c✅ Injected auto-image-styles.css from extension local resources', 'color: #10b981; font-weight: bold;');
console.log(' 📍 Source: Extension local file');
console.log(' 📏 Size: ' + window.AUTOBOT_THEMES['auto-image-styles.css'].length + ' characters');
@@ -3550,7 +3567,7 @@ localStorage.removeItem("lp");
console.log(' 📋 Available themes:', Object.keys(window.AUTOBOT_THEMES));
}
}
// Fallback: Load from CDN if local resources not available
if (!stylesLoaded) {
console.log('%c🌐 Falling back to CDN loading...', 'color: #8b5cf6;');
@@ -3563,13 +3580,13 @@ localStorage.removeItem("lp");
console.log(' 🌐 URL: https://wplace-autobot.github.io/WPlace-AutoBOT/main/auto-image-styles.css');
console.log(' ⚠️ Performance: Network request required');
}
console.groupEnd();
// Ensure default theme is loaded from extension resources
if (window.applyTheme && typeof window.applyTheme === 'function') {
console.group('%c🎨 Loading Default Theme from Extension', 'color: #8b5cf6; font-weight: bold;');
// Determine the current theme file name
let defaultTheme = 'classic'; // fallback
if (CONFIG.currentTheme === 'Neon Retro') {
@@ -3579,10 +3596,10 @@ localStorage.removeItem("lp");
} else if (CONFIG.currentTheme === 'Acrylic') {
defaultTheme = 'acrylic';
}
console.log(`%c🎯 Loading theme: ${defaultTheme} (${CONFIG.currentTheme})`, 'color: #8b5cf6;');
const success = window.applyTheme(defaultTheme);
if (success) {
console.log(`%c✅ Default theme loaded from extension local resources`, 'color: #10b981; font-weight: bold;');
console.log(` 📍 Source: Extension local file (themes/${defaultTheme}.css)`);
@@ -3592,7 +3609,7 @@ localStorage.removeItem("lp");
console.warn(`%c⚠️ Failed to load theme ${defaultTheme} from extension`, 'color: #f59e0b;');
console.log(` 📝 Note: Theme CSS classes will still work`);
}
console.groupEnd();
} else {
console.warn(`%c⚠️ Extension applyTheme() function not available`, 'color: #f59e0b; font-weight: bold;');
@@ -6834,6 +6851,7 @@ localStorage.removeItem("lp");
updateUI('startPaintingMsg', 'success');
try {
await getAccounts();
await processImage();
} catch (e) {
console.error('Unexpected error:', e);
@@ -7422,20 +7440,79 @@ localStorage.removeItem("lp");
pixelBatch.pixels = [];
}
if (!CONFIG.autoSwap) {
if (state.displayCharges < state.cooldownChargeThreshold && !state.stopFlag) {
await Utils.dynamicSleep(() => {
if (state.displayCharges >= state.cooldownChargeThreshold) {
NotificationManager.maybeNotifyChargesReached(true);
return 0;
}
if (state.stopFlag) return 0;
return getMsToTargetCharges(
state.preciseCurrentCharges,
state.cooldownChargeThreshold,
state.cooldown
);
});
}
}
else {
if (state.displayCharges < state.cooldownChargeThreshold && !state.stopFlag) {
console.log("⚠️ Charges too low, swapping to next account...");
if (state.displayCharges < state.cooldownChargeThreshold && !state.stopFlag) {
await Utils.dynamicSleep(() => {
if (state.displayCharges >= state.cooldownChargeThreshold) {
NotificationManager.maybeNotifyChargesReached(true);
return 0;
const accounts = JSON.parse(localStorage.getItem("accounts")) || [];
if (accounts.length === 0) {
console.warn("❌ No accounts available, stopping painting.");
state.stopFlag = true;
return;
}
if (state.stopFlag) return 0;
return getMsToTargetCharges(
state.preciseCurrentCharges,
state.cooldownChargeThreshold,
state.cooldown
);
});
state.accountIndex = (state.accountIndex + 1) % accounts.length;
console.log("🔄 Switching to account index:", state.accountIndex);
const nextToken = accounts[state.accountIndex];
console.log("🔑 Next token:", nextToken);
if (!nextToken) {
console.warn("⚠️ Invalid token, skipping...");
return;
}
swapAccountTrigger(nextToken);
let maxRetries = 20;
let retryCount = 0;
let swapSuccess = false;
while (!swapSuccess && retryCount < maxRetries) {
console.log(`⏳ Waiting for account swap... (Attempt ${retryCount + 1}/${maxRetries})`);
// Wait for a short period before checking.
await new Promise(resolve => setTimeout(resolve, 1000));
try {
await fetchAccount();
console.log("✅ Account swap confirmed.");
swapSuccess = true;
} catch (error) {
console.warn("❌ Account swap not yet successful. Retrying...", error);
retryCount++;
}
}
if (swapSuccess) {
const { charges, cooldown } = await WPlaceService.getCharges();
state.displayCharges = Math.floor(charges);
state.cooldown = cooldown;
Utils.performSmartSave();
updateStats();
} else {
console.error("❌ Failed to swap account after multiple retries. Stopping loop.");
state.stopFlag = true;
}
}
}
if (state.stopFlag) {
@@ -7998,7 +8075,7 @@ localStorage.removeItem("lp");
async function createWasmToken(regionX, regionY, payload) {
try {
// Load the Pawtect module and WASM
const mod = await import(new URL('/_app/immutable/chunks/'+pawtect_chunk, location.origin).href);
const mod = await import(new URL('/_app/immutable/chunks/' + pawtect_chunk, location.origin).href);
let wasm;
try {
wasm = await mod._();
@@ -8130,6 +8207,97 @@ localStorage.removeItem("lp");
console.error(`❌ Could not find Pawtect chunk: `, error);
}
async function purchase(type) {
// loadThemePreference()
let id;
let chargeMultiplier;
if (type === "max_charges") {
id = 70;
chargeMultiplier = 5;
} else if (type === "paint_charges") {
id = 80;
chargeMultiplier = 30;
} else {
console.error("Error: Invalid purchase type provided.");
return;
}
const { droplets } = await WPlaceService.getCharges();
console.log("There are currently : ", droplets, "droplets.");
try {
const amounts = Math.floor(droplets / 500);
if (amounts < 1) {
console.log("Not enough droplets to purchase.");
return;
}
const payload = {
"product": {
"id": id,
"amount": amounts
}
};
const res = fetch("https://backend.wplace.live/purchase", {
method: "POST",
headers: {
"Content-Type": "text/plain;charset=UTF-8"
},
body: JSON.stringify(payload),
credentials: "include"
});
console.log("Fetch POST return :", res);
const { droplets: newDroplets } = await WPlaceService.getCharges();
if (droplets != newDroplets) {
console.log("Successfully bought", amounts * chargeMultiplier, type.replace('_', ' '), ".");
}
else {
console.log("Failed to buy charges");
}
} catch (e) {
console.error("An error occurred during the purchase:", e);
}
}
function swapAccountTrigger(token) {
localStorage.removeItem("lp");
if (!token) return;
console.log("Sending token to extension...");
window.postMessage({
source: 'my-userscript',
type: 'setCookie',
value: token
}, '*');
}
async function getAccounts() {
return new Promise((resolve, reject) => {
console.log("Requesting accounts from extension...");
// Ask extension for accounts
window.postMessage({
source: "my-userscript",
type: "getAccounts"
}, "*");
function handler(event) {
if (event.source !== window) return;
if (event.data.source !== "extension") return;
if (event.data.type === "accountsData") {
window.removeEventListener("message", handler);
// Save to localStorage
try {
localStorage.setItem("accounts", JSON.stringify(event.data.accounts));
console.log("✅ Accounts saved to localStorage:", event.data.accounts);
} catch (e) {
console.error("❌ Failed to save accounts:", e);
}
resolve(event.data.accounts);
}
}
window.addEventListener("message", handler);
});
}
async function fetchAccount() {
const { ID, Charges, Max, Droplets } = await WPlaceService.fetchCheck();
console.log("User's ID :", ID);
console.log("User's Charges :", Charges, "/", Max);
console.log("User's Droplets :", Droplets);
}
createUI().then(() => {
// Generate token automatically after UI is ready
setTimeout(initializeTokenGenerator, 1000);