您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script that lets you add, store, and delete friends on Torn with custom descriptions.
- // ==UserScript==
- // @name TORN Friend Extender
- // @namespace http://tampermonkey.net/
- // @version 1.1.1
- // @author Clyoth
- // @description A script that lets you add, store, and delete friends on Torn with custom descriptions.
- // @match https://www.torn.com/friendlist.php
- // @icon https://play-lh.googleusercontent.com/BkaIDbibtUpGcziVQsgCya-eC7oxTUHL5G8m8v3XW3S11_-GZEItaxzeXxhKmoAiX8x6
- // @license MIT
- // @grant none
- // ==/UserScript==
- (function () {
- const apiKey = 'ADD_API_KEY_HERE';
- const FRIENDS_STORAGE_KEY = 'tornFriendList';
- let addButtonAdded = false;
- let addedFriends = new Set(); // Track added friends by ID
- let friendsLoaded = false; // Flag to track if friends have been loaded already
- const style = document.createElement('style');
- style.textContent = `
- .add-button {
- padding: 12px 20px;
- background-color: #3b3b3b;
- color: white;
- border: none;
- border-radius: 5px;
- cursor: pointer;
- font-size: 14px;
- transition: background-color 0.3s ease, transform 0.2s ease;
- margin-top: 4px;
- width: auto;
- text-align: center;
- }
- .add-button:hover {
- background-color: #5c5c5c;
- transform: scale(1.05);
- }
- #friendForm {
- padding: 20px;
- border-radius: 8px;
- margin-top: 10px;
- color: white;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
- background-color: #2c2f33;
- }
- #friendForm h3 {
- margin-top:4px;
- }
- #friendDataForm input[type="text"] {
- width: 30%;
- padding: 8px;
- margin-top: 8px;
- border: 2px solid #555;
- border-radius: 5px;
- background-color: #444;
- color: white;
- font-size: 12px;
- }
- #friendDataForm label {
- font-weight: bold;
- display: block;
- margin-bottom: 4px;
- color: #d3d3d3;
- }
- #friendDataForm button {
- padding: 8px 16px;
- background-color: #3b3b3b;
- color: white;
- border: none;
- border-radius: 5px;
- cursor: pointer;
- font-size: 12px;
- margin-top: 10px;
- transition: background-color 0.3s ease;
- }
- #friendDataForm button:hover {
- background-color: #5c5c5c;
- }
- #friendDataForm #cancelForm {
- background-color: #8b0000;
- margin-left: 10px;
- }
- #friendDataForm #cancelForm:hover {
- background-color: #b22222;
- }
- `;
- document.head.appendChild(style);
- function loadFriends() {
- const storedFriends = localStorage.getItem(FRIENDS_STORAGE_KEY);
- return storedFriends ? JSON.parse(storedFriends) : [];
- }
- function saveFriends(friends) {
- localStorage.setItem(FRIENDS_STORAGE_KEY, JSON.stringify(friends));
- }
- function createForm() {
- if (document.getElementById('friendForm')) return;
- const formHTML = `
- <div id="friendForm" style="padding: 10px; background-color: #323233; border-radius: 5px; margin-top: 10px;">
- <h3>Add Friend</h3>
- <form id="friendDataForm">
- <label for="friendId">ID:</label>
- <input type="text" id="friendId" name="id" required /><br><br>
- <label for="friendDescription">Description:</label>
- <input type="text" id="friendDescription" name="description" maxlength="40"/><br><br>
- <button type="submit">Fetch and Add Friend</button>
- <button type="button" id="cancelForm">Cancel</button>
- </form>
- </div>
- `;
- const formContainer = document.createElement('div');
- formContainer.innerHTML = formHTML;
- const paginationWrapper = document.querySelector('.pagination-wrapper');
- if (paginationWrapper) {
- paginationWrapper.appendChild(formContainer);
- } else {
- console.error('pagination-wrapper not found.');
- }
- document.getElementById('cancelForm').addEventListener('click', () => {
- formContainer.remove();
- });
- document.getElementById('friendDataForm').addEventListener('submit', async (event) => {
- event.preventDefault();
- const friendId = document.getElementById('friendId').value;
- const description = document.getElementById('friendDescription').value || 'None';
- // Only store the ID and description
- const friends = loadFriends();
- friends.push({ id: friendId, description });
- saveFriends(friends);
- addFriendToList({ id: friendId, description });
- formContainer.remove();
- });
- }
- async function fetchFriendData(id) {
- try {
- const response = await fetch(`https://api.torn.com/user/${id}?selections=profile&key=${apiKey}`);
- const data = await response.json();
- if (data.error) {
- alert(`Error: ${data.error.code} - ${data.error.error}`);
- return null;
- }
- return {
- id: id,
- name: data.name,
- level: data.level,
- status: data.status.description,
- profileUrl: `/profiles.php?XID=${id}`,
- description: "None" // The description will be stored separately
- };
- } catch (error) {
- console.error("Failed to fetch friend data:", error);
- alert("Failed to fetch friend data. Please check the console for details.");
- return null;
- }
- }
- function addFriendButton() {
- // Check if the button already exists
- if (document.querySelector('.add-button')) return;
- const addButton = document.createElement('button');
- addButton.textContent = 'Add Friend by ID';
- addButton.addEventListener('click', createForm);
- addButton.classList.add('add-button');
- const paginationWrapper = document.querySelector('.pagination-wrapper');
- if (paginationWrapper && !paginationWrapper.contains(addButton)) {
- paginationWrapper.appendChild(addButton);
- }
- }
- async function addFriendToList(friendData) {
- const targetUL = document.querySelector(".user-info-blacklist-wrap");
- if (targetUL) {
- if (addedFriends.has(friendData.id)) return; // Prevent adding duplicate friends
- // Fetch the latest data every time a friend is added
- const latestData = await fetchFriendData(friendData.id);
- if (!latestData) return;
- // Extract the first word from the status
- const firstWordStatus = latestData.status.split(' ')[0];
- const newLI = document.createElement("li");
- newLI.setAttribute('data-id', friendData.id);
- newLI.innerHTML = `
- <div class="delete">
- <i class="delete-user"></i>
- </div>
- <div class="acc-wrapper">
- <div class="expander left">
- <span class="honor-text-wrap blue big" style="display: block; text-align: center; width: 100%;">
- <a href="${latestData.profileUrl}" title="${latestData.name} [${latestData.id}]" style="text-decoration: none; color:white;">
- ${latestData.name}
- </a>
- </span>
- <div class="d-hide expand right">
- <i class="collapse-arrow"></i>
- </div>
- </div>
- <div class="acc-body">
- <div class="level left">
- <span class="d-hide bold">Level:</span> ${latestData.level}
- </div>
- <div class="status left">
- <span class="d-hide bold">Status:</span>
- <div class="status-description" style="text-overflow:elipsis;">${firstWordStatus}</div>
- </div>
- <div class="description">
- <div class="left"></div>
- <div class="text left t-overflow">${friendData.description}</div>
- </div>
- </div>
- </div>
- `;
- targetUL.appendChild(newLI);
- addedFriends.add(friendData.id); // Mark as added to prevent duplicates
- const deleteButton = newLI.querySelector('.delete-user');
- deleteButton.addEventListener('click', () => deleteFriend(friendData.id, newLI));
- }
- }
- function deleteFriend(id, listItem) {
- listItem.remove();
- addedFriends.delete(id); // Remove from the added friends set
- const friends = loadFriends().filter(friend => friend.id !== id);
- saveFriends(friends);
- }
- function loadAndDisplayFriends() {
- if (friendsLoaded) return; // Prevent loading friends again
- const friends = loadFriends();
- friends.forEach(friendData => {
- // Avoid re-adding the same friend
- if (!addedFriends.has(friendData.id)) {
- addFriendToList(friendData);
- }
- });
- friendsLoaded = true; // Set the flag to prevent reloading
- }
- const observer = new MutationObserver(() => {
- if (document.querySelector('.pagination-wrapper')) {
- addFriendButton();
- }
- if (document.querySelector('.user-info-blacklist-wrap')) {
- loadAndDisplayFriends();
- }
- });
- observer.observe(document.body, { childList: true, subtree: true });
- })();