NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Auto Skip Streaming Services
// @namespace Violentmonkey Scripts
// @match https://www.disneyplus.com/*
// @match https://www.starplus.com/*
// @match https://www.max.com/*
// @match https://www.netflix.com/*
// @match https://play.mercadolivre.com.br/*
// @grant none
// @version 1.5
// @author RedBlack
// @description 28/04/2024, 23:42:18 Clicar Automaticamente em "Pular Abertura" e em "Próximo Episódio" em diversas plataformas de streaming
// @license 0BSD
// ==/UserScript==
/* ============================================================
* Auto Skip para Plataformas de Streaming - Versão 3.1 Ultra-Fast
* Ultra-Fast Edition: Cliques em coordenadas com velocidade máxima,
* modos infinitos e controle total de automação
* ============================================================
*/
class AutoSkip {
constructor() {
// =========================
// Configuração dos serviços expandida
// =========================
this.config = {
'DisneyPlus': {
skipButton: ['button.skip__button.body-copy', '[data-testid="skip-intro-button"]'],
nextButton: ['button._5gjogg1', '[data-testid="next-episode-button"]'],
extraButtons: ['[data-testid="skip-credits-button"]']
},
'StarPlus': {
skipButton: ['button.skip__button.body-copy', '[data-testid="skip-intro-button"]'],
nextButton: ['button._5gjogg1', '[data-testid="next-episode-button"]'],
extraButtons: ['[data-testid="skip-credits-button"]']
},
'Max': {
skipButton: ['.skip-btn', '[data-testid="skip-intro"]'],
nextButton: ['.next-episode-btn', '[data-testid="next-episode"]'],
extraButtons: ['.SkipAdsButtonWrapper-Fuse-Web-Play__sc-1jahjvv-11.dSvPnQ', '[data-testid="skip-ad"]']
},
'Netflix': {
skipButton: ['.ltr-bf8b0m', 'button[data-uia="player-skip-intro"]', 'button[data-uia="player-skip-preplay"]'],
nextButton: ['button[data-uia="next-episode-seamless-button"]', 'button[data-uia="post-play-next-episode"]'],
extraButtons: ['button[data-uia="player-skip-recap"]']
},
'YouTube': {
skipButton: ['.ytp-ad-skip-button', '.ytp-skip-ad-button', 'button[class*="skip"]'],
nextButton: [],
extraButtons: ['.ytp-ad-skip-button-text', '.ytp-preview-ad__skip-button']
},
'Mercado Livre': {
skipButton: ['.skip-ad', '[data-testid="skip-ad"]', 'button[class*="skip"]'],
nextButton: [],
extraButtons: ['.ad-skip-button', '[aria-label*="pular"]']
},
'PrimeVideo': {
skipButton: ['button[data-testid="skip-intro-button"]', '.skipElement'],
nextButton: ['button[data-testid="next-episode-button"]'],
extraButtons: ['button[data-testid="skip-recap-button"]']
},
'HBOMax': {
skipButton: ['.skip-intro', '[data-testid="skip-intro"]'],
nextButton: ['.next-episode', '[data-testid="next-episode"]'],
extraButtons: ['.skip-ad', '[data-testid="skip-ad"]']
},
'Hulu': {
skipButton: ['.skip-intro-button', '[data-testid="skip-intro"]'],
nextButton: ['.next-episode-button', '[data-testid="next-episode"]'],
extraButtons: ['.skip-ad-button', '[data-testid="skip-ad"]']
},
'Crunchyroll': {
skipButton: ['.skip-intro-button', '[data-testid="skip-intro"]'],
nextButton: ['.next-episode-button', '[data-testid="next-episode"]'],
extraButtons: ['.skip-ad-button', '[data-testid="skip-ad"]']
}
};
// =========================
// Variáveis de estado aprimoradas
// =========================
this.modes = {};
this.clickCounter = 0;
this.clickHistory = new Map(); // Histórico de cliques para evitar repetições
this.initialized = false;
this.checkInterval = null;
this.currentPlatform = null;
this.executingModes = {}; // Controle de execução
this.ignoredSelectors = {}; // Seletores ignorados
this.observer = null;
this.lastClickTime = new Map(); // Tempo do último clique por seletor
this.clickCooldown = 800; // Cooldown reduzido para 800ms para cliques mais rápidos
this.debugMode = false; // Modo debug para logging detalhado
this.mouseTracker = {
x: 0,
y: 0,
active: false
}; // Rastreamento do mouse
this.configSaveVersion = '3.1'; // Versão para forçar recarga de config
this.lastMouseLog = 0; // Para controlar spam de logs do mouse
this.isInfiniteClicking = false; // Controle de clique infinito
this.init();
}
// =========================
// Inicialização principal
// =========================
init() {
this.loadConfig();
this.loadModes();
this.createConfigInterface();
this.setupEventListeners();
// Aguarda carregamento completo e inicia observer
window.onload = () => {
console.log('Página totalmente carregada, iniciando AutoSkip');
this.executeOnLoad();
this.startChecking();
this.setupObserver();
};
this.initialized = true;
console.log('AutoSkip inicializado');
}
// =========================
// Configura observer para mudanças no DOM
// =========================
setupObserver() {
// Desconecta observer anterior se existir
if (this.observer) {
this.observer.disconnect();
}
// Configura novo observer
this.observer = new MutationObserver((mutations) => {
let shouldCheck = false;
// Verifica se houve mudanças relevantes
for (const mutation of mutations) {
if (mutation.type === 'childList' || mutation.type === 'subtree') {
shouldCheck = true;
break;
}
}
// Se houve mudanças relevantes, verifica os botões
if (shouldCheck) {
this.checkAndClickButtons();
}
});
// Inicia observação
this.observer.observe(document.body, {
childList: true,
subtree: true
});
}
// =========================
// Executa ações ao carregar a página
// =========================
executeOnLoad() {
console.log('Executando ações iniciais');
// Garante que a página está totalmente carregada
if (document.readyState === 'complete') {
// Executa verificação inicial após um pequeno delay
setTimeout(() => {
// Executa apenas seletores configurados para "onLoad"
for (const selector in this.modes) {
if (this.isElementVisible(selector)) {
const mode = this.modes[selector];
if (mode && mode.checkMode === 'onLoad') {
console.log(`Executando modo inicial para: ${selector}`);
this.executeMode(selector);
}
}
}
}, 1000); // Delay de 1 segundo após carregamento
}
}
// =========================
// Carregar configuração do localStorage
// =========================
loadConfig() {
try {
const savedConfig = localStorage.getItem('autoSkipConfig_v3.1');
const savedVersion = localStorage.getItem('autoSkipConfigVersion');
if (savedConfig && savedVersion === this.configSaveVersion) {
const parsed = JSON.parse(savedConfig);
// Merge com configuração padrão para manter novos sites
this.config = {
...this.config,
...parsed
};
this.log('Configuração carregada com sucesso', 'success');
}
else {
this.log('Usando configuração padrão ou versão desatualizada', 'info');
this.saveConfig(); // Salva a configuração padrão
}
}
catch (e) {
console.error('Erro ao carregar configuração:', e);
this.log('Erro ao carregar configuração, usando padrão', 'error');
}
}
// =========================
// Salvar configuração no localStorage
// =========================
saveConfig() {
try {
localStorage.setItem('autoSkipConfig_v3.1', JSON.stringify(this.config));
localStorage.setItem('autoSkipConfigVersion', this.configSaveVersion);
this.log('Configuração salva com sucesso', 'debug');
}
catch (e) {
console.error('Erro ao salvar configuração:', e);
this.log('Erro ao salvar configuração', 'error');
}
}
// =========================
// Carregar modos do localStorage
// =========================
loadModes() {
try {
const savedModes = localStorage.getItem('autoSkipModes_v3.1');
const savedVersion = localStorage.getItem('autoSkipModesVersion');
if (savedModes && savedVersion === this.configSaveVersion) {
this.modes = JSON.parse(savedModes);
this.log('Modos carregados com sucesso', 'debug');
}
else {
this.log('Iniciando com modos padrão', 'info');
}
}
catch (e) {
console.error('Erro ao carregar modos:', e);
this.log('Erro ao carregar modos', 'error');
}
}
// =========================
// Salvar modos no localStorage
// =========================
saveModes() {
try {
localStorage.setItem('autoSkipModes_v3.1', JSON.stringify(this.modes));
localStorage.setItem('autoSkipModesVersion', this.configSaveVersion);
this.log('Modos salvos com sucesso', 'debug');
}
catch (e) {
console.error('Erro ao salvar modos:', e);
this.log('Erro ao salvar modos', 'error');
}
}
// =========================
// Detectar plataforma pelo URL com melhor precisão
// =========================
detectPlatform() {
if (this.currentPlatform) return this.currentPlatform;
const url = window.location.href.toLowerCase();
const hostname = window.location.hostname.toLowerCase();
// Mapeamento específico de domínios
const platformMap = {
'disneyplus.com': 'DisneyPlus',
'starplus.com': 'StarPlus',
'max.com': 'Max',
'play.max.com': 'Max',
'hbomax.com': 'HBOMax',
'netflix.com': 'Netflix',
'youtube.com': 'YouTube',
'play.mercadolivre.com.br': 'Mercado Livre',
'mercadolivre.com.br': 'Mercado Livre',
'primevideo.com': 'PrimeVideo',
'amazon.com/prime': 'PrimeVideo',
'hulu.com': 'Hulu',
'crunchyroll.com': 'Crunchyroll'
};
for (const [domain, platform] of Object.entries(platformMap)) {
if (hostname.includes(domain)) {
this.currentPlatform = platform;
this.log(`🎯 Plataforma detectada: ${platform}`);
return platform;
}
}
return null;
}
// =========================
// Sistema de logging aprimorado
// =========================
log(message, type = 'info') {
const timestamp = new Date().toLocaleTimeString();
const prefix = '🎬 AutoSkip';
switch (type) {
case 'success':
console.log(`%c${prefix} [${timestamp}] ✅ ${message}`, 'color: #28a745; font-weight: bold;');
break;
case 'warning':
console.warn(`%c${prefix} [${timestamp}] ⚠️ ${message}`, 'color: #ffc107; font-weight: bold;');
break;
case 'error':
console.error(`%c${prefix} [${timestamp}] ❌ ${message}`, 'color: #dc3545; font-weight: bold;');
break;
case 'debug':
if (this.debugMode) {
console.log(`%c${prefix} [${timestamp}] 🔍 ${message}`, 'color: #6c757d;');
}
break;
default:
console.log(`%c${prefix} [${timestamp}] ${message}`, 'color: #007bff; font-weight: bold;');
}
}
// =========================
// Verifica se o elemento está visível com melhor detecção
// =========================
isElementVisible(selectorOrElement) {
try {
let element;
if (typeof selectorOrElement === 'string') {
element = document.querySelector(selectorOrElement);
}
else {
element = selectorOrElement;
}
if (!element) return false;
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return element.offsetParent !== null &&
!element.hidden &&
style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.opacity !== '0' &&
rect.width > 0 &&
rect.height > 0 &&
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth;
}
catch (e) {
this.log(`Erro ao verificar visibilidade do elemento: ${selectorOrElement}`, 'error');
return false;
}
}
// =========================
// Verifica cooldown do elemento
// =========================
isElementInCooldown(selector) {
const lastClick = this.lastClickTime.get(selector);
if (!lastClick) return false;
const now = Date.now();
const timeDiff = now - lastClick;
return timeDiff < this.clickCooldown;
}
// =========================
// Clica no elemento com melhor controle
// =========================
clickElement(selector, reason = '') {
try {
if (this.isElementInCooldown(selector)) {
this.log(`Elemento em cooldown: ${selector}`, 'debug');
return false;
}
const element = document.querySelector(selector);
if (!element) {
this.log(`Elemento não encontrado: ${selector}`, 'debug');
return false;
}
if (!this.isElementVisible(selector)) {
this.log(`Elemento não visível: ${selector}`, 'debug');
return false;
}
const elementText = element.innerText || element.textContent || element.getAttribute('aria-label') || '';
this.log(`Clicando em: "${elementText}" (${selector}) ${reason}`, 'success');
// Adiciona highlight visual temporário
this.highlightElement(element);
// Executa o clique
element.click();
// Registra o clique
this.incrementClickCounter();
this.lastClickTime.set(selector, Date.now());
// Salva no histórico
this.clickHistory.set(selector, {
timestamp: Date.now(),
text: elementText,
reason: reason
});
return true;
}
catch (e) {
this.log(`Erro ao clicar no elemento ${selector}: ${e.message}`, 'error');
return false;
}
}
// =========================
// Destaca elemento visualmente
// =========================
highlightElement(element, duration = 2000) {
const originalOutline = element.style.outline;
const originalBoxShadow = element.style.boxShadow;
element.style.outline = '3px solid #ff0000';
element.style.boxShadow = '0 0 10px rgba(255, 0, 0, 0.5)';
setTimeout(() => {
element.style.outline = originalOutline;
element.style.boxShadow = originalBoxShadow;
}, duration);
}
// =========================
// Incrementa o contador de cliques com estatísticas
// =========================
incrementClickCounter() {
this.clickCounter++;
this.log(`Total de cliques executados: ${this.clickCounter}`, 'debug');
// Atualiza estatísticas na UI se disponível
const statsElement = document.getElementById('autoSkipStats');
if (statsElement) {
statsElement.textContent = `Cliques: ${this.clickCounter}`;
}
}
// =========================
// Verifica e clica nos botões com detecção inteligente
// =========================
checkAndClickButtons() {
const platform = this.detectPlatform();
if (!platform) {
this.log('Plataforma não detectada', 'debug');
return;
}
const {
skipButton = [], nextButton = [], extraButtons = []
} = this.config[platform] || {};
const allButtons = [...skipButton, ...nextButton, ...extraButtons];
this.log(`Verificando ${allButtons.length} seletores para ${platform}`, 'debug');
allButtons.forEach(selectorConfig => {
// Suporte tanto para string (formato antigo) quanto objeto (formato novo)
const selectorKey = typeof selectorConfig === 'string' ? selectorConfig : JSON.stringify(selectorConfig);
if (this.ignoredSelectors[selectorKey]) {
this.log(`Seletor ignorado: ${selectorKey}`, 'debug');
return;
}
if (this.isElementInCooldown(selectorKey)) {
this.log(`Seletor em cooldown: ${selectorKey}`, 'debug');
return;
}
// Verifica se elemento está visível (suporte a formatos antigo e novo)
let element;
if (typeof selectorConfig === 'string') {
element = document.querySelector(selectorConfig);
}
else {
element = this.findElementByAdvancedConfig(selectorConfig);
}
if (element && this.isElementVisible(element)) {
const mode = this.modes[selectorKey];
// Executa se for verificação contínua ou não definido (default)
if (!mode || mode.checkMode === 'continuous' || !mode.checkMode) {
this.log(`Elemento encontrado: ${selectorKey}`, 'debug');
this.executeMode(selectorKey, element);
}
}
});
// Busca por elementos baseados em texto (funcionalidade adicional)
this.checkTextBasedElements();
}
// =========================
// Busca elementos baseados em texto
// =========================
checkTextBasedElements() {
const textSelectors = [
'Pular Abertura',
'Skip Intro',
'Pular Anúncio',
'Skip Ad',
'Próximo Episódio',
'Next Episode',
'Pular',
'Skip'
];
textSelectors.forEach(text => {
const elements = this.findElementsByText(text);
elements.forEach(element => {
const selector = this.generateSelector(element);
if (!this.isElementInCooldown(selector) && this.isElementVisible(selector)) {
this.log(`Elemento encontrado por texto "${text}": ${selector}`, 'debug');
this.clickElement(selector, `texto: ${text}`);
}
});
});
}
// =========================
// Encontra elementos por texto
// =========================
findElementsByText(text) {
const xpath = `//*[contains(text(), '${text}') or contains(@aria-label, '${text}') or contains(@title, '${text}')]`;
const result = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
const elements = [];
for (let i = 0; i < result.snapshotLength; i++) {
elements.push(result.snapshotItem(i));
}
return elements.filter(el =>
el.tagName && ['BUTTON', 'A', 'DIV', 'SPAN'].includes(el.tagName.toUpperCase()) &&
(el.onclick || el.click || el.getAttribute('role') === 'button')
);
}
// =========================
// Inicia verificação periódica dos botões
// =========================
startChecking(interval = 500) { // Intervalo reduzido para 500ms para cliques mais rápidos
if (this.checkInterval) {
clearInterval(this.checkInterval);
}
this.checkInterval = setInterval(() => {
this.checkAndClickButtons();
}, interval);
this.log(`Verificação iniciada com intervalo de ${interval}ms`, 'debug');
}
// =========================
// Para a verificação dos botões
// =========================
stopChecking() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
}
// =========================
// Adiciona seletor à configuração
// =========================
addSelectorToConfig(platform, selector, buttonType = 'extraButtons') {
if (!this.config[platform]) {
this.config[platform] = {
skipButton: [],
nextButton: [],
extraButtons: []
};
}
if (!this.config[platform][buttonType]) {
this.config[platform][buttonType] = [];
}
if (!this.config[platform][buttonType].includes(selector)) {
this.config[platform][buttonType].push(selector);
this.saveConfig();
delete this.ignoredSelectors[selector]; // <--- Remove do ignorado ao adicionar novamente
return true;
}
return false;
}
// =========================
// Remove seletor da configuração
// =========================
removeSelector(platform, selector) {
if (!this.config[platform]) return false;
let removed = false;
['skipButton', 'nextButton', 'extraButtons'].forEach(type => {
if (this.config[platform][type]) {
const index = this.config[platform][type].indexOf(selector);
if (index > -1) {
this.config[platform][type].splice(index, 1);
removed = true;
}
}
});
if (removed) {
this.saveConfig();
}
// Also remove any associated modes
if (this.modes[selector]) {
delete this.modes[selector];
this.saveModes();
}
if (this.ignoredSelectors[selector]) {
delete this.ignoredSelectors[selector]; // <--- Remove do ignorado ao remover
}
return removed;
}
// =========================
// Limpa dados da plataforma
// =========================
clearPlatformData(platform) {
if (this.config[platform]) {
delete this.config[platform];
this.saveConfig();
// Remove any modes associated with this platform
Object.keys(this.modes).forEach(selector => {
const platformButtons = [
...(this.config[platform]?.skipButton || []),
...(this.config[platform]?.nextButton || []),
...(this.config[platform]?.extraButtons || [])
];
if (platformButtons.includes(selector)) {
delete this.modes[selector];
}
});
this.saveModes();
return true;
}
return false;
}
// =========================
// Executa modo para o seletor com melhor controle
// =========================
executeMode(selector) {
if (this.executingModes[selector]) {
this.log(`Modo já executando para: ${selector}`, 'debug');
return;
}
const modeConfig = this.modes[selector];
if (!modeConfig) {
// Se não há modo configurado, executa clique automático
this.clickAutomatically(selector);
return;
}
const {
mode
} = modeConfig;
this.log(`Executando modo "${mode}" para: ${selector}`, 'debug');
switch (mode) {
case 'clickAutomatically':
this.clickAutomatically(selector);
break;
case 'clickOnce':
this.executingModes[selector] = true;
this.clickOnce(selector, modeConfig.delay)
.finally(() => {
delete this.executingModes[selector];
});
break;
case 'clickRepeatedly':
this.executingModes[selector] = true;
this.clickRepeatedly(selector, modeConfig.interval, modeConfig.count)
.finally(() => {
delete this.executingModes[selector];
});
break;
case 'clickAndHold':
this.executingModes[selector] = true;
this.clickAndHold(selector, modeConfig.duration)
.finally(() => {
delete this.executingModes[selector];
});
break;
case 'clickAndDrag':
this.executingModes[selector] = true;
this.clickAndDrag(
selector,
modeConfig.startX,
modeConfig.startY,
modeConfig.endX,
modeConfig.endY
)
.finally(() => {
delete this.executingModes[selector];
});
break;
case 'clickAtCoordinates':
this.executingModes[selector] = true;
const clickMode = modeConfig.clickMode || 'once';
const options = {
count: modeConfig.count || 5,
interval: modeConfig.interval || 1000,
duration: modeConfig.duration || 2000
};
this.executeCoordinateClick(modeConfig.x, modeConfig.y, modeConfig.delay, clickMode, options)
.finally(() => {
delete this.executingModes[selector];
});
break;
default:
this.log(`Modo desconhecido: ${mode}`, 'warning');
this.clickAutomatically(selector);
}
}
// =========================
// Modo: Clicar automaticamente
// =========================
clickAutomatically(selector) {
this.clickElement(selector, 'modo automático');
}
// =========================
// Modo: Clicar uma vez com delay configurável
// =========================
async clickOnce(selector, delay = 500) {
if (this.clickElement(selector, 'modo único')) {
await new Promise(resolve => setTimeout(resolve, delay));
}
}
// =========================
// Modo: Clicar repetidamente com configuração avançada
// =========================
async clickRepeatedly(selector, interval = 1000, count = 5) {
let clicks = 0;
this.log(`Iniciando cliques repetidos: ${count}x com intervalo ${interval}ms`, 'debug');
while (clicks < count && this.isElementVisible(selector)) {
if (this.clickElement(selector, `repetido ${clicks + 1}/${count}`)) {
clicks++;
}
if (clicks < count) {
await new Promise(resolve => setTimeout(resolve, interval));
}
}
this.log(`Cliques repetidos concluídos: ${clicks}/${count}`, 'debug');
}
// =========================
// Modo: Clicar e segurar com duração configurável
// =========================
async clickAndHold(selector, duration = 1000) {
const element = document.querySelector(selector);
if (element) {
this.log(`Iniciando clique prolongado por ${duration}ms`, 'debug');
element.dispatchEvent(new MouseEvent('mousedown', {
bubbles: true
}));
this.highlightElement(element, duration);
this.incrementClickCounter();
await new Promise(resolve => setTimeout(resolve, duration));
element.dispatchEvent(new MouseEvent('mouseup', {
bubbles: true
}));
this.log('Clique prolongado concluído', 'debug');
}
}
// =========================
// Modo: Clicar e arrastar com coordenadas configuráveis
// =========================
async clickAndDrag(selector, startX, startY, endX, endY) {
const element = document.querySelector(selector);
if (element) {
this.log(`Iniciando arrastar de (${startX},${startY}) para (${endX},${endY})`, 'debug');
element.dispatchEvent(new MouseEvent('mousedown', {
clientX: startX,
clientY: startY,
bubbles: true
}));
this.highlightElement(element, 1000);
await new Promise(resolve => setTimeout(resolve, 100));
element.dispatchEvent(new MouseEvent('mousemove', {
clientX: endX,
clientY: endY,
bubbles: true
}));
await new Promise(resolve => setTimeout(resolve, 100));
element.dispatchEvent(new MouseEvent('mouseup', {
bubbles: true
}));
this.incrementClickCounter();
this.log('Arrastar concluído', 'debug');
}
}
// =========================
// Configura listeners de eventos aprimorados
// =========================
setupEventListeners() {
// Rastreamento do mouse para debug
document.addEventListener('mousemove', (event) => {
this.mouseTracker.x = event.clientX;
this.mouseTracker.y = event.clientY;
if (this.debugMode && this.mouseTracker.active) {
this.updateMouseDisplay(event.clientX, event.clientY);
}
});
// Alt+Click para adicionar seletor
document.addEventListener('click', (event) => {
if (event.altKey) {
event.preventDefault();
event.stopPropagation();
this.handleAltClick(event);
}
}, true);
// Shift+Alt+Click para testar elemento
document.addEventListener('click', (event) => {
if (event.shiftKey && event.altKey) {
event.preventDefault();
event.stopPropagation();
this.handleTestElement(event);
}
}, true);
// Teclas de atalho
document.addEventListener('keydown', (event) => {
if (event.ctrlKey && event.altKey) {
switch (event.key.toLowerCase()) {
case 's':
event.preventDefault();
this.toggleConfigInterface();
break;
case 'd':
event.preventDefault();
this.debugMode = !this.debugMode;
// Sincroniza mouse tracker com debug mode
if (this.debugMode && !this.mouseTracker.active) {
this.toggleMouseTracker();
}
else if (!this.debugMode && this.mouseTracker.active) {
this.toggleMouseTracker();
}
this.log(`Modo debug ${this.debugMode ? 'ativado' : 'desativado'}`, 'info');
console.log(`%c🔧 Debug Mode ${this.debugMode ? 'ON' : 'OFF'}`, `color: ${this.debugMode ? '#00ff00' : '#ff6600'}; font-weight: bold; font-size: 14px;`);
break;
case 'r':
event.preventDefault();
this.showClickHistory();
break;
case 'c':
event.preventDefault();
this.showCoordinateClick();
break;
case 'q':
event.preventDefault();
this.showDirectCoordinateClick();
break;
case 'm':
event.preventDefault();
this.toggleMouseTracker();
break;
case 'x':
event.preventDefault();
this.stopInfiniteClicking();
break;
case 't':
event.preventDefault();
this.testKeyboardShortcuts();
break;
}
}
});
}
// =========================
// Testa todos os atalhos de teclado
// =========================
testKeyboardShortcuts() {
console.log('🔧 Testando Atalhos de Teclado:');
console.log('📋 Ctrl+Alt+R: Histórico de cliques');
console.log('🎯 Ctrl+Alt+C: Popup completo de coordenadas');
console.log('⚡ Ctrl+Alt+Q: Clique direto em coordenadas');
console.log('🖱️ Ctrl+Alt+M: Alternar rastreamento do mouse');
console.log('⚙️ Ctrl+Alt+S: Interface de configuração');
console.log('🔧 Ctrl+Alt+D: Modo debug');
console.log('🚨 Ctrl+Alt+X: Parar clique infinito');
console.log('Para testar: pressione Ctrl+Alt + uma das teclas acima');
}
// =========================
// Handler para teste de elemento
// =========================
handleTestElement(event) {
const selector = this.generateSelector(event.target);
this.log(`Testando elemento: ${selector}`, 'info');
if (this.isElementVisible(selector)) {
this.highlightElement(event.target, 3000);
this.log(`Elemento visível e testado: ${selector}`, 'success');
}
else {
this.log(`Elemento não visível: ${selector}`, 'warning');
}
}
// =========================
// Alterna rastreamento do mouse
// =========================
toggleMouseTracker() {
this.mouseTracker.active = !this.mouseTracker.active;
if (this.mouseTracker.active) {
this.createMouseDisplay();
this.log('🖱️ Rastreamento do mouse ativado', 'info');
console.log('%c🖱️ Rastreamento do mouse ATIVADO', 'color: #00ff00; font-weight: bold;');
}
else {
this.removeMouseDisplay();
this.log('🖱️ Rastreamento do mouse desativado', 'info');
console.log('%c🖱️ Rastreamento do mouse DESATIVADO', 'color: #ff6600; font-weight: bold;');
}
}
// =========================
// Cria display de coordenadas do mouse
// =========================
createMouseDisplay() {
// Remove display anterior se existir
this.removeMouseDisplay();
const display = document.createElement('div');
display.id = 'autoSkipMouseDisplay';
Object.assign(display.style, {
position: 'fixed',
top: '50px',
left: '10px',
padding: '12px 16px',
backgroundColor: 'rgba(0, 0, 0, 0.9)',
color: '#00ff00',
fontFamily: 'Courier New, monospace',
fontSize: '14px',
borderRadius: '8px',
zIndex: '10003',
border: '2px solid #00ff00',
pointerEvents: 'none',
fontWeight: 'bold',
boxShadow: '0 4px 12px rgba(0, 255, 0, 0.3)',
minWidth: '180px',
textAlign: 'center'
});
display.innerHTML = `
<div style="margin-bottom: 4px; color: #00ff00; font-size: 12px;">🖱️ MOUSE TRACKER</div>
<div id="mouseCoords" style="font-size: 16px;">X: 0, Y: 0</div>
<div style="margin-top: 4px; color: #888; font-size: 10px;">Ctrl+Alt+M para desativar</div>
`;
document.body.appendChild(display);
console.log('%c🖱️ Display de coordenadas criado', 'color: #00ff00;');
}
// =========================
// Remove display de coordenadas do mouse
// =========================
removeMouseDisplay() {
const display = document.getElementById('autoSkipMouseDisplay');
if (display && display.parentNode) {
document.body.removeChild(display);
console.log('%c🖱️ Display de coordenadas removido', 'color: #ff6600;');
}
}
// =========================
// Atualiza display de coordenadas do mouse
// =========================
updateMouseDisplay(x, y) {
const coordsElement = document.getElementById('mouseCoords');
if (coordsElement) {
coordsElement.textContent = `X: ${x}, Y: ${y}`;
// Debug adicional no console se debug mode ativo
if (this.debugMode) {
// Log apenas a cada 100ms para não spammar
const now = Date.now();
if (!this.lastMouseLog || now - this.lastMouseLog > 100) {
this.lastMouseLog = now;
console.log(`🖱️ Mouse: X=${x}, Y=${y}`);
}
}
}
}
// =========================
// Mostra popup para clicar em coordenadas específicas
// =========================
showCoordinateClick() {
const popup = document.createElement('div');
popup.className = 'auto-skip-popup';
Object.assign(popup.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '400px',
maxWidth: '90vw',
maxHeight: '90vh',
padding: '25px',
backgroundColor: '#1e1e1e',
color: '#ffffff',
borderRadius: '12px',
zIndex: '10002',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5)',
border: '2px solid #007bff',
overflowY: 'auto'
});
const title = document.createElement('h3');
title.textContent = '🎯 Clicar em Coordenadas';
title.style.marginTop = '0';
title.style.color = '#007bff';
title.style.marginBottom = '20px';
popup.appendChild(title);
const currentCoords = document.createElement('div');
currentCoords.innerHTML = `<strong>📍 Posição atual do mouse:</strong> X: ${this.mouseTracker.x}, Y: ${this.mouseTracker.y}`;
currentCoords.style.marginBottom = '15px';
currentCoords.style.padding = '10px';
currentCoords.style.backgroundColor = '#2d2d2d';
currentCoords.style.borderRadius = '6px';
currentCoords.style.fontSize = '14px';
popup.appendChild(currentCoords);
const form = document.createElement('div');
// Modo de clique
const modeContainer = document.createElement('div');
modeContainer.style.marginBottom = '15px';
const modeLabel = document.createElement('label');
modeLabel.textContent = '🎮 Modo de Clique:';
modeLabel.style.display = 'block';
modeLabel.style.marginBottom = '8px';
modeLabel.style.fontWeight = 'bold';
const modeSelect = document.createElement('select');
Object.assign(modeSelect.style, {
width: '100%',
padding: '8px',
backgroundColor: '#333',
color: '#fff',
border: '1px solid #555',
borderRadius: '6px'
});
const modeOptions = [{
value: 'once',
text: 'Clicar Uma Vez'
},
{
value: 'repeatedly',
text: 'Clicar Repetidamente'
},
{
value: 'hold',
text: 'Clicar e Segurar'
},
{
value: 'rapidFire',
text: 'Clique Rápido (Ultra Fast)'
},
{
value: 'infinite',
text: 'Clique Infinito'
},
{
value: 'timedInfinite',
text: 'Clique Infinito por Tempo'
}
];
modeOptions.forEach(option => {
const opt = document.createElement('option');
opt.value = option.value;
opt.textContent = option.text;
modeSelect.appendChild(opt);
});
modeContainer.appendChild(modeLabel);
modeContainer.appendChild(modeSelect);
form.appendChild(modeContainer);
// Coordenadas
form.appendChild(this.createNumberInput('📍 Coordenada X:', 'coordX', this.mouseTracker.x));
form.appendChild(this.createNumberInput('📍 Coordenada Y:', 'coordY', this.mouseTracker.y));
form.appendChild(this.createNumberInput('⏱️ Delay antes do clique (ms):', 'delay', 1000));
// Campos condicionais baseados no modo
const conditionalFields = document.createElement('div');
conditionalFields.id = 'conditionalFields';
const updateConditionalFields = () => {
conditionalFields.innerHTML = '';
const selectedMode = modeSelect.value;
if (selectedMode === 'repeatedly') {
conditionalFields.appendChild(this.createNumberInput('🔢 Quantidade de cliques:', 'count', 5));
conditionalFields.appendChild(this.createNumberInput('⏱️ Intervalo entre cliques (ms):', 'interval', 1000));
}
else if (selectedMode === 'hold') {
conditionalFields.appendChild(this.createNumberInput('⏰ Duração do clique (ms):', 'duration', 2000));
}
else if (selectedMode === 'rapidFire') {
conditionalFields.appendChild(this.createNumberInput('🔢 Quantidade de cliques:', 'count', 10));
conditionalFields.appendChild(this.createNumberInput('⚡ Intervalo ultra-rápido (ms):', 'interval', 50));
const warningDiv = document.createElement('div');
warningDiv.innerHTML = '<strong style="color: #ff6600;">⚠️ Modo ultra-rápido: Use com cuidado!</strong>';
warningDiv.style.padding = '8px';
warningDiv.style.backgroundColor = '#2d2d2d';
warningDiv.style.borderRadius = '4px';
warningDiv.style.marginTop = '8px';
conditionalFields.appendChild(warningDiv);
}
else if (selectedMode === 'infinite') {
conditionalFields.appendChild(this.createNumberInput('⚡ Intervalo entre cliques (ms):', 'interval', 100));
const warningDiv = document.createElement('div');
warningDiv.innerHTML = '<strong style="color: #ff0000;">🚨 INFINITO: Pressione Ctrl+Alt+S para parar!</strong>';
warningDiv.style.padding = '8px';
warningDiv.style.backgroundColor = '#2d1a1a';
warningDiv.style.borderRadius = '4px';
warningDiv.style.marginTop = '8px';
warningDiv.style.border = '1px solid #ff0000';
conditionalFields.appendChild(warningDiv);
}
else if (selectedMode === 'timedInfinite') {
conditionalFields.appendChild(this.createNumberInput('⚡ Intervalo entre cliques (ms):', 'interval', 100));
conditionalFields.appendChild(this.createNumberInput('⏰ Duração total (segundos):', 'duration', 30));
const warningDiv = document.createElement('div');
warningDiv.innerHTML = '<strong style="color: #ff6600;">⚠️ Clique infinito por tempo limitado</strong>';
warningDiv.style.padding = '8px';
warningDiv.style.backgroundColor = '#2d2d2d';
warningDiv.style.borderRadius = '4px';
warningDiv.style.marginTop = '8px';
conditionalFields.appendChild(warningDiv);
}
};
modeSelect.addEventListener('change', updateConditionalFields);
updateConditionalFields(); // Inicializa campos
form.appendChild(conditionalFields);
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.gap = '10px';
buttonContainer.style.marginTop = '20px';
const useCurrentBtn = this.createButton('📍 Usar Posição Atual', () => {
const xInput = form.querySelector('input[name="coordX"]');
const yInput = form.querySelector('input[name="coordY"]');
xInput.value = this.mouseTracker.x;
yInput.value = this.mouseTracker.y;
currentCoords.innerHTML = `<strong>📍 Posição atual do mouse:</strong> X: ${this.mouseTracker.x}, Y: ${this.mouseTracker.y}`;
}, {
flex: '1',
backgroundColor: '#17a2b8'
});
const clickBtn = this.createButton('🖱️ Executar Clique', () => {
const x = parseInt(form.querySelector('input[name="coordX"]').value, 10);
const y = parseInt(form.querySelector('input[name="coordY"]').value, 10);
const delay = parseInt(form.querySelector('input[name="delay"]').value, 10);
const mode = modeSelect.value;
let count = 1;
let interval = 1000;
let duration = 2000;
if (mode === 'repeatedly' || mode === 'rapidFire') {
count = parseInt(form.querySelector('input[name="count"]')?.value, 10) || (mode === 'rapidFire' ? 10 : 5);
interval = parseInt(form.querySelector('input[name="interval"]')?.value, 10) || (mode === 'rapidFire' ? 50 : 1000);
}
else if (mode === 'hold') {
duration = parseInt(form.querySelector('input[name="duration"]')?.value, 10) || 2000;
}
else if (mode === 'infinite' || mode === 'timedInfinite') {
interval = parseInt(form.querySelector('input[name="interval"]')?.value, 10) || 100;
if (mode === 'timedInfinite') {
duration = parseInt(form.querySelector('input[name="duration"]')?.value, 10) || 30;
}
}
document.body.removeChild(popup);
// Aviso especial para modos perigosos
if (mode === 'infinite') {
if (confirm('🚨 ATENÇÃO: Clique INFINITO ativado!\n\nUse Ctrl+Alt+X para parar.\n\nContinuar?')) {
this.executeCoordinateClick(x, y, delay, mode, {
count,
interval,
duration
});
}
}
else {
this.executeCoordinateClick(x, y, delay, mode, {
count,
interval,
duration
});
}
}, {
flex: '2',
backgroundColor: '#28a745'
});
const testBtn = this.createButton('🧪 Teste Rápido', () => {
const x = parseInt(form.querySelector('input[name="coordX"]').value, 10);
const y = parseInt(form.querySelector('input[name="coordY"]').value, 10);
this.log(`🧪 Iniciando teste completo em (${x}, ${y})`, 'info');
// 1. Debug do elemento na posição
const debugInfo = this.debugElementAtCoordinates(x, y);
// 2. Teste imediato com indicador visual
this.fastClickAtCoordinates(x, y);
// 3. Se não tiver elemento válido, tenta métodos alternativos
if (!debugInfo.primary || debugInfo.primary === document.body) {
this.log(`⚠️ Nenhum elemento específico encontrado, testando métodos alternativos`, 'warn');
// Tenta clicar em todos os elementos na posição
debugInfo.all.forEach((element, index) => {
if (element !== document.body && element !== document.html) {
this.log(`🎯 Testando clique direto no elemento ${index + 1}: ${element.tagName}`, 'debug');
element.click();
}
});
}
this.log(`✅ Teste completo finalizado`, 'success');
}, {
flex: '1',
backgroundColor: '#ffc107',
color: '#000'
});
const cancelBtn = this.createButton('❌ Cancelar', () => {
document.body.removeChild(popup);
}, {
flex: '1',
backgroundColor: '#6c757d'
});
buttonContainer.appendChild(useCurrentBtn);
buttonContainer.appendChild(testBtn);
buttonContainer.appendChild(clickBtn);
buttonContainer.appendChild(cancelBtn);
popup.appendChild(form);
popup.appendChild(buttonContainer);
document.body.appendChild(popup);
}
// =========================
// Executa clique em coordenadas com diferentes modos
// =========================
async executeCoordinateClick(x, y, delay = 1000, mode = 'once', options = {}) {
const {
count = 5, interval = 1000, duration = 2000
} = options;
this.log(`🎯 Executando clique ${mode} em (${x}, ${y})`, 'info');
console.log(`%c🎯 Clique ${mode} em coordenadas (${x}, ${y})`, 'color: #00ff00; font-weight: bold;');
// Para modos rápidos, reduzir ou pular delay inicial
const actualDelay = ['rapidFire', 'infinite', 'timedInfinite'].includes(mode) ? Math.min(delay, 200) : delay;
if (actualDelay > 0) {
this.log(`⏱️ Aguardando ${actualDelay}ms antes de executar...`, 'debug');
await new Promise(resolve => setTimeout(resolve, actualDelay));
}
switch (mode) {
case 'once':
await this.clickAtCoordinates(x, y, 0);
break;
case 'repeatedly':
this.log(`🔄 Clicando ${count} vezes com intervalo de ${interval}ms`, 'info');
for (let i = 0; i < count; i++) {
await this.fastClickAtCoordinates(x, y);
this.log(`✅ Clique ${i + 1}/${count} executado`, 'debug');
if (i < count - 1) {
await new Promise(resolve => setTimeout(resolve, interval));
}
}
break;
case 'rapidFire':
this.log(`⚡ Clique ultra-rápido: ${count} cliques com ${interval}ms de intervalo`, 'info');
for (let i = 0; i < count; i++) {
await this.fastClickAtCoordinates(x, y);
if (i < count - 1) {
await new Promise(resolve => setTimeout(resolve, interval));
}
}
break;
case 'infinite':
this.log(`🚨 Iniciando clique INFINITO com intervalo de ${interval}ms`, 'warning');
this.isInfiniteClicking = true;
let infiniteCount = 0;
while (this.isInfiniteClicking) {
await this.fastClickAtCoordinates(x, y);
infiniteCount++;
if (infiniteCount % 100 === 0) {
this.log(`🔄 Cliques infinitos: ${infiniteCount}`, 'debug');
}
await new Promise(resolve => setTimeout(resolve, interval));
}
this.log(`🛑 Clique infinito parado. Total: ${infiniteCount} cliques`, 'info');
break;
case 'timedInfinite':
this.log(`⏰ Clique infinito por ${duration} segundos com intervalo de ${interval}ms`, 'info');
const endTime = Date.now() + (duration * 1000);
let timedCount = 0;
while (Date.now() < endTime) {
await this.fastClickAtCoordinates(x, y);
timedCount++;
await new Promise(resolve => setTimeout(resolve, interval));
}
this.log(`⏰ Clique por tempo finalizado. Total: ${timedCount} cliques`, 'success');
break;
case 'hold':
this.log(`⏰ Clique prolongado por ${duration}ms`, 'info');
await this.clickAndHoldAtCoordinates(x, y, duration);
break;
default:
this.log(`❌ Modo desconhecido: ${mode}`, 'error');
await this.clickAtCoordinates(x, y, 0);
}
this.log(`✅ Clique ${mode} concluído em (${x}, ${y})`, 'success');
}
// =========================
// Clique ultra-rápido em coordenadas (sem delays e verificações)
// =========================
async fastClickAtCoordinates(x, y) {
// Clique direto sem verificações para máxima velocidade
try {
// Múltiplos métodos para garantir que o clique funcione
// Método 1: Dispara eventos em sequência completa
const eventTypes = ['mousedown', 'mouseup', 'click'];
eventTypes.forEach(eventType => {
const event = new MouseEvent(eventType, {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window,
button: 0,
buttons: eventType === 'mousedown' ? 1 : 0
});
// Tenta disparar no elemento específico primeiro
const element = document.elementFromPoint(x, y);
if (element) {
element.dispatchEvent(event);
}
// Dispara também no document como fallback
document.dispatchEvent(event);
});
// Método 2: Clique direto no body se não houver elemento
const bodyClickEvent = new MouseEvent('click', {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window
});
document.body.dispatchEvent(bodyClickEvent);
this.incrementClickCounter();
// Log visual temporário para debug
if (this.debugMode) {
this.createTemporaryClickIndicator(x, y);
}
// Log reduzido para performance
if (this.clickCounter % 50 === 0) {
this.log(`⚡ Fast click #${this.clickCounter} em (${x}, ${y})`, 'debug');
console.log(`%c⚡ Fast Click #${this.clickCounter} em (${x}, ${y})`, 'color: #00ff00; font-weight: bold;');
}
}
catch (error) {
this.log(`❌ Erro no fast click: ${error.message}`, 'error');
}
}
// =========================
// Para clique infinito
// =========================
stopInfiniteClicking() {
this.isInfiniteClicking = false;
this.log('🛑 Clique infinito interrompido pelo usuário', 'warning');
console.log('%c🛑 Clique INFINITO PARADO', 'color: #ff0000; font-weight: bold; font-size: 16px;');
}
// =========================
// Cria indicador temporário para debug de cliques rápidos
// =========================
createTemporaryClickIndicator(x, y) {
const indicator = document.createElement('div');
Object.assign(indicator.style, {
position: 'fixed',
left: `${x - 5}px`,
top: `${y - 5}px`,
width: '10px',
height: '10px',
borderRadius: '50%',
backgroundColor: '#00ff00',
border: '2px solid #ffffff',
zIndex: '10005',
pointerEvents: 'none',
opacity: '0.8'
});
document.body.appendChild(indicator);
// Remove após 500ms
setTimeout(() => {
if (indicator.parentNode) {
document.body.removeChild(indicator);
}
}, 500);
}
// Função para debug avançado de elementos
debugElementAtCoordinates(x, y) {
const elementAtPoint = document.elementFromPoint(x, y);
const allElements = document.elementsFromPoint(x, y);
this.log(`🔍 Debug das coordenadas (${x}, ${y}):`, 'debug');
this.log(`- Elemento principal: ${elementAtPoint ? elementAtPoint.tagName : 'null'}`, 'debug');
if (elementAtPoint) {
this.log(`- ID: ${elementAtPoint.id || 'sem ID'}`, 'debug');
this.log(`- Classes: ${elementAtPoint.className || 'sem classes'}`, 'debug');
this.log(`- Texto: ${elementAtPoint.textContent?.slice(0, 50) || 'sem texto'}`, 'debug');
}
this.log(`- Total de elementos na posição: ${allElements.length}`, 'debug');
return {
primary: elementAtPoint,
all: allElements
};
}
async clickAndHoldAtCoordinates(x, y, duration = 2000) {
this.log(`🎯 Iniciando clique prolongado em (${x}, ${y}) por ${duration}ms`, 'info');
// Cria indicador visual
const indicator = this.createCoordinateIndicator(x, y, 'hold');
try {
// Método mais robusto para clique prolongado
const element = document.elementFromPoint(x, y);
// Executa mousedown com propriedades completas
const mouseDownEvent = new MouseEvent('mousedown', {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window,
button: 0,
buttons: 1,
detail: 1
});
// Dispara mousedown no elemento e documento
if (element) {
element.dispatchEvent(mouseDownEvent);
this.highlightElement(element, duration);
this.log(`⏰ Mousedown em elemento: ${element.tagName}`, 'debug');
}
document.dispatchEvent(mouseDownEvent);
document.body.dispatchEvent(mouseDownEvent);
this.log(`⏰ Segurando clique por ${duration}ms...`, 'debug');
// Aguarda duração
await new Promise(resolve => setTimeout(resolve, duration));
// Executa mouseup
const mouseUpEvent = new MouseEvent('mouseup', {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window,
button: 0,
buttons: 0,
detail: 1
});
// Dispara mouseup
if (element) {
element.dispatchEvent(mouseUpEvent);
}
document.dispatchEvent(mouseUpEvent);
document.body.dispatchEvent(mouseUpEvent);
// Executa click final
const clickEvent = new MouseEvent('click', {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window,
button: 0,
buttons: 0,
detail: 1
});
if (element) {
element.dispatchEvent(clickEvent);
}
document.dispatchEvent(clickEvent);
this.log(`✅ Clique prolongado finalizado em (${x}, ${y})`, 'success');
this.incrementClickCounter();
}
catch (error) {
this.log(`❌ Erro no clique prolongado: ${error.message}`, 'error');
}
// Remove indicador
this.removeCoordinateIndicator(indicator);
}
// =========================
// Cria indicador visual para coordenadas
// =========================
createCoordinateIndicator(x, y, type = 'click') {
const indicator = document.createElement('div');
const color = type === 'hold' ? '#ff9500' : '#ff0000';
Object.assign(indicator.style, {
position: 'fixed',
left: `${x - 15}px`,
top: `${y - 15}px`,
width: '30px',
height: '30px',
borderRadius: '50%',
backgroundColor: `rgba(255, 0, 0, 0.3)`,
border: `3px solid ${color}`,
zIndex: '10004',
pointerEvents: 'none'
});
// Adiciona animação
const animationName = type === 'hold' ? 'pulseHold' : 'pulseClick';
indicator.style.animation = `${animationName} 1s infinite`;
// Adiciona estilos CSS se não existirem
this.ensureCoordinateStyles();
document.body.appendChild(indicator);
return indicator;
}
// =========================
// Remove indicador visual
// =========================
removeCoordinateIndicator(indicator) {
if (indicator && indicator.parentNode) {
setTimeout(() => {
if (indicator.parentNode) {
document.body.removeChild(indicator);
}
}, 3000);
}
}
// =========================
// Garante que os estilos CSS estão presentes
// =========================
ensureCoordinateStyles() {
if (!document.getElementById('autoSkipCoordinateStyles')) {
const style = document.createElement('style');
style.id = 'autoSkipCoordinateStyles';
style.textContent = `
@keyframes pulseClick {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.5); opacity: 0.7; }
100% { transform: scale(1); opacity: 1; }
}
@keyframes pulseHold {
0% { transform: scale(1); opacity: 1; background-color: rgba(255, 149, 0, 0.3); }
50% { transform: scale(1.3); opacity: 0.8; background-color: rgba(255, 149, 0, 0.6); }
100% { transform: scale(1); opacity: 1; background-color: rgba(255, 149, 0, 0.3); }
}
`;
document.head.appendChild(style);
}
}
// =========================
// Clica em coordenadas específicas
// =========================
async clickAtCoordinates(x, y, delay = 1000) {
this.log(`🎯 Clicando em coordenadas (${x}, ${y}) após ${delay}ms`, 'info');
// Cria indicador visual
const indicator = this.createCoordinateIndicator(x, y, 'click');
// Aguarda delay
if (delay > 0) {
await new Promise(resolve => setTimeout(resolve, delay));
}
// Executa o clique com múltiplos métodos para garantir funcionamento
try {
// Método 1: Sequência completa de eventos de mouse
const events = [{
type: 'mousedown',
button: 0,
buttons: 1
},
{
type: 'mouseup',
button: 0,
buttons: 0
},
{
type: 'click',
button: 0,
buttons: 0
}
];
const element = document.elementFromPoint(x, y);
events.forEach(({
type,
button,
buttons
}) => {
const event = new MouseEvent(type, {
clientX: x,
clientY: y,
screenX: x,
screenY: y,
bubbles: true,
cancelable: true,
view: window,
button: button,
buttons: buttons,
detail: type === 'click' ? 1 : 0
});
// Dispara no elemento específico se existir
if (element) {
element.dispatchEvent(event);
this.log(`📍 Evento ${type} disparado no elemento: ${element.tagName}`, 'debug');
}
// Dispara também no document
document.dispatchEvent(event);
});
// Método 2: Clique adicional no body
const bodyEvent = new MouseEvent('click', {
clientX: x,
clientY: y,
bubbles: true,
cancelable: true,
view: window
});
document.body.dispatchEvent(bodyEvent);
// Método 3: Focus no elemento se possível
if (element && typeof element.focus === 'function') {
element.focus();
}
// Método 4: Trigger manual se for input/button
if (element && (element.tagName === 'BUTTON' || element.tagName === 'INPUT')) {
if (typeof element.click === 'function') {
element.click();
}
}
if (element) {
this.highlightElement(element, 2000);
this.log(`✅ Clique executado em (${x}, ${y}) no elemento: ${element.tagName}${element.id ? '#' + element.id : ''}${element.className ? '.' + element.className.split(' ')[0] : ''}`, 'success');
}
else {
this.log(`⚠️ Clique executado em (${x}, ${y}) - nenhum elemento específico detectado`, 'warning');
}
this.incrementClickCounter();
}
catch (error) {
this.log(`❌ Erro ao clicar em coordenadas: ${error.message}`, 'error');
}
// Remove indicador
this.removeCoordinateIndicator(indicator);
}
// =========================
// Mostra histórico de cliques
// =========================
showClickHistory() {
const history = Array.from(this.clickHistory.entries())
.sort((a, b) => b[1].timestamp - a[1].timestamp)
.slice(0, 10);
console.group('📋 Histórico de Cliques (últimos 10)');
history.forEach(([selector, data]) => {
const time = new Date(data.timestamp).toLocaleTimeString();
console.log(`${time} - "${data.text}" (${selector}) - ${data.reason}`);
});
console.groupEnd();
}
// =========================
// Alterna interface de configuração
// =========================
toggleConfigInterface() {
let container = document.getElementById('autoSkipContainer');
// Cria a interface se ela não existir
if (!container) {
this.createConfigInterface();
container = document.getElementById('autoSkipContainer');
}
// Alterna visibilidade
if (container) {
const isVisible = container.style.display !== 'none';
container.style.display = isVisible ? 'none' : 'block';
console.log(`🎬 Interface ${isVisible ? 'fechada' : 'aberta'}`);
}
}
// =========================
// Handler para Alt+Click (adicionar seletor) aprimorado
// =========================
handleAltClick(event) {
const selector = this.generateSelector(event.target);
const element = event.target;
const elementText = element.innerText || element.textContent || element.getAttribute('aria-label') || 'Elemento sem texto';
this.log(`Alt+Click detectado em: "${elementText}" (${selector})`, 'info');
this.highlightElement(element, 3000);
// Mostra popup de opções
this.showAddSelectorPopup(selector, elementText, element);
}
// =========================
// Mostra popup para adicionar seletor com mais opções
// =========================
showAddSelectorPopup(selector, elementText, element) {
const popup = document.createElement('div');
Object.assign(popup.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '500px',
maxWidth: '90vw',
padding: '20px',
backgroundColor: '#1e1e1e',
color: '#fff',
borderRadius: '12px',
zIndex: '10003',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5)',
border: '2px solid #007bff'
});
const title = document.createElement('h3');
title.textContent = '🎯 Adicionar Elemento';
title.style.margin = '0 0 20px 0';
title.style.color = '#007bff';
const info = document.createElement('div');
info.innerHTML = `
<strong>📍 Elemento:</strong> ${elementText.slice(0, 50)}${elementText.length > 50 ? '...' : ''}<br>
<strong>🔧 Seletor CSS:</strong> <code style="background: #333; padding: 2px 6px; border-radius: 3px;">${selector}</code>
`;
info.style.marginBottom = '20px';
info.style.fontSize = '14px';
// Tipo de busca
const searchTypeContainer = document.createElement('div');
searchTypeContainer.style.marginBottom = '15px';
const searchTypeLabel = document.createElement('label');
searchTypeLabel.textContent = '🔍 Método de Localização:';
searchTypeLabel.style.display = 'block';
searchTypeLabel.style.marginBottom = '8px';
searchTypeLabel.style.fontWeight = 'bold';
const searchTypeSelect = document.createElement('select');
Object.assign(searchTypeSelect.style, {
width: '100%',
padding: '8px',
backgroundColor: '#333',
color: '#fff',
border: '1px solid #555',
borderRadius: '6px'
});
const searchOptions = [{
value: 'selector',
text: 'Seletor CSS'
},
{
value: 'text',
text: 'Texto Exato'
},
{
value: 'selectorAndText',
text: 'Seletor CSS + Texto'
},
{
value: 'coordinates',
text: 'Coordenadas'
}
];
searchOptions.forEach(option => {
const opt = document.createElement('option');
opt.value = option.value;
opt.textContent = option.text;
searchTypeSelect.appendChild(opt);
});
searchTypeContainer.appendChild(searchTypeLabel);
searchTypeContainer.appendChild(searchTypeSelect);
// Campo de texto personalizado
const textContainer = document.createElement('div');
textContainer.style.marginBottom = '15px';
textContainer.style.display = 'none';
const textLabel = document.createElement('label');
textLabel.textContent = '📝 Texto a procurar:';
textLabel.style.display = 'block';
textLabel.style.marginBottom = '8px';
textLabel.style.fontWeight = 'bold';
const textInput = document.createElement('input');
textInput.type = 'text';
textInput.value = elementText.trim();
Object.assign(textInput.style, {
width: '100%',
padding: '8px',
backgroundColor: '#333',
color: '#fff',
border: '1px solid #555',
borderRadius: '6px',
boxSizing: 'border-box'
});
textContainer.appendChild(textLabel);
textContainer.appendChild(textInput);
// Atualiza visibilidade dos campos
const updateFields = () => {
const searchType = searchTypeSelect.value;
textContainer.style.display = ['text', 'selectorAndText'].includes(searchType) ? 'block' : 'none';
};
searchTypeSelect.addEventListener('change', updateFields);
// Botões
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.gap = '10px';
buttonContainer.style.marginTop = '20px';
const addBtn = this.createButton('➕ Adicionar', () => {
const platform = this.detectPlatform() || prompt('🎯 Digite o nome da plataforma:')?.trim();
if (!platform) return;
const searchType = searchTypeSelect.value;
const customText = textInput.value.trim();
let selectorConfig = {
type: searchType
};
switch (searchType) {
case 'selector':
selectorConfig.selector = selector;
break;
case 'text':
selectorConfig.text = customText || elementText.trim();
break;
case 'selectorAndText':
selectorConfig.selector = selector;
selectorConfig.text = customText || elementText.trim();
break;
case 'coordinates':
const rect = element.getBoundingClientRect();
selectorConfig.x = Math.round(rect.left + rect.width / 2);
selectorConfig.y = Math.round(rect.top + rect.height / 2);
break;
}
if (this.addAdvancedSelectorToConfig(platform, selectorConfig, 'extraButtons')) {
this.updateButtonList();
this.log(`Elemento adicionado: ${JSON.stringify(selectorConfig)}`, 'success');
document.body.removeChild(popup);
// Pergunta se deseja configurar modo
if (confirm('🎮 Deseja configurar um modo de clique para este elemento?')) {
// Para busca avançada, usa um ID único baseado na configuração
const uniqueId = JSON.stringify(selectorConfig);
this.showModeSelector(uniqueId);
}
}
}, {
flex: '2',
backgroundColor: '#28a745'
});
const cancelBtn = this.createButton('❌ Cancelar', () => {
document.body.removeChild(popup);
}, {
flex: '1',
backgroundColor: '#6c757d'
});
buttonContainer.appendChild(addBtn);
buttonContainer.appendChild(cancelBtn);
popup.appendChild(title);
popup.appendChild(info);
popup.appendChild(searchTypeContainer);
popup.appendChild(textContainer);
popup.appendChild(buttonContainer);
document.body.appendChild(popup);
updateFields();
}
// =========================
// Adiciona seletor avançado à configuração
// =========================
addAdvancedSelectorToConfig(platform, selectorConfig, buttonType) {
if (!this.config[platform]) {
this.config[platform] = {
skipButton: [],
nextButton: [],
extraButtons: []
};
}
// Verifica se já existe
const existingSelectors = this.config[platform][buttonType] || [];
const configString = JSON.stringify(selectorConfig);
if (existingSelectors.some(s => JSON.stringify(s) === configString)) {
this.log(`Seletor já existe: ${configString}`, 'warning');
return false;
}
// Adiciona novo seletor
existingSelectors.push(selectorConfig);
this.saveConfig();
return true;
}
// =========================
// Localiza elemento usando configuração avançada
// =========================
findElementByAdvancedConfig(config) {
switch (config.type) {
case 'selector':
return document.querySelector(config.selector);
case 'text':
return this.findElementByText(config.text);
case 'selectorAndText':
const candidates = document.querySelectorAll(config.selector);
for (const candidate of candidates) {
const text = candidate.innerText || candidate.textContent || '';
if (text.includes(config.text)) {
return candidate;
}
}
return null;
case 'coordinates':
return document.elementFromPoint(config.x, config.y);
default:
return null;
}
}
// =========================
// Encontra elemento por texto
// =========================
findElementByText(searchText) {
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT, {
acceptNode: function (node) {
if (node.style && node.style.display === 'none') {
return NodeFilter.FILTER_REJECT;
}
const text = node.innerText || node.textContent || '';
return text.toLowerCase().includes(searchText.toLowerCase()) ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
}
);
let node;
while (node = walker.nextNode()) {
// Procura por match exato primeiro
const text = node.innerText || node.textContent || '';
if (text.trim().toLowerCase() === searchText.toLowerCase()) {
return node;
}
}
// Se não encontrou match exato, procura por inclusão
const walker2 = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT, {
acceptNode: function (node) {
if (node.style && node.style.display === 'none') {
return NodeFilter.FILTER_REJECT;
}
const text = node.innerText || node.textContent || '';
return text.toLowerCase().includes(searchText.toLowerCase()) ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
}
);
return walker2.nextNode();
}
// =========================
// Atalho direto para clique em coordenadas (sem seletor)
// =========================
showDirectCoordinateClick() {
this.showCoordinateClick();
}
// =========================
// Pergunta ao usuário qual modo deseja para o seletor
// =========================
// =========================
// Gera seletor CSS melhorado para o elemento
// =========================
generateSelector(element) {
if (!element || !element.tagName) return '';
let selector = element.tagName.toLowerCase();
// Prioriza ID se existir e for único
if (element.id) {
const idSelector = `#${element.id}`;
if (document.querySelectorAll(idSelector).length === 1) {
return idSelector;
}
selector += `#${element.id}`;
}
// Adiciona classes se existirem
if (element.className && typeof element.className === 'string') {
const classes = element.className.split(/\s+/).filter(c => c && !c.match(/^[\d]/));
if (classes.length > 0) {
// Limita a 3 classes mais específicas
const significantClasses = classes.slice(0, 3);
selector += `.${significantClasses.join('.')}`;
}
}
// Adiciona atributos específicos se úteis
const specificAttrs = ['data-testid', 'data-uia', 'aria-label', 'role'];
for (const attr of specificAttrs) {
const value = element.getAttribute(attr);
if (value) {
selector += `[${attr}="${value}"]`;
break; // Usa apenas o primeiro atributo encontrado
}
}
// Verifica se o seletor é único, senão adiciona nth-child
if (document.querySelectorAll(selector).length > 1) {
const parent = element.parentElement;
if (parent) {
const siblings = Array.from(parent.children);
const index = siblings.indexOf(element) + 1;
selector += `:nth-child(${index})`;
}
}
return selector;
}
// =========================
// Handler para edição de texto
// =========================
// =========================
// Cria interface de configuração aprimorada
// =========================
createConfigInterface() {
if (document.getElementById('autoSkipContainer')) return;
// Cria container principal
const container = document.createElement('div');
container.id = 'autoSkipContainer';
container.className = 'auto-skip-container';
Object.assign(container.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '480px',
maxWidth: '95vw',
maxHeight: '90vh',
padding: '20px',
backgroundColor: '#1e1e1e',
color: '#ffffff',
borderRadius: '12px',
zIndex: '10000',
fontFamily: 'Arial, sans-serif',
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4)',
display: 'none',
overflowY: 'auto',
overflowX: 'hidden',
cursor: 'move',
border: '2px solid #007bff'
});
// Torna container arrastável
this.makeDraggable(container);
// Cria botão de alternância
const toggleButton = this.createToggleButton();
// Header com título e estatísticas
const header = document.createElement('div');
header.style.display = 'flex';
header.style.justifyContent = 'space-between';
header.style.alignItems = 'center';
header.style.marginBottom = '20px';
header.style.borderBottom = '1px solid #333';
header.style.paddingBottom = '10px';
const title = document.createElement('h3');
title.textContent = '⚙️ Auto Skip Pro v3.1';
title.style.margin = '0';
title.style.color = '#007bff';
title.style.fontSize = '18px';
const stats = document.createElement('div');
stats.id = 'autoSkipStats';
stats.textContent = `Cliques: ${this.clickCounter}`;
stats.style.color = '#28a745';
stats.style.fontSize = '14px';
stats.style.fontWeight = 'bold';
header.appendChild(title);
header.appendChild(stats);
container.appendChild(header);
// Info de plataforma detectada
const platformInfo = document.createElement('div');
platformInfo.style.marginBottom = '15px';
platformInfo.style.padding = '8px';
platformInfo.style.backgroundColor = '#2d2d2d';
platformInfo.style.borderRadius = '6px';
platformInfo.style.border = '1px solid #444';
const detectedPlatform = this.detectPlatform();
platformInfo.innerHTML = `
<strong>🎯 Plataforma:</strong> ${detectedPlatform || 'Não detectada'}<br>
<strong>🌐 URL:</strong> ${window.location.hostname}
`;
container.appendChild(platformInfo);
// Seleção de plataforma
const platformSelect = this.createPlatformSelect();
container.appendChild(platformSelect);
// Controles de debug
const debugControls = this.createDebugControls();
container.appendChild(debugControls);
// Lista de botões
const buttonList = document.createElement('div');
buttonList.id = 'autoSkipButtonList';
buttonList.style.marginBottom = '15px';
container.appendChild(buttonList);
// Botões de ação
const actionButtons = this.createActionButtons(platformSelect);
container.appendChild(actionButtons);
// Instruções de uso
const instructions = this.createInstructions();
container.appendChild(instructions);
// Adiciona ao documento
document.body.appendChild(container);
document.body.appendChild(toggleButton);
// Cria botão flutuante
this.createFloatingButton();
// Inicializa UI
this.updatePlatformSelect();
this.updateButtonList();
// Seleciona plataforma baseada na URL atual
if (detectedPlatform && platformSelect.querySelector(`option[value="${detectedPlatform}"]`)) {
platformSelect.value = detectedPlatform;
this.updateButtonList();
}
}
// =========================
// Cria botão flutuante para acesso rápido
// =========================
createFloatingButton() {
// Remove botão existente se houver
const existing = document.getElementById('autoSkipFloatingBtn');
if (existing) {
existing.remove();
}
const button = document.createElement('div');
button.id = 'autoSkipFloatingBtn';
Object.assign(button.style, {
position: 'fixed',
bottom: '20px',
right: '20px',
width: '50px',
height: '50px',
backgroundColor: '#3182ce',
color: 'white',
border: 'none',
borderRadius: '50%',
cursor: 'pointer',
zIndex: '999998',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '20px',
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
transition: 'all 0.3s ease',
userSelect: 'none'
});
button.innerHTML = '🎬';
button.title = 'AutoSkip Pro - Clique para abrir interface (Ctrl+Alt+S)';
// Efeitos hover
button.onmouseenter = () => {
button.style.transform = 'scale(1.1)';
button.style.backgroundColor = '#2c5aa0';
};
button.onmouseleave = () => {
button.style.transform = 'scale(1)';
button.style.backgroundColor = '#3182ce';
};
// Clique para abrir interface
button.onclick = () => {
this.toggleConfigInterface();
};
document.body.appendChild(button);
console.log('🎬 Botão flutuante criado!');
}
// =========================
// Cria controles de debug
// =========================
createDebugControls() {
const container = document.createElement('div');
container.style.marginBottom = '15px';
container.style.padding = '10px';
container.style.backgroundColor = '#2d2d2d';
container.style.borderRadius = '6px';
container.style.display = 'flex';
container.style.gap = '10px';
container.style.alignItems = 'center';
const debugLabel = document.createElement('span');
debugLabel.textContent = '🔍 Debug:';
debugLabel.style.fontWeight = 'bold';
const debugToggle = document.createElement('input');
debugToggle.type = 'checkbox';
debugToggle.checked = this.debugMode;
debugToggle.addEventListener('change', () => {
this.debugMode = debugToggle.checked;
this.log(`Modo debug ${this.debugMode ? 'ativado' : 'desativado'}`, 'info');
});
const historyBtn = this.createButton('📋 Histórico', () => {
this.showClickHistory();
}, {
padding: '4px 8px',
fontSize: '12px',
backgroundColor: '#6c757d'
});
const clearBtn = this.createButton('🗑️ Limpar', () => {
if (confirm('Limpar histórico de cliques?')) {
this.clickHistory.clear();
this.lastClickTime.clear();
this.log('Histórico limpo', 'info');
}
}, {
padding: '4px 8px',
fontSize: '12px',
backgroundColor: '#dc3545'
});
container.appendChild(debugLabel);
container.appendChild(debugToggle);
container.appendChild(historyBtn);
container.appendChild(clearBtn);
return container;
}
// =========================
// Cria botões de ação
// =========================
createActionButtons(platformSelect) {
const container = document.createElement('div');
container.style.display = 'grid';
container.style.gridTemplateColumns = '1fr 1fr';
container.style.gap = '10px';
container.style.marginBottom = '15px';
const addSelectorBtn = this.createButton('➕ Adicionar Seletor', () => {
const newSelector = prompt('🎯 Digite o seletor CSS:');
if (newSelector) {
const platform = platformSelect.value;
if (this.addSelectorToConfig(platform, newSelector, 'extraButtons')) {
this.log(`Seletor adicionado: ${newSelector}`, 'success');
this.updateButtonList();
}
else {
this.log(`Seletor já existe: ${newSelector}`, 'warning');
}
}
});
const addPlatformBtn = this.createButton('🌐 Nova Plataforma', () => {
const newPlatform = prompt('🆕 Nome da nova plataforma:');
if (newPlatform && newPlatform.trim()) {
this.config[newPlatform.trim()] = {
skipButton: [],
nextButton: [],
extraButtons: []
};
this.saveConfig();
this.updatePlatformSelect();
platformSelect.value = newPlatform.trim();
this.updateButtonList();
this.log(`Plataforma adicionada: ${newPlatform}`, 'success');
}
});
const scanBtn = this.createButton('🔍 Buscar Elementos', () => {
this.scanForSkipElements();
}, {
backgroundColor: '#17a2b8'
});
const clearDataBtn = this.createButton('🗑️ Limpar Dados', () => {
const platform = platformSelect.value;
if (confirm(`❌ Limpar todos os dados da plataforma "${platform}"?`)) {
this.clearPlatformData(platform);
this.updatePlatformSelect();
this.updateButtonList();
this.log(`Dados limpos para: ${platform}`, 'warning');
}
}, {
backgroundColor: '#dc3545'
});
container.appendChild(addSelectorBtn);
container.appendChild(addPlatformBtn);
container.appendChild(scanBtn);
container.appendChild(clearDataBtn);
return container;
}
// =========================
// Busca elementos automaticamente
// =========================
scanForSkipElements() {
this.log('🔍 Iniciando busca automática por elementos...', 'info');
const searchTerms = [
'skip', 'pular', 'próximo', 'next', 'continuar', 'continue',
'intro', 'abertura', 'anúncio', 'ad', 'advertisement'
];
let foundElements = 0;
const platform = this.detectPlatform() || 'Generic';
searchTerms.forEach(term => {
const elements = this.findElementsByText(term);
elements.forEach(element => {
const selector = this.generateSelector(element);
if (this.addSelectorToConfig(platform, selector, 'extraButtons')) {
foundElements++;
this.log(`Elemento encontrado: "${element.textContent?.trim()}" (${selector})`, 'success');
this.highlightElement(element, 1000);
}
});
});
if (foundElements > 0) {
this.updateButtonList();
this.log(`✅ Busca concluída: ${foundElements} elementos encontrados`, 'success');
}
else {
this.log('ℹ️ Nenhum elemento novo encontrado', 'info');
}
}
// =========================
// Cria instruções de uso
// =========================
createInstructions() {
const container = document.createElement('div');
container.style.marginTop = '15px';
container.style.padding = '10px';
container.style.backgroundColor = '#2d2d2d';
container.style.borderRadius = '6px';
container.style.fontSize = '12px';
container.style.lineHeight = '1.4';
container.innerHTML = `
<strong>📖 Instruções de Uso:</strong><br>
• <kbd>Alt + Click</kbd>: Adicionar elemento (com opções avançadas)<br>
• <kbd>Shift + Alt + Click</kbd>: Testar elemento<br>
• <kbd>Ctrl + Alt + S</kbd>: Abrir/fechar interface<br>
• <kbd>Ctrl + Alt + D</kbd>: Alternar debug + rastreamento mouse<br>
• <kbd>Ctrl + Alt + R</kbd>: Ver histórico<br>
• <kbd>Ctrl + Alt + C</kbd>: Clicar em coordenadas (popup completo)<br>
• <kbd>Ctrl + Alt + Q</kbd>: 🎯 Clique direto em coordenadas<br>
• <kbd>Ctrl + Alt + M</kbd>: Alternar rastreamento do mouse<br>
• <kbd>Ctrl + Alt + X</kbd>: 🚨 PARAR clique infinito<br>
• Use os botões "Modos" para configurar ações<br>
• <strong>🎯 Novo:</strong> Busca por texto, seletor+texto e coordenadas!<br>
• <strong>⚡ Ultra-Fast:</strong> Clique Rápido, Infinito e por Tempo disponíveis!
`;
return container;
}
// =========================
// Cria botão de alternância (toggle) melhorado
// =========================
createToggleButton() {
const button = document.createElement('button');
button.id = 'autoSkipToggle';
button.innerHTML = '⚙️'; // Emoji de engrenagem
Object.assign(button.style, {
position: 'fixed',
top: '15px',
right: '15px',
padding: '8px',
width: '40px',
height: '40px',
backgroundColor: '#007bff',
color: '#ffffff',
border: 'none',
borderRadius: '50%',
cursor: 'pointer',
zIndex: '10001',
fontWeight: 'bold',
boxShadow: '0 4px 12px rgba(0, 123, 255, 0.3)',
fontSize: '16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
opacity: '0.8',
transition: 'all 0.3s ease',
border: '2px solid rgba(255, 255, 255, 0.2)'
});
// Efeitos de hover
button.addEventListener('mouseover', () => {
button.style.opacity = '1';
button.style.transform = 'scale(1.1)';
button.style.boxShadow = '0 6px 16px rgba(0, 123, 255, 0.4)';
});
button.addEventListener('mouseout', () => {
button.style.opacity = '0.8';
button.style.transform = 'scale(1)';
button.style.boxShadow = '0 4px 12px rgba(0, 123, 255, 0.3)';
});
// Tooltip
button.title = 'Auto Skip Pro - Ctrl+Alt+S para alternar';
button.addEventListener('click', () => {
this.toggleConfigInterface();
});
return button;
}
// =========================
// Torna elemento arrastável
// =========================
makeDraggable(element) {
let isDragging = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
element.addEventListener('mousedown', dragStart);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', dragEnd);
function dragStart(e) {
// Ignora se for input ou botão
if (e.target.tagName.toLowerCase() === 'input' ||
e.target.tagName.toLowerCase() === 'button' ||
e.target.tagName.toLowerCase() === 'select') {
return;
}
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
if (e.target === element) {
isDragging = true;
}
}
function drag(e) {
if (isDragging) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
// Limita ao tamanho da janela
const rect = element.getBoundingClientRect();
const maxX = window.innerWidth - rect.width;
const maxY = window.innerHeight - rect.height;
currentX = Math.min(Math.max(currentX, 0), maxX);
currentY = Math.min(Math.max(currentY, 0), maxY);
setTranslate(currentX, currentY, element);
}
}
function setTranslate(xPos, yPos, el) {
el.style.transform = `translate(${xPos}px, ${yPos}px)`;
}
function dragEnd() {
isDragging = false;
}
}
// =========================
// Cria dropdown de plataformas
// =========================
createPlatformSelect() {
const select = document.createElement('select');
select.id = 'autoSkipPlatformSelect';
Object.assign(select.style, {
width: '100%',
padding: '8px',
marginBottom: '15px',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: '#ffffff',
border: '1px solid #4d4d4d'
});
select.addEventListener('change', () => this.updateButtonList());
return select;
}
// =========================
// Atualiza opções do dropdown de plataformas
// =========================
updatePlatformSelect() {
const select = document.getElementById('autoSkipPlatformSelect');
if (!select) return;
const currentValue = select.value;
select.innerHTML = '';
Object.keys(this.config).forEach(platform => {
const option = document.createElement('option');
option.value = platform;
option.textContent = platform;
select.appendChild(option);
});
if (currentValue && select.querySelector(`option[value="${currentValue}"]`)) {
select.value = currentValue;
}
}
// =========================
// Cria botão estilizado
// =========================
createButton(text, onClick, customStyles = {}) {
const button = document.createElement('button');
button.textContent = text;
Object.assign(button.style, {
padding: '8px',
backgroundColor: '#5bc0de',
color: '#ffffff',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontWeight: 'bold',
...customStyles
});
button.addEventListener('click', onClick);
return button;
}
// =========================
// Atualiza lista de seletores configurados com interface melhorada
// =========================
updateButtonList() {
const platform = document.getElementById('autoSkipPlatformSelect')?.value;
const buttonList = document.getElementById('autoSkipButtonList');
if (!platform || !buttonList) return;
buttonList.innerHTML = '<h4 style="margin: 0 0 15px 0; color: #007bff; font-size: 16px;">🎯 Seletores Configurados:</h4>';
const {
skipButton = [], nextButton = [], extraButtons = []
} = this.config[platform] || {};
const allSelectors = [
...skipButton.map(s => ({
selector: s,
type: 'pular',
color: '#ffc107',
emoji: '⏭️'
})),
...nextButton.map(s => ({
selector: s,
type: 'próximo',
color: '#28a745',
emoji: '▶️'
})),
...extraButtons.map(s => ({
selector: s,
type: 'extra',
color: '#17a2b8',
emoji: '🎯'
}))
];
if (allSelectors.length === 0) {
buttonList.innerHTML += '<p style="margin: 0; color: #aaa; font-style: italic; text-align: center; padding: 20px;">📭 Nenhum seletor configurado para esta plataforma</p>';
return;
}
allSelectors.forEach(({
selector,
type,
color,
emoji
}, index) => {
const item = document.createElement('div');
Object.assign(item.style, {
display: 'grid',
gridTemplateColumns: '40px 1fr auto',
gap: '10px',
alignItems: 'center',
marginBottom: '12px',
padding: '12px',
backgroundColor: '#2d2d2d',
borderRadius: '8px',
border: `2px solid ${color}20`,
borderLeft: `4px solid ${color}`,
transition: 'all 0.2s ease'
});
// Tipo com emoji
const typeInfo = document.createElement('div');
typeInfo.innerHTML = `
<div style="text-align: center;">
<div style="font-size: 18px; margin-bottom: 2px;">${emoji}</div>
<div style="font-size: 10px; color: ${color}; font-weight: bold; text-transform: uppercase;">${type}</div>
</div>
`;
// Informações do seletor
const selectorInfo = document.createElement('div');
const mode = this.modes[selector];
const checkMode = mode?.checkMode || 'continuous';
const actionMode = mode?.mode || 'automático';
selectorInfo.innerHTML = `
<div style="font-family: monospace; font-size: 12px; color: #fff; margin-bottom: 4px; word-break: break-all;">${selector}</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<span style="background: #333; padding: 2px 6px; border-radius: 3px; font-size: 11px; color: #aaa;">
🔄 ${checkMode === 'continuous' ? 'Contínuo' : 'Ao Carregar'}
</span>
<span style="background: ${color}30; color: ${color}; padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: bold;">
🎮 ${actionMode}
</span>
</div>
`;
// Controles
const controls = document.createElement('div');
Object.assign(controls.style, {
display: 'flex',
flexDirection: 'column',
gap: '6px',
alignItems: 'flex-end'
});
const topControls = document.createElement('div');
topControls.style.display = 'flex';
topControls.style.gap = '4px';
const bottomControls = document.createElement('div');
bottomControls.style.display = 'flex';
bottomControls.style.gap = '4px';
const smallBtnStyle = {
padding: '4px 8px',
fontSize: '11px',
borderRadius: '4px',
border: 'none',
cursor: 'pointer',
color: '#fff',
fontWeight: 'bold',
minWidth: '60px'
};
// Botão de teste
const testBtn = this.createButton('🧪 Teste', () => {
const element = document.querySelector(selector);
if (element) {
this.highlightElement(element, 3000);
this.log(`Teste bem-sucedido: ${selector}`, 'success');
// Scroll para o elemento se necessário
element.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
else {
this.log(`Teste falhou: elemento não encontrado - ${selector}`, 'error');
alert('❌ Elemento não encontrado na página atual!');
}
}, {
...smallBtnStyle,
backgroundColor: '#28a745'
});
// Botão de modos
const modeBtn = this.createButton('🎮 Modos', () => {
this.showModeSelector(selector);
}, {
...smallBtnStyle,
backgroundColor: '#17a2b8'
});
// Botão de executar agora
const runBtn = this.createButton('▶️ Executar', () => {
if (this.isElementVisible(selector)) {
this.executeMode(selector);
this.log(`Execução manual: ${selector}`, 'info');
}
else {
this.log(`Não pode executar: elemento não visível - ${selector}`, 'warning');
alert('⚠️ Elemento não está visível no momento!');
}
}, {
...smallBtnStyle,
backgroundColor: '#ffc107',
color: '#000'
});
// Botão de remover
const removeBtn = this.createButton('🗑️', () => {
if (confirm(`❌ Remover seletor:\n"${selector}"?`)) {
this.removeSelector(platform, selector);
this.updateButtonList();
this.log(`Seletor removido: ${selector}`, 'warning');
}
}, {
...smallBtnStyle,
backgroundColor: '#dc3545',
minWidth: '32px'
});
topControls.appendChild(testBtn);
topControls.appendChild(modeBtn);
bottomControls.appendChild(runBtn);
bottomControls.appendChild(removeBtn);
controls.appendChild(topControls);
controls.appendChild(bottomControls);
item.appendChild(typeInfo);
item.appendChild(selectorInfo);
item.appendChild(controls);
// Hover effect
item.addEventListener('mouseenter', () => {
item.style.backgroundColor = '#333';
item.style.borderColor = color + '40';
});
item.addEventListener('mouseleave', () => {
item.style.backgroundColor = '#2d2d2d';
item.style.borderColor = color + '20';
});
buttonList.appendChild(item);
});
// Adiciona resumo
const summary = document.createElement('div');
summary.style.marginTop = '15px';
summary.style.padding = '10px';
summary.style.backgroundColor = '#1a1a1a';
summary.style.borderRadius = '6px';
summary.style.fontSize = '12px';
summary.style.textAlign = 'center';
summary.style.color = '#aaa';
const totalSelectors = allSelectors.length;
const activeSelectors = allSelectors.filter(({
selector
}) => this.modes[selector]).length;
summary.innerHTML = `
📊 <strong>Resumo:</strong> ${totalSelectors} seletores configurados |
${activeSelectors} com modos ativos |
${this.clickCounter} cliques executados
`;
buttonList.appendChild(summary);
}
// =========================
// Mostra popup de seleção de modo
// =========================
showModeSelector(selector) {
const popup = document.createElement('div');
popup.className = 'auto-skip-popup';
Object.assign(popup.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '300px',
padding: '20px',
backgroundColor: '#2d2d2d',
color: '#ffffff',
borderRadius: '8px',
zIndex: '10002',
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.3)'
});
const title = document.createElement('h3');
title.textContent = 'Selecione o Modo de Ação';
title.style.marginTop = '0';
title.style.color = '#ffffff';
popup.appendChild(title);
const modes = [{
id: 'clickAutomatically',
label: 'Clicar Automaticamente'
},
{
id: 'clickOnce',
label: 'Clicar Uma Vez'
},
{
id: 'clickRepeatedly',
label: 'Clicar Repetidamente'
},
{
id: 'clickAndHold',
label: 'Clicar e Segurar'
},
{
id: 'clickAndDrag',
label: 'Clicar e Arrastar'
},
{
id: 'clickAtCoordinates',
label: 'Clicar em Coordenadas'
}
];
modes.forEach(mode => {
const btn = this.createButton(mode.label, () => {
document.body.removeChild(popup);
this.showModeConfig(mode.id, selector);
}, {
width: '100%',
marginBottom: '8px',
backgroundColor: this.modes[selector]?.mode === mode.id ? '#5cb85c' : '#5bc0de'
});
popup.appendChild(btn);
});
const closeBtn = this.createButton('Fechar', () => {
document.body.removeChild(popup);
}, {
width: '100%',
backgroundColor: '#6c757d'
});
popup.appendChild(closeBtn);
document.body.appendChild(popup);
}
// =========================
// Mostra popup de configuração do modo aprimorado
// =========================
showModeConfig(mode, selector) {
const popup = document.createElement('div');
popup.className = 'auto-skip-popup';
Object.assign(popup.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '450px',
minWidth: '320px',
maxWidth: '90vw',
maxHeight: '90vh',
padding: '25px',
backgroundColor: '#1e1e1e',
color: '#ffffff',
borderRadius: '12px',
zIndex: '10002',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5)',
overflowY: 'auto',
border: '2px solid #007bff'
});
const title = document.createElement('h3');
title.textContent = `🎮 Configurar ${mode.replace(/([A-Z])/g, ' $1')}`;
title.style.marginTop = '0';
title.style.color = '#007bff';
title.style.marginBottom = '20px';
popup.appendChild(title);
// Mostra seletor atual
const selectorInfo = document.createElement('div');
selectorInfo.innerHTML = `<strong>🎯 Seletor:</strong> <code style="background: #333; padding: 2px 6px; border-radius: 3px;">${selector}</code>`;
selectorInfo.style.marginBottom = '20px';
selectorInfo.style.fontSize = '14px';
popup.appendChild(selectorInfo);
const form = document.createElement('div');
// Configuração comum para todos os modos
const modeConfig = {
mode,
selector
};
// Modo de verificação
const checkModeContainer = document.createElement('div');
checkModeContainer.style.marginBottom = '15px';
const checkModeLabel = document.createElement('label');
checkModeLabel.textContent = '🔄 Modo de Verificação:';
checkModeLabel.style.display = 'block';
checkModeLabel.style.marginBottom = '8px';
checkModeLabel.style.fontWeight = 'bold';
const checkModeSelect = document.createElement('select');
Object.assign(checkModeSelect.style, {
width: '100%',
padding: '8px',
backgroundColor: '#333',
color: '#fff',
border: '1px solid #555',
borderRadius: '6px'
});
const contOption = document.createElement('option');
contOption.value = 'continuous';
contOption.textContent = 'Verificação Contínua (recomendado)';
const loadOption = document.createElement('option');
loadOption.value = 'onLoad';
loadOption.textContent = 'Apenas ao Carregar Página';
checkModeSelect.appendChild(contOption);
checkModeSelect.appendChild(loadOption);
checkModeSelect.value = this.modes[selector]?.checkMode || 'continuous';
checkModeContainer.appendChild(checkModeLabel);
checkModeContainer.appendChild(checkModeSelect);
form.appendChild(checkModeContainer);
// Adiciona campos específicos baseados no modo
switch (mode) {
case 'clickOnce':
form.appendChild(this.createNumberInput('⏱️ Delay após clique (ms):', 'delay', this.modes[selector]?.delay || 500));
break;
case 'clickRepeatedly':
form.appendChild(this.createNumberInput('⏱️ Intervalo entre cliques (ms):', 'interval', this.modes[selector]?.interval || 1000));
form.appendChild(this.createNumberInput('🔢 Quantidade de cliques:', 'count', this.modes[selector]?.count || 5));
break;
case 'clickAndHold':
form.appendChild(this.createNumberInput('⏰ Duração do clique (ms):', 'duration', this.modes[selector]?.duration || 1000));
break;
case 'clickAndDrag':
form.appendChild(this.createNumberInput('📍 Início X:', 'startX', this.modes[selector]?.startX || 0));
form.appendChild(this.createNumberInput('📍 Início Y:', 'startY', this.modes[selector]?.startY || 0));
form.appendChild(this.createNumberInput('📍 Fim X:', 'endX', this.modes[selector]?.endX || 100));
form.appendChild(this.createNumberInput('📍 Fim Y:', 'endY', this.modes[selector]?.endY || 100));
break;
case 'clickAtCoordinates':
// Modo de clique para coordenadas
const clickModeContainer = document.createElement('div');
clickModeContainer.style.marginBottom = '15px';
const clickModeLabel = document.createElement('label');
clickModeLabel.textContent = '🎮 Modo de Clique:';
clickModeLabel.style.display = 'block';
clickModeLabel.style.marginBottom = '6px';
clickModeLabel.style.fontWeight = 'bold';
const clickModeSelect = document.createElement('select');
clickModeSelect.name = 'clickMode';
Object.assign(clickModeSelect.style, {
width: '100%',
padding: '8px',
backgroundColor: '#333',
color: '#fff',
border: '1px solid #555',
borderRadius: '6px'
});
const clickModeOptions = [{
value: 'once',
text: 'Clicar Uma Vez'
},
{
value: 'repeatedly',
text: 'Clicar Repetidamente'
},
{
value: 'hold',
text: 'Clicar e Segurar'
},
{
value: 'rapidFire',
text: 'Clique Rápido (Ultra Fast)'
},
{
value: 'infinite',
text: 'Clique Infinito'
},
{
value: 'timedInfinite',
text: 'Clique Infinito por Tempo'
}
];
clickModeOptions.forEach(option => {
const opt = document.createElement('option');
opt.value = option.value;
opt.textContent = option.text;
clickModeSelect.appendChild(opt);
});
clickModeSelect.value = this.modes[selector]?.clickMode || 'once';
clickModeContainer.appendChild(clickModeLabel);
clickModeContainer.appendChild(clickModeSelect);
form.appendChild(clickModeContainer);
// Campos básicos
form.appendChild(this.createNumberInput('📍 Coordenada X:', 'x', this.modes[selector]?.x || this.mouseTracker.x || 100));
form.appendChild(this.createNumberInput('📍 Coordenada Y:', 'y', this.modes[selector]?.y || this.mouseTracker.y || 100));
form.appendChild(this.createNumberInput('⏱️ Delay antes do clique (ms):', 'delay', this.modes[selector]?.delay || 1000));
// Campos condicionais
const conditionalContainer = document.createElement('div');
conditionalContainer.id = 'coordinateConditionals';
const updateConditionals = () => {
conditionalContainer.innerHTML = '';
const selectedMode = clickModeSelect.value;
if (selectedMode === 'repeatedly') {
conditionalContainer.appendChild(this.createNumberInput('🔢 Quantidade de cliques:', 'count', this.modes[selector]?.count || 5));
conditionalContainer.appendChild(this.createNumberInput('⏱️ Intervalo entre cliques (ms):', 'interval', this.modes[selector]?.interval || 1000));
}
else if (selectedMode === 'hold') {
conditionalContainer.appendChild(this.createNumberInput('⏰ Duração do clique (ms):', 'duration', this.modes[selector]?.duration || 2000));
}
else if (selectedMode === 'rapidFire') {
conditionalContainer.appendChild(this.createNumberInput('🔢 Quantidade de cliques:', 'count', this.modes[selector]?.count || 10));
conditionalContainer.appendChild(this.createNumberInput('⚡ Intervalo ultra-rápido (ms):', 'interval', this.modes[selector]?.interval || 50));
const warning = document.createElement('div');
warning.innerHTML = '<strong style="color: #ff6600;">⚠️ Modo ultra-rápido! Use com moderação.</strong>';
warning.style.padding = '8px';
warning.style.backgroundColor = '#2d2d2d';
warning.style.borderRadius = '4px';
warning.style.marginTop = '8px';
conditionalContainer.appendChild(warning);
}
else if (selectedMode === 'infinite') {
conditionalContainer.appendChild(this.createNumberInput('⚡ Intervalo entre cliques (ms):', 'interval', this.modes[selector]?.interval || 100));
const warning = document.createElement('div');
warning.innerHTML = '<strong style="color: #ff0000;">🚨 CLIQUE INFINITO! Use Ctrl+Alt+X para parar!</strong>';
warning.style.padding = '10px';
warning.style.backgroundColor = '#2d1a1a';
warning.style.borderRadius = '4px';
warning.style.marginTop = '8px';
warning.style.border = '2px solid #ff0000';
conditionalContainer.appendChild(warning);
}
else if (selectedMode === 'timedInfinite') {
conditionalContainer.appendChild(this.createNumberInput('⚡ Intervalo entre cliques (ms):', 'interval', this.modes[selector]?.interval || 100));
conditionalContainer.appendChild(this.createNumberInput('⏰ Duração total (segundos):', 'duration', this.modes[selector]?.duration || 30));
const warning = document.createElement('div');
warning.innerHTML = '<strong style="color: #ff6600;">⚠️ Clique infinito com limite de tempo</strong>';
warning.style.padding = '8px';
warning.style.backgroundColor = '#2d2d2d';
warning.style.borderRadius = '4px';
warning.style.marginTop = '8px';
conditionalContainer.appendChild(warning);
}
};
clickModeSelect.addEventListener('change', updateConditionals);
updateConditionals();
form.appendChild(conditionalContainer);
break;
}
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.gap = '10px';
buttonContainer.style.marginTop = '20px';
const testBtn = this.createButton('🧪 Testar', () => {
const element = document.querySelector(selector);
if (element) {
this.highlightElement(element, 3000);
this.log(`Teste: elemento encontrado para ${selector}`, 'success');
}
else {
this.log(`Teste: elemento NÃO encontrado para ${selector}`, 'error');
alert('❌ Elemento não encontrado na página atual!');
}
}, {
flex: '1',
backgroundColor: '#17a2b8'
});
const saveBtn = this.createButton('💾 Salvar', () => {
// Coleta todos os valores do formulário
const inputs = form.querySelectorAll('input, select');
inputs.forEach(input => {
if (input.name && input.value) {
const value = input.type === 'number' ? parseInt(input.value, 10) : input.value;
modeConfig[input.name] = value;
}
});
// Adiciona modo de verificação
modeConfig.checkMode = checkModeSelect.value;
// Salva modo
this.modes[selector] = modeConfig;
this.saveModes();
document.body.removeChild(popup);
// Atualiza UI
this.updateButtonList();
this.log(`Modo configurado: ${mode} para ${selector}`, 'success');
}, {
flex: '2',
backgroundColor: '#28a745'
});
const cancelBtn = this.createButton('❌ Cancelar', () => {
document.body.removeChild(popup);
}, {
flex: '1',
backgroundColor: '#6c757d'
});
buttonContainer.appendChild(testBtn);
buttonContainer.appendChild(saveBtn);
buttonContainer.appendChild(cancelBtn);
popup.appendChild(form);
popup.appendChild(buttonContainer);
document.body.appendChild(popup);
}
// =========================
// Cria campo de input numérico aprimorado
// =========================
createNumberInput(label, name, defaultValue) {
const container = document.createElement('div');
container.style.marginBottom = '15px';
const labelEl = document.createElement('label');
labelEl.textContent = label;
labelEl.style.display = 'block';
labelEl.style.marginBottom = '6px';
labelEl.style.color = '#ffffff';
labelEl.style.fontWeight = 'bold';
labelEl.style.fontSize = '14px';
const input = document.createElement('input');
input.type = 'number';
input.name = name;
input.value = defaultValue;
input.min = name.includes('X') || name.includes('Y') ? '-1000' : '0';
input.max = name.includes('X') || name.includes('Y') ? '2000' : '10000';
input.step = name.includes('interval') || name.includes('delay') || name.includes('duration') ? '100' : '1';
Object.assign(input.style, {
width: '100%',
padding: '10px',
backgroundColor: '#333',
color: '#ffffff',
border: '1px solid #555',
borderRadius: '6px',
fontSize: '14px',
boxSizing: 'border-box'
});
// Adiciona dicas para alguns campos
const hints = {
'interval': 'Tempo entre cada clique (recomendado: 1000-3000ms)',
'delay': 'Tempo de espera após o clique (recomendado: 500-2000ms)',
'duration': 'Tempo que o botão ficará pressionado (recomendado: 1000-3000ms)',
'count': 'Número de vezes que será clicado (recomendado: 3-10)'
};
if (hints[name]) {
const hint = document.createElement('small');
hint.textContent = hints[name];
hint.style.color = '#aaa';
hint.style.fontSize = '12px';
hint.style.display = 'block';
hint.style.marginTop = '4px';
container.appendChild(labelEl);
container.appendChild(input);
container.appendChild(hint);
}
else {
container.appendChild(labelEl);
container.appendChild(input);
}
return container;
}
}
// ============================================================
// Inicializa AutoSkip ao carregar a página com melhor controle
// ============================================================
function initAutoSkip() {
// Previne múltiplas inicializações
if (window.autoSkip) {
console.log('🎬 AutoSkip já inicializado');
return;
}
const init = () => {
try {
window.autoSkip = new AutoSkip();
console.log('🎬 AutoSkip Pro v3.1 inicializado com sucesso!');
console.log('🔧 Teclas de atalho disponíveis:');
console.log(' • Ctrl+Alt+S: Abrir/fechar interface');
console.log(' • Ctrl+Alt+D: Alternar modo debug');
console.log(' • Ctrl+Alt+R: Ver histórico de cliques');
console.log(' • Ctrl+Alt+C: Popup de coordenadas');
console.log(' • Ctrl+Alt+Q: Clique direto em coordenadas');
console.log(' • Ctrl+Alt+M: Alternar rastreamento do mouse');
console.log(' • Ctrl+Alt+X: Parar clique infinito');
console.log(' • Ctrl+Alt+T: Testar todos os atalhos');
console.log(' • Alt+Click: Adicionar elemento');
console.log(' • Shift+Alt+Click: Testar elemento');
}
catch (error) {
console.error('❌ Erro ao inicializar AutoSkip:', error);
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
}
else {
// Pequeno delay para garantir que a página esteja totalmente pronta
setTimeout(init, 100);
}
}
// Executa inicialização
initAutoSkip();
// Logs finais para debug
console.log('%c🎬 AutoSkip Pro v3.1 Ultra-Fast carregado!', 'color: #007bff; font-size: 16px; font-weight: bold;');
console.log('%cNovos recursos v3.1 Ultra-Fast Edition:', 'color: #28a745; font-weight: bold;');
console.log('• ✅ Cliques 2.5x mais rápidos (cooldown reduzido para 800ms)');
console.log('• ✅ Verificação acelerada (intervalo de 500ms)');
console.log('• ⚡ NOVO: Clique Ultra-Rápido (50ms de intervalo)');
console.log('• 🚨 NOVO: Clique Infinito (com atalho Ctrl+Alt+X para parar)');
console.log('• ⏰ NOVO: Clique Infinito por Tempo Limitado');
console.log('• 🎯 Cliques diretos em coordenadas SEM esperar elementos');
console.log('• ✅ Sistema de salvamento melhorado com versionamento');
console.log('• ✅ Rastreamento de mouse em tempo real (debug)');
console.log('• ✅ Atalhos: Ctrl+Alt+C (coordenadas), Ctrl+Alt+X (parar infinito)');
console.log('• ✅ Detecção inteligente de elementos por texto');
console.log('• ✅ Sistema de cooldown anti-spam otimizado');
console.log('• ✅ Interface aprimorada com estatísticas');
console.log('• ✅ Busca automática de elementos');
console.log('• ✅ Logging detalhado com timestamps');
console.log('• ✅ Múltiplos modos de clique configuráveis');
console.log('• ✅ Destacar elementos testados');
console.log('• ✅ Histórico de cliques');
console.log('• ✅ Teclas de atalho para controle rápido');