Torn User ID Extractor

Replace status icon with checkbox and extract user IDs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Torn User ID Extractor
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Replace status icon with checkbox and extract user IDs
// @match        https://www.torn.com/page.php?sid=UserList*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_setClipboard
// ==/UserScript==

(function() {
    'use strict';

    let cachedIDs = GM_getValue('cachedUserIDs', []);

    const HALLOWEEN_COLORS = {
        orange: '#ff6b1a',
        darkOrange: '#cc4c00',
        purple: '#6b1aff',
        darkPurple: '#4c00cc',
        green: '#1aff6b',
        black: '#333333',
    };

    function addCheckboxes() {
        // Find all status icons and replace them
        const statusIcons = document.querySelectorAll('.iconShow[title*="Offline"], .iconShow[title*="Online"], .iconShow[title*="Idle"]');
        statusIcons.forEach(icon => {
            if (!icon.parentElement.querySelector('.user-checkbox')) {
                // Create checkbox
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.checked = true;
                checkbox.className = 'user-checkbox';
                checkbox.style.cssText = `
                    cursor: pointer;
                    margin: 0;
                    vertical-align: middle;
                `;

                // Replace icon with checkbox
                icon.parentElement.replaceChild(checkbox, icon);
            }
        });
    }

    function extractUserIDs() {
        const userList = document.querySelector('.user-info-list-wrap.bottom-round.cont-gray');
        if (!userList) {
            console.log('User list not found');
            return;
        }

        const userItems = document.querySelectorAll('li[class*="user"]');
        const newIDs = Array.from(userItems)
            .filter(item => {
                const checkbox = item.querySelector('.user-checkbox');
                return checkbox && checkbox.checked;
            })
            .map(item => {
                const match = item.className.match(/user(\d+)/);
                return match ? match[1] : null;
            })
            .filter(id => id !== null);

        // Add new IDs to cache, avoiding duplicates and limiting to 100
        newIDs.forEach(id => {
            if (!cachedIDs.includes(id) && cachedIDs.length < 100) {
                cachedIDs.push(id);
            }
        });

        // Save updated cache
        GM_setValue('cachedUserIDs', cachedIDs);

        // Update counter
        updateCounter();

        // Create a floating message
        showMessage(`${newIDs.length} user IDs extracted. Total cached: ${cachedIDs.length}`);
    }

    function formatAndCopyIDs() {
        const formattedData = {
            target_backup: cachedIDs.slice(0, 100).map(id => ({
                id: parseInt(id),
                notes: "",
                notes_color: ""
            }))
        };

        const jsonString = JSON.stringify(formattedData);
        GM_setClipboard(jsonString);
        console.log('Formatted user data copied to clipboard:', jsonString);

        showMessage(`${formattedData.target_backup.length} user IDs formatted and copied to clipboard!`);
    }

    function showMessage(text) {
        const message = document.createElement('div');
        message.textContent = text;
        message.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: ${HALLOWEEN_COLORS.purple};
            color: black;
            padding: 15px;
            border-radius: 5px;
            z-index: 9999;
            box-shadow: 0 0 10px ${HALLOWEEN_COLORS.orange};
            animation: glow 1s ease-in-out infinite alternate;
        `;

        // Add glow animation
        const style = document.createElement('style');
        style.textContent = `
            @keyframes glow {
                from {
                    box-shadow: 0 0 5px ${HALLOWEEN_COLORS.orange},
                               0 0 10px ${HALLOWEEN_COLORS.orange};
                }
                to {
                    box-shadow: 0 0 10px ${HALLOWEEN_COLORS.purple},
                               0 0 20px ${HALLOWEEN_COLORS.purple};
                }
            }
        `;
        document.head.appendChild(style);

        document.body.appendChild(message);
        setTimeout(() => {
            document.body.removeChild(message);
        }, 3000);
    }

    function updateCounter() {
        counterSpan.textContent = `${cachedIDs.length}/100`;
    }

    function clearCache() {
        cachedIDs = [];
        GM_setValue('cachedUserIDs', cachedIDs);
        updateCounter();
        showMessage("Cache cleared!");
    }

    // Create UI elements with consistent width
    const buttonContainer = document.createElement('div');
    buttonContainer.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        z-index: 9999;
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        gap: 10px;
    `;

    const baseButtonStyle = `
        padding: 10px;
        width: 200px;
        color: black;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-weight: bold;
        transition: all 0.3s ease;
        text-align: center;
        text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
        box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    `;

    const extractButton = document.createElement('button');
    extractButton.textContent = 'Extract Selected User IDs';
    extractButton.style.cssText = `
        ${baseButtonStyle}
        background-color: ${HALLOWEEN_COLORS.orange};
    `;
    extractButton.addEventListener('mouseover', () => {
        extractButton.style.backgroundColor = HALLOWEEN_COLORS.darkOrange;
        extractButton.style.transform = 'translateY(-2px)';
    });
    extractButton.addEventListener('mouseout', () => {
        extractButton.style.backgroundColor = HALLOWEEN_COLORS.orange;
        extractButton.style.transform = 'translateY(0)';
    });
    extractButton.addEventListener('click', extractUserIDs);

    const copyButton = document.createElement('button');
    copyButton.textContent = 'Format and Copy IDs';
    copyButton.style.cssText = `
        ${baseButtonStyle}
        background-color: ${HALLOWEEN_COLORS.purple};
    `;
    copyButton.addEventListener('mouseover', () => {
        copyButton.style.backgroundColor = HALLOWEEN_COLORS.darkPurple;
        copyButton.style.transform = 'translateY(-2px)';
    });
    copyButton.addEventListener('mouseout', () => {
        copyButton.style.backgroundColor = HALLOWEEN_COLORS.purple;
        copyButton.style.transform = 'translateY(0)';
    });
    copyButton.addEventListener('click', formatAndCopyIDs);

    const clearButton = document.createElement('button');
    clearButton.textContent = 'Clear Cache';
    clearButton.style.cssText = `
        ${baseButtonStyle}
        background-color: ${HALLOWEEN_COLORS.green};
    `;
    clearButton.addEventListener('mouseover', () => {
        clearButton.style.backgroundColor = '#008c45';
        clearButton.style.transform = 'translateY(-2px)';
    });
    clearButton.addEventListener('mouseout', () => {
        clearButton.style.backgroundColor = HALLOWEEN_COLORS.green;
        clearButton.style.transform = 'translateY(0)';
    });
    clearButton.addEventListener('click', clearCache);

    const counterSpan = document.createElement('span');
    counterSpan.style.cssText = `
        width: 180px;
        color: white;
        background-color: ${HALLOWEEN_COLORS.black};
        padding: 10px;
        border-radius: 5px;
        text-align: center;
        font-weight: bold;
        box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    `;
    updateCounter();

    buttonContainer.appendChild(extractButton);
    buttonContainer.appendChild(copyButton);
    buttonContainer.appendChild(clearButton);
    buttonContainer.appendChild(counterSpan);
    document.body.appendChild(buttonContainer);

    // Add Halloween style to checkboxes
    const checkboxStyle = document.createElement('style');
    checkboxStyle.textContent = `
        .user-checkbox {
            accent-color: ${HALLOWEEN_COLORS.orange} !important;
            width: 16px;
            height: 16px;
        }
        .user-checkbox:hover {
            transform: scale(1.1);
            transition: transform 0.2s ease;
        }
    `;
    document.head.appendChild(checkboxStyle);

    // Initial setup
    addCheckboxes();

    // Add mutation observer to handle dynamically loaded users
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                addCheckboxes();
            }
        });
    });

    const userList = document.querySelector('.user-info-list-wrap.bottom-round.cont-gray');
    if (userList) {
        observer.observe(userList, { childList: true, subtree: true });
    }
})();