您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Download Roblox thumbnails, game icons, badge icons, and user info
当前为
- // ==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;
- }
- })();