您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Track player status, hospital time, and attack links in Torn with persistent data, enhanced UI. Adds players by user ID.
当前为
// ==UserScript== // @name Torn Player Tracker // @namespace https://www.torn.com/ // @version 2.0 // @description Track player status, hospital time, and attack links in Torn with persistent data, enhanced UI. Adds players by user ID. // @author Xenocide [2216313] // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect api.torn.com // ==/UserScript== (function () { "use strict"; // === Configuration === const UPDATE_INTERVAL = 30000; // Update interval in milliseconds (30 seconds) // Retrieve API key from localStorage or prompt user to enter it let API_KEY = localStorage.getItem("tornAPIKey"); // If API key is not found, prompt the user to input it if (!API_KEY) { const apiKeyInputSection = document.createElement("div"); apiKeyInputSection.innerHTML = ` <div id="apiKeySection" style="position: fixed; top: 10px; right: 10px; background-color: #333; color: white; padding: 10px; border-radius: 8px; z-index: 10001; font-family: Arial, sans-serif;"> <h3>Enter Your Torn API Key</h3> <input type="text" id="apiKeyInput" placeholder="API Key" style="width: 100%; padding: 5px; margin-bottom: 5px;" /> <button id="saveAPIKeyButton" style="width: 100%; padding: 5px; background-color: green; color: white;">Save API Key</button> <small style="color: yellow;">You need an API key to fetch player data.</small> </div> `; document.body.appendChild(apiKeyInputSection); // Save API key when the user submits it document.getElementById("saveAPIKeyButton").addEventListener("click", () => { API_KEY = document.getElementById("apiKeyInput").value.trim(); if (API_KEY) { localStorage.setItem("tornAPIKey", API_KEY); // Save to localStorage document.getElementById("apiKeySection").style.display = "none"; // Hide the input form alert("API Key saved successfully!"); // Provide feedback to the user } else { alert("Please enter a valid API Key."); } }); } // If API key is already stored, proceed with the script as usual if (API_KEY) { // Retrieve tracked players from localStorage or initialize default IDs let trackedPlayers = JSON.parse(localStorage.getItem("trackedPlayers")) || [123456, 654321, 789012]; // === Create the Floating Box === const box = document.createElement("div"); box.id = "statusTracker"; box.innerHTML = ` <h3>Player Tracker</h3> <ul id="statusList">Loading...</ul> <div id="userControls"> <hr> <input type="text" id="addPlayerInput" placeholder="Add Player ID" /> <button id="addPlayerButton">Add</button> <ul id="trackedPlayersList"></ul> </div> <button id="toggleUI">Hide Add Section</button> `; document.body.appendChild(box); // Add some styles for the box GM_addStyle(` #statusTracker { position: fixed; top: 10px; right: 10px; width: 350px; background-color: #333; color: white; border: 2px solid #555; border-radius: 8px; padding: 10px; z-index: 10000; font-family: Arial, sans-serif; } #statusTracker h3 { margin: 0 0 10px 0; font-size: 16px; text-align: center; } #statusTracker ul { list-style-type: none; padding: 0; margin: 0; } #statusTracker li { margin: 5px 0; } #statusTracker li span { font-weight: bold; } #statusTracker input { width: calc(100% - 60px); margin-right: 5px; padding: 5px; } #statusTracker button { padding: 5px; cursor: pointer; } #statusTracker hr { margin: 10px 0; border: 0.5px solid #555; } `); // === Function to Format Time in Minutes and Seconds === function formatTime(seconds) { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds}s`; } // === Function to Fetch Player Info by ID === function fetchPlayerStatus(playerId) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: `https://api.torn.com/user/${playerId}?selections=basic,profile&key=${API_KEY}`, onload: (response) => { if (response.status === 200) { const data = JSON.parse(response.responseText); // Check for API errors if (data.error) { console.error(`Error fetching player ${playerId}:`, data.error); return resolve({ playerId, name: `Error: ${data.error.error}`, status: "Unknown", hospitalTimeLeft: 0, attackLink: "", lastActivity: "N/A", }); } // Extract data from API response const name = data.name || `ID ${playerId}`; const status = data.status?.state || "Unknown"; const hospitalTimeLeft = data.status?.until ? Math.max(0, Math.ceil((data.status.until * 1000 - Date.now()) / 1000)) : 0; const attackLink = `https://www.torn.com/loader.php?sid=attack&user2ID=${playerId}`; const lastActivity = data.last_action?.relative || "N/A"; resolve({ playerId, name, status, hospitalTimeLeft, attackLink, lastActivity }); } else { console.error(`Error fetching status for player ${playerId}:`, response.status); reject(`Error fetching status for player ${playerId}`); } }, onerror: (error) => { console.error(`Error fetching status for player ${playerId}:`, error); reject(`Error fetching status for player ${playerId}`); }, }); }); } // === Function to Update the Status List === async function updateStatusList() { const statusList = document.getElementById("statusList"); statusList.innerHTML = "Updating..."; try { const statusPromises = trackedPlayers.map((id) => fetchPlayerStatus(id)); const statuses = await Promise.all(statusPromises); statusList.innerHTML = ""; statuses.forEach(({ playerId, name, status, hospitalTimeLeft, attackLink, lastActivity }) => { const color = status === "Okay" ? "green" : status === "Hospital" ? "red" : status === "Traveling" ? "blue" : "gray"; const hospitalText = status === "Hospital" ? ` (Time left: ${formatTime(hospitalTimeLeft)})` : ""; const listItem = document.createElement("li"); listItem.innerHTML = ` <span style="color: ${color};">${status}</span> - <a href="${attackLink}" target="_blank" style="color: yellow;">${name}</a> (ID: ${playerId})${hospitalText} <br> <small>Last Activity: ${lastActivity}</small>`; statusList.appendChild(listItem); }); } catch (error) { console.error("Error updating statuses:", error); statusList.innerHTML = "Error updating statuses."; } } // === Function to Update Tracked Players List === function updateTrackedPlayersList() { const trackedPlayersList = document.getElementById("trackedPlayersList"); trackedPlayersList.innerHTML = ""; trackedPlayers.forEach((playerId) => { const listItem = document.createElement("li"); listItem.innerHTML = `Player ID: ${playerId} <button data-id="${playerId}" class="removePlayerButton">Remove</button>`; trackedPlayersList.appendChild(listItem); }); // Add event listeners to remove buttons document.querySelectorAll(".removePlayerButton").forEach((button) => { button.addEventListener("click", (event) => { const playerId = parseInt(event.target.getAttribute("data-id")); trackedPlayers = trackedPlayers.filter((id) => id !== playerId); localStorage.setItem("trackedPlayers", JSON.stringify(trackedPlayers)); // Save to localStorage updateTrackedPlayersList(); updateStatusList(); }); }); } // === Add Player by ID from Input === document.getElementById("addPlayerButton").addEventListener("click", () => { const input = document.getElementById("addPlayerInput"); const playerId = parseInt(input.value); if (!isNaN(playerId) && !trackedPlayers.includes(playerId)) { trackedPlayers.push(playerId); localStorage.setItem("trackedPlayers", JSON.stringify(trackedPlayers)); // Save to localStorage input.value = ""; updateTrackedPlayersList(); updateStatusList(); } else if (isNaN(playerId)) { alert("Please enter a valid player ID."); } else { alert("This player is already tracked."); } }); // === Hide/Show Add Section === const toggleUI = document.getElementById("toggleUI"); const userControls = document.getElementById("userControls"); // Retrieve the saved state of the visibility (default is "shown") const isHidden = localStorage.getItem("isUserControlsHidden") === "true"; // If hidden, hide the controls if (isHidden) { userControls.style.display = "none"; toggleUI.innerText = "Show Add Section"; } else { toggleUI.innerText = "Hide Add Section"; } toggleUI.addEventListener("click", () => { const isCurrentlyHidden = userControls.style.display === "none"; if (isCurrentlyHidden) { userControls.style.display = "block"; localStorage.setItem("isUserControlsHidden", "false"); // Store the state toggleUI.innerText = "Hide Add Section"; } else { userControls.style.display = "none"; localStorage.setItem("isUserControlsHidden", "true"); // Store the state toggleUI.innerText = "Show Add Section"; } }); // === Periodic Updates === setInterval(updateStatusList, UPDATE_INTERVAL); updateStatusList(); // Initial update updateTrackedPlayersList(); // Initial list update } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址