diff --git a/Auto-Image.js b/Auto-Image.js index 66de554..83bd5b0 100644 --- a/Auto-Image.js +++ b/Auto-Image.js @@ -16,19 +16,19 @@ MIN: 3, // Random range minimum MAX: 20, // Random range maximum }, - PAINTING_SPEED_ENABLED: false, // Off by default + PAINTING_SPEED_ENABLED: true, // On by default AUTO_CAPTCHA_ENABLED: true, // Turnstile generator enabled by default TOKEN_SOURCE: 'generator', // "generator", "manual", or "hybrid" - default to generator COOLDOWN_CHARGE_THRESHOLD: 1, // Default wait threshold // Desktop Notifications (defaults) NOTIFICATIONS: { - ENABLED: true, + ENABLED: false, ON_CHARGES_REACHED: true, ONLY_WHEN_UNFOCUSED: true, REPEAT_MINUTES: 5, // repeat reminder while threshold condition holds }, OVERLAY: { - OPACITY_DEFAULT: 0.6, + OPACITY_DEFAULT: 0.2, BLUE_MARBLE_DEFAULT: false, ditheringEnabled: false, }, @@ -238,22 +238,22 @@ } catch {} }; - setVar('--wplace-primary', theme.primary); - setVar('--wplace-secondary', theme.secondary); - setVar('--wplace-accent', theme.accent); - setVar('--wplace-text', theme.text); - setVar('--wplace-highlight', theme.highlight); - setVar('--wplace-success', theme.success); - setVar('--wplace-error', theme.error); - setVar('--wplace-warning', theme.warning); - - // Typography + look - setVar('--wplace-font', theme.fontFamily || "'Segoe UI', Roboto, sans-serif"); - setVar('--wplace-radius', '' + (theme.borderRadius || '12px')); - setVar('--wplace-border-style', '' + (theme.borderStyle || 'solid')); - setVar('--wplace-border-width', '' + (theme.borderWidth || '1px')); - setVar('--wplace-backdrop', '' + (theme.backdropFilter || 'blur(10px)')); - setVar('--wplace-border-color', 'rgba(255,255,255,0.1)'); + // setVar('--wplace-primary', theme.primary); + // setVar('--wplace-secondary', theme.secondary); + // setVar('--wplace-accent', theme.accent); + // setVar('--wplace-text', theme.text); + // setVar('--wplace-highlight', theme.highlight); + // setVar('--wplace-success', theme.success); + // setVar('--wplace-error', theme.error); + // setVar('--wplace-warning', theme.warning); + // + // // Typography + look + // setVar('--wplace-font', theme.fontFamily || "'Segoe UI', Roboto, sans-serif"); + // setVar('--wplace-radius', '' + (theme.borderRadius || '12px')); + // setVar('--wplace-border-style', '' + (theme.borderStyle || 'solid')); + // setVar('--wplace-border-width', '' + (theme.borderWidth || '1px')); + // setVar('--wplace-backdrop', '' + (theme.backdropFilter || 'blur(10px)')); + // setVar('--wplace-border-color', 'rgba(255,255,255,0.1)'); } const saveThemePreference = () => { @@ -470,12 +470,11 @@ const FALLBACK_TEXT = { en: { title: 'WPlace Auto-Image', - settings: 'Settings', - close: 'Close', - language: 'Language', - loadingError: 'Loading translations failed, using fallback', + toggleOverlay: 'Toggle Overlay', scanColors: 'Scan Colors', uploadImage: 'Upload Image', + resizeImage: 'Resize Image', + selectPosition: 'Select Position', startPainting: 'Start Painting', stopPainting: 'Stop Painting', progress: 'Progress', @@ -522,6 +521,8 @@ availableColors: [], activeColorPalette: [], // User-selected colors for conversion paintWhitePixels: true, // Default to ON + fullChargeData: null, + fullChargeInterval: null, paintTransparentPixels: false, // Default to OFF currentCharges: 0, maxCharges: 1, // Default max charges @@ -541,6 +542,7 @@ randomBatchMin: CONFIG.RANDOM_BATCH_RANGE.MIN, // Random range minimum randomBatchMax: CONFIG.RANDOM_BATCH_RANGE.MAX, // Random range maximum cooldownChargeThreshold: CONFIG.COOLDOWN_CHARGE_THRESHOLD, + chargesThresholdInterval: null, tokenSource: CONFIG.TOKEN_SOURCE, // "generator" or "manual" initialSetupComplete: false, // Track if initial startup setup is complete (only happens once) overlayOpacity: CONFIG.OVERLAY.OPACITY_DEFAULT, @@ -555,6 +557,12 @@ resizeSettings: null, originalImage: null, resizeIgnoreMask: null, + // Coordinate generation settings + coordinateMode: 'rows', + coordinateDirection: 'bottom-left', + coordinateSnake: true, + blockWidth: 6, + blockHeight: 2, // Notification prefs and runtime bookkeeping notificationsEnabled: CONFIG.NOTIFICATIONS.ENABLED, notifyOnChargesReached: CONFIG.NOTIFICATIONS.ON_CHARGES_REACHED, @@ -1159,6 +1167,14 @@ const Utils = { sleep: (ms) => new Promise((r) => setTimeout(r, ms)), + dynamicSleep: async function (getRemainingMsFn, interval = 500) { + let remaining = getRemainingMsFn(); + while (remaining > 0) { + await this.sleep(Math.min(interval, remaining)); + remaining = getRemainingMsFn(); + } + }, + waitForSelector: async (selector, interval = 200, timeout = 5000) => { const start = Date.now(); while (Date.now() - start < timeout) { @@ -1169,6 +1185,16 @@ return null; }, + msToTimeText(ms) { + const totalSeconds = Math.ceil(ms / 1000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`; + if (minutes > 0) return `${minutes}m ${seconds}s`; + return `${seconds}s`; + }, // Turnstile Generator Integration - Optimized with widget reuse and proper cleanup turnstileLoaded: false, _turnstileContainer: null, @@ -2059,6 +2085,35 @@ } }, + migrateProgressToV22: (data) => { + try { + const migrated = { ...data }; + migrated.version = '2.2'; + + // Добавляем новые поля с значениями по умолчанию + if (!migrated.state.coordinateMode) { + migrated.state.coordinateMode = 'rows'; + } + if (!migrated.state.coordinateDirection) { + migrated.state.coordinateDirection = 'bottom-left'; + } + if (!migrated.state.coordinateSnake) { + migrated.state.coordinateSnake = true; + } + if (!migrated.state.blockWidth) { + migrated.state.blockWidth = 6; + } + if (!migrated.state.blockHeight) { + migrated.state.blockHeight = 2; + } + + return migrated; + } catch (e) { + console.warn('Migration to v2.2 failed, using original data:', e); + return data; + } + }, + saveProgress: () => { try { // Pack painted map if available @@ -2080,7 +2135,7 @@ const progressData = { timestamp: Date.now(), - version: '2.1', + version: '2.2', state: { totalPixels: state.totalPixels, paintedPixels: state.paintedPixels, @@ -2090,6 +2145,12 @@ imageLoaded: state.imageLoaded, colorsChecked: state.colorsChecked, availableColors: state.availableColors, + // Добавляем настройки генерации координат + coordinateMode: state.coordinateMode, + coordinateDirection: state.coordinateDirection, + coordinateSnake: state.coordinateSnake, + blockWidth: state.blockWidth, + blockHeight: state.blockHeight, }, imageData: state.imageData ? { @@ -2117,13 +2178,18 @@ let data = JSON.parse(saved); const ver = data.version; let migrated = data; - if (ver === '2.1') { + + // Миграция для новых версий + if (ver === '2.2') { // already latest + } else if (ver === '2.1') { + migrated = Utils.migrateProgressToV22(data); } else if (ver === '2' || ver === '2.0') { - migrated = Utils.migrateProgressToV21(data); + migrated = Utils.migrateProgressToV22(Utils.migrateProgressToV21(data)); } else { - migrated = Utils.migrateProgressToV21(data); + migrated = Utils.migrateProgressToV22(Utils.migrateProgressToV21(data)); } + if (migrated && migrated !== data) { try { localStorage.setItem('wplace-bot-progress', JSON.stringify(migrated)); @@ -2144,6 +2210,12 @@ state.paintedMap = null; state._lastSavePixelCount = 0; state._lastSaveTime = 0; + // Сбрасываем настройки генерации координат к значениям по умолчанию + state.coordinateMode = 'rows'; + state.coordinateDirection = 'bottom-left'; + state.coordinateSnake = true; + state.blockWidth = 6; + state.blockHeight = 2; console.log('📋 Progress and painted map cleared'); return true; } catch (error) { @@ -2156,6 +2228,23 @@ try { Object.assign(state, savedData.state); + // Восстанавливаем настройки генерации координат + if (savedData.state.coordinateMode) { + state.coordinateMode = savedData.state.coordinateMode; + } + if (savedData.state.coordinateDirection) { + state.coordinateDirection = savedData.state.coordinateDirection; + } + if (savedData.state.coordinateSnake !== undefined) { + state.coordinateSnake = savedData.state.coordinateSnake; + } + if (savedData.state.blockWidth) { + state.blockWidth = savedData.state.blockWidth; + } + if (savedData.state.blockHeight) { + state.blockHeight = savedData.state.blockHeight; + } + if (savedData.imageData) { state.imageData = { ...savedData.imageData, @@ -2241,7 +2330,10 @@ paintedMapPacked: paintedMapPacked, }; - const filename = `wplace-bot-progress-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`; + const filename = `wplace-bot-progress-${new Date() + .toISOString() + .slice(0, 19) + .replace(/:/g, '-')}.json`; Utils.createFileDownloader(JSON.stringify(progressData, null, 2), filename); return true; } catch (error) { @@ -2387,7 +2479,11 @@ try { await ensureToken(); if (!turnstileToken) return 'token_error'; - const payload = { coords: [pixelX, pixelY], colors: [color], t: turnstileToken }; + const payload = { + coords: [pixelX, pixelY], + colors: [color], + t: turnstileToken, + }; const res = await fetch(`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`, { method: 'POST', headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, @@ -2411,23 +2507,32 @@ }, 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(); + return { - charges: data.charges?.count || 0, - max: data.charges?.max || 1, - cooldown: data.charges?.next || CONFIG.COOLDOWN_DEFAULT, + charges: data.charges?.count ?? 0, + max: data.charges?.max ?? 1, + cooldown: data.charges?.cooldownMs ?? CONFIG.COOLDOWN_DEFAULT, }; } catch (e) { console.error('Failed to get charges:', e); - return { - charges: 0, - max: 1, - cooldown: CONFIG.COOLDOWN_DEFAULT, - }; + return defaultResult; } }, }; @@ -2539,7 +2644,9 @@ function findClosestColor(targetRgb, availableColors) { if (!availableColors || availableColors.length === 0) return 1; - const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${state.colorMatchingAlgorithm}|${state.enableChromaPenalty ? 'c' : 'nc'}|${state.chromaPenaltyWeight}`; + const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${ + state.colorMatchingAlgorithm + }|${state.enableChromaPenalty ? 'c' : 'nc'}|${state.chromaPenaltyWeight}`; if (colorCache.has(cacheKey)) return colorCache.get(cacheKey); const whiteThreshold = state.customWhiteThreshold || CONFIG.WHITE_THRESHOLD; @@ -2706,7 +2813,9 @@ if (isAvailable) availableCount++; - const colorItem = Utils.createElement('div', { className: 'wplace-color-item' }); + const colorItem = Utils.createElement('div', { + className: 'wplace-color-item', + }); const swatch = Utils.createElement('button', { className: `wplace-color-swatch ${!isAvailable ? 'unavailable' : ''}`, title: `${name} (ID: ${id})${!isAvailable ? ' (Unavailable)' : ''}`, @@ -2799,7 +2908,15 @@ const token = await Utils.generatePaintToken(sitekey); console.log( - `🔍 Token received - Type: ${typeof token}, Value: ${token ? (typeof token === 'string' ? (token.length > 50 ? token.substring(0, 50) + '...' : token) : JSON.stringify(token)) : 'null/undefined'}, Length: ${token?.length || 0}` + `🔍 Token received - Type: ${typeof token}, Value: ${ + token + ? typeof token === 'string' + ? token.length > 50 + ? token.substring(0, 50) + '...' + : token + : JSON.stringify(token) + : 'null/undefined' + }, Length: ${token?.length || 0}` ); if (typeof token === 'string' && token.length > 20) { @@ -2808,7 +2925,9 @@ return token; } else { throw new Error( - `Invalid or empty token received - Type: ${typeof token}, Value: ${JSON.stringify(token)}, Length: ${token?.length || 0}` + `Invalid or empty token received - Type: ${typeof token}, Value: ${JSON.stringify( + token + )}, Length: ${token?.length || 0}` ); } } catch (error) { @@ -2868,14 +2987,26 @@ const centerY = Math.round(rect.top + rect.height / 2); canvas.dispatchEvent( - new MouseEvent('mousemove', { clientX: centerX, clientY: centerY, bubbles: true }) + new MouseEvent('mousemove', { + clientX: centerX, + clientY: centerY, + bubbles: true, + }) ); canvas.dispatchEvent( - new KeyboardEvent('keydown', { key: ' ', code: 'Space', bubbles: true }) + new KeyboardEvent('keydown', { + key: ' ', + code: 'Space', + bubbles: true, + }) ); await Utils.sleep(50); canvas.dispatchEvent( - new KeyboardEvent('keyup', { key: ' ', code: 'Space', bubbles: true }) + new KeyboardEvent('keyup', { + key: ' ', + code: 'Space', + bubbles: true, + }) ); await Utils.sleep(500); @@ -2950,7 +3081,7 @@ // Link external CSS files const cssLink = document.createElement('link'); cssLink.rel = 'stylesheet'; - cssLink.href = 'https://staninna.github.io/WPlace-AutoBOT/decoupled-css/auto-image-styles.css'; // TODO: Before merge change to https://raw.githubusercontent.com/Wplace-AutoBot/WPlace-AutoBOT/refs/heads/main/auto-image-styles.css + cssLink.href = 'https://skalsech.github.io/WPlace-AutoBOT/my_main/auto-image-styles.css'; cssLink.setAttribute('data-wplace-theme', 'true'); document.head.appendChild(cssLink); @@ -3098,7 +3229,9 @@