您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays various informations (NNB/Stats)
当前为
// ==UserScript== // @name YATA // @namespace yata.yt // @version 0.7 // @grant GM_addStyle // @description Displays various informations (NNB/Stats) // @author Kivou [2000607] // @grant GM.xmlHttpRequest // @match https://www.torn.com/factions.php* // @match https://www.torn.com/preferences.php* // @match https://www.torn.com/profiles.php* // @icon https://yata.yt/media/yata-small.png // @run-at document-end // @license WTFPL // ==/UserScript== // Copyright © 2023 Kivou [2000607] <[email protected]> // This work is free. You can redistribute it and/or modify it under the // terms of the Do What The Fuck You Want To Public License, Version 2, // as published by Sam Hocevar. See http://www.wtfpl.net/ for more details. // ---------------- // // HELPER FUNCTIONS // // ---------------- // const waitForElement = (target, selector) => { return new Promise(resolve => { if (target.querySelector(selector)) { return resolve(target.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (target.querySelector(selector)) { resolve(target.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); }; const waitForElements = (target, selector) => { return new Promise(resolve => { if (target.querySelector(selector)) { return resolve(target.querySelectorAll(selector)); } const observer = new MutationObserver(mutations => { if (target.querySelector(selector)) { resolve(target.querySelectorAll(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); }; const gmGet = async (url, cache_key) => { if (cache_key) { const cachedData = localStorage.getItem(cache_key); const cachedTimestamp = parseInt(localStorage.getItem(cache_key + "_timestamp")); if (cachedData && cachedTimestamp && (Date.now() - cachedTimestamp) < 60 * 60 * 1000) { return JSON.parse(cachedData); } } return new Promise((resolve, reject) => { GM.xmlHttpRequest({ url, method: "GET", onload: (response) => { resolve(new Response(response.response, { statusText: response.statusText, status: response.status })); }, onerror: (error) => { reject(error); } }); }) .catch((error) => { throw { message: "critical error", code: error.status }; }) .then((response) => { const result = response.json(); return result.then((body) => { if (typeof body.error == 'undefined') { localStorage.setItem(cache_key, JSON.stringify(body)); localStorage.setItem(cache_key + "_timestamp", Date.now()); return body; } else { throw { message: body.error.error, code: body.error.code }; } }); }); }; const display_player = (members, player) => { const urlParams = new URLSearchParams(player.children[0].children[0].href.split("?")[1]); const lvl = player.children[1].innerText.trim(); if (members.members && members.members.hasOwnProperty(urlParams.get("XID"))) { const m = members.members[urlParams.get("XID")]; if (m.nnb_share > 0) { player.children[1].innerHTML = `<span>#<b>${m.crimes_rank}</b> / <b>${m.nnb}</b> / ${lvl}</span>`; } else if (m.nnb_share < 0) { player.children[1].innerHTML = `<span title="Not on YATA">#<b>${m.crimes_rank}</b> / <b>!</b> / ${lvl}</span>`; } else { player.children[1].innerHTML = `<span title="Not sharing NNB">#<b>${m.crimes_rank}</b> / <b>?</b> / ${lvl}</span>`; } } else { player.children[1].innerHTML = `<span title="Not found">#<b>?</b> / <b>err</b> / ${lvl}</span>`; } }; function nFormatter(num, digits) { const lookup = [ { value: 1, symbol: "" }, { value: 1e3, symbol: "k" }, { value: 1e6, symbol: "m" }, { value: 1e9, symbol: "b" }, { value: 1e12, symbol: "t" }, { value: 1e15, symbol: "q" } ]; const rx = /\.0+$|(\.[0-9]*[1-9])0+$/; var item = lookup.slice().reverse().find(function (item) { return num >= item.value; }); return item ? (num / item.value).toPrecision(digits).replace(rx, "$1") + item.symbol : "0"; } const display_status = (page, element) => { const key = localStorage.getItem('key'); let innerHTML = ""; if (page == "preferences") { innerHTML += `<div>`; innerHTML += `<b>[YATA]</b> API key used <span id="yata-api-key" style="font-family: monospace; font-weight: bold;">${key}</span>`; if (key) { innerHTML += ` | Status <b id="yata-status" style="color: var(--default-green-color); font-weight: bold;">enabled</b>`; innerHTML += ` | Click <span id="yata-api-key-rm" class="t-blue" style="cursor: pointer;">here to disable</span> the script`; } else { innerHTML += ` | Status <b id="yata-status" style="color: var(--default-red-color); font-weight: bold;">disabled</b>`; innerHTML += ` | Click on a key to enable the script`; } innerHTML += `</div>`; innerHTML += `<div class="clear"></div>`; innerHTML += `<hr class="page-head-delimiter m-top10">`; } else if (page == "faction") { innerHTML += `<hr class="page-head-delimiter m-top10 m-bottom10">`; innerHTML += `<div>`; if (key) { innerHTML += `<b>[YATA]</b> <b style="color: var(--default-green-color)">Enabled</b>`; innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to change your key or disable the script`; } else { innerHTML += `<b>[YATA]</b> <b style="color: var(--default-red-color)">API key not found</b>`; innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to enable the script`; } innerHTML += `</div>`; innerHTML += `<div class="clear"></div>`; } else if (page == "profiles") { innerHTML += `<hr class="page-head-delimiter m-top10 m-bottom10">`; innerHTML += `<div>`; if (key) { innerHTML += `<b>[YATA]</b> <b style="color: var(--default-green-color)">Displaying stats estimate</b>`; innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to change your key or disable the script`; } else { innerHTML += `<b>[YATA]</b> <b style="color: var(--default-red-color)">API key not found</b>`; innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to enable the script`; } innerHTML += `</div>`; innerHTML += `<div class="clear"></div>`; } element.innerHTML = innerHTML; }; // const display_faction = document.createElement("div"); // ------------- // // SETUP API KEY // // ------------- // waitForElement(document, "div.preferences-container").then(div => { let injected = false; const display_element = document.createElement("div"); // triggered by clicking on crimes tab const callback = (mutations, observer) => { [...mutations].forEach(mutation => { [...mutation.addedNodes].filter(n => n.className && n.className.includes("keyRow___")).forEach(node => { const key_node = node.querySelector("input"); key_node.style.cursor = "pointer"; // if(!localStorage.getItem('key')) { // localStorage.setItem('key', key_node.value); // document.getElementById("yata-api-key").innerHTML = localStorage.getItem('key') // } }); }); if (!injected) { display_status("preferences", display_element); div.insertAdjacentElement('beforebegin', display_element); injected = true; } }; const observer = new MutationObserver(callback); observer.observe(div, { childList: true, subtree: true }); document.querySelector("div.content-wrapper").addEventListener('click', e => { const button = e.target; if (button.tagName == 'INPUT' && button.id.includes('key-row')) { localStorage.setItem('key', button.value); } else if (button.tagName == 'SPAN' && button.id == 'yata-api-key-rm') { localStorage.clear(); } display_status("preferences", display_element); }); }); // ----------- // // FILL UP NNB // // ----------- // waitForElement(document, "div#faction-crimes").then(div => { const API_KEY = localStorage.getItem('key'); display_status("faction", display_faction); div.insertAdjacentElement('beforebegin', display_faction); if (!API_KEY) { return; } const profile_url = new URLSearchParams(window.location.search); const target_id = profile_url.get("XID"); gmGet(`https://yata.yt/api/v1/faction/members/?key=${API_KEY}`, "nnb").then(members => { // triggered if directly landing on crimes div.querySelectorAll("ul.details-list, ul.plans-list").forEach(ul => { ul.querySelectorAll("ul.item").forEach(player => { display_player(members, player); }); }); div.querySelectorAll("ul.title li.level").forEach(t => { t.innerHTML = 'Rank / NNB / Level'; }); // triggered by clicking on crimes tab const callback = (mutations, observer) => { [...mutations].forEach(mutation => { [...mutation.addedNodes].filter(n => n.className && n.className.includes("faction-crimes-wrap")).forEach(node => { node.querySelectorAll("ul.details-list, ul.plans-list").forEach(ul => { ul.querySelectorAll("ul.item").forEach(player => { display_player(members, player); }); }); node.querySelectorAll("ul.title li.level").forEach(t => { t.innerHTML = 'Rank / NNB / Level'; }); }); }); }; const observer = new MutationObserver(callback); observer.observe(div, { childList: true }); }).catch(error => { alert(`[yata - oc] ${error.message}`); if (error.code == 4) { localStorage.removeItem('key'); } }); }); // ---------------------- // // DISPLAY STATS ESTIMATE // // Profile // // ---------------------- // waitForElement(document, "div#profileroot").then(div => { const API_KEY = localStorage.getItem('key'); const profile_url = new URLSearchParams(window.location.search); const target_id = profile_url.get("XID"); const display_element = document.createElement("div"); display_status("profiles", display_element); div.insertAdjacentElement('afterend', display_element); if (!API_KEY) { return; } gmGet(`https://yata.yt/api/v1/bs/${target_id}/?key=${API_KEY}`, `bs-${target_id}`).then(bs => { let innerHTML = ""; innerHTML += `<hr class="page-head-delimiter m-top10 m-bottom10">`; innerHTML += `<div>`; innerHTML += `<b>[YATA]</b> <b>Battle stats</b> ${nFormatter(bs[target_id].total, 3)}`; innerHTML += ` | <b>Build</b> ${bs[target_id].type} (${bs[target_id].skewness}%)`; innerHTML += `</div>`; innerHTML += `<hr class="page-head-delimiter m-top10 m-bottom10">`; innerHTML += `<div class="clear"></div>`; const bs_node = document.createElement("div"); bs_node.innerHTML = innerHTML; div.querySelector("div.profile-wrapper").insertAdjacentElement('afterend', bs_node); }).catch(error => { alert(`[yata - oc] ${error.message}`); if (error.code == 4) { localStorage.removeItem('key'); } }); }); // ---------------------- // // DISPLAY STATS ESTIMATE // // Member list // // ---------------------- // const add_bs_to_members_list = (line, key) => { const url = line.children[0].querySelector("a[id$=-user]").href.split("?")[1]; const profile_url = new URLSearchParams(url); const target_id = profile_url.get("XID"); gmGet(`https://yata.yt/api/v1/bs/${target_id}/?key=${key}`, `bs-${target_id}`).then(bs => { let color = "var(--default-blue-color)"; if (bs[target_id].type == "Offensive" && bs[target_id].skewness > 20) { color = "var(--default-red-color)"; } else if (bs[target_id].type == "Defensive" && bs[target_id].skewness > 20) { color = "var(--default-green-color)"; } const title = `Total stats: ${bs[target_id].total.toLocaleString("en-GB")} Build: ${bs[target_id].type} (${bs[target_id].skewness}%)`; const innerHTML = `<div title="${title}" style="color: ${color}; width: 5em; display: inline-block; cursor: help;">${nFormatter(bs[target_id].total, 3)}</div>`; const bs_node = document.createElement("div"); bs_node.innerHTML = innerHTML; line.children[3].insertAdjacentElement('afterbegin', bs_node); }); }; waitForElement(document, "div#faction-info, div.members-list").then(div => { const API_KEY = localStorage.getItem('key'); // display_status("faction", display_faction) // div.insertAdjacentElement('beforebegin', display_faction); if (!API_KEY) { return; } // triggered if directly landing on info tab waitForElements(div, "li.table-row").then(list => { list.forEach(line => add_bs_to_members_list(line, API_KEY)); }); // triggered by clicking on info tab const callback = (mutations, observer) => { [...mutations].forEach(mutation => { [...mutation.addedNodes].filter(node => node.id == "react-root-faction-info").forEach(node => { node.querySelectorAll("li.table-row").forEach(line => { add_bs_to_members_list(line, API_KEY); }); }); }); }; const observer = new MutationObserver(callback); observer.observe(div, { childList: true }); }); // ---------------------- // // DISPLAY STATS ESTIMATE // // Walls // // ---------------------- // const add_bs_to_wall = (line, key) => { const url = line.querySelector("a.user.name").href.split("?")[1]; const profile_url = new URLSearchParams(url); const target_id = profile_url.get("XID"); gmGet(`https://yata.yt/api/v1/bs/${target_id}/?key=${key}`, `bs-${target_id}`).then(bs => { let color = "var(--default-blue-color)"; if (bs[target_id].type == "Offensive" && bs[target_id].skewness > 20) { color = "var(--default-red-color)"; } else if (bs[target_id].type == "Defensive" && bs[target_id].skewness > 20) { color = "var(--default-green-color)"; } const title = `Total stats: ${bs[target_id].total.toLocaleString("en-GB")} Build: ${bs[target_id].type} (${bs[target_id].skewness}%)`; const innerHTML = `<div title="${title}" style="color: ${color}; display: inline-block; cursor: help;">${nFormatter(bs[target_id].total, 3)}</div>`; line.children[1].innerHTML = innerHTML; }); }; waitForElement(document, "ul#faction_war_list_id").then(ul => { const API_KEY = localStorage.getItem('key'); if (!API_KEY) { return; } const _f = (element) => { return element.className.includes("your") || element.className.includes("enemy"); }; const walls_callback = (mutations, observer) => { console.log("mutations on the wall"); console.log(mutations); [...mutations].forEach(mutation => { // player jump off the wall // [...mutation.removedNodes].filter(_f).forEach(e => { // const user = e.querySelectorAll("a[class^=user]"); // const faction_id = get_faction_id(user[0].href); // const player_id = get_player_id(user[1].href); // console.log(`[kiv - off the wall] Player ${player_id} faction ${faction_id} jumped off the wall`); // enable_member(player_id); // }); // player jump on the wall [...mutation.addedNodes].filter(_f).forEach(member => { console.log("Added nodes"); console.log(member); add_bs_to_wall(member, API_KEY); }); }); }; const wars_callback = (mutations, observer) => { [...mutations].forEach(mutation => { [...mutation.addedNodes].filter(node => node.className == "faction-war").forEach(node => { const wall = ul.querySelector("div.members-cont > ul.members-list"); console.log(wall); const walls_observer = new MutationObserver(walls_callback); walls_observer.observe(wall, { childList: true }); wall.querySelectorAll("li.your").forEach(member => { add_bs_to_wall(member, API_KEY); }); // walls_observer.disconnect(); }); }); }; const wars_observer = new MutationObserver(wars_callback); wars_observer.observe(ul, { childList: true, subtree: true }); });
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址