您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add NNB to the OC page
当前为
// ==UserScript== // @name YATA - OC // @namespace yata.yt // @version 0.4 // @grant GM_addStyle // @description Add NNB to the OC page // @author Kivou [2000607] // @grant GM.xmlHttpRequest // @match https://www.torn.com/factions.php* // @match https://www.torn.com/preferences.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 gmGet = async (url) => { console.log(`[kivou - gmGet] ${url}`) 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') { 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]); if(urlParams.get("XID") in members["members"]) { const m = members["members"][urlParams.get("XID")]; const lvl = player.children[1].innerText.trim() if(m.nnb_share) { player.children[1].innerHTML = `<b>#${m.crimes_rank}</b> / <b>${m.nnb}</b> / ${lvl}` } else { player.children[1].innerHTML = `<b>#${m.crimes_rank}</b> / <b title="Not shared">?</b> / ${lvl}` console.warn(`[yata - oc] ${m.name} NNB not shared on YATA`) } } else { player.children[1].innerHTML = `<b title="Not found"> NNB</b> / <b title="Not found"> NNB</b> / ${lvl}` console.warn(`[yata - oc] ${m.name} not found in the database`) } } // ------------- // // SETUP API KEY // // ------------- // waitForElement(document, "div.preferences-container").then(div => { let injected = false; // 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 name = node.querySelector("p[id^=key-name]").innerText const key_node = node.querySelector("input"); if(!localStorage.getItem('key')) { localStorage.setItem('key', key_node.value); document.getElementById("yata-api-key-oc").innerHTML = localStorage.getItem('key') } key_node.style.cursor = "pointer" }); }); if(!injected) { const modal = document.createElement("div"); modal.innerHTML = `<div class="content-title">` modal.innerHTML += `<b>[YATA - OC]</b> API key <span id="yata-api-key-oc" style="font-family: monospace; font-weight: bold;">${localStorage.getItem('key')}</span>` modal.innerHTML += ` | Click <a href="/preferences.php#tab=api" class="t-blue">on a key</a> to change` modal.innerHTML += ` | Go back to <a href="/factions.php?step=your#/tab=crimes" class="t-blue">organized crimes</a>` modal.innerHTML += ` | <span id="yata-api-key-oc-rm" class="t-blue" style="cursor: pointer;">Remove</span> your key` modal.innerHTML += `</div>` modal.innerHTML += `<div class="clear"></div>` modal.innerHTML += `<hr class="page-head-delimiter m-top10">` div.insertAdjacentElement('beforebegin', modal); 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); document.getElementById("yata-api-key-oc").innerHTML = `${localStorage.getItem('key')}` } else if(button.tagName == 'SPAN' && button.id == 'yata-api-key-oc-rm') { localStorage.removeItem('key'); document.getElementById("yata-api-key-oc").innerHTML = `${localStorage.getItem('key')}` } }) }); // ----------- // // FILL UP NNB // // ----------- // waitForElement(document, "div#faction-crimes").then(div => { API_KEY = localStorage.getItem('key') if(!API_KEY) { const modal = document.createElement("div"); modal.innerHTML = `<hr class="page-head-delimiter">` modal.innerHTML += `<div class="m-top10">` modal.innerHTML += `<b>[YATA - OC]</b> <b style="color: var(--default-red-color)">API key not found</b>` modal.innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to set it up` modal.innerHTML += `</div>` modal.innerHTML += `<div class="clear"></div>` div.insertAdjacentElement('afterend', modal); return } const modal = document.createElement("div"); modal.innerHTML = `<hr class="page-head-delimiter">` modal.innerHTML += `<div class="m-top10">` modal.innerHTML += `<b>[YATA - OC]</b> <b style="color: var(--default-green-color)">Filling NNB</b>` modal.innerHTML += ` | Visit <a href="/preferences.php#tab=api" class="t-blue">preferences</a> to change your key` modal.innerHTML += `</div>` modal.innerHTML += `<div class="clear"></div>` div.insertAdjacentElement('afterend', modal); gmGet(`https://yata.yt/api/v1/faction/members/?key=${API_KEY}`).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'); } }); });