Roblox Multi-Feature User Panel.

Download Roblox thumbnails, game icons, badge icons, and user info

Od 14.11.2024.. Pogledajte najnovija verzija.

// ==UserScript==
// @name         Roblox Multi-Feature User Panel.
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Download Roblox thumbnails, game icons, badge icons, and user info
// @author       NotRoblox
// @match        https://www.roblox.com/userpanel
// @match        https://www.roblox.com/getgameinfo
// @match        https://www.roblox.com/getbadgeinfo
// @match        https://www.roblox.com/getuserinfo
// @match        https://www.roblox.com/getgroupinfo
// @grant        GM_xmlhttpRequest
// @grant        Gm_download
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    const style = document.createElement('style');
    style.textContent = `
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f7f6;
            margin: 0;
            padding: 0;
        }

        .main-content-wrapper {
            width: 100%;
            padding: 20px;
            margin-bottom: 120px;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: calc(100vh - 200px);
        }

        .form-container {
            background-color: #ffffff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            width: 100%;
            max-width: 400px;
            text-align: center;
            margin: 20px auto;
            position: relative;
            z-index: 1;
        }

        .input-field {
            width: 100%;
            padding: 10px;
            margin: 10px 0;
            border: 2px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }

        .submit-button, .panel-button {
            background-color: #4CAF50;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            width: 100%;
            font-size: 16px;
            margin: 10px 0;
        }

        .submit-button:hover, .panel-button:hover {
            background-color: #45a049;
        }

        .result-container {
            background-color: #ffffff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            width: 100%;
            max-width: 800px;
            margin: 20px auto 120px auto;
            position: relative;
            z-index: 1;
        }

        .image-container {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            justify-content: center;
            margin: 20px 0;
        }

        .image-item {
            text-align: center;
        }

        .image-item img {
            max-width: 200px;
            border-radius: 8px;
            margin-bottom: 10px;
        }

        .info-text {
            margin: 10px 0;
            font-size: 16px;
        }

        .error-message {
            color: #ff0000;
            margin: 10px 0;
        }

        .success-message {
            color: #4CAF50;
            margin: 10px 0;
        }
    `;
    document.head.appendChild(style);

    async function getUserIdFromUsername(username) {
        const response = await fetch(`https://users.roblox.com/v1/usernames/users`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ usernames: [username] })
        });
        const data = await response.json();
        if (!data.data || data.data.length === 0) throw new Error('User not found');
        return data.data[0].id;
    }

    function createBasicForm(placeholder, buttonText) {
        const container = document.createElement('div');
        container.className = 'form-container';

        const input = document.createElement('input');
        input.type = 'text';
        input.className = 'input-field';
        input.placeholder = placeholder;

        const button = document.createElement('button');
        button.className = 'submit-button';
        button.textContent = buttonText;

        container.appendChild(input);
        container.appendChild(button);

        return { container, input, button };
    }

    function displayMessage(message, isError = false) {
        const messageDiv = document.createElement('div');
        messageDiv.className = isError ? 'error-message' : 'success-message';
        messageDiv.textContent = message;
        document.querySelector('.form-container').appendChild(messageDiv);
        setTimeout(() => messageDiv.remove(), 5000);
    }

    function createResultContainer() {
        const container = document.createElement('div');
        container.className = 'result-container';
        return container;
    }

async function initializeGameInfo() {
    const mainWrapper = document.createElement('div');
    mainWrapper.className = 'main-content-wrapper';
    document.body.appendChild(mainWrapper);

    const { container, input, button } = createBasicForm('Enter Game ID', 'Get Game Info');
    mainWrapper.appendChild(container);

    const refreshContent = async (gameId) => {
        const existingResults = mainWrapper.querySelectorAll('.result-container');
        existingResults.forEach(result => result.remove());

        try {
            // Get the universe ID first
            const placeResponse = await fetch(`https://apis.roblox.com/universes/v1/places/${gameId}/universe`);
            const placeData = await placeResponse.json();
            const universeId = placeData.universeId;

            // Now fetch all data with the universe ID
            const [gameResponse, thumbnailResponse, iconResponse] = await Promise.all([
                fetch(`https://games.roblox.com/v1/games?universeIds=${universeId}`),
                fetch(`https://thumbnails.roblox.com/v1/games/${universeId}/thumbnails?size=768x432&format=Png&limit=10`),
                fetch(`https://thumbnails.roblox.com/v1/games/icons?universeIds=${universeId}&size=512x512&format=Png&isCircular=false`)
            ]);

            const [gameData, thumbnailData, iconData] = await Promise.all([
                gameResponse.json(),
                thumbnailResponse.json(),
                iconResponse.json()
            ]);

            const resultContainer = createResultContainer();

            // Create image container for all images
            const imageContainer = document.createElement('div');
            imageContainer.className = 'image-container';

            // Display game icon first
            if (iconData.data && iconData.data[0]) {
                const iconDiv = document.createElement('div');
                iconDiv.className = 'image-item';

                const iconImg = document.createElement('img');
                iconImg.src = iconData.data[0].imageUrl;
                iconImg.alt = 'Game Icon';

                const downloadIconBtn = document.createElement('button');
                downloadIconBtn.className = 'submit-button';
                downloadIconBtn.textContent = 'Download Icon';
                downloadIconBtn.onclick = () => GM_download({
                    url: iconData.data[0].imageUrl,
                    name: `game_${gameId}_icon.png`
                });

                iconDiv.appendChild(iconImg);
                iconDiv.appendChild(downloadIconBtn);
                imageContainer.appendChild(iconDiv);
            }

            // Display game information
            if (gameData.data && gameData.data[0]) {
                const gameInfo = document.createElement('div');
                gameInfo.className = 'info-text';
                gameInfo.innerHTML = `
                    <h3>${gameData.data[0].name}</h3>
                    <p>Description: ${gameData.data[0].description || 'No description'}</p>
                    <p>Created: ${new Date(gameData.data[0].created).toLocaleDateString()}</p>
                    <p>Updated: ${new Date(gameData.data[0].updated).toLocaleDateString()}</p>
                    <p>Playing: ${gameData.data[0].playing || 0}</p>
                    <p>Visits: ${gameData.data[0].visits || 0}</p>
                    <p><a href="https://www.roblox.com/games/${gameId}" target="_blank">View Game Page</a></p>
                `;
                resultContainer.appendChild(gameInfo);
            }

            // Display all thumbnails
            if (thumbnailData.data) {
                thumbnailData.data.forEach((thumb, index) => {
                    const thumbDiv = document.createElement('div');
                    thumbDiv.className = 'image-item';

                    const thumbImg = document.createElement('img');
                    thumbImg.src = thumb.imageUrl;
                    thumbImg.alt = `Game Thumbnail ${index + 1}`;

                    const downloadThumbBtn = document.createElement('button');
                    downloadThumbBtn.className = 'submit-button';
                    downloadThumbBtn.textContent = `Download Thumbnail ${index + 1}`;
                    downloadThumbBtn.onclick = () => GM_download({
                        url: thumb.imageUrl,
                        name: `game_${gameId}_thumbnail_${index + 1}.png`
                    });

                    thumbDiv.appendChild(thumbImg);
                    thumbDiv.appendChild(downloadThumbBtn);
                    imageContainer.appendChild(thumbDiv);
                });
            }

            resultContainer.appendChild(imageContainer);
            mainWrapper.appendChild(resultContainer);
            displayMessage('Game information fetched successfully!');
        } catch (error) {
            displayMessage(error.message, true);
        }
    };

    button.onclick = async () => {
        const gameId = input.value.trim();
        if (!gameId) {
            displayMessage('Please enter a game ID', true);
            return;
        }
        await refreshContent(gameId);
    };
}

    async function initializeBadgeInfo() {
        const mainWrapper = document.createElement('div');
        mainWrapper.className = 'main-content-wrapper';
        document.body.appendChild(mainWrapper);

        const { container, input, button } = createBasicForm('Enter Badge ID', 'Get Badge Info');
        mainWrapper.appendChild(container);

        const refreshContent = async (badgeId) => {
            // Remove any existing result containers
            const existingResults = mainWrapper.querySelectorAll('.result-container');
            existingResults.forEach(result => result.remove());

            try {
                // Fetch badge info
                const infoResponse = await fetch(`https://badges.roblox.com/v1/badges/${badgeId}`);
                const badgeInfo = await infoResponse.json();

                // Fetch badge icon
                const iconResponse = await fetch(`https://thumbnails.roblox.com/v1/badges/icons?badgeIds=${badgeId}&size=150x150&format=Png`);
                const iconData = await iconResponse.json();

                const resultContainer = createResultContainer();

                // Create image container first
                const imageContainer = document.createElement('div');
                imageContainer.className = 'image-container';

                // Display badge icon
                if (iconData.data && iconData.data[0]) {
                    const iconDiv = document.createElement('div');
                    iconDiv.className = 'image-item';

                    const iconImg = document.createElement('img');
                    iconImg.src = iconData.data[0].imageUrl;
                    iconImg.alt = 'Badge Icon';

                    const downloadBtn = document.createElement('button');
                    downloadBtn.className = 'submit-button';
                    downloadBtn.textContent = 'Download Badge Icon';
                    downloadBtn.onclick = () => GM_download({
                        url: iconData.data[0].imageUrl,
                        name: `badge_${badgeId}.png`
                    });

                    iconDiv.appendChild(iconImg);
                    iconDiv.appendChild(downloadBtn);
                    imageContainer.appendChild(iconDiv);
                }

                // Display badge information
                const infoDiv = document.createElement('div');
                infoDiv.className = 'info-text';
                infoDiv.innerHTML = `
                    <h3>${badgeInfo.name}</h3>
                    <p>${badgeInfo.description}</p>
                    <p>Enabled: ${badgeInfo.enabled}</p>
                    <p>Statistics:</p>
                    <p>- Created: ${new Date(badgeInfo.created).toLocaleDateString()}</p>
                    <p>- Updated: ${new Date(badgeInfo.updated).toLocaleDateString()}</p>
                `;

                resultContainer.appendChild(imageContainer);
                resultContainer.appendChild(infoDiv);
                mainWrapper.appendChild(resultContainer);
                displayMessage('Badge information fetched successfully!');
            } catch (error) {
                displayMessage(error.message, true);
            }
        };

        button.onclick = async () => {
            const badgeId = input.value.trim();
            if (!badgeId) {
                displayMessage('Please enter a badge ID', true);
                return;
            }
            await refreshContent(badgeId);
        };
    }

async function initializeUserInfo() {
    const mainWrapper = document.createElement('div');
    mainWrapper.className = 'main-content-wrapper';
    document.body.appendChild(mainWrapper);

    const { container, input, button } = createBasicForm('Enter Username', 'Get User Info');
    mainWrapper.appendChild(container);

    // Create a result container to hold the user info, initially hidden
    const resultContainer = createResultContainer();
    resultContainer.style.display = 'none'; // Hide initially
    mainWrapper.appendChild(resultContainer);

    button.onclick = async () => {
        try {
            const username = input.value.trim();
            if (!username) throw new Error('Please enter a username');

            const userId = await getUserIdFromUsername(username);

            // Fetch all data in parallel
            const [
                presenceResponse,
                friendsResponse,
                followersResponse,
                thumbnailResponse,
                bustResponse,
                headshotResponse
            ] = await Promise.all([
                fetch(`https://presence.roblox.com/v1/presence/users`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ userIds: [userId] })
                }),
                fetch(`https://friends.roblox.com/v1/users/${userId}/friends/count`),
                fetch(`https://friends.roblox.com/v1/users/${userId}/followers/count`),
                fetch(`https://thumbnails.roblox.com/v1/users/avatar?userIds=${userId}&size=420x420&format=Png`),
                fetch(`https://thumbnails.roblox.com/v1/users/avatar-bust?userIds=${userId}&size=420x420&format=Png`),
                fetch(`https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${userId}&size=420x420&format=Png`)
            ]);

            const [presence, friends, followers, thumbnail, bust, headshot] = await Promise.all([
                presenceResponse.json(),
                friendsResponse.json(),
                followersResponse.json(),
                thumbnailResponse.json(),
                bustResponse.json(),
                headshotResponse.json()
            ]);

            // Clear previous content in the result container
            resultContainer.innerHTML = '';

            // Create thumbnails section
            const imageContainer = document.createElement('div');
            imageContainer.className = 'image-container';

            // Helper function to create image sections
            const createImageSection = (data, type) => {
                if (data.data && data.data[0]) {
                    const div = document.createElement('div');
                    div.className = 'image-item';

                    const img = document.createElement('img');
                    img.src = data.data[0].imageUrl;
                    img.alt = `${type} thumbnail`;

                    const downloadBtn = document.createElement('button');
                    downloadBtn.className = 'submit-button';
                    downloadBtn.textContent = `Download ${type}`;
                    downloadBtn.onclick = () => GM_download({
                        url: data.data[0].imageUrl,
                        name: `${username}_${type}.png`
                    });

                    div.appendChild(img);
                    div.appendChild(downloadBtn);
                    imageContainer.appendChild(div);
                }
            };

            // Add all thumbnails
            createImageSection(thumbnail, 'Full Avatar');
            createImageSection(bust, 'Bust');
            createImageSection(headshot, 'Headshot');

            // Create user info section
            const userInfo = document.createElement('div');
            userInfo.className = 'info-text';

            const userPresence = presence.userPresences[0];
            userInfo.innerHTML = `
                <h3>User Information for ${username}</h3>
                <p>User ID: ${userId}</p>
                <p>Online Status: ${userPresence.userPresenceType === 0 ? 'Offline' : 'Online'}</p>
                <p>Friends Count: ${friends.count}</p>
                <p>Followers Count: ${followers.count}</p>
                <p>Profile Link: <a href="https://www.roblox.com/users/${userId}/profile" target="_blank">View Profile</a></p>
                ${userPresence.userPresenceType !== 0 ? `<p>Last Location: ${userPresence.lastLocation}</p>` : ''}
            `;

            // Append the new content to the result container
            resultContainer.appendChild(imageContainer);
            resultContainer.appendChild(userInfo);
            resultContainer.style.display = 'block'; // Show the result container
            displayMessage('User information fetched successfully!');
        } catch (error) {
            displayMessage(error.message, true);
        }
    };
}
        // Add this new function:
async function initializeGroupInfo() {
    const mainWrapper = document.createElement('div');
    mainWrapper.className = 'main-content-wrapper';
    document.body.appendChild(mainWrapper);

    const { container, input, button } = createBasicForm('Enter Group ID', 'Get Group Info');
    mainWrapper.appendChild(container);

    const refreshContent = async (groupId) => {
        // Remove any existing result containers
        const existingResults = mainWrapper.querySelectorAll('.result-container');
        existingResults.forEach(result => result.remove());

        try {
            // Fetch all group data in parallel
            const [
                groupResponse,
                membersResponse,
                iconResponse,
                rolesResponse
            ] = await Promise.all([
                fetch(`https://groups.roblox.com/v1/groups/${groupId}`),
                fetch(`https://groups.roblox.com/v1/groups/${groupId}/membership`),
                fetch(`https://thumbnails.roblox.com/v1/groups/icons?groupIds=${groupId}&size=420x420&format=Png`),
                fetch(`https://groups.roblox.com/v1/groups/${groupId}/roles`)
            ]);

            const [groupInfo, membersInfo, iconData, rolesInfo] = await Promise.all([
                groupResponse.json(),
                membersResponse.json(),
                iconResponse.json(),
                rolesResponse.json()
            ]);

            const resultContainer = createResultContainer();

            // Create image container for group icon
            const imageContainer = document.createElement('div');
            imageContainer.className = 'image-container';

            // Display group icon
            if (iconData.data && iconData.data[0]) {
                const iconDiv = document.createElement('div');
                iconDiv.className = 'image-item';

                const iconImg = document.createElement('img');
                iconImg.src = iconData.data[0].imageUrl;
                iconImg.alt = 'Group Icon';

                const downloadBtn = document.createElement('button');
                downloadBtn.className = 'submit-button';
                downloadBtn.textContent = 'Download Group Icon';
                downloadBtn.onclick = () => GM_download({
                    url: iconData.data[0].imageUrl,
                    name: `group_${groupId}_icon.png`
                });

                iconDiv.appendChild(iconImg);
                iconDiv.appendChild(downloadBtn);
                imageContainer.appendChild(iconDiv);
            }

            // Display group information
            const infoDiv = document.createElement('div');
            infoDiv.className = 'info-text';
            infoDiv.innerHTML = `
                <h3>${groupInfo.name}</h3>
                <p>Description: ${groupInfo.description || 'No description'}</p>
                <p>Owner: ${groupInfo.owner ? groupInfo.owner.username : 'No owner'}</p>
                <p>Member Count: ${membersInfo.memberCount || 0}</p>
                <p>Created: ${new Date(groupInfo.created).toLocaleDateString()}</p>
                <p>Public Entry: ${groupInfo.publicEntryAllowed ? 'Yes' : 'No'}</p>
                <p><a href="https://www.roblox.com/groups/${groupId}" target="_blank">View Group Page</a></p>
                <h4>Roles:</h4>
                <ul>
                    ${rolesInfo.roles.map(role => `
                        <li>${role.name} (${role.memberCount} members)</li>
                    `).join('')}
                </ul>
            `;

            resultContainer.appendChild(imageContainer);
            resultContainer.appendChild(infoDiv);
            mainWrapper.appendChild(resultContainer);
            displayMessage('Group information fetched successfully!');
        } catch (error) {
            displayMessage(error.message, true);
        }
    };

    button.onclick = async () => {
        const groupId = input.value.trim();
        if (!groupId) {
            displayMessage('Please enter a group ID', true);
            return;
        }
        await refreshContent(groupId);
    };
}
            // Panel Implementation
    function createPanel() {
        const mainWrapper = document.createElement('div');
        mainWrapper.className = 'main-content-wrapper';
        document.body.appendChild(mainWrapper);

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

        const title = document.createElement('h2');
        title.textContent = 'Roblox Multi-Feature Tool';
        container.appendChild(title);

        const buttons = [
            { text: 'Game Information', url: '/getgameinfo' },
            { text: 'Badge Information', url: '/getbadgeinfo' },
            { text: 'User Information', url: '/getuserinfo' },
            { text: 'Group Information', url: '/getgroupinfo' }
        ];

        buttons.forEach(button => {
            const btn = document.createElement('button');
            btn.className = 'panel-button';
            btn.textContent = button.text;
            btn.onclick = () => window.location.href = 'https://www.roblox.com' + button.url;
            container.appendChild(btn);
        });

        mainWrapper.appendChild(container);
    }

    // Initialize based on current page
    const currentPath = window.location.pathname;
    switch(currentPath) {
        case '/userpanel':
            createPanel();
            break;
        case '/getgameinfo':
            initializeGameInfo();
            break;
        case '/getbadgeinfo':
            initializeBadgeInfo();
            break;
        case '/getuserinfo':
            initializeUserInfo();
            break;
        case '/getgroupinfo':
            initializeGroupInfo();
            break;
    }
})();