[Popmundo] Detector de Doentes v3.9.2

Exibe doentes dos locais.

// ==UserScript==
// @name         [Popmundo] Detector de Doentes v3.9.2
// @namespace    http://tampermonkey.net/
// @version      3.9.2
// @description  Exibe doentes dos locais.
// @author       Popper
// @match        *://*.popmundo.com/World/Popmundo.aspx/Locale/CharactersPresent/*
// @match        *://popmundo.com/World/Popmundo.aspx/Locale/CharactersPresent/*
// @match        *://*.popmundo.com/World/Popmundo.aspx/City/PeopleOnline/*
// @match        *://popmundo.com/World/Popmundo.aspx/City/PeopleOnline/*
// @match        *://*.popmundo.com/World/Popmundo.aspx/Character/Diary/* // Necessário para buscar diário
// @match        *://popmundo.com/World/Popmundo.aspx/Character/Diary/* // Necessário para buscar diário
// @match        *://*.popmundo.com/World/Popmundo.aspx/Character/* // Necessário para links de perfil nos resultados
// @match        *://popmundo.com/World/Popmundo.aspx/Character/* // Necessário para links de perfil nos resultados
// @icon         https://www.google.com/s2/favicons?sz=64&domain=popmundo.com
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @connect      self
// @connect      *.popmundo.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    console.log("Detector Doentes v3.9.2 (Somente Detecção) Popmundo - Ativado");

    // --- Configurações ---
    const REQUEST_DELAY_MS = 1500; // Atraso entre verificações de diário
    const SCRIPT_ID_PREFIX = 'pm-sick-detector-v3-9-2'; // Prefixo para IDs
    const RESULTS_DIV_ID = `${SCRIPT_ID_PREFIX}-results`;
    const SCAN_BUTTON_ID = `${SCRIPT_ID_PREFIX}-scan-button`;
    const CONTAINER_ID = `${SCRIPT_ID_PREFIX}-container`;
    const PROGRESS_LIST_ID = `${SCRIPT_ID_PREFIX}-progress-list`;
    const ENABLE_DETAILED_LOGGING = false; // Mude para true para mais detalhes no console

    // --- Mensagens Chave (lowercase) ---
    const realIllnessMessages = [
        'não estou me sentindo bem', 'zumbi me mordeu', 'clamídia está acabando comigo'
        // Adicione outras mensagens de doença real aqui, em minúsculas
    ];
    const cureMessage = 'curou minha indisposição';
    const ignoredMessage = 'sobrecarga sináptica está acabando comigo'; // Exemplo de mensagem a ignorar

    // --- Variáveis Globais ---
    let charactersToCheck = []; // Armazena { id, name, profileUrl, diaryUrl }
    let currentlySickCharacters = []; // Armazena { id, name, profileUrl, diaryUrl }
    let scanInProgress = false;
    let contextName = "Contexto não encontrado";
    let isCityPage = window.location.pathname.includes('/City/PeopleOnline/');

    // --- Funções Auxiliares ---
    function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

    function extractContextInfo() {
        if (isCityPage) {
            const h1 = document.querySelector('#ppm-content h1');
            if (h1) {
                const h1Text = h1.textContent.trim();
                const cityMatch = h1Text.match(/^Pessoas em (.*)$/i);
                contextName = (cityMatch && cityMatch[1]) ? cityMatch[1].trim() : "Cidade desconhecida";
                if(ENABLE_DETAILED_LOGGING) console.log(`Contexto (Cidade): ${contextName}`);
            } else { contextName = "Cidade desconhecida"; console.warn("H1 não encontrado na página da cidade."); }
        } else {
            const localeInfoDiv = document.querySelector('div[id*="divLocaleInfo"]');
            if (localeInfoDiv) {
                const localeBox = localeInfoDiv.querySelector('.localebox');
                if (localeBox) {
                    const h2 = localeBox.querySelector('h2');
                    let localeName = h2 ? h2.textContent.trim() : "Local desconhecido";
                    const cityLink = localeBox.querySelector('.right a');
                    let cityName = cityLink ? cityLink.textContent.trim() : "Cidade desconhecida";
                    contextName = `${localeName} (${cityName})`;
                   if(ENABLE_DETAILED_LOGGING) console.log(`Contexto (Local): ${localeName}, Cidade: ${cityName}`);
                } else { contextName = "Local/Cidade desconhecidos"; console.warn(".localebox não encontrado."); }
            } else { contextName = "Local/Cidade desconhecidos"; console.warn("divLocaleInfo não encontrado."); }
        }
    }

    // --- Coleta de Dados da Tabela ---
    function getCharactersFromTable() {
        charactersToCheck = [];
        const localeTable = document.getElementById('tablechars');
        const cityTable = document.getElementById('tablepeople');
        let targetTable = localeTable || cityTable;
        let nameCellIndex = localeTable ? 1 : (cityTable ? 0 : -1);

        if (!targetTable) { console.error("Nenhuma tabela de personagens encontrada."); return; }
        if(ENABLE_DETAILED_LOGGING) console.log(`Tabela encontrada: #${targetTable.id}`);
        const tbody = targetTable.querySelector('tbody');
        if (!tbody) { console.error("TBODY não encontrado."); return; }

        const rows = tbody.querySelectorAll('tr');
        rows.forEach(row => {
            const cells = row.querySelectorAll('td');
            if (cells.length > nameCellIndex) {
                const nameCell = cells[nameCellIndex];
                const nameLink = nameCell.querySelector('a');

                if (nameLink) {
                    const name = nameLink.textContent.trim();
                    const profileHref = nameLink.getAttribute('href');
                    const charIdMatch = profileHref.match(/Character\/(\d+)/);

                    if (charIdMatch) {
                        const id = charIdMatch[1];
                        const profileUrl = profileHref; // URL Relativa do Perfil
                        const diaryUrl = `/World/Popmundo.aspx/Character/Diary/${id}`; // URL Relativa do Diário

                        if (!charactersToCheck.some(c => c.id === id)) {
                            charactersToCheck.push({
                                id: id,
                                name: name,
                                profileUrl: profileUrl,
                                diaryUrl: diaryUrl
                            });
                        }
                    } else if (ENABLE_DETAILED_LOGGING) {
                        console.warn(`Link encontrado para ${name}, mas não foi possível extrair o ID do personagem de: ${profileHref}`);
                    }
                }
            }
        });
        console.log(`Encontrados ${charactersToCheck.length} personagens na tabela para verificar.`);
    }


    // --- Verificação de Diário ---
      function fetchAndCheckDiaryReverse(character) {
        return new Promise((resolve) => {
            const fullDiaryUrl = window.location.origin + character.diaryUrl;
            if(ENABLE_DETAILED_LOGGING) console.log(`--- [${character.name}] Analisando Diário: ${fullDiaryUrl} ---`);

            GM_xmlhttpRequest({
                method: "GET", url: fullDiaryUrl, timeout: 15000,
                onload: function(response) {
                    let isCurrentlyConsideredSickState = false;
                    if (response.status >= 200 && response.status < 300) {
                        const parser = new DOMParser();
                        const diaryDoc = parser.parseFromString(response.responseText, "text/html");
                        const diaryContainer = diaryDoc.querySelector('#ppm-content');
                        if (diaryContainer) {
                            const diaryEventEntries = Array.from(diaryContainer.querySelectorAll('ul > li > ul > li'));
                            for (let index = diaryEventEntries.length - 1; index >= 0; index--) { // Verifica do mais recente para o mais antigo
                                const item = diaryEventEntries[index];
                                let rawHtml = item.innerHTML;
                                // Limpa o HTML e extrai o texto relevante
                                rawHtml = rawHtml.replace(/^<span.*?<\/span>\s*/i, ''); // Remove span de tempo/ícone no início
                                let textContentOnly = rawHtml.replace(/<[^>]*>/g, ' '); // Remove tags HTML
                                textContentOnly = textContentOnly.replace(/^\s*\d{2}:\d{2}:\s*/, ''); // Remove hora se presente
                                let textToSearch = textContentOnly.replace(/\s+/g, ' ').trim().toLowerCase(); // Normaliza espaços e caixa
                                if (!textToSearch) continue; // Pula entradas vazias

                                let illnessDetectedInThisItem = false;
                                // Verifica se é uma mensagem de doença real
                                for (const illness of realIllnessMessages) {
                                    if (textToSearch.includes(illness) && !textToSearch.includes(ignoredMessage)) {
                                        isCurrentlyConsideredSickState = true; // Encontrou doença, marca como doente
                                        illnessDetectedInThisItem = true;
                                        if (ENABLE_DETAILED_LOGGING) console.log(`[${character.name}] DOENTE detectado: "${textToSearch}" (Match: ${illness})`);
                                        break; // Para de procurar doenças nesta entrada
                                    }
                                }

                                // Se não encontrou doença nesta entrada, verifica se é uma mensagem de cura
                                if (!illnessDetectedInThisItem && textToSearch.includes(cureMessage)) {
                                    isCurrentlyConsideredSickState = false; // Encontrou cura, marca como não doente
                                    if (ENABLE_DETAILED_LOGGING) console.log(`[${character.name}] CURADO detectado: "${textToSearch}"`);
                                    // IMPORTANTE: Não para aqui, pois pode haver uma mensagem de doença mais recente
                                }
                                // Se encontrou uma condição de doença ou cura, pode decidir parar (break) se a lógica for "a mais recente define tudo"
                                // Se a lógica for "qualquer doença desde a última cura", continue verificando
                            }
                        } else { console.warn(`[${character.name}] #ppm-content não encontrado no diário.`); }
                    } else { console.error(`[${character.name}] Erro ${response.status} ao buscar diário.`); }

                    resolve({ character: character, isCurrentlySick: isCurrentlyConsideredSickState });
                },
                onerror: function(error) { console.error(`[${character.name}] Erro de rede ao buscar diário:`, error); resolve({ character: character, isCurrentlySick: false }); },
                ontimeout: function() { console.error(`[${character.name}] Timeout ao buscar diário.`); resolve({ character: character, isCurrentlySick: false }); }
            });
        });
    }


    // --- Controle da Varredura ---
    async function startDiaryScan() {
        if (scanInProgress) return;
        scanInProgress = true;
        currentlySickCharacters = [];
        getCharactersFromTable();

        const resultsDiv = document.getElementById(RESULTS_DIV_ID);
        const scanButton = document.getElementById(SCAN_BUTTON_ID);
        const progressList = document.getElementById(PROGRESS_LIST_ID);

        if (!resultsDiv || !scanButton || !progressList) { console.error("UI não encontrada."); scanInProgress = false; return; }
        if (charactersToCheck.length === 0) {
            updateProgressList("<p>Nenhum personagem encontrado na tabela para verificar.</p>");
             resultsDiv.style.display = 'block'; scanInProgress = false; return;
         }

        scanButton.disabled = true; scanButton.value = 'Verificando... (0%)';
        resultsDiv.style.display = 'block';
        progressList.innerHTML = `<p>Iniciando verificação... Total: ${charactersToCheck.length}.</p><p class="small italic">(Atraso: ${REQUEST_DELAY_MS / 1000}s/diário)</p>`;
        if (ENABLE_DETAILED_LOGGING) { progressList.innerHTML += `<p class="small bold">VERIFIQUE O CONSOLE (F12) PARA LOGS DETALHADOS!</p>`; }

        for (let i = 0; i < charactersToCheck.length; i++) {
            const character = charactersToCheck[i];
            const progressPercent = Math.round(((i + 1) / charactersToCheck.length) * 100);
            scanButton.value = `Verificando... (${progressPercent}%)`;
            updateProgressList(`(${i + 1}/${charactersToCheck.length}) ${character.name}... `, 'progress-item');

            try {
                const scanResult = await fetchAndCheckDiaryReverse(character);
                const lastProgressItem = progressList.querySelector('.progress-item:last-child');

                if (scanResult.isCurrentlySick) {
                    // Adiciona à lista de doentes
                    currentlySickCharacters.push({
                        id: character.id,
                        name: character.name,
                        profileUrl: character.profileUrl, // URL relativa do perfil
                        diaryUrl: window.location.origin + character.diaryUrl // URL completa do diário
                    });
                    if(lastProgressItem) lastProgressItem.innerHTML += `<span class="sick-found"> DOENTE!</span>`;
                } else {
                   if(lastProgressItem) lastProgressItem.innerHTML += `<span class="ok-status"> OK.</span>`;
                }
            } catch (error) {
                const lastProgressItem = progressList.querySelector('.progress-item:last-child');
                  if(lastProgressItem) lastProgressItem.innerHTML += `<span class="error-status"> ERRO!</span>`;
                  console.error(`Erro ao processar ${character.name} durante scan:`, error);
            }

            if (i < charactersToCheck.length - 1) { await sleep(REQUEST_DELAY_MS); }
        }

        // --- Atualização Final da Varredura ---
        let finalHtml = `<h3>Verificação Concluída!</h3>`;
        finalHtml += `<p><strong>${isCityPage ? 'Cidade' : 'Contexto'}:</strong> ${contextName}</p>`;
        if (currentlySickCharacters.length > 0) {
            finalHtml += `<p class="sick-summary"><strong>Personagens DOENTES encontrados (${currentlySickCharacters.length}):</strong></p><ul id="${SCRIPT_ID_PREFIX}-sick-list">`;
            currentlySickCharacters.forEach(char => {
                // Constrói URL completa do perfil para o link
                const fullProfileUrl = window.location.origin + char.profileUrl;
                // Lista sem o span de status de cura
                finalHtml += `<li id="${SCRIPT_ID_PREFIX}-sick-${char.id}"><a href="${fullProfileUrl}" target="_blank">${char.name}</a> (<a href="${char.diaryUrl}" target="_blank">Ver Diário</a>)</li>`;
            });
            finalHtml += `</ul>`;
        } else {
            finalHtml += `<p class="ok-summary">Nenhum personagem atualmente doente foi encontrado.</p>`;
        }
        progressList.innerHTML = finalHtml;
        scanButton.disabled = false; scanButton.value = 'Iniciar Nova Varredura';
        scanInProgress = false;
        console.log("Verificação de diários concluída.");
    }

    // --- Função Helper para UI ---
    function updateProgressList(message, className = '') {
        const progressList = document.getElementById(PROGRESS_LIST_ID);
        if (progressList) {
            const p = document.createElement('p');
            if (className) p.className = className;
            p.innerHTML = message; // Use innerHTML para permitir spans de formatação
            progressList.appendChild(p);
            progressList.scrollTop = progressList.scrollHeight; // Auto-scroll
        } else {
            console.log("Fallback Log:", message); // Log se a UI não for encontrada
        }
    }

    // --- Criação da UI ---
    function createUI() {
         const oldContainer = document.getElementById(CONTAINER_ID);
         if (oldContainer) oldContainer.remove(); // Remove UI antiga se existir

         const containerDiv = document.createElement('div');
         containerDiv.className = 'box'; containerDiv.id = CONTAINER_ID;
         const title = document.createElement('h2');
         title.textContent = 'Detector de Doentes (v3.9.2)'; // Título atualizado
         containerDiv.appendChild(title);

         const buttonContainer = document.createElement('p');
         buttonContainer.className = 'actionbuttons tmargin10';

         // Apenas o botão de Scan
         const scanButton = document.createElement('input');
         scanButton.setAttribute('type', 'button'); scanButton.id = SCAN_BUTTON_ID;
         scanButton.value = 'Iniciar Varredura';
         scanButton.addEventListener('click', startDiaryScan);
         buttonContainer.appendChild(scanButton);

         containerDiv.appendChild(buttonContainer);

         const resultsDiv = document.createElement('div');
         resultsDiv.id = RESULTS_DIV_ID;
         resultsDiv.style.marginTop = '10px'; resultsDiv.style.maxHeight = '350px';
         resultsDiv.style.overflowY = 'auto'; resultsDiv.style.display = 'none'; // Começa escondido
         const progressListDiv = document.createElement('div');
         progressListDiv.id = PROGRESS_LIST_ID;
         resultsDiv.appendChild(progressListDiv);
         containerDiv.appendChild(resultsDiv);

         // Insere a UI na página
         const targetTable = document.getElementById('tablechars') || document.getElementById('tablepeople');
         if (targetTable) {
             targetTable.parentNode.insertBefore(containerDiv, targetTable);
             console.log(`UI Detector v3.9.2 (Detect Only) inserida antes da tabela #${targetTable.id}.`);
         } else {
             // Fallback para inserir a UI se a tabela não for encontrada
             const contentDiv = document.getElementById('ppm-content');
             const firstHeading = contentDiv ? contentDiv.querySelector('h1') : null;
              if (firstHeading) {
                  firstHeading.parentNode.insertBefore(containerDiv, firstHeading.nextSibling);
                  console.log("UI Detector v3.9.2 (Detect Only) inserida após H1.");
             } else if (contentDiv) {
                  contentDiv.insertBefore(containerDiv, contentDiv.firstChild);
                  console.log("UI Detector v3.9.2 (Detect Only) inserida no início de #ppm-content.");
             } else { document.body.insertBefore(containerDiv, document.body.firstChild); console.error("Local ideal para UI Detector v3.9.2 não encontrado."); }
         }
    }

    // --- Estilos CSS (removidos os de cura) ---
    GM_addStyle(`
        #${CONTAINER_ID} { margin-bottom: 15px; }
        #${SCAN_BUTTON_ID} { padding: 4px 10px; font-size: 1em; font-weight: bold; cursor: pointer; border: 1px solid #a0a0a0; background-color: #e0e0e0; color: #333; border-radius: 3px; margin: 0; vertical-align: middle; }
        #${SCAN_BUTTON_ID}:hover:not(:disabled) { background-color: #d0d0d0; border-color: #888888; }
        #${SCAN_BUTTON_ID}:disabled { background-color: #f0f0f0; border-color: #c0c0c0; color: #999; cursor: not-allowed; }
        #${RESULTS_DIV_ID} { border-top: 1px solid #ccc; padding-top: 10px; font-size: 0.9em; }
        #${PROGRESS_LIST_ID} p { margin: 3px 0; line-height: 1.4; }
        #${PROGRESS_LIST_ID} p.small { font-size: 0.9em; }
        #${PROGRESS_LIST_ID} p.italic { font-style: italic; color: #666; }
        #${PROGRESS_LIST_ID} p.bold { font-weight: bold; }
        #${PROGRESS_LIST_ID} .sick-found, #${RESULTS_DIV_ID} .sick-summary { color: red; font-weight: bold; }
        #${PROGRESS_LIST_ID} .ok-status, #${RESULTS_DIV_ID} .ok-summary { color: green; }
        #${PROGRESS_LIST_ID} .error-status { color: orange; font-weight: bold; }
        #${RESULTS_DIV_ID} ul { list-style: disc; margin-left: 25px; margin-top: 5px; margin-bottom: 5px; }
        #${RESULTS_DIV_ID} li { margin-bottom: 4px; }
        #${RESULTS_DIV_ID} a {} /* Estilo padrão para links */
        #${RESULTS_DIV_ID} h3 { margin-bottom: 8px; }
    `);

    // --- Execução Principal ---
    setTimeout(() => {
        try {
            extractContextInfo();
            createUI();
        } catch (e) {
            console.error("Erro ao inicializar o script Detector de Doentes:", e);
        }
    }, 800); // Atraso para garantir que a página carregou

})();