Bitcointalk Board Stats (Dynamic Header)

Statistiche board Bitcointalk con intestazione dinamica in base ai mesi selezionati

当前为 2025-09-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         Bitcointalk Board Stats (Dynamic Header)
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  Statistiche board Bitcointalk con intestazione dinamica in base ai mesi selezionati
// @author       Ace
// @match        https://bitcointalk.org/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Crea la pagina fittizia delle statistiche
    function createStatPage() {
        if (document.querySelector('#fake-stat-page')) return;

        const page = document.createElement('div');
        page.id = 'fake-stat-page';
        page.style.position = 'fixed';
        page.style.top = '0';
        page.style.left = '0';
        page.style.width = '100%';
        page.style.height = '100%';
        page.style.backgroundColor = 'rgba(0,0,0,0.5)';
        page.style.zIndex = '9999';
        page.style.overflowY = 'auto';
        page.style.fontFamily = 'Verdana, Arial, sans-serif';
        page.style.fontSize = '14px';

        page.innerHTML = `
            <div style="
                max-width: 950px;
                margin: 20px auto;
                background: white;
                padding: 20px;
                border-radius: 5px;
                box-shadow: 0 0 10px rgba(0,0,0,0.2);
                border: 1px solid #ddd;
            ">
                <h2 style="text-align: center; margin-bottom: 20px; color: #2e3b4e;">Statistiche Board</h2>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-weight: bold;">Board ID o nome:</label>
                    <input type="text" id="board-id" value="28" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 3px;">
                </div>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-weight: bold;">Mese corrente (inizio):</label>
                    <input type="datetime-local" id="current-start" value="2025-08-01T00:00:00" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 3px;">
                </div>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-weight: bold;">Mese corrente (fine):</label>
                    <input type="datetime-local" id="current-end" value="2025-08-31T23:59:59" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 3px;">
                </div>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-weight: bold;">Mese precedente (inizio):</label>
                    <input type="datetime-local" id="previous-start" value="2025-07-01T00:00:00" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 3px;">
                </div>

                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 5px; font-weight: bold;">Mese precedente (fine):</label>
                    <input type="datetime-local" id="previous-end" value="2025-07-31T23:59:59" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 3px;">
                </div>

                <div style="margin-bottom: 20px;">
                    <label style="display: inline-flex; align-items: center; cursor: pointer;">
                        <input type="checkbox" id="child-boards" style="margin-right: 8px;">
                        Includi child boards
                    </label>
                </div>

                <button id="generate-stats" style="
                    width: 100%;
                    padding: 10px;
                    font-weight: bold;
                    background: #2e3b4e;
                    color: white;
                    border: none;
                    border-radius: 3px;
                    cursor: pointer;
                ">Genera Statistiche</button>

                <div id="stats-preview" style="margin-top: 20px; display: none;">
                    <h3 style="border-bottom: 1px solid #eee; padding-bottom: 5px;">Anteprima Tabella</h3>
                    <div id="preview-table" style="overflow-x: auto;"></div>
                </div>

                <div id="stats-output" style="
                    margin-top: 20px;
                    padding: 15px;
                    background: #f5f5f5;
                    border-radius: 3px;
                    border: 1px solid #ddd;
                    min-height: 100px;
                    display: none;
                ">
                    <h3 style="border-bottom: 1px solid #eee; padding-bottom: 5px;">BBCode</h3>
                    <textarea id="bbcode-output" style="
                        width: 100%;
                        height: 300px;
                        padding: 10px;
                        font-family: monospace;
                        border: 1px solid #ccc;
                        border-radius: 3px;
                        resize: vertical;
                    "></textarea>
                    <button id="copy-bbcode" style="
                        display: block;
                        margin: 10px auto 0;
                        padding: 8px 16px;
                        background: #2e3b4e;
                        color: white;
                        border: none;
                        border-radius: 3px;
                        cursor: pointer;
                    ">Copia BBCode</button>
                </div>

                <button id="close-page" style="
                    display: block;
                    margin: 20px auto 0;
                    padding: 8px 16px;
                    font-weight: bold;
                    background: #ccc;
                    border: none;
                    border-radius: 3px;
                    cursor: pointer;
                ">Chiudi</button>
            </div>
        `;

        document.body.appendChild(page);

        document.querySelector('#close-page').onclick = () => page.remove();
        document.querySelector('#generate-stats').onclick = generateStats;
        document.querySelector('#copy-bbcode').onclick = copyBBCode;
    }

    // Copia BBCode negli appunti
    function copyBBCode() {
        const textarea = document.querySelector('#bbcode-output');
        textarea.select();
        try {
            navigator.clipboard.writeText(textarea.value)
                .then(() => alert('BBCode copiato negli appunti!'))
                .catch(() => {
                    document.execCommand('copy');
                    alert('BBCode copiato negli appunti!');
                });
        } catch (err) {
            document.execCommand('copy');
            alert('BBCode copiato negli appunti!');
        }
    }

    // Ottieni il nome del mese da una data
    function getMonthName(dateString) {
        const months = ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'];
        const date = new Date(dateString);
        return months[date.getMonth()];
    }

    // Genera le statistiche con intestazione dinamica
    async function generateStats() {
        const boardId = document.querySelector('#board-id').value.trim();
        const currentStart = document.querySelector('#current-start').value;
        const currentEnd = document.querySelector('#current-end').value;
        const previousStart = document.querySelector('#previous-start').value;
        const previousEnd = document.querySelector('#previous-end').value;
        const childBoards = document.querySelector('#child-boards').checked;

        if (!boardId || !currentStart || !currentEnd || !previousStart || !previousEnd) {
            alert('Compila tutti i campi!');
            return;
        }

        // Nomi dei mesi per l'intestazione
        const currentMonthName = getMonthName(currentStart);
        const previousMonthName = getMonthName(previousStart);

        const previewDiv = document.querySelector('#stats-preview');
        const outputDiv = document.querySelector('#stats-output');
        previewDiv.style.display = 'none';
        outputDiv.style.display = 'none';

        const loadingMsg = document.createElement('p');
        loadingMsg.style.textAlign = 'center';
        loadingMsg.style.color = '#666';
        loadingMsg.textContent = 'Caricamento dati...';
        previewDiv.parentNode.insertBefore(loadingMsg, previewDiv);

        try {
            // Fetch dati mese corrente
            const currentUrl = `https://api.ninjastic.space/posts/authors?board=${boardId}&child_boards=${childBoards}&after_date=${currentStart}&before_date=${currentEnd}&limit=1000`;
            const currentRes = await fetch(currentUrl);
            const currentJson = await currentRes.json();

            // Fetch dati mese precedente
            const previousUrl = `https://api.ninjastic.space/posts/authors?board=${boardId}&child_boards=${childBoards}&after_date=${previousStart}&before_date=${previousEnd}&limit=1000`;
            const previousRes = await fetch(previousUrl);
            const previousJson = await previousRes.json();

            if (currentJson.result !== "success" || previousJson.result !== "success") {
                loadingMsg.textContent = `Errore API: ${currentJson.message || previousJson.message || "Sconosciuto"}`;
                loadingMsg.style.color = 'red';
                return;
            }

            const currentAuthors = currentJson.data.authors;
            const previousAuthors = previousJson.data.authors;

            // Crea mappa post mese precedente (author_uid -> count)
            const previousPostsMap = {};
            previousAuthors.forEach(a => {
                previousPostsMap[a.author_uid] = a.count || 0;
            });

            // Unisci e ordina gli utenti per post del mese corrente
            const allAuthors = [...currentAuthors];
            allAuthors.sort((a, b) => (b.count || 0) - (a.count || 0));

            // Anteprima tabella HTML
            let previewTable = `
                <table style="width: 100%; border-collapse: collapse; margin-bottom: 15px; font-size: 13px;">
                    <tr style="background: #f0f0f0;">
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 5%;">Pos.</th>
                        <th style="padding: 8px; text-align: left; border: 1px solid #ddd; width: 25%;">User</th>
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 10%;">Post (${currentMonthName})</th>
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 10%;">Post (${previousMonthName})</th>
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 10%;">Change</th>
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 10%;">BPIP</th>
                        <th style="padding: 8px; text-align: center; border: 1px solid #ddd; width: 10%;">Ninjastic</th>
                    </tr>
            `;
            allAuthors.forEach((a, index) => {
                const username = a.author || 'Sconosciuto';
                const userUid = a.author_uid || '';
                const currentCount = a.count || 0;
                const previousCount = previousPostsMap[userUid] || 0;
                const diff = currentCount - previousCount;
                const variationColor = diff >= 0 ? 'green' : 'red';
                const variationText = diff >= 0 ? `▲${diff}` : `▼${Math.abs(diff)}`;
                const userLink = userUid ? `<a href="https://bitcointalk.org/index.php?action=profile;u=${userUid}" target="_blank">${username}</a>` : username;

                previewTable += `
                    <tr style="border: 1px solid #ddd;">
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center;">${index + 1}.</td>
                        <td style="padding: 8px; border: 1px solid #ddd;">${userLink}</td>
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center;">${currentCount}</td>
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center;">${previousCount}</td>
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center; color: ${variationColor};">${variationText}</td>
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center;">
                            <a href="https://bpip.org/Profile?p=${username}" target="_blank">
                                <img src="https://www.talkimg.com/images/2023/08/03/GXlZb.png" width="15">
                            </a>
                        </td>
                        <td style="padding: 8px; border: 1px solid #ddd; text-align: center;">
                            <a href="https://ninjastic.space/user/${username}" target="_blank">
                                <img src="https://talkimg.com/images/2023/08/03/GwdMz.png" width="15">
                            </a>
                        </td>
                    </tr>
                `;
            });
            previewTable += `</table>`;

            // BBCode con intestazione dinamica
            let bbcode = `[center][b][size=12pt]Statistiche Board[/size][/b][/center]
[center][i]Confronto: ${previousMonthName} vs ${currentMonthName}[/i][/center]

[table]
[tr]
[td][b]Pos.[/b][/td]
[td][b]User[/b][/td]
[td][b]Post (${currentMonthName})[/b][/td]
[td][b]Post (${previousMonthName})[/b][/td]
[td][b]Change[/b][/td]
[td][b]BPIP[/b][/td]
[td][b]Ninjastic[/b][/td]
[/tr]
`;
            allAuthors.forEach((a, index) => {
                const username = a.author || 'Sconosciuto';
                const userUid = a.author_uid || '';
                const currentCount = a.count || 0;
                const previousCount = previousPostsMap[userUid] || 0;
                const diff = currentCount - previousCount;
                const variationColor = diff >= 0 ? 'green' : 'red';
                const variationText = diff >= 0 ? `[color=${variationColor}]▲${diff}[/color]` : `[color=${variationColor}]▼${Math.abs(diff)}[/color]`;
                const userLink = userUid ? `[url=https://bitcointalk.org/index.php?action=profile;u=${userUid}]${username}[/url]` : username;

                bbcode += `[tr]
[td]${index + 1}.[/td]
[td]${userLink}[/td]
[td]${currentCount}[/td]
[td]${previousCount}[/td]
[td]${variationText}[/td]
[td][url=https://bpip.org/Profile?p=${username}][img width=15]https://www.talkimg.com/images/2023/08/03/GXlZb.png[/img][/url][/td]
[td][url=https://ninjastic.space/user/${username}][img width=15]https://talkimg.com/images/2023/08/03/GwdMz.png[/img][/url][/td]
[/tr]
`;
            });
            bbcode += `[/table]`;

            // Mostra anteprima e BBCode
            loadingMsg.remove();
            previewDiv.style.display = 'block';
            outputDiv.style.display = 'block';
            document.querySelector('#preview-table').innerHTML = previewTable;
            document.querySelector('#bbcode-output').value = bbcode;

        } catch (err) {
            console.error(err);
            loadingMsg.textContent = 'Errore durante il recupero dei dati.';
            loadingMsg.style.color = 'red';
        }
    }

    // Aggiunge pulsante Stat nella navbar
    function addStatButton() {
        const navbar = document.querySelector('table[style*="margin-left: 10px;"]');
        if (!navbar) {
            setTimeout(addStatButton, 1000);
            return;
        }

        const lastCell = navbar.querySelector('td.maintab_last');
        if (lastCell.querySelector('#stat-button')) return;

        const statButton = document.createElement('td');
        statButton.id = 'stat-button';
        statButton.className = 'maintab_back';
        statButton.innerHTML = `<a href="javascript:void(0)" class="maintab_link" style="padding: 0 10px;">Stat</a>`;
        statButton.querySelector('a').onclick = createStatPage;

        navbar.querySelector('tr').insertBefore(statButton, lastCell);
    }

    window.addEventListener('load', () => setTimeout(addStatButton, 1000));
    window.copyBBCode = copyBBCode;
})();