WME PLN Module - Stats Handler

Módulo de estadísticas para WME Place Normalizer. No funciona por sí solo.

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/548858/1657861/WME%20PLN%20Module%20-%20Stats%20Handler.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         WME PLN Module - Stats Handler
// @version      9.0.0
// @description  Módulo de estadísticas para WME Place Normalizer. No funciona por sí solo.
// @author       mincho77
// @license      MIT
// @grant        none
// ==/UserScript==
// Clave para almacenar las estadísticas en localStorage
const STATS_STORAGE_KEY = (window.PLN_META ? `WME_PLN_stats_${window.PLN_META.version}` : 'WME_PLN_stats');
let statsPanelElement = null;
// Crea el panel de estadísticas flotante en la interfaz de usuario.
function createStatsPanel()
{
    // Evitar crear múltiples paneles
    if (document.getElementById('wme-pln-stats-panel')) return;
    // Contenedor principal del panel
    statsPanelElement = document.createElement('div');
    statsPanelElement.id = 'wme-pln-stats-panel';
    statsPanelElement.setAttribute('role', 'region');
    statsPanelElement.setAttribute('aria-label', 'NrmliZer Stats');
    plnLog('ui', '[stats] Panel de estadísticas creado');
    Object.assign(statsPanelElement.style, 
    {
        position: 'fixed',
        bottom: '60px',
        left: '23%', // <-- Ancla el panel a 20px del borde izquierdo
        // Se elimina la propiedad 'transform' que ya no es necesaria
        backgroundColor: 'rgba(45, 45, 45, 0.9)',
        color: 'white',
        padding: '5px 12px',
        borderRadius: '15px',
        fontSize: '13px',
        fontFamily: "'Helvetica Neue', Helvetica, Arial, sans-serif",
        zIndex: '10000',
        cursor: 'pointer',
        display: 'none', // Oculto inicialmente
        border: '1px solid #555',
        boxShadow: '0 2px 10px rgba(0,0,0,0.5)',
        userSelect: 'none',
        whiteSpace: 'nowrap'
    });
    // Vista de resumen (la que siempre está visible)
    const summaryView = document.createElement('div');
    summaryView.id = 'stats-summary-view';
    Object.assign(summaryView.style, 
        {
        display: 'flex',
        alignItems: 'center',
        gap: '6px'
    });
    // Texto resumen
    const summaryText = document.createElement('span');
    summaryText.id = 'stats-summary-text';
    summaryText.textContent = '📊 0 NrmliZer Stats';
    // Flecha desplegable
    const dropdownArrow = document.createElement('span');
    dropdownArrow.id = 'stats-arrow';
    dropdownArrow.textContent = '▼';
    dropdownArrow.style.fontSize = '10px';
    // Ensamblar la vista de resumen
    summaryView.appendChild(summaryText);
    summaryView.appendChild(dropdownArrow);
    // Vista detallada (la que se expande)
    const detailView = document.createElement('div');
    detailView.id = 'stats-detail-view';
    Object.assign(detailView.style, {
        display: 'none',
        marginTop: '8px',
        paddingTop: '8px',
        borderTop: '1px solid #666'
    });
    // Lista de estadísticas
    const list = document.createElement('ul');
    Object.assign(list.style, {
        margin: '0',
        padding: '0',
        listStyle: 'none',
        textAlign: 'left'
    });
    // Crear elementos de la lista
    const items = {
        'Hoy': 'stats-count-today',
        'Esta Semana': 'stats-count-week',
        'Este Mes': 'stats-count-month',
        'Total': 'stats-count-total'
    };
    // Recorre los items para crear cada entrada en la lista
    for (const [label, id] of Object.entries(items)) 
    {
        const listItem = document.createElement('li');
        listItem.style.marginBottom = '4px';
        // Etiqueta y contador
        const countBold = document.createElement('b');
        countBold.id = id;
        countBold.textContent = '0';
        // Ensamblar el item
        listItem.append(`${label}: `, countBold);
        list.appendChild(listItem);
    }
    detailView.appendChild(list);
    // Ensamblar el panel
    statsPanelElement.appendChild(summaryView);
    statsPanelElement.appendChild(detailView);
    document.body.appendChild(statsPanelElement);
    // Lógica para desplegar/contraer
    statsPanelElement.addEventListener('click', () => {
        const isHidden = detailView.style.display === 'none';
        detailView.style.display = isHidden ? 'block' : 'none';
        dropdownArrow.textContent = isHidden ? '▲' : '▼';
    });
    // Lógica para cerrar al hacer clic fuera
    document.addEventListener('click', (e) => {
        if (!statsPanelElement.contains(e.target)) 
        {
            detailView.style.display = 'none';
            dropdownArrow.textContent = '▼';
        }
    }, true);
    // Mostrar el panel
    if (typeof window.toggleStatsPanelVisibility === 'function') {
        window.toggleStatsPanelVisibility();
    } else {
        statsPanelElement.style.display = 'block';
    }
}// createStatsPanel

// Muestra los contadores en el panel flotante
function updateStatsDisplay()
{
    // Asegura que el panel y la info del usuario estén disponibles
    if (!statsPanelElement || !window.currentGlobalUserInfo || !window.currentGlobalUserInfo.id) return;
    const userId = String(window.currentGlobalUserInfo.id);
    // Obtiene los datos guardados o valores por defecto si no existen
    const stats = (window.editorStats && window.editorStats[userId]) || 
    {
        daily_count: 0,
        weekly_count: 0,
        monthly_count: 0,
        total_count: 0
    };
    // Actualiza los elementos de la UI con los valores guardados
    const summaryText = statsPanelElement.querySelector('#stats-summary-text');
    const todayCountSpan = statsPanelElement.querySelector('#stats-count-today');
    const weekCountSpan = statsPanelElement.querySelector('#stats-count-week');
    const monthCountSpan = statsPanelElement.querySelector('#stats-count-month');
    const totalCountSpan = statsPanelElement.querySelector('#stats-count-total');
    // Actualiza los textos
    if (summaryText) summaryText.textContent = `📊 ${stats.daily_count || 0} Places NrmliZed`;
    if (todayCountSpan) todayCountSpan.textContent = stats.daily_count || 0;
    if (weekCountSpan) weekCountSpan.textContent = stats.weekly_count || 0;
    if (monthCountSpan) monthCountSpan.textContent = stats.monthly_count || 0;
    if (totalCountSpan) totalCountSpan.textContent = stats.total_count || 0;
    plnLog('ui', `[stats] Display actualizado: hoy=${stats.daily_count||0}, semana=${stats.weekly_count||0}, mes=${stats.monthly_count||0}, total=${stats.total_count||0}`);
}// updateStatsDisplay
// Carga las estadísticas desde localStorage
function loadEditorStats()
{
    // Intenta cargar las estadísticas guardadas
    const savedStats = localStorage.getItem(STATS_STORAGE_KEY);
    if (savedStats)
    {
        try
        {
            window.editorStats = JSON.parse(savedStats);
            if (typeof window.editorStats !== 'object' || window.editorStats === null)
            {
                window.editorStats = {};
            }
        }
        catch (e)
        {
            plnLog('error','[WME PLN Stats] Error al parsear estadísticas desde localStorage:', e);
            window.editorStats = {};
        }
    }
    else
    {
        window.editorStats = {};
    }
}// loadEditorStats

// Guarda las estadísticas en localStorage
function saveEditorStats()
{
    try
    {
        localStorage.setItem(STATS_STORAGE_KEY, JSON.stringify(window.editorStats || {}));
    }
    catch (e)
    {
        plnLog('error','[WME PLN Stats] Error al guardar estadísticas en localStorage:', e);
    }
}// Guarda una acción de normalización para el usuario actual

// Registra una edición y actualiza los contadores
function recordNormalizationEvent()
{
    const user = window.currentGlobalUserInfo || {};
    const userId = user.id;
    const userName = user.name;

    if (!userId || userId === 0 || userName === 'No detectado')
    {
        plnLog('warn','[stats] No se registró evento: usuario no detectado.');
        return;
    }
    // Obtiene las estadísticas del usuario o las inicializa si no existen
    window.editorStats = window.editorStats || {};
    const userKey = String(userId);
    let userStats = window.editorStats[userKey];
    if (!userStats)
    {
        userStats = 
        {
            userName: userName,
            total_count: 0,
            monthly_count: 0,
            monthly_period: "N/A",
            weekly_count: 0,
            weekly_period: "N/A",
            daily_count: 0,
            daily_period: "N/A",
            last_update: 0
        };
        window.editorStats[userKey] = userStats;
    }
    // Obtiene los periodos de tiempo actuales
    const todayStr = PLNCore.utils.getCurrentDateString();
    const weekStr = PLNCore.utils.getCurrentISOWeekString();
    const monthStr = PLNCore.utils.getCurrentMonthString();
    // --- Lógica de reseteo de contadores ---
    // Si la fecha guardada es diferente a la de hoy, resetea el contador diario.
    if (userStats.daily_period !== todayStr)
    {
        userStats.daily_count = 0;
        userStats.daily_period = todayStr;
    }
    // Si la semana guardada es diferente a la de hoy, resetea el contador semanal.
    if (userStats.weekly_period !== weekStr)
    {
        userStats.weekly_count = 0;
        userStats.weekly_period = weekStr;
    }
    // Si el mes guardado es diferente al de hoy, resetea el contador mensual.
    if (userStats.monthly_period !== monthStr)
    {
        userStats.monthly_count = 0;
        userStats.monthly_period = monthStr;
    }
    // --- Incrementar los contadores ---
    userStats.daily_count++;
    userStats.weekly_count++;
    userStats.monthly_count++;
    userStats.total_count++;
    userStats.last_update = Date.now();
    userStats.userName = userName; // Asegurarse de que el nombre esté actualizado
    // Guardar los nuevos datos y actualizar la pantalla
    saveEditorStats();
    updateStatsDisplay();
}// recordNormalizationEvent