Bitcointalk All-in-One Enhancer

Tema AMOLED, gestione merit, note utente con tag, e thread pinnati per Bitcointalk.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Bitcointalk All-in-One Enhancer
// @namespace    Violentmonkey Scripts
// @version      1.0.0
// @description  Tema AMOLED, gestione merit, note utente con tag, e thread pinnati per Bitcointalk.
// @match        https://bitcointalk.org/*
// @match        https://bitcointalk.org/index.php?board=*
// @grant        GM.setValue
// @grant        GM.getValue
// @author       Ace D.Portugal
// @license      MIT
// @require      https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/purify.min.js
// ==/UserScript==

(function() {
    'use strict';

    // Funzioni per GM storage
    const getValue = typeof GM_getValue === 'undefined' ? GM.getValue : GM.getValue;
    const setValue = typeof GM_setValue === 'undefined' ? GM.setValue : GM_setValue;

    // Funzioni per le note utente
    const getNotes = async () => {
        try {
            const notes = await getValue('notes');
            return notes ? JSON.parse(notes) : {};
        } catch (error) {
            return {};
        }
    };

    const setNotes = async (notes) => {
        await setValue('notes', JSON.stringify(notes));
    };

    const getUserNote = async (userId) => {
        const notes = await getNotes();
        return notes[userId];
    };

    const setUserNote = async (userId, note, tags = []) => {
        const notes = await getNotes();
        notes[userId] = { text: note, tags };
        await setNotes(notes);
    };

    const deleteUserNote = async (userId) => {
        const notes = await getNotes();
        delete notes[userId];
        await setNotes(notes);
    };

    const getSavedTags = async () => {
        try {
            const savedTags = await getValue('savedTags');
            return savedTags ? JSON.parse(savedTags) : {};
        } catch (error) {
            return {};
        }
    };

    const setSavedTags = async (tags) => {
        await setValue('savedTags', JSON.stringify(tags));
    };

    const findUserContainer = (link) => {
        let container = link.closest('.poster_info');
        if (container) return container;

        if (window.location.href.includes('action=profile')) {
            const profileContainer = document.querySelector('.profile_info');
            if (profileContainer) return profileContainer;
        }

        return null;
    };

    const openNoteModal = async (userId, existingNote = '', existingTags = []) => {
        const savedTags = await getSavedTags();

        const modal = document.createElement('div');
        modal.id = 'note-modal';
        modal.style.position = 'fixed';
        modal.style.top = '0';
        modal.style.left = '0';
        modal.style.width = '100%';
        modal.style.height = '100%';
        modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
        modal.style.display = 'flex';
        modal.style.justifyContent = 'center';
        modal.style.alignItems = 'center';
        modal.style.zIndex = '1000';

        const modalContent = document.createElement('div');
        modalContent.style.backgroundColor = 'white';
        modalContent.style.padding = '20px';
        modalContent.style.borderRadius = '10px';
        modalContent.style.width = '500px';
        modalContent.style.maxHeight = '80vh';
        modalContent.style.overflowY = 'auto';

        const tagsHTML = Object.entries(savedTags).map(([tag, style]) => {
            return `<span class="saved-tag" style="background-color: ${style.backgroundColor}; color: ${style.color}; padding: 2px 6px; border-radius: 10px; margin: 2px; display: inline-block; cursor: pointer;">${tag}</span>`;
        }).join('');

        modalContent.innerHTML = `
            <h2 style="margin-top: 0;">Edit Note</h2>
            <textarea id="note-text" style="width: 100%; min-height: 100px; margin: 10px 0;">${existingNote}</textarea>
            <div style="margin: 10px 0;">
                <label for="note-tags">Tags:</label>
                <div id="tags-container" style="margin-top: 5px; border: 1px solid #ddd; padding: 10px; border-radius: 5px; min-height: 50px; display: flex; flex-wrap: wrap; gap: 3px;">
                    ${existingTags.map(tag => {
                        const style = savedTags[tag] || { backgroundColor: '#757575', color: 'white' };
                        return `<span class="tag-badge" style="background-color: ${style.backgroundColor}; color: ${style.color}; padding: 2px 6px; border-radius: 10px; margin: 2px; display: inline-block;">${tag}</span>`;
                    }).join('')}
                </div>
                <div style="margin-top: 10px;">
                    <label>Saved Tags:</label>
                    <div id="saved-tags-container" style="margin-top: 5px; display: flex; flex-wrap: wrap; gap: 3px;">
                        ${tagsHTML}
                    </div>
                    <div style="margin-top: 10px;">
                        <input type="text" id="new-tag-name" placeholder="New Tag Name" style="padding: 5px; margin-right: 5px;">
                        <button id="add-new-tag" style="padding: 5px 10px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer;">Add New Tag</button>
                        <div id="color-picker-container" style="margin-top: 10px; display: none;">
                            <div style="margin-bottom: 10px;">
                                <label>Background Color:</label>
                                <input type="color" id="background-color-picker" value="#757575" style="margin-left: 10px;">
                            </div>
                            <div style="margin-bottom: 10px;">
                                <label>Text Color:</label>
                                <input type="color" id="text-color-picker" value="#ffffff" style="margin-left: 10px;">
                            </div>
                            <button id="save-new-tag" style="padding: 5px 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">Save Tag</button>
                        </div>
                    </div>
                </div>
            </div>
            <div style="display: flex; justify-content: space-between; margin-top: 10px;">
                <button id="delete-note" style="padding: 5px 10px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer;">Delete Note</button>
                <div>
                    <button id="cancel-note" style="padding: 5px 10px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px;">Cancel</button>
                    <button id="save-note" style="padding: 5px 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">Save</button>
                </div>
            </div>
        `;

        modal.appendChild(modalContent);
        document.body.appendChild(modal);

        let newTagName = '';
        let backgroundColor = '#757575';
        let textColor = '#ffffff';

        document.getElementById('add-new-tag').addEventListener('click', () => {
            newTagName = document.getElementById('new-tag-name').value.trim();
            if (newTagName) {
                document.getElementById('color-picker-container').style.display = 'block';
            }
        });

        document.getElementById('background-color-picker').addEventListener('input', (e) => {
            backgroundColor = e.target.value;
        });

        document.getElementById('text-color-picker').addEventListener('input', (e) => {
            textColor = e.target.value;
        });

        document.getElementById('save-new-tag').addEventListener('click', async () => {
            if (newTagName) {
                const savedTags = await getSavedTags();
                savedTags[newTagName] = { backgroundColor, color: textColor };
                await setSavedTags(savedTags);
                document.getElementById('color-picker-container').style.display = 'none';
                document.getElementById('new-tag-name').value = '';
                const savedTagsContainer = document.getElementById('saved-tags-container');
                savedTagsContainer.innerHTML += `<span class="saved-tag" style="background-color: ${backgroundColor}; color: ${textColor}; padding: 2px 6px; border-radius: 10px; margin: 2px; display: inline-block; cursor: pointer;">${newTagName}</span>`;
                newTagName = '';
                backgroundColor = '#757575';
                textColor = '#ffffff';
            }
        });

        document.querySelectorAll('.saved-tag').forEach(tagElement => {
            tagElement.addEventListener('click', async () => {
                const tagName = tagElement.textContent;
                const tagsContainer = document.getElementById('tags-container');
                const existingTag = Array.from(tagsContainer.querySelectorAll('.tag-badge')).find(el => el.textContent === tagName);
                if (!existingTag) {
                    const savedTags = await getSavedTags();
                    const style = savedTags[tagName] || { backgroundColor: '#757575', color: 'white' };
                    tagsContainer.innerHTML += `<span class="tag-badge" style="background-color: ${style.backgroundColor}; color: ${style.color}; padding: 2px 6px; border-radius: 10px; margin: 2px; display: inline-block;">${tagName}</span>`;
                }
            });
        });

        document.getElementById('save-note').addEventListener('click', async () => {
            const noteText = document.getElementById('note-text').value;
            const tagBadges = document.querySelectorAll('#tags-container .tag-badge');
            const tags = Array.from(tagBadges).map(tag => tag.textContent);
            await setUserNote(userId, noteText, tags);
            document.body.removeChild(modal);
            updateAllNotes();
        });

        document.getElementById('delete-note').addEventListener('click', async () => {
            if (confirm('Are you sure you want to delete this note?')) {
                await deleteUserNote(userId);
                document.body.removeChild(modal);
                updateAllNotes();
            }
        });

        document.getElementById('cancel-note').addEventListener('click', () => {
            document.body.removeChild(modal);
        });
    };

    const updateNoteElement = async (link) => {
        const userIdMatch = link.href.match(/u=(\d+)/);
        if (!userIdMatch) return;
        const userId = userIdMatch[1];

        const noteContainer = findUserContainer(link);
        if (!noteContainer) return;

        const existingNoteDiv = noteContainer.querySelector('.user-note-div');
        if (existingNoteDiv) existingNoteDiv.remove();

        const noteData = await getUserNote(userId);
        const savedTags = await getSavedTags();

        const noteDiv = document.createElement('div');
        noteDiv.className = 'user-note-div';
        noteDiv.style.marginTop = '5px';
        noteDiv.style.fontSize = '0.9em';

        if (noteData) {
            const tagsHTML = noteData.tags.map(tag => {
                const style = savedTags[tag] || { backgroundColor: '#757575', color: 'white' };
                return `<span class="tag-badge" style="background-color: ${style.backgroundColor}; color: ${style.color}; padding: 2px 6px; border-radius: 10px; margin: 2px; display: inline-block;">${tag}</span>`;
            }).join('');

            noteDiv.innerHTML = `
                <div>📃 ${DOMPurify.sanitize(noteData.text)}</div>
                ${noteData.tags.length > 0 ? `<div style="margin-top: 3px; display: flex; flex-wrap: wrap; gap: 3px;">${tagsHTML}</div>` : ''}
                <span class="edit-note" style="cursor: pointer; color: #2e518b; margin-left: 5px; font-weight: bold;">✏️</span>
                <span class="delete-note" style="cursor: pointer; color: #f44336; margin-left: 5px; font-weight: bold;">🗑️</span>
            `;
        } else {
            noteDiv.innerHTML = '<span class="add-note" style="cursor: pointer; font-weight: bold; color: #2e518b;">➕ Add Note</span>';
        }

        noteContainer.appendChild(noteDiv);

        noteDiv.querySelector('.edit-note')?.addEventListener('click', async () => {
            const noteData = await getUserNote(userId);
            openNoteModal(userId, noteData?.text || '', noteData?.tags || []);
        });

        noteDiv.querySelector('.add-note')?.addEventListener('click', () => {
            openNoteModal(userId);
        });

        noteDiv.querySelector('.delete-note')?.addEventListener('click', async () => {
            if (confirm('Are you sure you want to delete this note?')) {
                await deleteUserNote(userId);
                updateAllNotes();
            }
        });
    };

    const updateAllNotes = async () => {
        const userLinks = document.querySelectorAll('a[href*="action=profile;u="]');
        for (const link of userLinks) {
            await updateNoteElement(link);
        }
    };

    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            .user-note-div {
                margin-top: 5px;
                font-size: 0.9em;
            }
            .edit-note, .add-note, .delete-note {
                cursor: pointer;
                font-weight: bold;
            }
            .edit-note {
                color: #2e518b;
            }
            .delete-note {
                color: #f44336;
            }
            .tag-badge {
                display: inline-block;
            }
        `;
        document.head.appendChild(style);
    };

    // Funzioni per Bitcointalk Mobile Enhancer
    let sMerit = null;

    const rankTable = [
        { name: "Brand New", merit: 0, activity: 0 },
        { name: "Newbie", merit: 0, activity: 1 },
        { name: "Jr. Member", merit: 1, activity: 30 },
        { name: "Member", merit: 10, activity: 60 },
        { name: "Full Member", merit: 100, activity: 120 },
        { name: "Sr. Member", merit: 250, activity: 240 },
        { name: "Hero Member", merit: 500, activity: 480 },
        { name: "Legendary", merit: 1000, activity: 775 },
        { name: "🌀 Mythical", merit: 1500, activity: 1200 },
        { name: "🔺 Ascendant", merit: 2500, activity: 2000 },
        { name: "🌌 Celestial", merit: 5000, activity: 3000 },
        { name: "♾️ Immortal", merit: 10000, activity: 4000 }
    ];

    function getCsrfToken() {
        const logoutLink = document.querySelector('td.maintab_back a[href*="index.php?action=logout;sesc="]');
        if (!logoutLink) return null;
        const match = /;sesc=(.*)/.exec(logoutLink.href);
        return match ? match[1] : null;
    }

    function sendMerit(msgId, merits, sc, popup) {
        const formData = new FormData();
        formData.append('merits', merits);
        formData.append('msgID', msgId);
        formData.append('sc', sc);

        fetch('https://bitcointalk.org/index.php?action=merit', {
            method: 'POST',
            credentials: 'include',
            body: formData,
        })
        .then(response => response.text())
        .then(data => {
            if (data.includes('<title>An Error Has Occurred!</title>')) {
                alert('Errore nell\'invio del merit.');
            } else if (data.includes(`#msg${msgId}`)) {
                alert('Merit inviato con successo!');
                fetchSmerit();
                popup.style.display = 'none';
            } else {
                alert('Risposta del server indeterminata.');
            }
        })
        .catch(() => alert('Errore di rete.'))
        .finally(() => {
            const submitBtn = popup.querySelector('input[type="submit"]');
            if (submitBtn) {
                submitBtn.disabled = false;
                submitBtn.value = 'Invia';
            }
        });
    }

    function openMeritPopup(msgId, sc) {
        let popup = document.getElementById(`merit-popup-${msgId}`);
        if (popup) {
            popup.remove();
        }

        popup = document.createElement('div');
        popup.id = `merit-popup-${msgId}`;
        popup.className = 'merit-popup';
        popup.style.position = 'absolute';
        popup.style.right = '40px';
        popup.style.zIndex = '10000';
        popup.style.display = 'none';

        popup.innerHTML = `
            <form>
                <div style="margin-bottom: 8px;">
                    Merit points: <input size="4" name="merits" value="1" type="text" style="text-align: center;" />
                </div>
                <div style="text-align: right;">
                    <input value="Invia" type="submit" style="margin-left: 8px;" />
                </div>
            </form>
        `;

        popup.querySelector('form').onsubmit = (e) => {
            e.preventDefault();
            const merits = e.target.elements['merits'].value;
            const submitBtn = e.target.querySelector('input[type="submit"]');
            submitBtn.disabled = true;
            submitBtn.value = 'Invio...';

            sendMerit(msgId, merits, sc, popup);
        };

        return popup;
    }

    function addMeritPopups() {
        const sc = getCsrfToken();
        if (!sc) return;

        document.querySelectorAll('a[href*="index.php?action=merit;msg="]').forEach(link => {
            const msgId = /msg=([0-9]+)/.exec(link.href)[1];
            const popup = openMeritPopup(msgId, sc);
            link.parentNode.insertBefore(popup, link.nextSibling);

            link.onclick = (e) => {
                e.preventDefault();
                popup.style.display = popup.style.display === 'none' ? 'block' : 'none';
            };
        });
    }

    function fetchSmerit() {
        const meritPage = 'https://bitcointalk.org/index.php?action=merit';
        fetch(meritPage, { credentials: 'include', redirect: 'manual' })
        .then(res => {
            if (res.type === 'opaqueredirect' || res.status === 0 || res.status === 302) {
                sMerit = '?';
                updateSmeritIndicator();
                return null;
            }
            return res.text();
        })
        .then(html => {
            if (!html) return;
            const match = html.match(/You\s+have\s+(?:<b>)?(\d+)(?:<\/b>)?\s+sendable/i);
            sMerit = match ? match[1] : '?';
            updateSmeritIndicator();
        })
        .catch(() => {
            sMerit = 'x';
            updateSmeritIndicator();
        });
    }

    function updateSmeritIndicator() {
        let indicator = document.getElementById('smerit-indicator');
        if (!indicator) {
            indicator = document.createElement('div');
            indicator.id = 'smerit-indicator';
            document.body.appendChild(indicator);
        }
        indicator.textContent = `🪙 ${sMerit ?? '...'}`;
    }

    function fixQuotes() {
        document.querySelectorAll('.quote').forEach(quote => {
            if (quote.classList.contains('enhanced')) return;
            quote.classList.add('enhanced');

            if (quote.scrollHeight > 140) {
                const button = document.createElement('div');
                button.className = 'show-more';
                button.textContent = 'Mostra tutto';
                button.onclick = () => {
                    quote.classList.add('expanded');
                    button.remove();
                };
                quote.appendChild(button);
            }
        });
    }

    function addButtons() {
        document.querySelectorAll('td[class^="windowbg"] > div:nth-child(2)').forEach(post => {
            if (post.closest('.windowbg:first-child')) return;
            if (post.querySelector('.mobile-buttons')) return;

            const links = post.querySelectorAll('a');
            let quote, report, merit;

            links.forEach(a => {
                const href = a.getAttribute('href') || '';
                if (href.includes('quote')) quote = a;
                if (href.includes('report')) report = a;
                if (href.includes('merit')) merit = a;
            });

            const box = document.createElement('div');
            box.className = 'mobile-buttons';

            if (quote) {
                const q = quote.cloneNode(true);
                q.textContent = 'Quote';
                box.appendChild(q);
            }
            if (report) {
                const r = report.cloneNode(true);
                r.textContent = 'Report';
                box.appendChild(r);
            }

            post.appendChild(box);
        });
    }

    function addRankBarsInThreads() {
        document.querySelectorAll('td.poster_info').forEach(avatarCell => {
            if (avatarCell.querySelector('.rank-container')) return;

            const text = avatarCell.textContent;
            const meritMatch = text.match(/Merit:\s*(\d+)/i);
            const activityMatch = text.match(/Activity:\s*(\d+)/i);
            if (!meritMatch || !activityMatch) return;

            const merit = parseInt(meritMatch[1], 10);
            const activity = parseInt(activityMatch[1], 10);

            let currentRankIndex = 0;
            for (let i = 0; i < rankTable.length; i++) {
                if (merit >= rankTable[i].merit && activity >= rankTable[i].activity) {
                    currentRankIndex = i;
                }
            }

            const currentRank = rankTable[currentRankIndex];
            const nextRank = rankTable[Math.min(currentRankIndex + 1, rankTable.length - 1)];

            let totalProgress;
            if (currentRankIndex === rankTable.length - 1) {
                totalProgress = 100;
            } else {
                const meritProgress = Math.min(
                    (merit - currentRank.merit) / (nextRank.merit - currentRank.merit || 1),
                    1
                );
                const activityProgress = Math.min(
                    (activity - currentRank.activity) / (nextRank.activity - currentRank.activity || 1),
                    1
                );
                totalProgress = Math.min(meritProgress, activityProgress) * 100;
            }

            const container = document.createElement('div');
            container.className = 'rank-container';

            const rankName = document.createElement('div');
            rankName.className = 'rank-name';
            rankName.textContent = currentRank.name;
            container.appendChild(rankName);

            const bar = document.createElement('div');
            bar.className = 'rank-progress-bar';
            const fill = document.createElement('div');
            fill.className = 'rank-progress-fill';
            fill.style.width = totalProgress + '%';
            bar.appendChild(fill);
            container.appendChild(bar);

            avatarCell.appendChild(container);
        });
    }

    function removeOfficialRank() {
        document.querySelectorAll('td.poster_info div.smalltext').forEach(div => {
            const rankTexts = [
                "Brand New", "Newbie", "Jr. Member", "Member",
                "Full Member", "Sr. Member", "Hero Member", "Legendary"
            ];
            let lines = div.innerHTML.split('<br>');
            lines = lines.filter(line => {
                return !rankTexts.some(rank => line.includes(rank));
            });
            div.innerHTML = lines.join('<br>');
        });
    }

    function getLoggedInUsername() {
        const helloElement = document.querySelector('#hellomember b');
        if (!helloElement) {
            console.error("Utente loggato non trovato.");
            return null;
        }
        const userName = helloElement.textContent.replace(/\*/g, '').trim();
        console.log("Utente loggato trovato:", userName);
        return userName;
    }

    function highlightUserMerits() {
        const loggedInUser = getLoggedInUsername();
        if (!loggedInUser) {
            console.error("Utente loggato non trovato.");
            return;
        }

        console.log("Evidenzio i merit per l'utente:", loggedInUser);

        const meritElements = document.querySelectorAll('div.smalltext i');
        meritElements.forEach(el => {
            if (el.textContent.includes('Merited by')) {
                const meritLinks = el.querySelectorAll('a');
                let totalMerits = 0;

                meritLinks.forEach(link => {
                    const meritText = link.nextSibling?.textContent.trim();
                    if (!meritText) return;

                    const meritCountMatch = meritText.match(/\((\d+)\)/);
                    const meritCount = meritCountMatch ? parseInt(meritCountMatch[1], 10) : 0;
                    totalMerits += meritCount;

                    const linkUserName = link.textContent.replace(/\*/g, '').trim();
                    if (linkUserName === loggedInUser) {
                        link.style.fontWeight = 'bold';
                        link.style.color = '#3b82f6';
                        console.log(`Merit di ${loggedInUser} evidenziato:`, link);
                    }
                });

                if (!el.querySelector('.total-merit')) {
                    const totalElement = document.createElement('span');
                    totalElement.className = 'total-merit';
                    totalElement.style.fontWeight = 'bold';
                    totalElement.style.color = 'black';
                    totalElement.textContent = `Total Merit: ${totalMerits} `;

                    el.innerHTML = totalElement.outerHTML + el.innerHTML;
                }
            }
        });
    }

    const lightTheme = `
        body {
            font-family: "Segoe UI", sans-serif !important;
            font-size: 16px;
            background: #f9fafb !important;
            color: #222;
        }
        table, .windowbg, .windowbg2 {
            background: #fff !important;
            border-radius: 10px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            border: 1px solid #e5e7eb !important;
        }
        td.poster_info {
            width: 70px !important;
            max-width: 70px !important;
            background: #fff !important;
            text-align: center;
            padding: 4px !important;
        }
        td.poster_info img {
            max-width: 48px !important;
            height: auto;
            border-radius: 6px;
        }
        .quote {
            background: #e0f2fe;
            border-left: 4px solid #3b82f6;
        }
        .mobile-buttons a {
            background: #3b82f6;
            color: white !important;
        }
        .mobile-buttons a:hover {
            background: #1d4ed8;
        }
        #smerit-indicator {
            background: #10b981;
            color: white;
        }
        .rank-progress-bar {
            background: #ddd;
        }
        .rank-progress-fill {
            background: #3b82f6;
            height: 6px;
            border-radius: 3px;
        }
        .merit-popup {
            background: #f0f0f0 !important;
            color: #333 !important;
            border: 1px solid #ccc !important;
            border-radius: 6px !important;
            padding: 10px !important;
            font-size: 14px !important;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1) !important;
        }
        .merit-popup input[type="text"] {
            background: #fff !important;
            color: #333 !important;
            border: 1px solid #ccc !important;
            padding: 4px 8px !important;
            border-radius: 4px !important;
        }
        .merit-popup input[type="submit"] {
            background: #3b82f6 !important;
            color: white !important;
            border: none !important;
            padding: 6px 12px !important;
            border-radius: 4px !important;
            cursor: pointer !important;
        }
        .merit-popup input[type="submit"]:hover {
            background: #1d4ed8 !important;
        }
    `;

    const darkTheme = `
        body, td, tr, th {
            font-family: "Segoe UI", sans-serif !important;
            font-size: 16px;
            background: #000000 !important;
            color: #e5e7eb !important;
        }
        table, .windowbg, .windowbg2, td.td_headerandpost, table.bordercolor {
            background: #0a0a0a !important;
            color: #f1f1f1 !important;
            border-radius: 10px;
            box-shadow: 0 0 8px rgba(0,0,0,0.8);
            border: 1px solid #222 !important;
        }
        td.titlebg, td.catbg {
            background: #111 !important;
            color: #00d4ff !important;
            font-weight: bold;
        }
        td.titlebg a, td.catbg a {
            color: #00d4ff !important;
            font-weight: bold;
            text-decoration: none !important;
        }
        td.poster_info {
            width: 70px !important;
            max-width: 70px !important;
            background: #0a0a0a !important;
            text-align: center;
            padding: 4px !important;
            color: #f1f1f1 !important;
        }
        td.poster_info small {
            color: #a0a0a0 !important;
            font-size: 11px;
        }
        td.poster_info img {
            max-width: 48px !important;
            border-radius: 6px;
            box-shadow: 0 0 6px rgba(0,0,0,0.8);
        }
        .quote {
            background: #111111 !important;
            border-left: 4px solid #00d4ff !important;
            color: #f8f8f8 !important;
        }
        .quote cite, .quote .quoteheader {
            color: #00d4ff !important;
            font-weight: bold;
        }
        .quote .quote {
            background: #1a1a1a !important;
            border-left: 3px solid #0077ff !important;
        }
        .mobile-buttons a {
            background: linear-gradient(135deg, #00d4ff, #0077ff);
            color: white !important;
            box-shadow: 0 0 6px rgba(0, 122, 255, 0.6);
        }
        .mobile-buttons a:hover {
            background: linear-gradient(135deg, #00aaff, #0055cc);
        }
        #smerit-indicator {
            background: linear-gradient(135deg, #10b981, #065f46);
            color: white !important;
            box-shadow: 0 0 6px rgba(16, 185, 129, 0.6);
        }
        .rank-progress-bar {
            background: #1f1f1f;
        }
        .rank-progress-fill {
            background: linear-gradient(90deg, #00d4ff, #0077ff);
            height: 6px;
            border-radius: 3px;
        }
        a.board, a:link, a:visited {
            color: #00d4ff !important;
            font-weight: bold;
            text-decoration: none !important;
        }
        a:hover {
            color: #ffffff !important;
            text-decoration: underline !important;
        }
        .smerit_received, .smerit_given, .activity {
            color: #00d4ff !important;
            font-weight: bold;
            background: #111111 !important;
            padding: 2px 4px;
            border-radius: 4px;
            display: inline-block;
        }
        .smerit_received a, .smerit_given a, .activity a {
            color: #00d4ff !important;
            text-decoration: none !important;
        }
        .smerit_received:hover, .smerit_given:hover, .activity:hover {
            color: #ffffff !important;
            background: #0077ff !important;
        }
        .smalltext, .smalltext a {
            color: #c0c0c0 !important;
        }
        .smalltext a:hover {
            color: #00d4ff !important;
        }
        input, select, textarea {
            background: #111 !important;
            color: #f1f1f1 !important;
            border: 1px solid #333 !important;
            border-radius: 6px !important;
            padding: 4px 6px !important;
        }
        input[type="submit"], input[type="button"], button {
            background: linear-gradient(135deg, #00d4ff, #0077ff) !important;
            color: #fff !important;
            border: none !important;
            padding: 6px 12px !important;
            border-radius: 6px !important;
            cursor: pointer !important;
        }
        input[type="submit"]:hover, input[type="button"]:hover, button:hover {
            background: linear-gradient(135deg, #00aaff, #0055cc) !important;
        }
        tr td:nth-child(1) .trust img {
            filter: brightness(2) contrast(2) !important;
        }
        .merit-popup {
            background: #1e1e1e !important;
            color: #e0e0e0 !important;
            border: 1px solid #444 !important;
            border-radius: 6px !important;
            padding: 10px !important;
            font-size: 14px !important;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3) !important;
        }
        .merit-popup input[type="text"] {
            background: #2d2d2d !important;
            color: #e0e0e0 !important;
            border: 1px solid #444 !important;
            padding: 4px 8px !important;
            border-radius: 4px !important;
        }
        .merit-popup input[type="submit"] {
            background: linear-gradient(135deg, #00d4ff, #0077ff) !important;
            color: white !important;
            border: none !important;
            padding: 6px 12px !important;
            border-radius: 4px !important;
            cursor: pointer !important;
        }
        .merit-popup input[type="submit"]:hover {
            background: linear-gradient(135deg, #00aaff, #0055cc) !important;
        }
    `;

    const commonStyles = `
        .quote { max-height: 120px; overflow: hidden; padding: 8px; border-radius: 6px; position: relative; margin: 6px 0; }
        .quote.expanded { max-height: none !important; }
        .quote .show-more { position: absolute; bottom: 4px; right: 6px; font-size: 12px; background: rgba(0,0,0,0.3); color: #fff; padding: 2px 6px; border-radius: 4px; cursor: pointer; }
        .mobile-buttons { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; font-size: 14px; }
        .mobile-buttons a { padding: 6px 10px; border-radius: 20px; text-decoration: none; transition: background 0.2s; }
        #smerit-indicator { position: fixed; top: 14px; left: 14px; background: #6b7280; color: white; padding: 6px 10px; font-size: 13px; border-radius: 10px; z-index: 9999; font-weight: bold; }
        #theme-toggle { position: fixed; top: 14px; right: 14px; background: #6b7280; color: white; padding: 6px 10px; font-size: 13px; border-radius: 10px; z-index: 9999; cursor: pointer; }
        .rank-container { margin-top: 6px; text-align: center; font-size: 12px; font-weight: bold; }
        .rank-name { margin-bottom: 2px; }
        .rank-progress-bar { width: 100%; margin: 0 auto; height: 6px; border-radius: 3px; }
        .rank-progress-fill { height: 6px; border-radius: 3px; }
    `;

    const style = document.createElement("style");
    document.head.appendChild(style);

    function applyTheme(theme) {
        const css = (theme === 'dark' ? darkTheme : lightTheme) + commonStyles;
        style.textContent = css;
        localStorage.setItem('bitcointalk-theme', theme);
    }

    const toggle = document.createElement("div");
    toggle.id = "theme-toggle";
    toggle.textContent = "🔆🌘";
    toggle.onclick = () => {
        const current = localStorage.getItem('bitcointalk-theme') === 'dark' ? 'light' : 'dark';
        applyTheme(current);
    };
    document.body.appendChild(toggle);

    // Funzioni per BitcoinTalk Pinned Threads
    function savePinnedThreads(pinnedThreads) {
        localStorage.setItem('pinnedThreads', JSON.stringify(pinnedThreads));
    }

    function loadPinnedThreads() {
        const pinnedThreads = localStorage.getItem('pinnedThreads');
        return pinnedThreads ? JSON.parse(pinnedThreads) : [];
    }

    function createPinnedTable() {
        const pinnedThreads = loadPinnedThreads();
        if (pinnedThreads.length === 0) return;

        const table = document.createElement('table');
        table.style.width = '100%';
        table.style.marginBottom = '10px';
        table.style.borderCollapse = 'collapse';
        table.style.backgroundColor = '#f5f5f5';
        table.style.border = '1px solid #ddd';

        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');
        const headers = ['', 'Thread', 'Autore'];

        headers.forEach(headerText => {
            const th = document.createElement('th');
            th.style.padding = '8px';
            th.style.textAlign = 'left';
            th.style.borderBottom = '1px solid #ddd';
            th.textContent = headerText;
            headerRow.appendChild(th);
        });

        thead.appendChild(headerRow);
        table.appendChild(thead);

        const tbody = document.createElement('tbody');

        pinnedThreads.forEach(thread => {
            const row = document.createElement('tr');
            row.style.borderBottom = '1px solid #ddd';

            const removeCell = document.createElement('td');
            removeCell.style.padding = '8px';
            removeCell.style.textAlign = 'center';
            const removeButton = document.createElement('button');
            removeButton.textContent = '❌';
            removeButton.style.cursor = 'pointer';
            removeButton.style.background = 'none';
            removeButton.style.border = 'none';
            removeButton.onclick = () => removePinnedThread(thread.id);
            removeCell.appendChild(removeButton);
            row.appendChild(removeCell);

            const titleCell = document.createElement('td');
            titleCell.style.padding = '8px';
            const titleLink = document.createElement('a');
            titleLink.href = thread.url;
            titleLink.textContent = thread.title;
            titleLink.style.fontWeight = 'bold';
            titleCell.appendChild(titleLink);
            row.appendChild(titleCell);

            const authorCell = document.createElement('td');
            authorCell.style.padding = '8px';
            const authorLink = document.createElement('a');
            authorLink.href = thread.authorUrl;
            authorLink.textContent = thread.author;
            authorCell.appendChild(authorLink);
            row.appendChild(authorCell);

            tbody.appendChild(row);
        });

        table.appendChild(tbody);

        const navBar = document.querySelector('table[style="margin-left: 10px;"]');
        const bodyArea = document.querySelector('div#bodyarea');

        if (navBar) {
            navBar.after(table);
        } else if (bodyArea) {
            const firstChild = bodyArea.firstChild;
            if (firstChild) {
                bodyArea.insertBefore(table, firstChild);
            } else {
                bodyArea.appendChild(table);
            }
        }
    }

    function addPinnedThread(threadId, title, url, author, authorUrl) {
        const pinnedThreads = loadPinnedThreads();
        const threadExists = pinnedThreads.some(thread => thread.id === threadId);

        if (!threadExists) {
            pinnedThreads.push({ id: threadId, title, url, author, authorUrl });
            savePinnedThreads(pinnedThreads);
            alert('Thread aggiunto ai pinnati!');
            location.reload();
        } else {
            alert('Thread già presente nei pinnati!');
        }
    }

    function removePinnedThread(threadId) {
        let pinnedThreads = loadPinnedThreads();
        pinnedThreads = pinnedThreads.filter(thread => thread.id !== threadId);
        savePinnedThreads(pinnedThreads);
        alert('Thread rimosso dai pinnati!');
        location.reload();
    }

    function addPinButtons() {
        const threadRows = document.querySelectorAll('table.bordercolor tbody tr:not(:first-child)');

        threadRows.forEach(row => {
            const titleLink = row.querySelector('td:nth-child(3) a[href*="topic="], td:nth-child(4) a[href*="topic="]');
            if (!titleLink) return;

            const firstCell = row.querySelector('td:first-child');
            if (!firstCell || firstCell.querySelector('.pin-button')) return;

            const pinButton = document.createElement('button');
            pinButton.textContent = '📌';
            pinButton.style.cursor = 'pointer';
            pinButton.style.marginLeft = '5px';
            pinButton.style.background = 'none';
            pinButton.style.border = 'none';
            pinButton.className = 'pin-button';

            const threadId = titleLink.href.match(/topic=(\d+)/)[1];
            const title = titleLink.textContent.trim();
            const url = titleLink.href;
            const authorCell = row.querySelector('td:nth-child(4) a, td:nth-child(5) a');
            const author = authorCell ? authorCell.textContent.trim() : 'N/A';
            const authorUrl = authorCell ? authorCell.href : '#';

            pinButton.onclick = () => addPinnedThread(threadId, title, url, author, authorUrl);

            firstCell.appendChild(pinButton);
        });
    }

    // Avvio
    applyTheme(localStorage.getItem('bitcointalk-theme') || 'light');
    updateSmeritIndicator();
    addMeritPopups();
    addButtons();
    fixQuotes();
    addRankBarsInThreads();
    removeOfficialRank();
    injectStyles();

    if (document.querySelector('a[href*="action=profile"]')) {
        fetchSmerit();
    }

    setTimeout(highlightUserMerits, 2000);

    window.addEventListener('load', () => {
        updateAllNotes();

        const observer = new MutationObserver(async (mutations) => {
            let needsUpdate = false;
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.querySelectorAll('a[href*="action=profile;u="]').length > 0 || node.matches('a[href*="action=profile;u="]')) {
                            needsUpdate = true;
                            break;
                        }
                    }
                }
                if (needsUpdate) break;
            }
            if (needsUpdate) {
                await updateAllNotes();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        console.log('Bitcointalk All-in-One Enhancer is running!');

        // Esegui le funzioni per i thread pinnati
        if (window.location.href.includes('index.php?board=')) {
            createPinnedTable();
            addPinButtons();
        }
    });
})();