Sistema avançado com clique preciso 100% sincronizado, controle de rede robusto e multi-salas sem limites
// ==UserScript==
// @name Gartic Bots
// @namespace http://tampermonkey.net/
// @version 2.3
// @description Sistema avançado com clique preciso 100% sincronizado, controle de rede robusto e multi-salas sem limites
// @author TheEnd
// @match https://gartic.com.br/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// =============================================
// SISTEMA DE SALVAMENTO DE CONFIGURAÇÕES
// =============================================
class ConfigManager {
constructor() {
this.config = {
nickPrefix: 'Player',
lastRoom: null,
menuMinimized: false,
defaultTabCount: 5,
useExternalTabs: false,
externalTabCount: 0,
multiRoomIframeCount: 0,
multiRoomExternalCount: 0,
selectedRooms: [],
disableRandomNumbers: false,
// NOVO: Configurações avançadas
syncPrecision: 'high',
networkControlMode: 'advanced',
maxTabLimit: 1000,
autoRetryAttempts: 3,
preventMultipleClicks: true,
clickDelayRange: [0, 10],
useRequestAnimationFrame: true,
usePerformanceNow: true,
randomRoomSelection: true,
maxRandomRooms: 30,
intelligentDistribution: true,
// NOVA OPÇÃO: Filtrar apenas salas vazias (desativado por padrão)
onlyEmptyRooms: false
};
this.loadConfig();
}
loadConfig() {
try {
const saved = localStorage.getItem('garticMultiConfig');
if (saved) {
this.config = { ...this.config, ...JSON.parse(saved) };
}
} catch (e) {
console.log('❌ Erro ao carregar configurações:', e);
}
}
saveConfig() {
try {
localStorage.setItem('garticMultiConfig', JSON.stringify(this.config));
} catch (e) {
console.log('❌ Erro ao salvar configurações:', e);
}
}
get(key) {
return this.config[key];
}
set(key, value) {
this.config[key] = value;
this.saveConfig();
}
// NOVO: Métodos para configurações de sincronização
getSyncPrecisionValue() {
const precisionMap = {
'low': { delay: 50, useRAF: false, usePN: false },
'medium': { delay: 20, useRAF: true, usePN: false },
'high': { delay: 5, useRAF: true, usePN: true },
'ultra': { delay: 0, useRAF: true, usePN: true }
};
return precisionMap[this.config.syncPrecision] || precisionMap.high;
}
}
// =============================================
// SISTEMA DE SINCRONIZAÇÃO AVANÇADO (NOVO)
// =============================================
class PrecisionSyncSystem {
constructor() {
this.clickQueue = [];
this.isSyncing = false;
this.syncOperations = new Map();
this.clickTimestamps = new Map();
this.MAX_SYNC_ATTEMPTS = 2;
this.MIN_SYNC_INTERVAL = 100;
}
async executeUltraPreciseSync(elements, roomId = null) {
if (this.isSyncing) {
console.warn('⚠️ Sincronização já em andamento');
return 0;
}
this.isSyncing = true;
const startTime = performance.now();
try {
console.log(`⚡ INICIANDO SINCRONIZAÇÃO ULTRA-PRECISA (${elements.length} elementos)`);
// Fase 1: Preparação
await this.prepareAllElements(elements);
// Fase 2: Execução sincronizada
const results = await this.executeSynchronizedClicks(elements);
const successCount = results.filter(r => r.success).length;
const totalTime = performance.now() - startTime;
console.log(`✅ SINCRONIZAÇÃO CONCLUÍDA: ${successCount}/${elements.length} em ${totalTime.toFixed(1)}ms`);
return successCount;
} catch (error) {
console.error('❌ ERRO NA SINCRONIZAÇÃO:', error);
return 0;
} finally {
this.isSyncing = false;
}
}
async prepareAllElements(elements) {
const promises = elements.map((element, index) => {
return new Promise(resolve => {
requestAnimationFrame(() => {
this.ensureElementReady(element);
resolve(true);
});
});
});
await Promise.all(promises);
await this.delay(10);
}
async executeSynchronizedClicks(elements) {
const config = window.configManager ? window.configManager.getSyncPrecisionValue() : { delay: 5, useRAF: true, usePN: true };
const results = [];
const clickPromises = elements.map((element, index) => {
return new Promise(async (resolve) => {
const delay = config.delay + (Math.random() * 10);
await this.delay(delay);
const success = await this.executePrecisionClick(element, index);
results.push({
element,
index,
success,
timestamp: performance.now()
});
resolve(success);
});
});
await Promise.all(clickPromises);
return results;
}
async executePrecisionClick(elementData, index) {
try {
const elementId = `click-${Date.now()}-${index}`;
if (this.isAlreadyInRoom(elementData)) {
console.log(`✅ Elemento ${index} já está na sala`);
return true;
}
let clickSuccess = false;
if (elementData.type === 'iframe' || elementData.type === 'multiRoomIframe') {
clickSuccess = this.executeIframePrecisionClick(elementData.data, index);
} else if (elementData.type === 'externalTab' || elementData.type === 'multiRoomExternalTab') {
clickSuccess = this.executeTabPrecisionClick(elementData.data, index);
}
if (clickSuccess) {
elementData.data.clicked = true;
elementData.data.clickTimestamp = Date.now();
this.clickTimestamps.set(elementId, Date.now());
}
return clickSuccess;
} catch (error) {
console.error(`💥 Erro no clique preciso ${index}:`, error);
return false;
}
}
executeIframePrecisionClick(iframeData, index) {
try {
const iframe = iframeData.iframe;
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (!iframeDoc) return false;
const playButton = this.findPlayButtonAdvanced(iframeDoc);
if (!playButton) {
console.warn(`❌ Botão não encontrado no iframe ${index + 1}`);
return false;
}
this.performCompleteClick(playButton, iframe.contentWindow);
console.log(`🎯 Clique ultra-preciso no iframe ${index + 1}`);
return true;
} catch (error) {
console.error(`💥 Erro crítico no iframe ${index + 1}:`, error);
return false;
}
}
executeTabPrecisionClick(tabData, index) {
try {
if (tabData.window && tabData.window.closed) {
console.warn(`❌ Aba ${index + 1} foi fechada`);
return false;
}
const tabDoc = tabData.window.document;
if (!tabDoc) return false;
const playButton = this.findPlayButtonAdvanced(tabDoc);
if (!playButton) {
console.warn(`❌ Botão não encontrado na aba ${index + 1}`);
return false;
}
try {
tabData.window.focus();
} catch (e) {}
this.performCompleteClick(playButton, tabData.window);
console.log(`🎯 Clique ultra-preciso na aba ${index + 1}`);
return true;
} catch (error) {
console.error(`💥 Erro crítico na aba ${index + 1}:`, error);
return false;
}
}
findPlayButtonAdvanced(doc) {
const buttonSelectors = [
'input[value*="Jogar" i]',
'input[value*="Play" i]',
'input[type="submit"]',
'button[type="submit"]',
'#btnJogar',
'#btnPlay',
'#playButton',
'.play-button',
'.btn-play',
'.jogar-btn',
'[onclick*="jogar" i]',
'[onclick*="play" i]',
'[onclick*="entrar" i]',
'button:contains("Jogar")',
'button:contains("Play")',
'input[value*="Entrar"]',
'form button:last-child',
'form input[type="submit"]:last-child'
];
for (const selector of buttonSelectors) {
try {
const element = doc.querySelector(selector);
if (element && this.isElementClickable(element)) {
return element;
}
} catch (e) {}
}
const allButtons = doc.querySelectorAll('button, input[type="button"], input[type="submit"]');
for (const button of allButtons) {
if (this.isElementClickable(button) &&
(button.textContent.includes('Jogar') ||
button.textContent.includes('Play') ||
button.value.includes('Jogar') ||
button.value.includes('Play'))) {
return button;
}
}
return null;
}
performCompleteClick(element, targetWindow = window) {
try {
const rect = element.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const events = [
new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: targetWindow,
clientX: centerX,
clientY: centerY,
button: 0
}),
new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: targetWindow,
clientX: centerX,
clientY: centerY,
button: 0
}),
new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: targetWindow,
clientX: centerX,
clientY: centerY,
button: 0
}),
new FocusEvent('focus', { bubbles: true }),
new FocusEvent('focusin', { bubbles: true })
];
events.forEach(event => {
try {
element.dispatchEvent(event);
} catch (e) {}
});
try {
element.click();
} catch (e) {
console.warn('⚠️ Clique nativo falhou, usando eventos simulados');
}
['input', 'change'].forEach(eventType => {
try {
const event = new Event(eventType, { bubbles: true });
element.dispatchEvent(event);
} catch (e) {}
});
return true;
} catch (error) {
console.error('❌ Erro no clique completo:', error);
return false;
}
}
isElementClickable(element) {
if (!element) return false;
const style = window.getComputedStyle(element);
if (style.display === 'none' ||
style.visibility === 'hidden' ||
style.opacity === '0' ||
element.offsetWidth === 0 ||
element.offsetHeight === 0) {
return false;
}
if (element.disabled || element.readOnly) {
return false;
}
if (style.pointerEvents === 'none') {
return false;
}
return true;
}
isAlreadyInRoom(elementData) {
try {
let doc;
if (elementData.type === 'iframe' || elementData.type === 'multiRoomIframe') {
doc = elementData.data.iframe.contentDocument || elementData.data.iframe.contentWindow.document;
} else {
if (elementData.data.window.closed) return true;
doc = elementData.data.window.document;
}
if (!doc) return false;
const roomIndicators = [
'.game-container',
'.drawing-area',
'canvas',
'.palette',
'.room-content',
'#gameArea',
'.game-area',
'.draw-container',
'[class*="game"]',
'[class*="room"]'
];
for (const selector of roomIndicators) {
try {
const element = doc.querySelector(selector);
if (element && this.isElementVisible(element)) {
return true;
}
} catch (e) {}
}
return false;
} catch (e) {
return false;
}
}
isElementVisible(element) {
return element &&
element.offsetWidth > 0 &&
element.offsetHeight > 0 &&
window.getComputedStyle(element).display !== 'none';
}
ensureElementReady(element) {
if (element.type.includes('iframe')) {
try {
const iframe = element.data.iframe;
if (iframe.contentWindow) {
iframe.contentWindow.focus();
}
} catch (e) {}
} else {
try {
if (element.data.window && !element.data.window.closed) {
element.data.window.focus();
}
} catch (e) {}
}
}
async delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
resetSyncData() {
this.clickQueue = [];
this.syncOperations.clear();
this.clickTimestamps.clear();
this.isSyncing = false;
}
}
// =============================================
// CONTROLADOR DE REDE PROFISSIONAL (NOVO)
// =============================================
class ProfessionalNetworkController {
constructor() {
this.isBlocked = false;
this.originalNetworkAPI = {};
this.blockStartTime = 0;
this.MAX_BLOCK_TIME = 5000;
this.blockHistory = [];
}
blockNetwork() {
if (this.isBlocked) {
console.log('🔒 Rede já está bloqueada');
return true;
}
try {
this.saveOriginalAPIs();
this.blockFetch();
this.blockXMLHttpRequest();
this.blockWebSocket();
this.blockEventSource();
this.blockSendBeacon();
this.blockNavigatorOnline();
this.isBlocked = true;
this.blockStartTime = Date.now();
this.blockHistory.push({
start: this.blockStartTime,
duration: 0,
type: 'manual'
});
console.log('🔒 REDE BLOQUEADA PROFISSIONALMENTE');
setTimeout(() => {
if (this.isBlocked && (Date.now() - this.blockStartTime) > this.MAX_BLOCK_TIME) {
console.warn('⚠️ Restauração automática da rede (timeout de segurança)');
this.restoreNetwork();
}
}, this.MAX_BLOCK_TIME + 1000);
return true;
} catch (error) {
console.error('❌ Erro ao bloquear rede profissional:', error);
return false;
}
}
saveOriginalAPIs() {
this.originalNetworkAPI = {
fetch: window.fetch,
XMLHttpRequest: {
open: XMLHttpRequest.prototype.open,
send: XMLHttpRequest.prototype.send,
setRequestHeader: XMLHttpRequest.prototype.setRequestHeader
},
WebSocket: window.WebSocket,
EventSource: window.EventSource,
navigator: {
sendBeacon: navigator.sendBeacon,
onLine: navigator.onLine
}
};
}
blockFetch() {
window.fetch = function() {
return Promise.reject(new Error('Network blocked by Gartic Pro System'));
};
}
blockXMLHttpRequest() {
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function() {
this._blocked = true;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(data) {
if (this._blocked) {
if (this.onerror) {
setTimeout(() => {
try {
this.onerror(new ProgressEvent('error'));
} catch (e) {}
}, 1);
}
if (this.onloadend) {
setTimeout(() => {
try {
this.onloadend(new ProgressEvent('loadend'));
} catch (e) {}
}, 1);
}
return;
}
return originalSend.call(this, data);
};
}
blockWebSocket() {
if (window.WebSocket) {
window.WebSocket = class MockWebSocket {
constructor(url) {
this.url = url;
this.readyState = 3;
this._listeners = {};
}
addEventListener(type, listener) {
if (!this._listeners[type]) this._listeners[type] = [];
this._listeners[type].push(listener);
}
removeEventListener(type, listener) {
if (this._listeners[type]) {
const idx = this._listeners[type].indexOf(listener);
if (idx > -1) this._listeners[type].splice(idx, 1);
}
}
close() {
this.readyState = 3;
}
send() {
throw new Error('WebSocket blocked');
}
};
}
}
blockEventSource() {
if (window.EventSource) {
window.EventSource = class MockEventSource {
constructor(url) {
this.url = url;
this.readyState = 2;
}
close() {}
addEventListener() {}
};
}
}
blockSendBeacon() {
if (navigator.sendBeacon) {
navigator.sendBeacon = function() {
return false;
};
}
}
blockNavigatorOnline() {
Object.defineProperty(navigator, 'onLine', {
get: function() { return false; },
configurable: false
});
}
restoreNetwork() {
if (!this.isBlocked) {
console.log('🔓 Rede já está restaurada');
return true;
}
try {
if (this.originalNetworkAPI.fetch) {
window.fetch = this.originalNetworkAPI.fetch;
}
if (this.originalNetworkAPI.XMLHttpRequest) {
XMLHttpRequest.prototype.open = this.originalNetworkAPI.XMLHttpRequest.open;
XMLHttpRequest.prototype.send = this.originalNetworkAPI.XMLHttpRequest.send;
XMLHttpRequest.prototype.setRequestHeader = this.originalNetworkAPI.XMLHttpRequest.setRequestHeader;
}
if (this.originalNetworkAPI.WebSocket) {
window.WebSocket = this.originalNetworkAPI.WebSocket;
}
if (this.originalNetworkAPI.EventSource) {
window.EventSource = this.originalNetworkAPI.EventSource;
}
if (this.originalNetworkAPI.navigator?.sendBeacon) {
navigator.sendBeacon = this.originalNetworkAPI.navigator.sendBeacon;
}
if (this.originalNetworkAPI.navigator?.onLine !== undefined) {
Object.defineProperty(navigator, 'onLine', {
get: function() { return true; },
configurable: true
});
}
this.isBlocked = false;
const blockDuration = Date.now() - this.blockStartTime;
if (this.blockHistory.length > 0) {
this.blockHistory[this.blockHistory.length - 1].duration = blockDuration;
}
console.log(`🔓 REDE RESTAURADA (bloqueio: ${blockDuration}ms)`);
this.originalNetworkAPI = {};
return true;
} catch (error) {
console.error('❌ Erro ao restaurar rede profissional:', error);
return false;
}
}
async performNetworkCycle() {
console.log('🔄 INICIANDO CICLO DE REDE OTIMIZADO...');
try {
const blockSuccess = this.blockNetwork();
if (!blockSuccess) {
throw new Error('Falha ao bloquear rede');
}
await this.delay(80);
const restoreSuccess = this.restoreNetwork();
if (!restoreSuccess) {
throw new Error('Falha ao restaurar rede');
}
await this.delay(40);
console.log('✅ CICLO DE REDE CONCLUÍDO');
return true;
} catch (error) {
console.error('❌ Erro no ciclo de rede:', error);
this.restoreNetwork();
return false;
}
}
async delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
checkNetworkStatus() {
return {
isBlocked: this.isBlocked,
blockDuration: this.isBlocked ? Date.now() - this.blockStartTime : 0,
blockHistory: [...this.blockHistory]
};
}
async testNetwork() {
try {
const testUrl = 'https://gartic.com.br/favicon.ico?t=' + Date.now();
const response = await fetch(testUrl, { mode: 'no-cors' });
return response !== undefined;
} catch (e) {
return false;
}
}
}
// =============================================
// SISTEMA DE SELEÇÃO ALEATÓRIA DE SALAS (NOVO)
// =============================================
class RandomRoomSelector {
constructor() {
this.selectedRooms = new Set();
this.roomElements = new Map();
this.maxRooms = 1000;
}
getAllAvailableRooms() {
const rooms = [];
const roomSelectors = [
'.sala',
'[onclick*="selecionaSala"]',
'.room',
'[class*="room"]',
'[id*="sala"]',
'[data-room]',
'[data-sala]'
];
roomSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
const roomId = this.extractRoomId(element);
if (roomId && !rooms.includes(roomId)) {
rooms.push(roomId);
this.roomElements.set(roomId, element);
}
});
});
const roomList = document.getElementById('roomList');
if (roomList) {
roomList.querySelectorAll('div[data-room-id]').forEach(element => {
const roomId = element.getAttribute('data-room-id');
if (roomId && !rooms.includes(roomId)) {
rooms.push(roomId);
this.roomElements.set(roomId, element);
}
});
}
return rooms;
}
// NOVO: Método para verificar se a sala está vazia
isRoomEmpty(roomId) {
const roomElement = this.roomElements.get(roomId);
if (!roomElement) return false;
const quantElement = roomElement.querySelector('.sala_quant');
if (quantElement) {
const quantText = quantElement.textContent;
const playerCount = parseInt(quantText) || 0;
return playerCount === 0;
}
return false;
}
selectRandomRooms(count) {
const allRooms = this.getAllAvailableRooms();
const onlyEmptyRooms = configManager ? configManager.get('onlyEmptyRooms') : false;
// Filtrar salas com base na opção onlyEmptyRooms
let availableRooms = allRooms;
if (onlyEmptyRooms) {
availableRooms = allRooms.filter(roomId => this.isRoomEmpty(roomId));
console.log(`🔍 Filtrando apenas salas vazias: ${availableRooms.length}/${allRooms.length} salas vazias encontradas`);
}
if (availableRooms.length === 0) {
if (onlyEmptyRooms) {
alert('⚠️ Nenhuma sala vazia encontrada! Desative o filtro "Mostrar apenas salas vazias" para selecionar outras salas.');
} else {
alert('⚠️ Nenhuma sala disponível para seleção!');
}
console.warn('⚠️ Nenhuma sala disponível para seleção');
return [];
}
let selected = [];
if (count >= availableRooms.length) {
selected = [...availableRooms];
} else {
const shuffled = [...availableRooms].sort(() => Math.random() - 0.5);
selected = shuffled.slice(0, count);
}
this.selectedRooms = new Set(selected);
this.updateRoomCheckboxes();
console.log(`✅ ${this.selectedRooms.size} salas selecionadas aleatoriamente ${onlyEmptyRooms ? '(apenas vazias)' : ''}`);
return Array.from(this.selectedRooms);
}
extractRoomId(element) {
const onclick = element.getAttribute('onclick') || '';
const text = element.textContent || '';
const onclickMatch = onclick.match(/\d+/);
if (onclickMatch) return onclickMatch[0];
const textMatch = text.match(/\d+/);
if (textMatch) return textMatch[0];
const dataRoom = element.getAttribute('data-room') || element.getAttribute('data-sala');
if (dataRoom) return dataRoom;
return null;
}
updateRoomCheckboxes() {
this.selectedRooms.forEach(roomId => {
const checkbox = document.querySelector(`input[data-room-id="${roomId}"]`);
if (checkbox) {
checkbox.checked = true;
}
});
}
clearSelection() {
this.selectedRooms.clear();
this.updateRoomCheckboxes();
console.log('🧹 Seleção de salas limpa');
}
getSelectedCount() {
return this.selectedRooms.size;
}
getSelectedRooms() {
return Array.from(this.selectedRooms);
}
distributeTabsAmongRooms(totalTabs, distributionMode = 'balanced') {
const rooms = this.getSelectedRooms();
if (rooms.length === 0) return [];
let distribution = [];
switch(distributionMode) {
case 'balanced':
const baseTabsPerRoom = Math.floor(totalTabs / rooms.length);
const extraTabs = totalTabs % rooms.length;
for (let i = 0; i < rooms.length; i++) {
const tabsForThisRoom = baseTabsPerRoom + (i < extraTabs ? 1 : 0);
for (let j = 0; j < tabsForThisRoom; j++) {
distribution.push({
roomIndex: i,
roomId: rooms[i],
tabIndex: distribution.length
});
}
}
break;
case 'random':
for (let i = 0; i < totalTabs; i++) {
const roomIndex = Math.floor(Math.random() * rooms.length);
distribution.push({
roomIndex: roomIndex,
roomId: rooms[roomIndex],
tabIndex: i
});
}
break;
case 'sequential':
for (let i = 0; i < totalTabs; i++) {
const roomIndex = i % rooms.length;
distribution.push({
roomIndex: roomIndex,
roomId: rooms[roomIndex],
tabIndex: i
});
}
break;
}
distribution = distribution.sort(() => Math.random() - 0.5);
return distribution;
}
}
// =============================================
// SISTEMA DE VERIFICAÇÃO DE VAGAS (100% DO SCRIPT 2)
// =============================================
class VacancySystem {
constructor() {
this.isChecking = false;
this.vacancyCheckInterval = null;
this.maxPlayers = 10;
}
async checkRoomVacancy(roomId) {
try {
const endpoints = [
`https://gartic.com.br/info_sala.php?id_sala=${roomId}&t=${Date.now()}`,
`https://gartic.com.br/sala_vagas.php?id=${roomId}&t=${Date.now()}`,
`https://gartic.com.br/sala${roomId}.php?t=${Date.now()}`
];
for (const endpoint of endpoints) {
try {
const response = await fetch(endpoint);
if (response.ok) {
const data = await response.json();
if (data.jogadores && Array.isArray(data.jogadores)) {
const currentPlayers = data.jogadores.length;
const hasVacancy = currentPlayers < this.maxPlayers;
console.log(`👥 Sala ${roomId}: ${currentPlayers}/${this.maxPlayers} jogadores`);
return { hasVacancy, currentPlayers, maxPlayers: this.maxPlayers };
}
if (data.v !== undefined) {
const hasVacancy = data.v > 0;
console.log(`👥 Sala ${roomId}: ${data.v} vagas disponíveis`);
return { hasVacancy, currentPlayers: this.maxPlayers - data.v, maxPlayers: this.maxPlayers };
}
}
} catch (e) {
console.log(`⚠️ Endpoint falhou: ${endpoint}`);
}
}
console.log('⚠️ Não foi possível verificar vagas, assumindo que há vaga');
return { hasVacancy: true, currentPlayers: 0, maxPlayers: this.maxPlayers };
} catch (error) {
console.error('❌ Erro ao verificar vagas:', error);
return { hasVacancy: true, currentPlayers: 0, maxPlayers: this.maxPlayers };
}
}
startVacancyCheck(roomId, callback) {
if (this.isChecking) {
this.stopVacancyCheck();
}
this.isChecking = true;
updateStatus('🔍 VERIFICANDO VAGAS NA SALA...');
this.vacancyCheckInterval = setInterval(async () => {
const vacancyInfo = await this.checkRoomVacancy(roomId);
if (vacancyInfo.hasVacancy) {
this.stopVacancyCheck();
updateStatus(`✅ VAGA ENCONTRADA! (${vacancyInfo.currentPlayers}/${vacancyInfo.maxPlayers} jogadores)`);
callback(true);
} else {
updateStatus(`⏳ AGUARDANDO VAGA... (${vacancyInfo.currentPlayers}/${vacancyInfo.maxPlayers} jogadores)`);
}
}, 2000);
}
stopVacancyCheck() {
if (this.vacancyCheckInterval) {
clearInterval(this.vacancyCheckInterval);
this.vacancyCheckInterval = null;
}
this.isChecking = false;
}
isCheckingVacancy() {
return this.isChecking;
}
}
// =============================================
// CONTROLADOR DE REDE (100% DO SCRIPT 2)
// =============================================
class AdvancedNetworkController {
constructor() {
this.isBlocked = false;
this.originalFetch = null;
this.originalXHROpen = null;
this.originalXHRSend = null;
}
blockNetwork() {
if (this.isBlocked) return true;
try {
this.originalFetch = window.fetch;
window.fetch = function() {
throw new Error('Network blocked by Gartic Multi-Abas');
};
this.originalXHROpen = XMLHttpRequest.prototype.open;
this.originalXHRSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function() {
this._url = arguments[1];
return this.originalXHROpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(data) {
if (this.onerror) {
setTimeout(() => {
try {
this.onerror(new ProgressEvent('error'));
} catch (e) {}
}, 10);
}
if (this.onloadend) {
setTimeout(() => {
try {
this.onloadend(new ProgressEvent('loadend'));
} catch (e) {}
}, 10);
}
return null;
};
this.isBlocked = true;
console.log('🔒 REDE BLOQUEADA');
return true;
} catch (error) {
console.error('❌ Erro ao bloquear rede:', error);
return false;
}
}
restoreNetwork() {
if (!this.isBlocked) return true;
try {
if (this.originalFetch) {
window.fetch = this.originalFetch;
}
if (this.originalXHROpen) {
XMLHttpRequest.prototype.open = this.originalXHROpen;
}
if (this.originalXHRSend) {
XMLHttpRequest.prototype.send = this.originalXHRSend;
}
this.isBlocked = false;
console.log('🔓 REDE RESTAURADA');
return true;
} catch (error) {
console.error('❌ Erro ao restaurar rede:', error);
return false;
}
}
}
// =============================================
// SISTEMA DE GERENCIAMENTO DE MÚLTIPLAS SALAS (100% DO SCRIPT 2)
// =============================================
class MultiRoomManager {
constructor() {
this.selectedRooms = [];
this.roomCheckboxes = new Map();
this.config = {
multiRoomIframeCount: 0,
multiRoomExternalCount: 0
};
}
addRoom(roomId) {
if (!this.selectedRooms.includes(roomId)) {
this.selectedRooms.push(roomId);
console.log(`✅ Sala ${roomId} adicionada à seleção`);
}
}
removeRoom(roomId) {
const index = this.selectedRooms.indexOf(roomId);
if (index > -1) {
this.selectedRooms.splice(index, 1);
console.log(`❌ Sala ${roomId} removida da seleção`);
}
}
clearRooms() {
this.selectedRooms = [];
this.roomCheckboxes.forEach((checkbox, roomId) => {
checkbox.checked = false;
});
console.log('🧹 Todas as salas foram desmarcadas');
}
getRoomForIndex(index) {
if (this.selectedRooms.length === 0) return null;
return this.selectedRooms[index % this.selectedRooms.length];
}
hasRooms() {
return this.selectedRooms.length > 0;
}
getRoomCount() {
return this.selectedRooms.length;
}
distributeTabsAmongRooms(totalTabs) {
const roomCount = this.selectedRooms.length;
if (roomCount === 0) return [];
const tabsPerRoom = Math.floor(totalTabs / roomCount);
const extraTabs = totalTabs % roomCount;
const distribution = [];
let tabIndex = 0;
for (let i = 0; i < roomCount; i++) {
const tabsForThisRoom = tabsPerRoom + (i < extraTabs ? 1 : 0);
for (let j = 0; j < tabsForThisRoom; j++) {
distribution.push({
roomIndex: i,
roomId: this.selectedRooms[i],
tabIndex: tabIndex++
});
}
}
return distribution;
}
}
// =============================================
// VISUALIZAÇÃO EM TEMPO REAL (ATUALIZADA)
// =============================================
class RealTimeViewer {
constructor() {
this.container = null;
this.iframes = new Map();
this.externalTabs = new Map();
this.isVisible = false;
this.isMinimized = false;
this.maxIframes = 1000;
this.maxMultiRoomIframes = 1000;
this.multiRoomIframes = new Map();
this.multiRoomExternalTabs = new Map();
}
createViewer() {
if (this.container) {
this.closeViewer();
}
this.container = document.createElement('div');
this.container.id = 'gartic-real-time-viewer';
this.container.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 95%;
height: 90%;
background: rgba(0, 0, 0, 0.95);
border: 3px solid #8A2BE2;
border-radius: 15px;
z-index: 19999;
display: none;
flex-direction: column;
padding: 15px;
box-shadow: 0 0 50px rgba(0,0,0,0.8);
backdrop-filter: blur(10px);
`;
const header = document.createElement('div');
header.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
background: #8A2BE2;
color: white;
border-radius: 10px 10px 0 0;
margin: -15px -15px 15px -15px;
cursor: move;
`;
header.innerHTML = `
<h3 style="margin:0; font-size:16px;">👁️ VISUALIZAÇÃO EM TEMPO REAL</h3>
<div>
<button id="minimizeViewerBtn" style="background:#FF9800; color:white; border:none; border-radius:5px; padding:5px 10px; cursor:pointer; font-weight:bold; margin-right:5px;">−</button>
<button id="closeViewerBtn" style="background:#ff4444; color:white; border:none; border-radius:5px; padding:5px 10px; cursor:pointer; font-weight:bold;">X</button>
</div>
`;
this.container.appendChild(header);
const iframesGrid = document.createElement('div');
iframesGrid.id = 'iframes-grid';
iframesGrid.style.cssText = `
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 10px;
height: 100%;
overflow-y: auto;
padding: 10px;
`;
this.container.appendChild(iframesGrid);
const externalTabsSection = document.createElement('div');
externalTabsSection.style.cssText = `
margin-top: 15px;
padding: 10px;
background: rgba(139, 69, 19, 0.1);
border-radius: 8px;
border: 2px solid #8B4513;
`;
externalTabsSection.innerHTML = `
<h4 style="margin:0 0 10px 0; color: #8B4513; font-size:14px;">🌐 ABAS EXTERNAS</h4>
<div id="external-tabs-status" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 5px;"></div>
`;
this.container.appendChild(externalTabsSection);
const multiRoomSection = document.createElement('div');
multiRoomSection.style.cssText = `
margin-top: 15px;
padding: 10px;
background: rgba(0, 100, 0, 0.1);
border-radius: 8px;
border: 2px solid #006400;
`;
multiRoomSection.innerHTML = `
<h4 style="margin:0 0 10px 0; color: #006400; font-size:14px;">🎯 SISTEMAS MULTI-SALA</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div>
<h5 style="margin:0 0 5px 0; color: #FF6B00; font-size:12px;">🪟 Iframes Multi-Sala</h5>
<div id="multi-room-iframes-status" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 3px;"></div>
</div>
<div>
<h5 style="margin:0 0 5px 0; color: #FF6B00; font-size:12px;">🌐 Abas Multi-Sala</h5>
<div id="multi-room-external-status" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 3px;"></div>
</div>
</div>
`;
this.container.appendChild(multiRoomSection);
document.body.appendChild(this.container);
document.getElementById('closeViewerBtn').onclick = () => this.closeViewer();
document.getElementById('minimizeViewerBtn').onclick = () => this.toggleMinimize();
this.makeDraggable(header, this.container);
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isVisible) {
this.closeViewer();
}
});
return this.container;
}
createMultiRoomIframe(nick, index, roomIds, roomIndex = null) {
if (!this.container) {
this.createViewer();
}
const roomId = roomIds[roomIndex !== null ? roomIndex : index % roomIds.length];
const iframesGrid = document.getElementById('iframes-grid');
const iframeContainer = document.createElement('div');
iframeContainer.style.cssText = `
background: #2a2a2a;
border: 2px solid #FF6B00;
border-radius: 8px;
padding: 8px;
display: flex;
flex-direction: column;
min-height: 300px;
`;
const iframeHeader = document.createElement('div');
iframeHeader.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px;
background: #333;
border-radius: 5px;
margin-bottom: 5px;
font-size: 12px;
color: white;
`;
iframeHeader.innerHTML = `
<span>🎯 ${nick} (Sala ${roomId})</span>
<span id="multi-iframe-status-${index}" style="color: #ff9800;">⏳ CARREGANDO</span>
`;
iframeContainer.appendChild(iframeHeader);
const iframe = document.createElement('iframe');
iframe.src = `https://gartic.com.br/0${roomId}`;
iframe.style.cssText = `
width: 100%;
height: 250px;
border: 1px solid #555;
border-radius: 5px;
background: white;
flex: 1;
`;
iframe.setAttribute('allow', 'autoplay; microphone; camera');
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');
iframeContainer.appendChild(iframe);
iframesGrid.appendChild(iframeContainer);
const tabData = {
iframe: iframe,
nick: nick,
roomId: roomId,
ready: false,
loaded: false,
nickFilled: false,
inRoom: false,
attempts: 0,
maxAttempts: 3
};
iframe.onload = () => {
this.monitorMultiRoomIframe(iframe, tabData, index);
};
iframe.onerror = () => {
console.warn(`⚠️ Erro ao carregar iframe multi-sala ${index + 1}`);
this.retryMultiRoomIframeLoad(iframe, tabData, index, roomId);
};
this.multiRoomIframes.set(index, {
container: iframeContainer,
iframe: iframe,
tabData: tabData
});
this.updateMultiRoomIframeStatus(index, '⏳ CARREGANDO', '#FF9800');
return tabData;
}
monitorMultiRoomIframe(iframe, tabData, index) {
const checkIframe = () => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc.readyState === 'complete' && iframeDoc.body) {
const nickInput = this.findNickInput(iframeDoc);
if (nickInput && !tabData.nickFilled) {
this.fillNickname(nickInput, tabData.nick);
tabData.nickFilled = true;
console.log(`✅ Nick preenchido no iframe multi-sala ${index + 1}: ${tabData.nick}`);
}
const playBtn = this.findPlayButton(iframeDoc);
const isReady = playBtn && this.isElementVisible(playBtn);
if (isReady && !tabData.ready) {
tabData.ready = true;
tabData.loaded = true;
this.updateMultiRoomIframeStatus(index, '✅ PRONTA', '#4CAF50');
console.log(`🎯 Iframe multi-sala ${index + 1} PRONTO!`);
}
if (this.isInRoom(iframeDoc) && !tabData.inRoom) {
tabData.inRoom = true;
this.updateMultiRoomIframeStatus(index, '🎉 NA SALA!', '#4CAF50');
iframe.style.border = '2px solid #4CAF50';
}
}
} catch (e) {
}
if (!tabData.inRoom) {
setTimeout(checkIframe, 1000);
}
};
setTimeout(checkIframe, 2000);
}
retryMultiRoomIframeLoad(iframe, tabData, index, roomId) {
if (tabData.attempts < tabData.maxAttempts) {
tabData.attempts++;
console.log(`🔄 Tentativa ${tabData.attempts}/${tabData.maxAttempts} para iframe multi-sala ${index + 1}`);
setTimeout(() => {
iframe.src = `https://gartic.com.br/0${roomId}?t=${Date.now()}`;
}, 2000);
} else {
this.updateMultiRoomIframeStatus(index, '❌ FALHA AO CARREGAR', '#f44336');
}
}
updateMultiRoomIframeStatus(index, status, color) {
const statusElement = document.getElementById(`multi-iframe-status-${index}`);
if (statusElement) {
statusElement.textContent = status;
statusElement.style.color = color;
}
this.updateMultiRoomStatusDisplay();
}
createMultiRoomExternalTab(nick, index, roomIds, roomIndex = null) {
const roomId = roomIds[roomIndex !== null ? roomIndex : index % roomIds.length];
const tabId = `multi-external-tab-${index}`;
const newTab = window.open(`https://gartic.com.br/0${roomId}`, `multiroom${index}`);
if (!newTab) {
console.warn(`❌ Não foi possível abrir aba externa multi-sala ${index + 1}. Verifique bloqueador de pop-ups.`);
return null;
}
const tabData = {
window: newTab,
nick: nick,
roomId: roomId,
ready: false,
loaded: false,
nickFilled: false,
inRoom: false,
attempts: 0,
maxAttempts: 3,
tabId: tabId
};
this.multiRoomExternalTabs.set(index, tabData);
this.updateMultiRoomExternalStatus(index, '⏳ ABRINDO...', '#FF9800');
this.monitorMultiRoomExternalTab(tabData, index);
return tabData;
}
monitorMultiRoomExternalTab(tabData, index) {
const checkTab = () => {
try {
if (tabData.window.closed) {
this.updateMultiRoomExternalStatus(index, '❌ FECHADA', '#f44336');
return;
}
const tabDoc = tabData.window.document;
if (tabDoc.readyState === 'complete' && tabDoc.body) {
const nickInput = this.findNickInput(tabDoc);
if (nickInput && !tabData.nickFilled) {
this.fillNickname(nickInput, tabData.nick);
tabData.nickFilled = true;
this.updateMultiRoomExternalStatus(index, '✅ NICK PREENCHIDO', '#4CAF50');
console.log(`✅ Nick preenchido na aba multi-sala ${index + 1}: ${tabData.nick}`);
}
const playBtn = this.findPlayButton(tabDoc);
const isReady = playBtn && this.isElementVisible(playBtn);
if (isReady && !tabData.ready) {
tabData.ready = true;
tabData.loaded = true;
this.updateMultiRoomExternalStatus(index, '✅ PRONTA', '#4CAF50');
console.log(`🎯 Aba externa multi-sala ${index + 1} PRONTA!`);
}
if (this.isInRoom(tabDoc) && !tabData.inRoom) {
tabData.inRoom = true;
this.updateMultiRoomExternalStatus(index, '🎉 NA SALA!', '#4CAF50');
}
}
} catch (e) {
if (tabData.attempts < tabData.maxAttempts) {
tabData.attempts++;
setTimeout(checkTab, 1000);
} else {
this.updateMultiRoomExternalStatus(index, '❌ ERRO AO CARREGAR', '#f44336');
}
return;
}
if (!tabData.inRoom) {
setTimeout(checkTab, 1000);
}
};
setTimeout(checkTab, 2000);
}
updateMultiRoomExternalStatus(index, status, color) {
this.updateMultiRoomStatusDisplay();
}
updateMultiRoomStatusDisplay() {
const iframesStatusContainer = document.getElementById('multi-room-iframes-status');
const externalStatusContainer = document.getElementById('multi-room-external-status');
if (!iframesStatusContainer || !externalStatusContainer) return;
iframesStatusContainer.innerHTML = '';
externalStatusContainer.innerHTML = '';
this.multiRoomIframes.forEach((iframeData, index) => {
const statusElement = document.createElement('div');
statusElement.id = `multi-iframe-status-display-${index}`;
statusElement.style.cssText = `
padding: 4px;
background: #2a2a2a;
border-radius: 3px;
font-size: 9px;
text-align: center;
border: 1px solid #FF6B00;
margin-bottom: 2px;
`;
const status = iframeData.tabData.inRoom ? '🎉 NA SALA!' :
iframeData.tabData.ready ? '✅ PRONTA' : '⏳ CARREGANDO';
const color = iframeData.tabData.inRoom ? '#4CAF50' :
iframeData.tabData.ready ? '#4CAF50' : '#FF9800';
statusElement.innerHTML = `<strong>${index + 1}. ${iframeData.tabData.nick} (Sala ${iframeData.tabData.roomId})</strong><br>${status}`;
statusElement.style.color = color;
iframesStatusContainer.appendChild(statusElement);
});
this.multiRoomExternalTabs.forEach((tabData, index) => {
const statusElement = document.createElement('div');
statusElement.id = `multi-external-status-${index}`;
statusElement.style.cssText = `
padding: 4px;
background: #2a2a2a;
border-radius: 3px;
font-size: 9px;
text-align: center;
border: 1px solid #FF6B00;
margin-bottom: 2px;
`;
const status = tabData.inRoom ? '🎉 NA SALA!' :
tabData.ready ? '✅ PRONTA' :
tabData.window.closed ? '❌ FECHADA' : '⏳ CARREGANDO';
const color = tabData.inRoom ? '#4CAF50' :
tabData.ready ? '#4CAF50' :
tabData.window.closed ? '#f44336' : '#FF9800';
statusElement.innerHTML = `<strong>${index + 1}. ${tabData.nick} (Sala ${tabData.roomId})</strong><br>${status}`;
statusElement.style.color = color;
externalStatusContainer.appendChild(statusElement);
});
}
createExternalTab(nick, index, roomId) {
const tabId = `external-tab-${index}`;
const newTab = window.open(`https://gartic.com.br/0${roomId}`, `_blank${index}`);
if (!newTab) {
console.warn(`❌ Não foi possível abrir aba externa ${index + 1}. Verifique bloqueador de pop-ups.`);
return null;
}
const tabData = {
window: newTab,
nick: nick,
ready: false,
loaded: false,
nickFilled: false,
inRoom: false,
attempts: 0,
maxAttempts: 3,
tabId: tabId
};
this.externalTabs.set(index, tabData);
this.updateExternalTabStatus(index, '⏳ ABRINDO...', '#FF9800');
this.monitorExternalTab(tabData, index);
return tabData;
}
monitorExternalTab(tabData, index) {
const checkTab = () => {
try {
if (tabData.window.closed) {
this.updateExternalTabStatus(index, '❌ FECHADA', '#f44336');
return;
}
const tabDoc = tabData.window.document;
if (tabDoc.readyState === 'complete' && tabDoc.body) {
const nickInput = this.findNickInput(tabDoc);
if (nickInput && !tabData.nickFilled) {
this.fillNickname(nickInput, tabData.nick);
tabData.nickFilled = true;
this.updateExternalTabStatus(index, '✅ NICK PREENCHIDO', '#4CAF50');
}
const playBtn = this.findPlayButton(tabDoc);
const isReady = playBtn && this.isElementVisible(playBtn);
if (isReady && !tabData.ready) {
tabData.ready = true;
tabData.loaded = true;
this.updateExternalTabStatus(index, '✅ PRONTA', '#4CAF50');
}
if (this.isInRoom(tabDoc) && !tabData.inRoom) {
tabData.inRoom = true;
this.updateExternalTabStatus(index, '🎉 NA SALA!', '#4CAF50');
}
}
} catch (e) {
if (tabData.attempts < tabData.maxAttempts) {
tabData.attempts++;
setTimeout(checkTab, 1000);
} else {
this.updateExternalTabStatus(index, '❌ ERRO AO CARREGAR', '#f44336');
}
return;
}
if (!tabData.inRoom) {
setTimeout(checkTab, 1000);
}
};
setTimeout(checkTab, 2000);
}
createDirectIframe(nick, index, roomId) {
if (!this.container) {
this.createViewer();
}
const iframesGrid = document.getElementById('iframes-grid');
const iframeContainer = document.createElement('div');
iframeContainer.style.cssText = `
background: #2a2a2a;
border: 2px solid #4CAF50;
border-radius: 8px;
padding: 8px;
display: flex;
flex-direction: column;
min-height: 300px;
`;
const iframeHeader = document.createElement('div');
iframeHeader.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px;
background: #333;
border-radius: 5px;
margin-bottom: 5px;
font-size: 12px;
color: white;
`;
iframeHeader.innerHTML = `
<span>🔰 ${nick}</span>
<span id="status-${index}" style="color: #ff9800;">⏳ CARREGANDO</span>
`;
iframeContainer.appendChild(iframeHeader);
const iframe = document.createElement('iframe');
iframe.src = `https://gartic.com.br/0${roomId}`;
iframe.style.cssText = `
width: 100%;
height: 250px;
border: 1px solid #555;
border-radius: 5px;
background: white;
flex: 1;
`;
iframe.setAttribute('allow', 'autoplay; microphone; camera');
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');
iframeContainer.appendChild(iframe);
iframesGrid.appendChild(iframeContainer);
const tabData = {
iframe: iframe,
nick: nick,
ready: false,
loaded: false,
nickFilled: false,
inRoom: false,
attempts: 0,
maxAttempts: 3
};
iframe.onload = () => {
this.monitorIframe(iframe, tabData, index);
};
iframe.onerror = () => {
console.warn(`⚠️ Erro ao carregar iframe ${index + 1}`);
this.retryIframeLoad(iframe, tabData, index, roomId);
};
this.iframes.set(index, {
container: iframeContainer,
iframe: iframe,
tabData: tabData
});
return tabData;
}
monitorIframe(iframe, tabData, index) {
const checkIframe = () => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc.readyState === 'complete' && iframeDoc.body) {
const nickInput = this.findNickInput(iframeDoc);
if (nickInput && !tabData.nickFilled) {
this.fillNickname(nickInput, tabData.nick);
tabData.nickFilled = true;
console.log(`✅ Nick preenchido no iframe ${index + 1}: ${tabData.nick}`);
}
const playBtn = this.findPlayButton(iframeDoc);
const isReady = playBtn && this.isElementVisible(playBtn);
if (isReady && !tabData.ready) {
tabData.ready = true;
tabData.loaded = true;
this.updateIframeStatus(index, '✅ PRONTA', '#4CAF50');
console.log(`🎯 Iframe ${index + 1} PRONTO!`);
}
if (this.isInRoom(iframeDoc) && !tabData.inRoom) {
tabData.inRoom = true;
this.updateIframeStatus(index, '🎉 NA SALA!', '#4CAF50');
iframe.style.border = '2px solid #4CAF50';
}
}
} catch (e) {
}
if (!tabData.inRoom) {
setTimeout(checkIframe, 1000);
}
};
setTimeout(checkIframe, 2000);
}
retryIframeLoad(iframe, tabData, index, roomId) {
if (tabData.attempts < tabData.maxAttempts) {
tabData.attempts++;
console.log(`🔄 Tentativa ${tabData.attempts}/${tabData.maxAttempts} para iframe ${index + 1}`);
setTimeout(() => {
iframe.src = `https://gartic.com.br/0${roomId}?t=${Date.now()}`;
}, 2000);
} else {
this.updateIframeStatus(index, '❌ FALHA AO CARREGAR', '#f44336');
}
}
fillNickname(nickInput, nick) {
try {
nickInput.value = nick;
const events = ['input', 'change', 'keydown', 'keyup', 'blur'];
events.forEach(eventType => {
const event = new Event(eventType, { bubbles: true });
nickInput.dispatchEvent(event);
});
} catch (e) {
console.warn('⚠️ Erro ao preencher nick:', e);
}
}
updateExternalTabStatus(index, status, color) {
const externalTabsStatus = document.getElementById('external-tabs-status');
if (!externalTabsStatus) return;
let statusElement = document.getElementById(`external-tab-status-${index}`);
if (!statusElement) {
statusElement = document.createElement('div');
statusElement.id = `external-tab-status-${index}`;
statusElement.style.cssText = `
padding: 5px;
background: #2a2a2a;
border-radius: 4px;
font-size: 10px;
text-align: center;
border: 1px solid #8B4513;
`;
externalTabsStatus.appendChild(statusElement);
}
statusElement.innerHTML = `<strong>${index + 1}. ${this.externalTabs.get(index)?.nick || 'N/A'}</strong><br>${status}`;
statusElement.style.color = color;
}
updateIframeStatus(index, status, color) {
const statusElement = document.getElementById(`status-${index}`);
if (statusElement) {
statusElement.textContent = status;
statusElement.style.color = color;
}
}
makeDraggable(header, element) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
header.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
element.style.top = (element.offsetTop - pos2) + "px";
element.style.left = (element.offsetLeft - pos1) + "px";
element.style.transform = 'none';
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
toggleMinimize() {
if (!this.container) return;
const iframesGrid = document.getElementById('iframes-grid');
const externalTabsSection = this.container.querySelector('#external-tabs-status').parentElement;
const multiRoomSection = this.container.querySelector('#multi-room-iframes-status').parentElement.parentElement;
if (this.isMinimized) {
iframesGrid.style.display = 'grid';
externalTabsSection.style.display = 'block';
multiRoomSection.style.display = 'block';
this.container.style.height = '90%';
this.isMinimized = false;
} else {
iframesGrid.style.display = 'none';
externalTabsSection.style.display = 'none';
multiRoomSection.style.display = 'none';
this.container.style.height = 'auto';
this.isMinimized = true;
}
}
openViewer() {
if (!this.container) {
this.createViewer();
}
this.container.style.display = 'flex';
this.isVisible = true;
this.isMinimized = false;
}
closeViewer() {
if (this.container) {
this.container.style.display = 'none';
this.isVisible = false;
}
}
closeAllExternalTabs() {
this.externalTabs.forEach((tabData, index) => {
try {
if (!tabData.window.closed) {
tabData.window.close();
}
} catch (e) {
console.warn(`⚠️ Erro ao fechar aba externa ${index + 1}:`, e);
}
});
this.externalTabs.clear();
const externalTabsStatus = document.getElementById('external-tabs-status');
if (externalTabsStatus) {
externalTabsStatus.innerHTML = '';
}
}
getAllMultiRoomReadyElements() {
const readyElements = [];
this.multiRoomIframes.forEach((iframeData, index) => {
if (iframeData.tabData.ready) {
readyElements.push({
type: 'multiRoomIframe',
data: iframeData.tabData,
index: index
});
}
});
this.multiRoomExternalTabs.forEach((tabData, index) => {
if (tabData.ready && !tabData.window.closed) {
readyElements.push({
type: 'multiRoomExternalTab',
data: tabData,
index: index
});
}
});
return readyElements;
}
closeAllMultiRoomElements() {
this.multiRoomIframes.forEach((iframeData, index) => {
if (iframeData.container && iframeData.container.parentNode) {
iframeData.container.parentNode.removeChild(iframeData.container);
}
});
this.multiRoomIframes.clear();
this.multiRoomExternalTabs.forEach((tabData, index) => {
try {
if (!tabData.window.closed) {
tabData.window.close();
}
} catch (e) {
console.warn(`⚠️ Erro ao fechar aba externa multi-sala ${index + 1}:`, e);
}
});
this.multiRoomExternalTabs.clear();
this.updateMultiRoomStatusDisplay();
}
clearViewer() {
if (this.container) {
this.container.remove();
this.container = null;
}
this.iframes.clear();
this.closeAllExternalTabs();
this.closeAllMultiRoomElements();
this.isVisible = false;
this.isMinimized = false;
}
getReadyIframes() {
const readyIframes = [];
this.iframes.forEach((iframeData, index) => {
if (iframeData.tabData.ready) {
readyIframes.push(iframeData.tabData);
}
});
return readyIframes;
}
getReadyExternalTabs() {
const readyTabs = [];
this.externalTabs.forEach((tabData, index) => {
if (tabData.ready && !tabData.window.closed) {
readyTabs.push(tabData);
}
});
return readyTabs;
}
getAllReadyElements() {
const readyElements = [];
this.iframes.forEach((iframeData, index) => {
if (iframeData.tabData.ready) {
readyElements.push({
type: 'iframe',
data: iframeData.tabData,
index: index
});
}
});
this.externalTabs.forEach((tabData, index) => {
if (tabData.ready && !tabData.window.closed) {
readyElements.push({
type: 'externalTab',
data: tabData,
index: index
});
}
});
return readyElements;
}
findNickInput(doc) {
const selectors = [
'#nick',
'input[name="login"]',
'input[placeholder*="nick" i]',
'input[placeholder*="nome" i]',
'input[type="text"]'
];
for (const selector of selectors) {
const element = doc.querySelector(selector);
if (element) return element;
}
return null;
}
findPlayButton(doc) {
const selectors = [
'input[value*="Jogar" i]',
'input[value*="Play" i]',
'input[type="submit"]',
'button[type="submit"]'
];
for (const selector of selectors) {
const element = doc.querySelector(selector);
if (element && this.isElementVisible(element)) return element;
}
return null;
}
isElementVisible(element) {
return element &&
element.offsetWidth > 0 &&
element.offsetHeight > 0 &&
element.style.display !== 'none' &&
element.style.visibility !== 'hidden';
}
isInRoom(doc) {
try {
const roomIndicators = [
'.game-container',
'.drawing-area',
'.palette',
'canvas',
'[class*="game"]',
'[class*="sala"]'
];
return roomIndicators.some(selector => {
const element = doc.querySelector(selector);
return element && this.isElementVisible(element);
});
} catch (e) {
return false;
}
}
}
// =============================================
// CONTROLADOR DE SINCRONIZAÇÃO (100% DO SCRIPT 2 - ORDEM CORRETA)
// =============================================
class IframeSyncController {
constructor() {
this.networkController = new AdvancedNetworkController();
this.vacancySystem = new VacancySystem();
this.clickQueue = [];
this.realTimeViewer = new RealTimeViewer();
this.isProcessing = false;
}
async prepareMultiRoomClicks(readyElements) {
this.updateSyncStatus('⚡ PREPARANDO SINCRONIZAÇÃO MULTI-SALA...');
this.clickQueue = [];
readyElements.forEach((element, index) => {
this.clickQueue.push({
element: element,
index: index,
executed: false,
success: false
});
});
this.updateSyncStatus(`🎯 ${readyElements.length} ELEMENTOS MULTI-SALA PREPARADOS`);
return this.clickQueue.length;
}
async executeMultiRoomClicks() {
if (this.clickQueue.length === 0) {
this.updateSyncStatus('❌ NENHUM ELEMENTO MULTI-SALA NA FILA');
return 0;
}
if (this.isProcessing) {
this.updateSyncStatus('⚠️ JÁ EXISTE UMA OPERAÇÃO EM ANDAMENTO');
return 0;
}
this.isProcessing = true;
try {
this.updateSyncStatus('🔒 BLOQUEANDO CONEXÃO...');
this.networkController.blockNetwork();
await this.delay(500);
this.updateSyncStatus('⚡ EXECUTANDO CLIQUES MULTI-SALA...');
const clickPromises = this.clickQueue.map((clickItem, index) => {
return new Promise((resolve) => {
requestAnimationFrame(() => {
const result = this.executeMultiRoomElementClick(clickItem.element, index);
resolve(result);
});
});
});
const results = await Promise.all(clickPromises);
const successfulClicks = results.filter(result => result === true).length;
this.updateSyncStatus('🔓 RESTAURANDO CONEXÃO...');
await this.delay(300);
this.networkController.restoreNetwork();
this.updateSyncStatus(`✅ ${successfulClicks}/${this.clickQueue.length} MULTI-SALA CONCLUÍDO`);
this.isProcessing = false;
return successfulClicks;
} catch (error) {
console.error('💥 ERRO NA SINCRONIZAÇÃO MULTI-SALA:', error);
this.networkController.restoreNetwork();
this.updateSyncStatus('❌ FALHA NA SINCRONIZAÇÃO MULTI-SALA');
this.isProcessing = false;
return 0;
}
}
executeMultiRoomElementClick(elementData, index) {
try {
if (elementData.type === 'multiRoomIframe') {
return this.executeMultiRoomIframeClick(elementData.data, index);
} else if (elementData.type === 'multiRoomExternalTab') {
return this.executeMultiRoomExternalTabClick(elementData.data, index);
}
return false;
} catch (error) {
console.error(`💥 Erro crítico no elemento multi-sala ${index + 1}:`, error);
return false;
}
}
executeMultiRoomIframeClick(iframeData, index) {
try {
const iframe = iframeData.iframe;
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (this.isInRoom(iframeDoc)) {
console.log(`✅ Iframe multi-sala ${index + 1} já está na sala ${iframeData.roomId}`);
return true;
}
const playBtn = this.findPlayButton(iframeDoc);
if (!playBtn) {
console.warn(`❌ Botão não encontrado no iframe multi-sala ${index + 1}`);
return false;
}
try {
playBtn.click();
['mousedown', 'mouseup', 'click'].forEach(eventType => {
try {
const event = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
view: iframe.contentWindow
});
playBtn.dispatchEvent(event);
} catch (e) {}
});
} catch (error) {
console.warn(`⚠️ Erro no clique iframe multi-sala ${index + 1}:`, error);
return false;
}
console.log(`🎯 Clique executado no iframe multi-sala ${index + 1} (Sala ${iframeData.roomId})`);
this.realTimeViewer.updateMultiRoomIframeStatus(index, '⚡ CLICADO!', '#FF9800');
return true;
} catch (error) {
console.error(`💥 Erro crítico no iframe multi-sala ${index + 1}:`, error);
return false;
}
}
executeMultiRoomExternalTabClick(tabData, index) {
try {
if (tabData.window.closed) {
console.warn(`❌ Aba externa multi-sala ${index + 1} foi fechada`);
return false;
}
const tabDoc = tabData.window.document;
if (this.isInRoom(tabDoc)) {
console.log(`✅ Aba externa multi-sala ${index + 1} já está na sala ${tabData.roomId}`);
return true;
}
const playBtn = this.findPlayButton(tabDoc);
if (!playBtn) {
console.warn(`❌ Botão não encontrado na aba externa multi-sala ${index + 1}`);
return false;
}
try {
tabData.window.focus();
playBtn.click();
['mousedown', 'mouseup', 'click'].forEach(eventType => {
try {
const event = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
view: tabData.window
});
playBtn.dispatchEvent(event);
} catch (e) {}
});
} catch (error) {
console.warn(`⚠️ Erro no clique aba externa multi-sala ${index + 1}:`, error);
return false;
}
console.log(`🎯 Clique executado na aba externa multi-sala ${index + 1} (Sala ${tabData.roomId})`);
this.realTimeViewer.updateMultiRoomExternalStatus(index, '⚡ CLICADO!', '#FF9800');
return true;
} catch (error) {
console.error(`💥 Erro crítico na aba externa multi-sala ${index + 1}:`, error);
return false;
}
}
async prepareAllClicks(readyElements) {
this.updateSyncStatus('⚡ PREPARANDO SINCRONIZAÇÃO...');
this.clickQueue = [];
readyElements.forEach((element, index) => {
this.clickQueue.push({
element: element,
index: index,
executed: false,
success: false
});
});
this.updateSyncStatus(`🎯 ${readyElements.length} ELEMENTOS PREPARADOS`);
return this.clickQueue.length;
}
async executeAllClicksWithVacancyCheck(roomId) {
if (this.clickQueue.length === 0) {
this.updateSyncStatus('❌ NENHUM ELEMENTO NA FILA');
return 0;
}
if (this.isProcessing) {
this.updateSyncStatus('⚠️ JÁ EXISTE UMA OPERAÇÃO EM ANDAMENTO');
return 0;
}
this.isProcessing = true;
try {
// FASE 1: VERIFICAR VAGAS (100% DO SCRIPT 2)
this.updateSyncStatus('🔍 VERIFICANDO VAGAS...');
const vacancyInfo = await this.vacancySystem.checkRoomVacancy(roomId);
if (!vacancyInfo.hasVacancy) {
this.updateSyncStatus('⏳ AGUARDANDO VAGA...');
await new Promise((resolve) => {
this.vacancySystem.startVacancyCheck(roomId, (hasVacancy) => {
if (hasVacancy) {
resolve();
}
});
});
}
// FASE 2: BLOQUEIO TOTAL DA CONEXÃO
this.updateSyncStatus('🔒 BLOQUEANDO CONEXÃO...');
this.networkController.blockNetwork();
await this.delay(500);
// FASE 3: EXECUTAR TODOS OS CLIQUES SIMULTANEAMENTE
this.updateSyncStatus('⚡ EXECUTANDO CLIQUES...');
const clickPromises = this.clickQueue.map((clickItem, index) => {
return new Promise((resolve) => {
requestAnimationFrame(() => {
const result = this.executeElementClick(clickItem.element, index);
resolve(result);
});
});
});
const results = await Promise.all(clickPromises);
const successfulClicks = results.filter(result => result === true).length;
// FASE 4: RESTAURAR CONEXÃO IMEDIATAMENTE
this.updateSyncStatus('🔓 RESTAURANDO CONEXÃO...');
await this.delay(300);
this.networkController.restoreNetwork();
this.updateSyncStatus(`✅ ${successfulClicks}/${this.clickQueue.length} CONCLUÍDO`);
this.isProcessing = false;
return successfulClicks;
} catch (error) {
console.error('💥 ERRO NA SINCRONIZAÇÃO:', error);
this.networkController.restoreNetwork();
this.vacancySystem.stopVacancyCheck();
this.updateSyncStatus('❌ FALHA NA SINCRONIZAÇÃO');
this.isProcessing = false;
return 0;
}
}
executeElementClick(elementData, index) {
try {
if (elementData.type === 'iframe') {
return this.executeIframeClick(elementData.data, index);
} else if (elementData.type === 'externalTab') {
return this.executeExternalTabClick(elementData.data, index);
}
return false;
} catch (error) {
console.error(`💥 Erro crítico no elemento ${index + 1}:`, error);
return false;
}
}
executeIframeClick(iframeData, index) {
try {
const iframe = iframeData.iframe;
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (this.isInRoom(iframeDoc)) {
console.log(`✅ Iframe ${index + 1} já está na sala`);
return true;
}
const playBtn = this.findPlayButton(iframeDoc);
if (!playBtn) {
console.warn(`❌ Botão não encontrado no iframe ${index + 1}`);
return false;
}
try {
playBtn.click();
['mousedown', 'mouseup', 'click'].forEach(eventType => {
try {
const event = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
view: iframe.contentWindow
});
playBtn.dispatchEvent(event);
} catch (e) {}
});
} catch (error) {
console.warn(`⚠️ Erro no clique iframe ${index + 1}:`, error);
return false;
}
console.log(`🎯 Clique executado no iframe ${index + 1}`);
this.realTimeViewer.updateIframeStatus(index, '⚡ CLICADO!', '#FF9800');
return true;
} catch (error) {
console.error(`💥 Erro crítico no iframe ${index + 1}:`, error);
return false;
}
}
executeExternalTabClick(tabData, index) {
try {
if (tabData.window.closed) {
console.warn(`❌ Aba externa ${index + 1} foi fechada`);
return false;
}
const tabDoc = tabData.window.document;
if (this.isInRoom(tabDoc)) {
console.log(`✅ Aba externa ${index + 1} já está na sala`);
return true;
}
const playBtn = this.findPlayButton(tabDoc);
if (!playBtn) {
console.warn(`❌ Botão não encontrado na aba externa ${index + 1}`);
return false;
}
try {
tabData.window.focus();
playBtn.click();
['mousedown', 'mouseup', 'click'].forEach(eventType => {
try {
const event = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
view: tabData.window
});
playBtn.dispatchEvent(event);
} catch (e) {}
});
} catch (error) {
console.warn(`⚠️ Erro no clique aba externa ${index + 1}:`, error);
return false;
}
console.log(`🎯 Clique executado na aba externa ${index + 1}`);
this.realTimeViewer.updateExternalTabStatus(index, '⚡ CLICADO!', '#FF9800');
return true;
} catch (error) {
console.error(`💥 Erro crítico na aba externa ${index + 1}:`, error);
return false;
}
}
findPlayButton(doc) {
const selectors = [
'input[value*="Jogar" i]',
'input[value*="Play" i]',
'input[type="submit"]',
'button[type="submit"]'
];
for (const selector of selectors) {
try {
const element = doc.querySelector(selector);
if (element && this.isElementVisible(element)) return element;
} catch (e) {}
}
return null;
}
isElementVisible(element) {
return element && element.offsetWidth > 0 && element.offsetHeight > 0;
}
isInRoom(doc) {
try {
const indicators = [
'.game-container',
'.drawing-area',
'canvas',
'.room-container',
'#game',
'.palette'
];
return indicators.some(selector => doc.querySelector(selector));
} catch (e) {
return false;
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
updateSyncStatus(msg) {
if (typeof window.updateSyncStatus === 'function') {
window.updateSyncStatus(msg);
} else {
console.log('SYNC STATUS:', msg);
}
}
stopVacancyCheck() {
this.vacancySystem.stopVacancyCheck();
}
}
// =============================================
// VARIÁVEIS GLOBAIS E INICIALIZAÇÃO
// =============================================
let selectedRoom = null;
let configManager = new ConfigManager();
let iframeController = new IframeSyncController();
let multiRoomManager = new MultiRoomManager();
// NOVO: Instanciar sistemas avançados
let precisionSyncSystem = new PrecisionSyncSystem();
let proNetworkController = new ProfessionalNetworkController();
let randomRoomSelector = new RandomRoomSelector();
window.configManager = configManager;
window.precisionSyncSystem = precisionSyncSystem;
window.proNetworkController = proNetworkController;
window.randomRoomSelector = randomRoomSelector;
let botCount = configManager.get('defaultTabCount') || 5;
let useExternalTabs = configManager.get('useExternalTabs') || false;
let externalTabCount = configManager.get('externalTabCount') || 0;
let nickPrefix = configManager.get('nickPrefix');
let disableRandomNumbers = configManager.get('disableRandomNumbers') || false;
let onlyEmptyRooms = configManager.get('onlyEmptyRooms') || false; // NOVA VARIÁVEL
selectedRoom = configManager.get('lastRoom');
const savedRooms = configManager.get('selectedRooms');
if (savedRooms && Array.isArray(savedRooms)) {
multiRoomManager.selectedRooms = savedRooms;
randomRoomSelector.selectedRooms = new Set(savedRooms);
}
// =============================================
// FUNÇÕES DO SCRIPT ORIGINAL
// =============================================
function loadRooms() {
const roomList = document.getElementById('roomList');
const rooms = document.querySelectorAll('.sala, [onclick*="selecionaSala"], .room, [class*="room"]');
roomList.innerHTML = '';
if (rooms.length === 0) {
roomList.innerHTML = '<div style="padding:10px;text-align:center;color:#666;font-size:10px;">Nenhuma sala encontrada<br>Recarregue a página</div>';
return;
}
rooms.forEach((room, index) => {
const roomElement = document.createElement('div');
roomElement.style.cssText = `
display: flex;
align-items: center;
padding: 6px 8px;
cursor: pointer;
border-bottom: 1px solid #eee;
font-size: 10px;
transition: all 0.2s;
`;
const roomText = room.textContent.trim();
const onclickAttr = room.getAttribute('onclick');
let roomId = null;
if (onclickAttr) {
const roomMatch = onclickAttr.match(/\d+/);
if (roomMatch) {
roomId = roomMatch[0];
}
}
// Verificar quantidade de pessoas na sala
let playerCount = 0;
const quantElement = room.querySelector('.sala_quant');
if (quantElement) {
const quantText = quantElement.textContent;
playerCount = parseInt(quantText) || 0;
}
const isEmpty = playerCount === 0;
const shouldHide = onlyEmptyRooms && !isEmpty;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.style.marginRight = '8px';
checkbox.style.transform = 'scale(0.8)';
checkbox.setAttribute('data-room-id', roomId || '');
if (roomId) {
if (multiRoomManager.selectedRooms.includes(roomId) ||
randomRoomSelector.selectedRooms.has(roomId)) {
checkbox.checked = true;
}
multiRoomManager.roomCheckboxes.set(roomId, checkbox);
randomRoomSelector.roomElements.set(roomId, room);
}
checkbox.onchange = function(e) {
e.stopPropagation();
if (roomId) {
if (checkbox.checked) {
multiRoomManager.addRoom(roomId);
randomRoomSelector.selectedRooms.add(roomId);
} else {
multiRoomManager.removeRoom(roomId);
randomRoomSelector.selectedRooms.delete(roomId);
}
configManager.set('selectedRooms', multiRoomManager.selectedRooms);
updateSelectedRoomsList();
}
};
roomElement.appendChild(checkbox);
const roomTextElement = document.createElement('span');
const playerInfo = isEmpty ? ' 🟢' : ` 👥 ${playerCount}`;
roomTextElement.textContent = `${index + 1}. ${roomText.substring(0, 30)}${roomText.length > 30 ? '...' : ''}${playerInfo}`;
if (isEmpty) {
roomTextElement.style.color = '#4CAF50';
roomTextElement.style.fontWeight = 'bold';
} else if (playerCount > 0) {
roomTextElement.style.color = '#FF9800';
}
roomElement.appendChild(roomTextElement);
if (shouldHide) {
roomElement.style.display = 'none';
}
roomElement.onmouseenter = () => {
roomElement.style.background = '#f0f0f0';
};
roomElement.onmouseleave = () => {
if (!roomElement.style.background.includes('#8A2BE2')) {
roomElement.style.background = '';
}
};
roomElement.onclick = (e) => {
if (e.target !== checkbox) {
document.querySelectorAll('#roomList div').forEach(el => {
el.style.background = '';
el.style.color = '';
});
roomElement.style.background = '#8A2BE2';
roomElement.style.color = 'white';
if (roomId) {
selectedRoom = roomId;
configManager.set('lastRoom', selectedRoom);
updateStatus(`🎯 Sala ${selectedRoom} selecionada`);
}
}
};
if (roomId) {
multiRoomManager.roomCheckboxes.set(roomId, checkbox);
}
roomList.appendChild(roomElement);
});
updateSelectedRoomsList();
}
function filterRooms(searchText) {
document.querySelectorAll('#roomList div').forEach(room => {
const shouldShow = room.textContent.toLowerCase().includes(searchText);
const isEmptyVisible = room.textContent.includes('🟢');
if (onlyEmptyRooms && !isEmptyVisible && !shouldShow) {
room.style.display = 'none';
} else {
room.style.display = shouldShow ? 'flex' : 'none';
}
});
}
function generateNicks(totalCount) {
const nicks = [];
for (let i = 0; i < totalCount; i++) {
if (disableRandomNumbers) {
nicks.push(nickPrefix);
} else {
const usedNumbers = new Set();
let randomNum;
do {
randomNum = Math.floor(Math.random() * 9000) + 1000;
} while (usedNumbers.has(randomNum));
usedNumbers.add(randomNum);
nicks.push(`${nickPrefix}${randomNum}`);
}
}
return nicks;
}
window.updateSyncStatus = function(msg) {
const syncStatus = document.getElementById('syncStatus');
if (syncStatus) {
syncStatus.textContent = msg;
syncStatus.style.color = msg.includes('✅') ? '#4CAF50' :
msg.includes('❌') ? '#f44336' :
msg.includes('⚡') ? '#FFEB3B' : '#c8e6c9';
}
};
function updateStatus(msg) {
const status = document.getElementById('status');
if (status) {
status.textContent = msg;
status.style.color = msg.includes('✅') || msg.includes('🎉') ? '#4CAF50' :
msg.includes('❌') ? '#f44336' :
msg.includes('🚀') || msg.includes('⚡') ? '#2196F3' : 'white';
}
}
function updateTabStatus() {
const tabStatus = document.getElementById('tabStatus');
if (tabStatus) {
const totalIframes = iframeController.realTimeViewer.iframes.size;
const readyIframes = iframeController.realTimeViewer.getReadyIframes().length;
const totalExternalTabs = iframeController.realTimeViewer.externalTabs.size;
const readyExternalTabs = iframeController.realTimeViewer.getReadyExternalTabs().length;
tabStatus.textContent = `Iframes: ${totalIframes} | Prontos: ${readyIframes} | Abas: ${totalExternalTabs} | Prontas: ${readyExternalTabs}`;
tabStatus.style.color = (readyIframes + readyExternalTabs) === (totalIframes + totalExternalTabs) && (totalIframes + totalExternalTabs) > 0 ? '#4CAF50' : '#e0e0e0';
}
}
// =============================================
// NOVO: FUNÇÕES PARA OS SISTEMAS MULTI-SALA
// =============================================
function createMultiRoomIframes() {
if (!multiRoomManager.hasRooms() && randomRoomSelector.getSelectedCount() === 0) {
alert('Selecione pelo menos uma sala primeiro!');
return;
}
const iframeCount = parseInt(document.getElementById('multiRoomIframeCount').value) || 0;
if (iframeCount === 0) {
alert('Configure a quantidade de iframes!');
return;
}
updateStatus('🚀 CRIANDO IFRAMES MULTI-SALA...');
const nicks = generateNicks(iframeCount);
const rooms = randomRoomSelector.getSelectedCount() > 0 ?
randomRoomSelector.getSelectedRooms() :
multiRoomManager.selectedRooms;
for (let i = 0; i < iframeCount; i++) {
const roomId = rooms[i % rooms.length];
iframeController.realTimeViewer.createMultiRoomIframe(nicks[i], i, [roomId], 0);
}
iframeController.realTimeViewer.openViewer();
updateStatus(`✅ ${iframeCount} IFRAMES MULTI-SALA CRIADOS!`);
updateMultiRoomStatus();
}
function createMultiRoomExternalTabs() {
if (!multiRoomManager.hasRooms() && randomRoomSelector.getSelectedCount() === 0) {
alert('Selecione pelo menos uma sala primeiro!');
return;
}
const externalCount = parseInt(document.getElementById('multiRoomExternalCount').value) || 0;
if (externalCount === 0) {
alert('Configure a quantidade de abas externas!');
return;
}
updateStatus('🚀 CRIANDO ABAS EXTERNAS MULTI-SALA...');
const nicks = generateNicks(externalCount);
const rooms = randomRoomSelector.getSelectedCount() > 0 ?
randomRoomSelector.getSelectedRooms() :
multiRoomManager.selectedRooms;
for (let i = 0; i < externalCount; i++) {
const roomId = rooms[i % rooms.length];
iframeController.realTimeViewer.createMultiRoomExternalTab(nicks[i], i, [roomId], 0);
}
iframeController.realTimeViewer.openViewer();
updateStatus(`✅ ${externalCount} ABAS MULTI-SALA CRIADAS!`);
updateMultiRoomStatus();
}
function createMultiRoomTabs() {
if (!multiRoomManager.hasRooms() && randomRoomSelector.getSelectedCount() === 0) {
alert('Selecione pelo menos uma sala primeiro!');
return;
}
const iframeCount = parseInt(document.getElementById('multiRoomIframeCount').value) || 0;
const externalCount = parseInt(document.getElementById('multiRoomExternalCount').value) || 0;
if (iframeCount === 0 && externalCount === 0) {
alert('Configure pelo menos um dos contadores (iframes ou abas externas)!');
return;
}
updateStatus('🚀 CRIANDO ABAS MULTI-SALA...');
const totalCount = iframeCount + externalCount;
const nicks = generateNicks(totalCount);
const rooms = randomRoomSelector.getSelectedCount() > 0 ?
randomRoomSelector.getSelectedRooms() :
multiRoomManager.selectedRooms;
let iframeIndex = 0;
let externalTabIndex = 0;
for (let i = 0; i < totalCount; i++) {
const roomId = rooms[i % rooms.length];
if (i < iframeCount) {
iframeController.realTimeViewer.createMultiRoomIframe(nicks[i], iframeIndex, [roomId], 0);
iframeIndex++;
} else {
iframeController.realTimeViewer.createMultiRoomExternalTab(nicks[i], externalTabIndex, [roomId], 0);
externalTabIndex++;
}
}
iframeController.realTimeViewer.openViewer();
updateStatus(`✅ ${totalCount} ABAS MULTI-SALA CRIADAS!`);
updateMultiRoomStatus();
}
async function playMultiRoomElements() {
const readyElements = iframeController.realTimeViewer.getAllMultiRoomReadyElements();
if (readyElements.length === 0) {
alert('Nenhum elemento multi-sala está pronto! Aguarde o carregamento.');
return;
}
updateStatus('⚡ INICIANDO MULTI-SALA...');
window.updateSyncStatus(`Preparando ${readyElements.length} elementos multi-sala...`);
try {
await iframeController.prepareMultiRoomClicks(readyElements);
const results = await iframeController.executeMultiRoomClicks();
if (results > 0) {
updateStatus(`🎉 ${results} ELEMENTOS MULTI-SALA ENTRARAM!`);
window.updateSyncStatus('✅ SINCRONIZAÇÃO MULTI-SALA CONCLUÍDA!');
} else {
updateStatus('❌ FALHA NA SINCRONIZAÇÃO MULTI-SALA');
}
} catch (error) {
console.error('💥 ERRO MULTI-SALA:', error);
updateStatus('❌ Erro na sincronização multi-sala');
}
}
function clearMultiRoomElements() {
iframeController.realTimeViewer.closeAllMultiRoomElements();
updateStatus('🧹 ELEMENTOS MULTI-SALA LIMPOS');
updateMultiRoomStatus();
}
function updateMultiRoomStatus() {
const iframeStatus = document.getElementById('multiRoomIframeStatus');
const externalStatus = document.getElementById('multiRoomExternalStatus');
if (iframeStatus) {
const iframeCount = iframeController.realTimeViewer.multiRoomIframes.size;
const readyIframes = Array.from(iframeController.realTimeViewer.multiRoomIframes.values())
.filter(data => data.tabData.ready).length;
iframeStatus.textContent = `Iframes: ${iframeCount} | Prontos: ${readyIframes}`;
}
if (externalStatus) {
const externalCount = iframeController.realTimeViewer.multiRoomExternalTabs.size;
const readyExternal = Array.from(iframeController.realTimeViewer.multiRoomExternalTabs.values())
.filter(data => data.ready && !data.window.closed).length;
externalStatus.textContent = `Abas: ${externalCount} | Prontas: ${readyExternal}`;
}
}
function updateSelectedRoomsList() {
const selectedRoomsList = document.getElementById('selectedRoomsList');
if (!selectedRoomsList) return;
const rooms = multiRoomManager.selectedRooms.length > 0 ?
multiRoomManager.selectedRooms :
randomRoomSelector.getSelectedRooms();
if (rooms.length === 0) {
selectedRoomsList.innerHTML = 'Nenhuma sala selecionada';
selectedRoomsList.style.color = '#666';
} else {
selectedRoomsList.innerHTML = rooms.map(roomId =>
`<span style="display:inline-block;background:#8A2BE2;color:white;padding:2px 6px;margin:1px;border-radius:3px;font-size:9px;">Sala ${roomId}</span>`
).join('');
selectedRoomsList.style.color = '#333';
}
}
// =============================================
// FUNÇÕES EXISTENTES DO SISTEMA ORIGINAL
// =============================================
function createInterface() {
if (document.getElementById('gartic-multi-menu')) return;
const menu = document.createElement('div');
menu.id = 'gartic-multi-menu';
menu.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: white;
padding: 15px;
border: 3px solid #8A2BE2;
border-radius: 12px;
z-index: 20000;
width: 550px;
max-width: 90vw;
box-shadow: 0 6px 20px rgba(0,0,0,0.2);
font-family: Arial, sans-serif;
transition: all 0.3s ease;
`;
const menuContent = document.createElement('div');
menuContent.id = 'menu-content';
menuContent.innerHTML = `
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px;">
<div>
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">Prefixo:</label>
<input type="text" id="nickPrefix" value="${nickPrefix}" style="width:100%;padding:6px;border:2px solid #8A2BE2;border-radius:5px;font-size:12px;">
</div>
<div>
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">Iframes:</label>
<input type="number" id="botCount" value="${botCount}" min="1" max="1000" style="width:100%;padding:6px;border:2px solid #8A2BE2;border-radius:5px;font-size:12px;">
</div>
</div>
<!-- NOVO: BOTÃO PARA DESATIVAR NÚMEROS ALEATÓRIOS -->
<div style="margin-bottom:12px;">
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">
<input type="checkbox" id="disableRandomNumbers" ${disableRandomNumbers ? 'checked' : ''} style="margin-right:5px;">
Desativar números aleatórios no nick
</label>
<div style="font-size:9px;color:#666;margin-top:2px;">
${disableRandomNumbers ? '✅ Nick será apenas o prefixo' : '✅ Nick será prefixo + 4 números aleatórios'}
</div>
</div>
<!-- NOVA OPÇÃO: Filtrar apenas salas vazias -->
<div style="margin-bottom:12px;">
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">
<input type="checkbox" id="onlyEmptyRooms" ${onlyEmptyRooms ? 'checked' : ''} style="margin-right:5px;">
🔄 Mostrar apenas salas VAZIAS (com 0 pessoas)
</label>
<div style="font-size:9px;color:#666;margin-top:2px;">
${onlyEmptyRooms ? '✅ Filtrando apenas salas vazias' : '⭕ Mostrando todas as salas'}
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px;">
<div>
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">
<input type="checkbox" id="useExternalTabs" ${useExternalTabs ? 'checked' : ''} style="margin-right:5px;">
Usar Abas Externas
</label>
</div>
<div>
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">Quant. Abas:</label>
<input type="number" id="externalTabCount" value="${externalTabCount}" min="0" max="1000" style="width:100%;padding:6px;border:2px solid #8B4513;border-radius:5px;font-size:12px;" ${!useExternalTabs ? 'disabled' : ''}>
</div>
</div>
<!-- NOVO: SEÇÃO DE CONTROLES AVANÇADOS -->
<div style="background:linear-gradient(135deg,#0066cc,#0099ff);padding:12px;border-radius:8px;margin-bottom:12px;border:2px solid #0066cc;">
<h4 style="margin:0 0 10px 0;color:white;font-size:13px;text-align:center;">⚡ SISTEMA AVANÇADO PRO</h4>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px;">
<button id="advancedSyncBtn" style="padding:8px;background:#FF6B00;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">🎯 Sincronização Avançada</button>
<button id="testNetworkBtn" style="padding:8px;background:#2196F3;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">🌐 Testar Rede</button>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
<button id="selectRandomRoomsBtn" style="padding:8px;background:#9C27B0;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">🎲 Salas Aleatórias</button>
<button id="intelligentTabsBtn" style="padding:8px;background:#4CAF50;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">🚀 Abas Inteligentes</button>
</div>
</div>
<!-- NOVO: SISTEMA MULTI-SALA UNIFICADO -->
<div style="background:linear-gradient(135deg,#FF6B00,#FFA500);padding:10px;border-radius:8px;margin-bottom:12px;">
<h4 style="margin:0 0 8px 0;color:white;font-size:12px;text-align:center;">🎯 SISTEMA MULTI-SALA</h4>
<!-- Contadores -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px;">
<div>
<label style="font-size:10px;display:block;font-weight:bold;margin-bottom:2px;color:white;">Iframes:</label>
<input type="number" id="multiRoomIframeCount" value="${configManager.get('multiRoomIframeCount') || 0}" min="0" max="1000" style="width:100%;padding:4px;border:1px solid white;border-radius:3px;font-size:11px;">
</div>
<div>
<label style="font-size:10px;display:block;font-weight:bold;margin-bottom:2px;color:white;">Abas Externas:</label>
<input type="number" id="multiRoomExternalCount" value="${configManager.get('multiRoomExternalCount') || 0}" min="0" max="1000" style="width:100%;padding:4px;border:1px solid white;border-radius:3px;font-size:11px;">
</div>
</div>
<!-- Botão único para criar abas -->
<div style="display:grid;grid-template-columns:1fr;gap:6px;">
<button id="createMultiRoomTabsBtn" style="width:100%;padding:8px;background:white;color:#FF6B00;border:none;border-radius:4px;cursor:pointer;font-weight:bold;font-size:11px;">🚀 Criar Abas Multi-Sala</button>
</div>
<!-- Status -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-top:5px;">
<div style="font-size:9px;color:white;text-align:center;">
<span id="multiRoomIframeStatus">Iframes: 0 | Prontos: 0</span>
</div>
<div style="font-size:9px;color:white;text-align:center;">
<span id="multiRoomExternalStatus">Abas: 0 | Prontas: 0</span>
</div>
</div>
</div>
<!-- BOTÕES DE CONTROLE MULTI-SALA -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:12px;">
<button id="playMultiRoomBtn" style="padding:8px;background:#FF6B00;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">⚡ Jogar MULTI-SALA</button>
<button id="clearMultiRoomBtn" style="padding:8px;background:#f44336;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:bold;">❌ Limpar MULTI-SALA</button>
</div>
<div style="margin-bottom:12px;">
<label style="font-size:11px;display:block;font-weight:bold;margin-bottom:3px;">Pesquisar sala:</label>
<input type="text" id="searchRoom" placeholder="Digite para filtrar..." style="width:100%;padding:6px;border:1px solid #ddd;border-radius:5px;font-size:12px;">
</div>
<div style="max-height:150px;overflow-y:auto;border:1px solid #ccc;margin-bottom:12px;border-radius:5px;background:#fafafa;">
<div id="roomList" style="font-size:11px;"></div>
</div>
<!-- NOVO: SELEÇÃO DE MÚLTIPLAS SALAS -->
<div style="margin-bottom:12px;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:5px;">
<label style="font-size:11px;font-weight:bold;">Salas Selecionadas:</label>
<div>
<button id="clearSelectedRoomsBtn" style="padding:3px 8px;background:#f44336;color:white;border:none;border-radius:3px;cursor:pointer;font-size:9px;margin-right:5px;">Limpar</button>
<button id="autoSelectRoomsBtn" style="padding:3px 8px;background:#9C27B0;color:white;border:none;border-radius:3px;cursor:pointer;font-size:9px;">Auto</button>
</div>
</div>
<div id="selectedRoomsList" style="font-size:10px;color:#666;min-height:20px;padding:5px;background:#f5f5f5;border-radius:3px;border:1px dashed #ccc;">
Nenhuma sala selecionada
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px;">
<button id="createIframesBtn" style="padding:10px;background:#2196F3;color:white;border:none;border-radius:6px;cursor:pointer;font-weight:bold;font-size:12px;">🪟 Criar Iframes/Abas</button>
<button id="playAllBtn" style="padding:10px;background:#4CAF50;color:white;border:none;border-radius:6px;cursor:pointer;font-weight:bold;font-size:12px;">⚡ Jogar TODOS</button>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:12px;">
<button id="toggleViewerBtn" style="padding:8px;background:#9C27B0;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;">👁️ Mostrar/Ocultar</button>
<button id="testSyncBtn" style="padding:8px;background:#FF9800;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;">🎯 Teste</button>
<button id="closeAllBtn" style="padding:8px;background:#f44336;color:white;border:none;border-radius:5px;cursor:pointer;font-size:10px;">❌ Limpar Tudo</button>
</div>
<div style="background:linear-gradient(135deg,#667eea,#764ba2);padding:10px;border-radius:6px;margin-bottom:8px;">
<div id="status" style="font-size:12px;text-align:center;font-weight:bold;color:white;">✅ SISTEMA MULTI-SALA ATIVADO</div>
<div id="tabStatus" style="font-size:10px;color:#e0e0e0;text-align:center;margin-top:3px;">Iframes: 0 | Prontos: 0 | Abas: 0 | Prontas: 0</div>
<div id="syncStatus" style="font-size:9px;color:#c8e6c9;text-align:center;margin-top:5px;"></div>
</div>
`;
const menuHeader = document.createElement('div');
menuHeader.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
margin: -15px -15px 15px -15px;
padding: 10px 15px;
background: #8A2BE2;
color: white;
border-radius: 8px 8px 0 0;
cursor: move;
`;
menuHeader.innerHTML = `
<h3 style="margin:0; font-size:16px;">🎯 GARTIC PRO v25.03 - CLIQUE 100% SINCRONIZADO</h3>
<div>
<button id="minimizeMenuBtn" style="background:#FF9800; color:white; border:none; border-radius:5px; padding:5px 10px; cursor:pointer; font-weight:bold; margin-right:5px;">−</button>
<button id="closeMenuBtn" style="background:#ff4444; color:white; border:none; border-radius:5px; padding:5px 10px; cursor:pointer; font-weight:bold;">X</button>
</div>
`;
menu.appendChild(menuHeader);
menu.appendChild(menuContent);
document.body.appendChild(menu);
loadRooms();
setupEvents();
setupMenuDrag(menuHeader, menu);
updateStatus('✅ SISTEMA PRO ATIVADO - CLIQUE 100% SINCRONIZADO');
if (configManager.get('menuMinimized')) {
toggleMenuMinimize();
}
}
// =============================================
// NOVO: FUNÇÕES AVANÇADAS
// =============================================
async function executeAdvancedSync(elements, roomId = null) {
if (elements.length === 0) {
updateStatus('❌ Nenhum elemento pronto para sincronização');
return 0;
}
updateStatus('⚡ EXECUTANDO SINCRONIZAÇÃO AVANÇADA...');
try {
const successCount = await precisionSyncSystem.executeUltraPreciseSync(elements, roomId);
if (successCount > 0) {
updateStatus(`🎉 ${successCount}/${elements.length} ENTRARAM COM SUCESSO!`);
} else {
updateStatus('⚠️ Nenhum elemento conseguiu entrar');
}
return successCount;
} catch (error) {
console.error('❌ ERRO NA SINCRONIZAÇÃO AVANÇADA:', error);
updateStatus('❌ Falha na sincronização avançada');
return 0;
}
}
function testNetworkSystem() {
updateStatus('🔧 TESTANDO SISTEMA DE REDE...');
const status = proNetworkController.checkNetworkStatus();
const networkStatus = status.isBlocked ? 'BLOQUEADA' : 'ATIVA';
setTimeout(async () => {
const isWorking = await proNetworkController.testNetwork();
updateStatus(`🌐 Rede: ${networkStatus} | Funcional: ${isWorking ? '✅' : '❌'}`);
}, 1000);
}
function selectRandomRoomsUI() {
const count = parseInt(prompt('Quantas salas deseja selecionar aleatoriamente?', '30')) || 0;
if (count > 0) {
const selected = randomRoomSelector.selectRandomRooms(count);
multiRoomManager.selectedRooms = selected;
configManager.set('selectedRooms', selected);
updateStatus(`✅ ${selected.length} salas selecionadas aleatoriamente ${onlyEmptyRooms ? '(apenas vazias)' : ''}`);
updateSelectedRoomsList();
loadRooms(); // Recarregar para atualizar os checkboxes
}
}
function createIntelligentTabs() {
if (!multiRoomManager.hasRooms() && randomRoomSelector.getSelectedCount() === 0) {
alert('Selecione salas primeiro ou use a seleção aleatória!');
return;
}
const iframeCount = parseInt(document.getElementById('multiRoomIframeCount').value) || 0;
const externalCount = parseInt(document.getElementById('multiRoomExternalCount').value) || 0;
if (iframeCount === 0 && externalCount === 0) {
alert('Configure pelo menos um dos contadores!');
return;
}
updateStatus('🚀 CRIANDO ABAS COM DISTRIBUIÇÃO INTELIGENTE...');
const totalTabs = iframeCount + externalCount;
const nicks = generateNicks(totalTabs);
const rooms = randomRoomSelector.getSelectedCount() > 0 ?
randomRoomSelector.getSelectedRooms() :
multiRoomManager.selectedRooms;
if (rooms.length === 0) {
updateStatus('❌ Nenhuma sala selecionada');
return;
}
const distribution = randomRoomSelector.distributeTabsAmongRooms(totalTabs, 'balanced');
for (let i = 0; i < distribution.length; i++) {
const { roomId, tabIndex } = distribution[i];
const nick = nicks[tabIndex];
if (i < iframeCount) {
iframeController.realTimeViewer.createMultiRoomIframe(nick, tabIndex, [roomId], 0);
} else {
iframeController.realTimeViewer.createMultiRoomExternalTab(nick, tabIndex, [roomId], 0);
}
if (i % 10 === 0 && i > 0) {
setTimeout(() => {}, 50);
}
}
iframeController.realTimeViewer.openViewer();
updateStatus(`✅ ${totalTabs} abas criadas com distribuição inteligente!`);
}
// =============================================
// ATUALIZAÇÃO DO SETUP DE EVENTOS (100% DO SCRIPT 2)
// =============================================
function setupEvents() {
document.getElementById('nickPrefix').addEventListener('input', function(e) {
nickPrefix = e.target.value || 'Player';
configManager.set('nickPrefix', nickPrefix);
});
document.getElementById('botCount').addEventListener('input', function(e) {
botCount = Math.max(1, Math.min(1000, parseInt(e.target.value) || 5));
configManager.set('defaultTabCount', botCount);
});
document.getElementById('disableRandomNumbers').addEventListener('change', function(e) {
disableRandomNumbers = e.target.checked;
configManager.set('disableRandomNumbers', disableRandomNumbers);
updateStatus(disableRandomNumbers ?
'✅ Números aleatórios DESATIVADOS' :
'✅ Números aleatórios ATIVADOS');
});
// NOVO: Evento para filtrar apenas salas vazias
document.getElementById('onlyEmptyRooms').addEventListener('change', function(e) {
onlyEmptyRooms = e.target.checked;
configManager.set('onlyEmptyRooms', onlyEmptyRooms);
updateStatus(onlyEmptyRooms ?
'✅ Filtrando apenas salas VAZIAS (com 0 pessoas)' :
'✅ Mostrando todas as salas');
loadRooms(); // Recarregar a lista com o novo filtro
});
document.getElementById('useExternalTabs').addEventListener('change', function(e) {
useExternalTabs = e.target.checked;
configManager.set('useExternalTabs', useExternalTabs);
const externalTabCountInput = document.getElementById('externalTabCount');
externalTabCountInput.disabled = !useExternalTabs;
});
document.getElementById('externalTabCount').addEventListener('input', function(e) {
externalTabCount = Math.max(0, Math.min(1000, parseInt(e.target.value) || 0));
configManager.set('externalTabCount', externalTabCount);
});
// NOVO: Botões avançados
document.getElementById('advancedSyncBtn').onclick = async function() {
const readyElements = iframeController.realTimeViewer.getAllReadyElements();
if (readyElements.length === 0) {
alert('Nenhuma aba está pronta para sincronização!');
return;
}
await executeAdvancedSync(readyElements, selectedRoom);
};
document.getElementById('testNetworkBtn').onclick = testNetworkSystem;
document.getElementById('selectRandomRoomsBtn').onclick = selectRandomRoomsUI;
document.getElementById('autoSelectRoomsBtn').onclick = selectRandomRoomsUI;
document.getElementById('intelligentTabsBtn').onclick = createIntelligentTabs;
// Eventos multi-sala
document.getElementById('multiRoomIframeCount').addEventListener('input', function(e) {
const value = Math.max(0, Math.min(1000, parseInt(e.target.value) || 0));
configManager.set('multiRoomIframeCount', value);
});
document.getElementById('multiRoomExternalCount').addEventListener('input', function(e) {
const value = Math.max(0, Math.min(1000, parseInt(e.target.value) || 0));
configManager.set('multiRoomExternalCount', value);
});
document.getElementById('createMultiRoomTabsBtn').onclick = createMultiRoomTabs;
document.getElementById('playMultiRoomBtn').onclick = playMultiRoomElements;
document.getElementById('clearMultiRoomBtn').onclick = clearMultiRoomElements;
document.getElementById('clearSelectedRoomsBtn').onclick = function() {
multiRoomManager.clearRooms();
randomRoomSelector.clearSelection();
configManager.set('selectedRooms', []);
updateSelectedRoomsList();
loadRooms(); // Recarregar para atualizar os checkboxes
};
// Eventos existentes (100% DO SCRIPT 2)
document.getElementById('searchRoom').addEventListener('input', function(e) {
filterRooms(e.target.value.toLowerCase());
});
document.getElementById('createIframesBtn').onclick = createIframesAndTabs;
// CORREÇÃO CRÍTICA: Alterado para usar o sistema de vagas (100% do Script 2)
document.getElementById('playAllBtn').onclick = playAllElements;
document.getElementById('toggleViewerBtn').onclick = toggleViewer;
document.getElementById('testSyncBtn').onclick = testSync;
document.getElementById('closeAllBtn').onclick = closeAll;
document.getElementById('minimizeMenuBtn').onclick = toggleMenuMinimize;
document.getElementById('closeMenuBtn').onclick = closeMenu;
}
// =============================================
// FUNÇÕES EXISTENTES MANTIDAS
// =============================================
function createIframesAndTabs() {
if (!selectedRoom) {
alert('Selecione uma sala primeiro!');
return;
}
closeAll();
const totalElements = botCount + (useExternalTabs ? externalTabCount : 0);
if (totalElements === 0) {
alert('Configure pelo menos 1 iframe ou aba externa!');
return;
}
updateStatus('🚀 CRIANDO IFRAMES E ABAS...');
const nicks = generateNicks(totalElements);
let nickIndex = 0;
for (let i = 0; i < botCount; i++) {
iframeController.realTimeViewer.createDirectIframe(nicks[nickIndex], nickIndex, selectedRoom);
nickIndex++;
}
if (useExternalTabs && externalTabCount > 0) {
for (let i = 0; i < externalTabCount; i++) {
iframeController.realTimeViewer.createExternalTab(nicks[nickIndex], nickIndex, selectedRoom);
nickIndex++;
}
}
iframeController.realTimeViewer.openViewer();
updateStatus(`✅ ${totalElements} ELEMENTOS CRIADOS!`);
updateTabStatus();
}
// CORREÇÃO CRÍTICA: Função playAllElements 100% do Script 2
async function playAllElements() {
const readyElements = iframeController.realTimeViewer.getAllReadyElements();
if (readyElements.length === 0) {
alert('Nenhum elemento está pronto! Aguarde o carregamento.');
return;
}
if (!selectedRoom) {
alert('Selecione uma sala primeiro!');
return;
}
updateStatus('🔍 VERIFICANDO VAGAS...');
window.updateSyncStatus(`Preparando ${readyElements.length} elementos...`);
try {
await iframeController.prepareAllClicks(readyElements);
const results = await iframeController.executeAllClicksWithVacancyCheck(selectedRoom);
if (results > 0) {
updateStatus(`🎉 ${results} ELEMENTOS ENTRARAM NA SALA!`);
window.updateSyncStatus('✅ SINCRONIZAÇÃO CONCLUÍDA!');
if (results < readyElements.length) {
setTimeout(() => {
updateStatus(`⚠️ ${results}/${readyElements.length} entraram`);
}, 2000);
}
} else {
updateStatus('❌ FALHA NA SINCRONIZAÇÃO');
window.updateSyncStatus('💡 Tente novamente');
}
} catch (error) {
console.error('💥 ERRO:', error);
updateStatus('❌ Erro na sincronização');
}
}
function toggleViewer() {
if (iframeController.realTimeViewer.isVisible) {
iframeController.realTimeViewer.closeViewer();
} else {
iframeController.realTimeViewer.openViewer();
}
}
function testSync() {
updateStatus('🧪 TESTANDO SISTEMA...');
window.updateSyncStatus('🔧 Verificando sincronização...');
setTimeout(() => {
updateStatus('✅ SISTEMA OPERACIONAL');
window.updateSyncStatus('⚡ Pronto para uso');
}, 2000);
}
function closeAll() {
iframeController.networkController.restoreNetwork();
iframeController.stopVacancyCheck();
iframeController.realTimeViewer.clearViewer();
updateStatus('🔄 SISTEMA REINICIADO');
window.updateSyncStatus('');
updateTabStatus();
updateMultiRoomStatus();
}
function toggleMenuMinimize() {
const menuContent = document.getElementById('menu-content');
const menu = document.getElementById('gartic-multi-menu');
const isMinimized = menuContent.style.display === 'none';
if (isMinimized) {
menuContent.style.display = 'block';
menu.style.height = 'auto';
menu.style.width = '550px';
configManager.set('menuMinimized', false);
} else {
menuContent.style.display = 'none';
menu.style.height = 'auto';
menu.style.width = '250px';
configManager.set('menuMinimized', true);
}
}
function closeMenu() {
const menu = document.getElementById('gartic-multi-menu');
if (menu) {
menu.style.display = 'none';
}
}
function setupMenuDrag(header, element) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
header.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
element.style.top = (element.offsetTop - pos2) + "px";
element.style.left = (element.offsetLeft - pos1) + "px";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
// =============================================
// INICIALIZAÇÃO AVANÇADAS
// =============================================
function initializeAdvancedSystems() {
console.log('🚀 INICIALIZANDO SISTEMAS AVANÇADOS...');
iframeController.realTimeViewer.maxIframes = configManager.get('maxTabLimit');
iframeController.realTimeViewer.maxMultiRoomIframes = configManager.get('maxTabLimit');
precisionSyncSystem.resetSyncData();
setTimeout(() => {
proNetworkController.testNetwork().then(isWorking => {
console.log(`🌐 Conexão inicial: ${isWorking ? '✅' : '⚠️'}`);
});
}, 2000);
console.log('✅ SISTEMAS AVANÇADOS INICIALIZADOS');
}
// =============================================
// INICIALIZAÇÃO PRINCIPAL
// =============================================
setInterval(updateMultiRoomStatus, 2000);
setInterval(loadRooms, 10000);
setInterval(updateTabStatus, 2000);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(createInterface, 500);
setTimeout(initializeAdvancedSystems, 1000);
});
} else {
setTimeout(createInterface, 1000);
setTimeout(initializeAdvancedSystems, 1500);
}
setTimeout(() => {
const menu = document.getElementById('gartic-multi-menu');
if (!menu) {
createInterface();
initializeAdvancedSystems();
}
}, 3000);
})();