Torn Xanax Usage Viewer

View individual Xanax usage on Faction page.

  1. // ==UserScript==
  2. // @name Torn Xanax Usage Viewer
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description View individual Xanax usage on Faction page.
  6. // @author Microbes
  7. // @match https://www.torn.com/profiles.php?XID=*
  8. // @match https://www.torn.com/factions.php*
  9. // @match https://www.torn.com/preferences.php
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // Get current setting if exist
  19. let apiKey = localStorage.getItem(`xanaxviewer_apikey`) || '';
  20. let autoLimit = localStorage.getItem(`xanaxviewer_autoLimit`) || '0';
  21. let showRelative = localStorage.getItem(`xanaxviewer_relative_values`) === 'true' || false;
  22.  
  23. // Fetech our own stats
  24. let myInfo;
  25. $.get(`https://api.torn.com/user/?selections=basic,personalstats&key=${apiKey}&comment=xanaxviewer`, (data, status) => {
  26. if ("error" in data) {
  27. $(".content-title").first().append(`<p style="color: red;">XanaxViewerError: ${data["error"]["error"]}.</p>`);
  28. } else {
  29. XanaxViewerMain(data, apiKey, autoLimit, showRelative);
  30. }
  31. });
  32.  
  33. // Perferences Page
  34. if (GetPageName() == "preferences.php") {
  35. $(".preferences-container").after(`
  36. <div class="xanaxviewer_container " data-feature="connect">
  37. <div class="xanaxviewer_head">
  38. <span class="xanaxviewer_title">Xanax Viewer Settings</span>
  39. </div>
  40.  
  41. <div class="xanaxviewer_content">
  42. <br/>
  43. <p>API Key (Public Only): <input id="xanaxviewer_api" type="text" maxlength="16" required="" autocomplete="off" value="${apiKey}" style="color: rgb(0, 0, 0); border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); border-image: initial; width: 20em;"></p>
  44.  
  45. <br/><br/>
  46. <p>Automatically fetch <span id="xanaxviewer_autolimit">${autoLimit}</span> users (cloesest level) when I visit a faction page.</p>
  47. <div class="slidecontainer">
  48. <input type="range" min="0" max="100" value="${autoLimit}" class="slider" id="xanaxviewer_autolimit_slider">
  49. </div>
  50.  
  51. <br/>
  52. <p>Show Relative Value: <input id="xanaxviewer_relative_checkbox" type="checkbox" /></p>
  53.  
  54. <br/><br/>
  55. <p><span id="xanaxviewer_storage_counter">250</span> Profiles saved. <a id="xanaxviewer_deleteall_btn">Delete all</a>?</p>
  56.  
  57. <br/>
  58. <a id="xanaxviewer_update_btn" class="torn-btn btn-big update">Update</a>
  59. <span id="updateText">Updated successfully!</span>
  60. </div>
  61. </div>
  62. `);
  63.  
  64. document.getElementById("xanaxviewer_autolimit_slider").oninput = function() {
  65. $("#xanaxviewer_autolimit").text(this.value);
  66. };
  67.  
  68. $('#xanaxviewer_relative_checkbox').prop('checked', showRelative);
  69.  
  70. let cache = GetXanaxViewerCache();
  71. $("#xanaxviewer_storage_counter").text(Object.keys(cache).length);
  72. $("#xanaxviewer_deleteall_btn").click(() => {
  73. localStorage.removeItem("xanaxviewer_cache");
  74. $("#xanaxviewer_storage_counter").text(0);
  75. });
  76.  
  77. $("#xanaxviewer_update_btn").click(() => {
  78. localStorage.setItem(`xanaxviewer_apikey`, $("#xanaxviewer_api").val());
  79. localStorage.setItem(`xanaxviewer_autoLimit`, $("#xanaxviewer_autolimit_slider").val());
  80. localStorage.setItem(`xanaxviewer_relative_values`, $("#xanaxviewer_relative_checkbox").is(":checked"));
  81. $("#updateText").fadeIn();
  82. });
  83.  
  84. $("#updateText").hide();
  85. }
  86.  
  87. function XanaxViewerMain(myInfo, apiKey, autoLimit, showRelative) {
  88. if (GetPageName() == "profiles.php" && apiKey != '') {
  89. var uid = window.location.href.split("=").slice(-1);
  90. var selector = $("#profileroot .profile-buttons .title-black")
  91.  
  92. GetUserStats(uid).then((stats) => {
  93. selector.append(`<span class="xanaxviewer-profile">${showRelative ? stats["xantaken"] - myInfo.personalstats.xantaken : stats["xantaken"]} Xanax</span>`);
  94. selector.append(`<span class="xanaxviewer-profile">${stats["refills"]} Refills</span>`);
  95. });
  96. } else if (GetPageName() == "factions.php" && apiKey != '') {
  97.  
  98. let profiles = {};
  99.  
  100. waitForElementToExist('.members-list .positionCol___Lk6E4').then((elm) => {
  101. delay(250).then(() => {
  102. $('.faction-info-wrap .table-header').append(`<li tabindex="0" class="table-cell xanaxviewer_header torn-divider divider-vertical c-pointer">Xanax<div class="sortIcon___ALgdi asc___bb84w"></div></li>`);
  103.  
  104. // Add cached result or refresh button
  105. $('.faction-info-wrap .table-body').find(".table-row").each(function() {
  106. var uid = $(this).find("a").eq(1);
  107. uid = uid.attr('href').split("=").slice(-1);
  108.  
  109. let info = GetXanaxViewerCache()[uid];
  110.  
  111. if (info) {
  112. let xantaken = showRelative ? info["xantaken"] - myInfo.personalstats.xantaken : info["xantaken"];
  113. $(this).append(`<div class="table-cell xanaxviewer_header"><a class="xanaxviewer_refresh">${xantaken}</a></div>`);
  114. } else {
  115. $(this).append(`<div class="table-cell xanaxviewer_header"><a class="xanaxviewer_refresh">⟳</a></div>`);
  116. }
  117.  
  118. // Add level into profiles, to auto refresh.
  119. var level = $(this).find(".lvl").first().text();
  120. if (level in profiles) {
  121. profiles[level].push(this);
  122. } else {
  123. profiles[level] = [this];
  124. }
  125.  
  126. // XanaxViewerLog(level + ": " + profiles[level].length);
  127. });
  128.  
  129. // On Refresh Clicked
  130. $(".xanaxviewer_refresh").click(function() {
  131. UpdateViewer(this, myInfo);
  132. });
  133.  
  134. // Refresh autoLimit amonunt of Xanax field
  135. let memberCount = $(".members-list .c-pointer span").first();
  136. memberCount = memberCount.html().split("/")[0].replace(/ /g, '');
  137.  
  138. if (autoLimit > memberCount) {
  139. autoLimit = memberCount;
  140. }
  141.  
  142. if (autoLimit > 0) {
  143. let toBeRefreshed = [];
  144. let refreshed = 0;
  145. let level = myInfo.level;
  146. let cursorLevel = level;
  147. let generation = 0;
  148. let nextMinus = true;
  149.  
  150. // XanaxViewerLog(Object.keys(profiles));
  151.  
  152. while (refreshed < autoLimit) {
  153. if (nextMinus == true) {
  154. cursorLevel = level + generation;
  155. generation++;
  156. } else {
  157. cursorLevel = level - generation;
  158. }
  159.  
  160. nextMinus = !nextMinus;
  161.  
  162. if (cursorLevel in profiles) {
  163. profiles[cursorLevel].every(function(profile) {
  164. toBeRefreshed.push(profile);
  165. $(profile).find(".xanaxviewer_header").html(`<a class="xanaxviewer_refresh">L</a></div>`);
  166. refreshed++;
  167.  
  168. if (refreshed >= autoLimit) {
  169. return false;
  170. }
  171.  
  172. return true;
  173. });
  174. }
  175. }
  176.  
  177. // XanaxViewerLog(toBeRefreshed.length);
  178.  
  179. // Start refreshing
  180. StartRefreshing(toBeRefreshed, 0, myInfo);
  181. }
  182. });
  183. });
  184. }
  185. }
  186.  
  187. function StartRefreshing(toBeRefreshed, counter, myInfo) {
  188. // XanaxViewerLog("updating " + counter);
  189. if (!counter in toBeRefreshed) return;
  190.  
  191. let item = toBeRefreshed[counter];
  192. UpdateViewer($(item).find(".xanaxviewer_refresh"), myInfo).then(() => {
  193. if (counter < toBeRefreshed.length - 1) {
  194. StartRefreshing(toBeRefreshed, counter + 1, myInfo);
  195. }
  196. });
  197. }
  198.  
  199. function XanaxViewerLog(data) {
  200. console.log("XanaxViewer: " + data);
  201. }
  202.  
  203. function GetUserStats(uid) {
  204. let apiKey = localStorage.getItem(`xanaxviewer_apikey`) || '';
  205.  
  206. if (apiKey == '') return;
  207.  
  208. return new Promise(resolve => {
  209. $.get(`https://api.torn.com/user/${uid}?selections=personalstats&key=${apiKey}&comment=xanaxviewer`, function(data, status) {
  210. // XanaxViewerLog("Xanax Usage: " + data["personalstats"]["xantaken"]);
  211.  
  212. let cache = GetXanaxViewerCache();
  213.  
  214. cache[uid] = {
  215. "xantaken": data["personalstats"]["xantaken"],
  216. "cantaken": data["personalstats"]["xantaken"],
  217. "lsdtaken": data["personalstats"]["lsdtaken"],
  218. "refills": data["personalstats"]["refills"],
  219. "updated": Date.now()
  220. }
  221.  
  222. localStorage.setItem(`xanaxviewer_cache`, JSON.stringify(cache));
  223.  
  224. return resolve(data["personalstats"]);
  225. });
  226. });
  227. }
  228.  
  229. function GetXanaxViewerCache() {
  230. let cache = localStorage.getItem(`xanaxviewer_cache`);
  231.  
  232. if (cache) {
  233. cache = JSON.parse(cache);
  234. } else {
  235. cache = {};
  236. }
  237.  
  238. return cache;
  239. }
  240.  
  241. function UpdateViewer(element, myInfo) {
  242. var uid = $(element).parent().parent().find("a").eq(1);
  243. uid = uid.attr('href').split("=").slice(-1);
  244.  
  245. XanaxViewerLog(myInfo.personalstats.xantaken);
  246.  
  247. return new Promise(resolve => {
  248. GetUserStats(uid).then((stats) => {
  249. let xantaken = showRelative ? stats.xantaken - myInfo.personalstats.xantaken : stats.xantaken;
  250. $(element).html(`${xantaken}`);
  251.  
  252. return resolve();
  253. });
  254. });
  255. }
  256.  
  257. /* HELPERS */
  258. function GetPageName() {
  259. var path = window.location.pathname;
  260. var page = path.split("/").pop();
  261.  
  262. return page;
  263. }
  264.  
  265. function waitForElementToExist(selector) {
  266. return new Promise(resolve => {
  267. if (document.querySelector(selector)) {
  268. return resolve(document.querySelector(selector));
  269. }
  270.  
  271. const observer = new MutationObserver(() => {
  272. if (document.querySelector(selector)) {
  273. resolve(document.querySelector(selector));
  274. observer.disconnect();
  275. }
  276. });
  277.  
  278. observer.observe(document.body, {
  279. subtree: true,
  280. childList: true,
  281. });
  282. });
  283. }
  284.  
  285. // Style
  286. function delay(time) {
  287. return new Promise(resolve => setTimeout(resolve, time));
  288. }
  289.  
  290. function GM_addStyle(css) {
  291. const style = document.getElementById("GM_addStyleBy8626") || (function() {
  292. const style = document.createElement('style');
  293. style.type = 'text/css';
  294. style.id = "GM_addStyleBy8626";
  295. document.head.appendChild(style);
  296. return style;
  297. })();
  298. const sheet = style.sheet;
  299. sheet.insertRule(css, (sheet.rules || sheet.cssRules || []).length);
  300. }
  301.  
  302. GM_addStyle(".xanaxviewer_header { width:6%; }");
  303. GM_addStyle(".xanaxviewer-profile { float: right; padding-right: 10px; color: red; }");
  304. GM_addStyle("#xanaxviewer_autolimit_slider { width: 20em; }");
  305. GM_addStyle(".member-icons { width: 25% !important; }");
  306. GM_addStyle(".xanaxviewer_container { margin-top: 10px; display: flex; flex-direction: column; box-sizing: border-box; }");
  307. GM_addStyle(".xanaxviewer_head { background: black; padding: 2px; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-bottom: none; }");
  308. GM_addStyle(".xanaxviewer_title { color: var(--re-title-color); text-shadow: rgba(0, 0, 0, 0.65) 1px 1px 2px; }");
  309. GM_addStyle(".xanaxviewer_content { background-color: grey; padding: 1em 2em; color: white; }");
  310. GM_addStyle("#xanaxviewer_storage_counter, #xanaxviewer_deleteall_btn { color: yellow; }");
  311. GM_addStyle("#xanaxviewer_deleteall_btn:hover { text-decoration: underline; }");
  312. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址