diff --git a/Auto-Image.js b/Auto-Image.js index 320a564..25f60de 100644 --- a/Auto-Image.js +++ b/Auto-Image.js @@ -2,6 +2,7 @@ const CONFIG = { COOLDOWN_DEFAULT: 31000, TRANSPARENCY_THRESHOLD: 100, + WHITE_THRESHOLD: 250, LOG_INTERVAL: 10, THEME: { primary: '#000000', @@ -15,6 +16,77 @@ } }; + const TEXTS = { + pt: { + title: "WPlace Auto-Image", + initBot: "Iniciar Auto-BOT", + uploadImage: "Upload da Imagem", + resizeImage: "Redimensionar Imagem", + selectPosition: "Selecionar Posição", + startPainting: "Iniciar Pintura", + stopPainting: "Parar Pintura", + checkingColors: "🔍 Verificando cores disponíveis...", + noColorsFound: "❌ Abra a paleta de cores no site e tente novamente!", + colorsFound: "✅ {count} cores disponíveis encontradas", + loadingImage: "🖼️ Carregando imagem...", + imageLoaded: "✅ Imagem carregada com {count} pixels válidos", + imageError: "❌ Erro ao carregar imagem", + selectPositionAlert: "Pinte o primeiro pixel na localização onde deseja que a arte comece!", + waitingPosition: "👆 Aguardando você pintar o pixel de referência...", + positionSet: "✅ Posição definida com sucesso!", + positionTimeout: "❌ Tempo esgotado para selecionar posição", + startPaintingMsg: "🎨 Iniciando pintura...", + paintingProgress: "🧱 Progresso: {painted}/{total} pixels...", + noCharges: "⌛ Sem cargas. Aguardando {time}...", + paintingStopped: "⏹️ Pintura interrompida pelo usuário", + paintingComplete: "✅ Pintura concluída! {count} pixels pintados.", + paintingError: "❌ Erro durante a pintura", + missingRequirements: "❌ Carregue uma imagem e selecione uma posição primeiro", + progress: "Progresso", + pixels: "Pixels", + charges: "Cargas", + estimatedTime: "Tempo estimado", + initMessage: "Clique em 'Iniciar Auto-BOT' para começar", + waitingInit: "Aguardando inicialização...", + resizeSuccess: "✅ Imagem redimensionada para {width}x{height}", + paintingPaused: "⏸️ Pintura pausada na posição X: {x}, Y: {y}" + }, + en: { + title: "WPlace Auto-Image", + initBot: "Start Auto-BOT", + uploadImage: "Upload Image", + resizeImage: "Resize Image", + selectPosition: "Select Position", + startPainting: "Start Painting", + stopPainting: "Stop Painting", + checkingColors: "🔍 Checking available colors...", + noColorsFound: "❌ Open the color palette on the site and try again!", + colorsFound: "✅ {count} available colors found", + loadingImage: "🖼️ Loading image...", + imageLoaded: "✅ Image loaded with {count} valid pixels", + imageError: "❌ Error loading image", + selectPositionAlert: "Paint the first pixel at the location where you want the art to start!", + waitingPosition: "👆 Waiting for you to paint the reference pixel...", + positionSet: "✅ Position set successfully!", + positionTimeout: "❌ Timeout for position selection", + startPaintingMsg: "🎨 Starting painting...", + paintingProgress: "🧱 Progress: {painted}/{total} pixels...", + noCharges: "⌛ No charges. Waiting {time}...", + paintingStopped: "⏹️ Painting stopped by user", + paintingComplete: "✅ Painting complete! {count} pixels painted.", + paintingError: "❌ Error during painting", + missingRequirements: "❌ Load an image and select a position first", + progress: "Progress", + pixels: "Pixels", + charges: "Charges", + estimatedTime: "Estimated time", + initMessage: "Click 'Start Auto-BOT' to begin", + waitingInit: "Waiting for initialization...", + resizeSuccess: "✅ Image resized to {width}x{height}", + paintingPaused: "⏸️ Painting paused at position X: {x}, Y: {y}" + } + }; + const state = { running: false, imageLoaded: false, @@ -32,9 +104,22 @@ region: null, minimized: false, lastPosition: { x: 0, y: 0 }, + estimatedTime: 0, language: 'en' }; + async function detectLanguage() { + try { + const response = await fetch('https://ipapi.co/json/'); + const data = await response.json(); + state.language = data.country === 'BR' ? 'pt' : 'en'; + return state.language; + } catch { + state.language = 'en'; + return 'en'; + } + } + const Utils = { sleep: ms => new Promise(r => setTimeout(r, ms)), @@ -58,24 +143,33 @@ extractAvailableColors: () => { const colorElements = document.querySelectorAll('[id^="color-"]'); - const availableColors = []; - - colorElements.forEach(el => { - if (!el.querySelector('svg')) { + return Array.from(colorElements) + .filter(el => !el.querySelector('svg')) + .filter(el => { + const id = parseInt(el.id.replace('color-', '')); + return id !== 0 && id !== 5; + }) + .map(el => { const id = parseInt(el.id.replace('color-', '')); const rgbStr = el.style.backgroundColor.match(/\d+/g); const rgb = rgbStr ? rgbStr.map(Number) : [0, 0, 0]; - availableColors.push({ id, rgb }); - } - }); - - return availableColors; + return { id, rgb }; + }); }, formatTime: ms => { const seconds = Math.floor((ms / 1000) % 60); const minutes = Math.floor((ms / (1000 * 60)) % 60); - return `${minutes}m ${seconds}s`; + const hours = Math.floor((ms / (1000 * 60 * 60)) % 24); + const days = Math.floor(ms / (1000 * 60 * 60 * 24)); + + let result = ''; + if (days > 0) result += `${days}d `; + if (hours > 0 || days > 0) result += `${hours}h `; + if (minutes > 0 || hours > 0 || days > 0) result += `${minutes}m `; + result += `${seconds}s`; + + return result; }, showAlert: (message, type = 'info') => { @@ -85,9 +179,7 @@ alert.style.left = '50%'; alert.style.transform = 'translateX(-50%)'; alert.style.padding = '15px 20px'; - alert.style.background = type === 'error' ? CONFIG.THEME.error : - type === 'success' ? CONFIG.THEME.success : - type === 'warning' ? CONFIG.THEME.warning : CONFIG.THEME.accent; + alert.style.background = CONFIG.THEME[type] || CONFIG.THEME.accent; alert.style.color = CONFIG.THEME.text; alert.style.borderRadius = '5px'; alert.style.zIndex = '10000'; @@ -95,10 +187,16 @@ alert.style.display = 'flex'; alert.style.alignItems = 'center'; alert.style.gap = '10px'; + + const icons = { + error: 'exclamation-circle', + success: 'check-circle', + warning: 'exclamation-triangle', + info: 'info-circle' + }; + alert.innerHTML = ` - + ${message} `; @@ -109,6 +207,26 @@ alert.style.transition = 'opacity 0.5s'; setTimeout(() => alert.remove(), 500); }, 3000); + }, + + calculateEstimatedTime: (remainingPixels, currentCharges, cooldown) => { + const pixelsPerCharge = currentCharges > 0 ? currentCharges : 0; + const fullCycles = Math.ceil((remainingPixels - pixelsPerCharge) / Math.max(currentCharges, 1)); + return (fullCycles * cooldown) + ((remainingPixels - 1) * 100); + }, + + isWhitePixel: (r, g, b) => { + return r >= CONFIG.WHITE_THRESHOLD && + g >= CONFIG.WHITE_THRESHOLD && + b >= CONFIG.WHITE_THRESHOLD; + }, + + t: (key, params = {}) => { + let text = TEXTS[state.language][key] || TEXTS.en[key] || key; + for (const [k, v] of Object.entries(params)) { + text = text.replace(`{${k}}`, v); + } + return text; } }; @@ -123,7 +241,7 @@ }); const data = await res.json(); return data?.painted === 1; - } catch (error) { + } catch { return false; } }, @@ -138,7 +256,7 @@ charges: data.charges?.count || 0, cooldown: data.charges?.cooldownMs || CONFIG.COOLDOWN_DEFAULT }; - } catch (error) { + } catch { return { charges: 0, cooldown: CONFIG.COOLDOWN_DEFAULT }; } } @@ -150,16 +268,19 @@ this.img = new Image(); this.canvas = document.createElement('canvas'); this.ctx = this.canvas.getContext('2d'); + this.previewCanvas = document.createElement('canvas'); + this.previewCtx = this.previewCanvas.getContext('2d'); } async load() { - return new Promise(resolve => { + return new Promise((resolve, reject) => { this.img.onload = () => { this.canvas.width = this.img.width; this.canvas.height = this.img.height; this.ctx.drawImage(this.img, 0, 0); resolve(); }; + this.img.onerror = reject; this.img.src = this.imageSrc; }); } @@ -171,92 +292,42 @@ getDimensions() { return { width: this.canvas.width, height: this.canvas.height }; } + + resize(newWidth, newHeight) { + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = newWidth; + tempCanvas.height = newHeight; + const tempCtx = tempCanvas.getContext('2d'); + + tempCtx.drawImage(this.img, 0, 0, newWidth, newHeight); + + this.canvas.width = newWidth; + this.canvas.height = newHeight; + this.ctx.drawImage(tempCanvas, 0, 0); + + return this.getPixelData(); + } + + generatePreview(newWidth, newHeight) { + this.previewCanvas.width = newWidth; + this.previewCanvas.height = newHeight; + this.previewCtx.imageSmoothingEnabled = false; + this.previewCtx.drawImage(this.img, 0, 0, newWidth, newHeight); + return this.previewCanvas.toDataURL(); + } } function findClosestColor(rgb, palette) { - let closestColor = palette[0]; - let minDistance = Utils.colorDistance(rgb, palette[0].rgb); - - for (let i = 1; i < palette.length; i++) { - const distance = Utils.colorDistance(rgb, palette[i].rgb); - if (distance < minDistance) { - minDistance = distance; - closestColor = palette[i]; - } - } - - return closestColor.id; + return palette.reduce((closest, current) => { + const currentDistance = Utils.colorDistance(rgb, current.rgb); + return currentDistance < closest.distance + ? { color: current, distance: currentDistance } + : closest; + }, { color: palette[0], distance: Utils.colorDistance(rgb, palette[0].rgb) }).color.id; } - async function detectUserLanguage() { - try { - const response = await fetch('https://ipapi.co/json/'); - const data = await response.json(); - if (data.country === 'BR') { - state.language = 'pt'; - } else if (data.country === 'US') { - state.language = 'en'; - } else { - state.language = 'en'; - } - } catch { - state.language = 'en'; - } - } - - function createUI() { - const translations = { - pt: { - title: "WPlace Auto-Image", - initBot: "Iniciar Auto-BOT", - uploadImage: "Upload da Imagem", - selectPos: "Selecionar Posição", - startPaint: "Iniciar Pintura", - stopPaint: "Parar Pintura", - noPosition: "Nenhuma posição selecionada", - waiting: "Aguardando inicialização...", - checkingColors: "Verificando cores disponíveis...", - noColors: "Nenhuma cor disponível encontrada", - colorsFound: "cores disponíveis encontradas", - loadingImage: "Carregando imagem...", - imageLoaded: "Imagem carregada com sucesso!", - selectPosition: "Aguardando você pintar o pixel de referência...", - positionSet: "Posição definida com sucesso!", - startPainting: "Iniciando pintura na região", - paintingStopped: "Pintura interrompida pelo usuário", - paintingComplete: "Pintura concluída!", - progress: "Progresso", - pixels: "Pixels", - charges: "Cargas", - remaining: "Restantes" - }, - en: { - title: "WPlace Auto-Image", - initBot: "Start Auto-BOT", - uploadImage: "Upload Image", - selectPos: "Select Position", - startPaint: "Start Painting", - stopPaint: "Stop Painting", - noPosition: "No position selected", - waiting: "Waiting for initialization...", - checkingColors: "Checking available colors...", - noColors: "No available colors found", - colorsFound: "available colors found", - loadingImage: "Loading image...", - imageLoaded: "Image loaded successfully!", - selectPosition: "Waiting for you to paint the reference pixel...", - positionSet: "Position set successfully!", - startPainting: "Starting painting in region", - paintingStopped: "Painting stopped by user", - paintingComplete: "Painting completed!", - progress: "Progress", - pixels: "Pixels", - charges: "Charges", - remaining: "Remaining" - } - }; - - const t = translations[state.language] || translations.en; + async function createUI() { + await detectLanguage(); const fontAwesome = document.createElement('link'); fontAwesome.rel = 'stylesheet'; @@ -444,20 +515,63 @@ .wplace-minimized .wplace-content { display: none; } + .resize-container { + display: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: ${CONFIG.THEME.primary}; + padding: 20px; + border-radius: 8px; + z-index: 10000; + box-shadow: 0 0 20px rgba(0,0,0,0.5); + max-width: 90%; + max-height: 90%; + overflow: auto; + } + .resize-preview { + max-width: 100%; + max-height: 300px; + margin: 10px 0; + border: 1px solid ${CONFIG.THEME.accent}; + } + .resize-controls { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 15px; + } + .resize-slider { + width: 100%; + } + .resize-buttons { + display: flex; + gap: 10px; + } + .resize-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.7); + z-index: 9999; + display: none; + } `; document.head.appendChild(style); const container = document.createElement('div'); container.id = 'wplace-image-bot-container'; container.innerHTML = ` -