Advertisement
Guest User

Untitled

a guest
Feb 16th, 2020
421
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.77 KB | None | 0 0
  1. // ==UserScript==
  2. // @name TORN: Stat Estimate
  3. // @namespace dekleinekobini.statestimate
  4. // @version 2.7.0
  5. // @author DeKleineKobini
  6. // @description Estimate the stats of a player based on their rank.
  7. // @match https://www.torn.com/index.php*
  8. // @match https://www.torn.com/profiles.php*
  9. // @match https://www.torn.com/userlist.php*
  10. // @match https://www.torn.com/halloffame.php*
  11. // @match https://www.torn.com/bounties.php*
  12. // @match https://www.torn.com/blacklist.php*
  13. // @match https://www.torn.com/factions.php*
  14. // @match https://www.torn.com/competition.php*
  15. // @require https://greasyfork.org/scripts/390917-dkk-torn-utilities/code/DKK%20Torn%20Utilities.js?version=744690
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_setValue
  18. // @grant GM_getValue
  19. // ==/UserScript==
  20.  
  21. var settings = {
  22. apiDelay: 1000, // in milliseconds, default 1000ms
  23. pages: {
  24. profile: true,
  25. search: true,
  26. searchAdvanced: true,
  27. abroad: true,
  28. hallOfFame: true,
  29. bounties: true,
  30. blacklist: true,
  31. faction: {
  32. wall: true,
  33. profile: true
  34. },
  35. competition: true
  36. },
  37. ignore: {
  38. enabled: true,
  39. level: 101, // only show stats below this level
  40. showEmpty: true
  41. },
  42. cache: { // in milliseconds, -1 is infinite
  43. normal: 12 * 60 * 60 * 1000, // default 12h
  44. last: 31 * 24 * 60 * 60 * 1000 // default 31d
  45. }
  46. }
  47.  
  48. setDebug(true);
  49.  
  50. /* --------------------
  51. CODE - EDIT ON OWN RISK
  52. -------------------- */
  53. initScript("statestimate", "Stat Estimate", "SE", true);
  54.  
  55. var ranks = {
  56. 'Absolute beginner': 1,
  57. 'Beginner': 2,
  58. 'Inexperienced': 3,
  59. 'Rookie': 4,
  60. 'Novice': 5,
  61. 'Below average': 6,
  62. 'Average': 7,
  63. 'Reasonable': 8,
  64. 'Above average': 9,
  65. 'Competent': 10,
  66. 'Highly competent': 11,
  67. 'Veteran': 12,
  68. 'Distinguished': 13,
  69. 'Highly distinguished': 14,
  70. 'Professional': 15,
  71. 'Star': 16,
  72. 'Master': 17,
  73. 'Outstanding': 18,
  74. 'Celebrity': 19,
  75. 'Supreme': 20,
  76. 'Idolised': 21,
  77. 'Champion': 22,
  78. 'Heroic': 23,
  79. 'Legendary': 24,
  80. 'Elite': 25,
  81. 'Invincible': 26
  82. }
  83.  
  84. const EMPTY_CHAR = " ";
  85. const triggerLevel = [ 2, 6, 11, 26, 31, 50, 71, 100 ];
  86. const triggerCrime = [ 100, 5000, 10000, 20000, 30000, 50000 ];
  87. const triggerNetworth = [ 5000000, 50000000, 500000000, 5000000000, 50000000000 ];
  88.  
  89. const estimatedStats = [
  90. "under 2k",
  91. "2k - 25k",
  92. "20k - 250k",
  93. "200k - 2.5m",
  94. "2m - 25m",
  95. "20m - 250m",
  96. "over 200m",
  97. ];
  98. const PREFIX_CACHE = "id_";
  99.  
  100. var cache = {};
  101.  
  102. getCachedEstimated("statestimate", true).then(c => {
  103. cache = c || {};
  104.  
  105. start();
  106. });
  107.  
  108. async function getCachedEstimated(key, subbed) {
  109. let _obj = await GM_getValue(key, subbed ? "{}" : "{\"end\":0}");
  110. let obj = JSON.parse(_obj);
  111.  
  112. return obj;
  113. }
  114.  
  115. function start() {
  116. var page = getCurrentPage();
  117.  
  118. debug("Current page is '" + page + "' with step '" + new URL(window.location.href).searchParams.get("step") + "'");
  119. if (!shouldLoad(page)) return;
  120.  
  121. log("Starting listeners.");
  122. startListeners(page);
  123. }
  124.  
  125. function startListeners(page){
  126. var run = true;
  127. var ignore = 0;
  128.  
  129. switch(page) {
  130. case "profiles": // profile
  131. xhrIntercept((page, json, uri) => {
  132. if(page != "profiles" || !json) return;
  133.  
  134. if (run) {
  135. run = false;
  136. updateUser(json.user.userID, json.userInformation.level, function(result) {
  137. if (result === EMPTY_CHAR) return;
  138.  
  139. $(".content-title > h4").append("<div>" + result + "</div>");
  140. }, 0);
  141. }
  142. });
  143. break;
  144. case "userlist": // (advanced) search
  145. ajax((page, json, uri) => {
  146. if(page != "userlist" || !json) return;
  147.  
  148. let first = json.list[0].userID;
  149. let firstPage = $(".user-info-list-wrap > li:eq(0) .user > img").attr("alt");
  150. if (firstPage) firstPage = firstPage.substring(firstPage.indexOf("[") + 1, firstPage.length - 1);
  151.  
  152. if (firstPage != first) observeMutations(document, ".user-info-list-wrap > li:eq(0) .user > img[alt]", false, (mut, obs) => {
  153. firstPage = $(".user-info-list-wrap > li:eq(0) .user > img").attr("alt");
  154. firstPage = firstPage.substring(firstPage.indexOf("[") + 1, firstPage.length - 1);
  155. if (firstPage != first) return;
  156.  
  157. obs.disconnect();
  158. execute(json);
  159. }, { childList: true, subtree: true });
  160. else execute(json);
  161.  
  162. function execute() {
  163. if (!$(".se-header").length) $("<div class='se-header level t-hide left' style='border-left: 0px solid transparent; width: 75px;'>Stats</div>").insertAfter($(".level").eq(0));
  164. $(".user-icons").eq(0).css("width", "initial");
  165. json.list.forEach((player, index) => {
  166. let delay = settings.apiDelay * (index - ignore);
  167.  
  168. if (shouldIgnore(player.level * 1)){
  169. ignore++;
  170.  
  171. if (!settings.ignore.showEmpty) return;
  172. else delay = 0;
  173. }
  174. if (getSubCache(cache, PREFIX_CACHE + player.userID)) {
  175. ignore++;
  176. delay = 0;
  177. }
  178.  
  179. updateUser(player.userID, player.level * 1, (result) => {
  180. if (result === EMPTY_CHAR) return;
  181. var row = $(".user-info-list-wrap > li").eq(index);
  182. var iconWrap = row.find(".icons-wrap");
  183.  
  184. $("<span class='level' style='border-left: 0px solid transparent; width: 75px;'>" + result + "</p>").insertAfter(row.find(".level"));
  185. row.find(".user-icons").css("width", "initial");
  186. iconWrap.css("width", "initial");
  187. iconWrap.find("ul").css("width", "initial");
  188. }, delay);
  189. });
  190. }
  191. });
  192. break;
  193. case "halloffame": // hall of fame
  194. observeMutations(document, ".hall-of-fame-list-wrap", true, function(mut, obs){
  195. observeMutations($(".hall-of-fame-list-wrap")[0], ".players-list", false, function(mut, obs){
  196. ignore = 0;
  197.  
  198. var indexLevel;
  199. $(".table-titles > li").each(function(index) {
  200. if ($(this).html().includes("Level")) {
  201. indexLevel = index + 1;
  202. }
  203. });
  204.  
  205. $(".rank").eq(1).html("Stats");
  206. $(".players-list > li").each(function(index) {
  207. var row = $(this);
  208. let id = row.find(".player > .name").attr("href");
  209. if (!id) {
  210. ignore++;
  211. return;
  212. }
  213. id = id.substring(id.indexOf("=") + 1);
  214. let level = stripHtml(row.find(".player-info > li").eq(indexLevel).html());
  215. debug(level);
  216. level = level.substring(level.indexOf(":") + 1) * 1;
  217.  
  218. let delay = settings.apiDelay * (index - ignore);
  219.  
  220. if (shouldIgnore(level)){
  221. ignore++;
  222.  
  223. if (!settings.ignore.showEmpty) return;
  224. else delay = 0;
  225. }
  226. if (getSubCache(cache, PREFIX_CACHE + id)) {
  227. ignore++;
  228. delay = 0;
  229. }
  230.  
  231. updateUser(id, level, (result) => {
  232. row.find(".rank").html(result);
  233. let iconWrap = row.find(".icons-wrap");
  234.  
  235. row.find(".user-icons").css("width", "initial");
  236. iconWrap.css("width", "initial");
  237. iconWrap.find("ul").css("width", "initial");
  238. }, delay);
  239. });
  240. });
  241. }, { childList: true, subtree: true });
  242. break;
  243. case "index": // travelling TODO - test
  244. observeMutations(document, ".users-list", true, function(mut, obs){
  245. ignore = 0;
  246.  
  247. $(".users-list > li").each(function(index) {
  248. var row = $(this);
  249. let id = row.find(".name").attr("href");
  250. id = id.substring(id.indexOf("=") + 1);
  251. let level = stripHtml(row.find(".level").html());
  252. level = level.substring(level.indexOf(":") + 1) * 1;
  253.  
  254. let delay = settings.apiDelay * (index - ignore);
  255.  
  256. if (shouldIgnore(level)){
  257. ignore++;
  258.  
  259. if (!settings.ignore.showEmpty) return;
  260. else delay = 0;
  261. }
  262. if (getSubCache(cache, PREFIX_CACHE + id)) {
  263. ignore++;
  264. delay = 0;
  265. }
  266.  
  267. updateUser(id, level, (result) => {
  268. row.find(".rank").html(result);
  269. let iconWrap = row.find(".icons-wrap");
  270.  
  271. $("<span class='level' style='width: 75px;'>" + result + "</p>").insertAfter(row.find(".status"));
  272. row.find(".center-side-bottom").css("width", "initial");
  273. iconWrap.css("width", "initial");
  274. iconWrap.find("ul").css("width", "initial");
  275. }, delay);
  276. });
  277. }, { childList: true, subtree: true });
  278. break;
  279. case "bounties": // bounties
  280. ajax((page, json, uri) => {
  281. if (page != "bounties" || !uri) return;
  282.  
  283. observeMutations(document, ".bounties-list", true, (mut, obs) => {
  284. let names = [];
  285. ignore = 0;
  286.  
  287. $(".bounties-list-title .listed").html("STATS");
  288. $(".bounties-list > li[data-id]").slice(0, 20).each((index, el) => {
  289. let row = $(el);
  290.  
  291. let id = row.find(".target > a").attr("href");
  292. id = id.substring(id.indexOf("XID=") + 4);
  293. let level = row.find(".level").html().split("\n")[2];
  294. let name = row.find(".target > a").html();
  295.  
  296. let delay = settings.apiDelay * (index - ignore);
  297. if (names.includes(name)) {
  298. ignore++;
  299. return;
  300. } else if (shouldIgnore(level)){
  301. ignore++;
  302.  
  303. if (!settings.ignore.showEmpty) return;
  304. else delay = 0;
  305. }
  306. if (getSubCache(cache, PREFIX_CACHE + id)) {
  307. ignore++;
  308. delay = 0;
  309. }
  310.  
  311. names.push(name);
  312. updateUser(id, level, (result) => {
  313. $("li:has(a[href='profiles.php?XID=" + id + "'])").each(function(){
  314. $(this).find(".listed").html(result);
  315. });
  316. }, delay);
  317.  
  318. });
  319. }, { childList: true, subtree: true, attributes: true });
  320. });
  321. break;
  322. case "blacklist": // enemies
  323. var checkBlacklist = () => {
  324. observeMutations($(".blacklist")[0], ".user-info-blacklist-wrap", true, function(mut, obs) {
  325. ignore = 0;
  326.  
  327. $(".user-info-blacklist-wrap > li").each(function(index) {
  328. var row = $(this);
  329. let id = row.find(".name").attr("href");
  330. id = id.substring(id.indexOf("XID=") + 4);
  331. let level = stripHtml(row.find(".level").html());
  332. level = level.substring(level.indexOf(":") + 1) * 1;
  333.  
  334. let delay = settings.apiDelay * (index - ignore);
  335.  
  336. if (shouldIgnore(level)){
  337. ignore++;
  338.  
  339. if (!settings.ignore.showEmpty) return;
  340. else delay = 0;
  341. }
  342. if (getSubCache(cache, PREFIX_CACHE + id)) {
  343. ignore++;
  344. delay = 0;
  345. }
  346.  
  347. updateUser(id, level, (result) => {
  348. var iconWrap = row.find(".description-editor");
  349.  
  350. var ele = $("<span class='level right' style='width: 75px;'>" + result + "</p>");
  351. ele.insertAfter(row.find(".edit"));
  352. ele.css("float", "right");
  353. row.find(".description .text").css("width", "initial");
  354. }, delay);
  355. });
  356. });
  357. }
  358.  
  359. checkBlacklist();
  360. ajax((page, json, uri) => {
  361. if(page != "userlist" || !uri) return;
  362.  
  363. checkBlacklist();
  364. });
  365. break;
  366. case "factions": // territory walls
  367. if (settings.pages.faction.wall && hasSearchTag("step", "your")) {
  368. runOnEvent(() => {
  369. let hashSplit = window.location.hash.split("/");
  370. if (hashSplit[1] != "war" || isNaN(hashSplit[2])) return;
  371.  
  372. observeMutations(document, ".members-list", true, function(mut, obs) {
  373. $(".user-icons").eq(0).html("Stats");
  374.  
  375. updateWall();
  376. observeMutations($(".members-list")[0], ".members-list > .enemy", false, function(mut, obs) {
  377. debug("Member list got updated.")
  378. updateWall();
  379. });
  380. }, { childList: true, subtree: true });
  381. }, "hashchange", true);
  382. } else if (settings.pages.faction.profile && hasSearchTag("step", "profile")) {
  383. $(".member-list > li").each((index, element) => {
  384. var row = $(element);
  385.  
  386. let id = row.find(".member .name").attr("href");
  387. id = id.substring(id.indexOf("=") + 1);
  388. let level = row.find(".lvl").html().split(" ")[2] * 1;
  389.  
  390. let delay = settings.apiDelay * (index - ignore);
  391.  
  392. if (shouldIgnore(level)){
  393. ignore++;
  394.  
  395. if (!settings.ignore.showEmpty) return;
  396. else delay = 0;
  397. }
  398. if (getSubCache(cache, PREFIX_CACHE + id)) {
  399. ignore++;
  400. delay = 0;
  401. }
  402.  
  403. updateUser(id, level, (result) => row.find(".days").html(result), delay);
  404. });
  405. }
  406. break;
  407. case "competition": // competitions (elimination)
  408. var linked = false;
  409. runOnEvent(() => {
  410. if (linked) return;
  411.  
  412. if (hasSpecialTag("p", "team")) { // Elimination 2019
  413. log("Starting to check for elimination!");
  414. xhrIntercept((page, json, uri) => {
  415. if(page != "competition" || !uri || !hasSpecialTag("p", "team")) return;
  416.  
  417. observeMutations($("#competition-wrap")[0], ".competition-list", true, (mut, obs) => {
  418. ignore = 0;
  419. debug($(".competition-list").find(".name a").first().attr("data-placeholder"));
  420. $(".competition-list > li > ul").each(function(index) {
  421. var row = $(this);
  422. let id = row.find(".user").attr("href");
  423. if (!id) {
  424. ignore++;
  425. return;
  426. }
  427. id = id.substring(id.indexOf("=") + 1);
  428. let level = stripHtml(row.find(".level").html()) * 1;
  429. debug(id + " / " + level)
  430.  
  431. let delay = settings.apiDelay * (index - ignore);
  432.  
  433. if (shouldIgnore(level)){
  434. ignore++;
  435.  
  436. if (!settings.ignore.showEmpty) return;
  437. else delay = 0;
  438. }
  439. if (getSubCache(cache, PREFIX_CACHE + id)) {
  440. ignore++;
  441. delay = 0;
  442. }
  443.  
  444. updateUser(id, level, (result) => row.find(".icons").html(result), delay);
  445. });
  446.  
  447. });
  448. });
  449. linked = true;
  450. }
  451. }, "hashchange", true);
  452. break;
  453. }
  454. }
  455.  
  456. function loadWall() {
  457. var hashSplit = window.location.hash.split("/");
  458. if (hashSplit[1] != "war" || isNaN(hashSplit[2])) return;
  459.  
  460. observeMutations(document, ".members-list", true, function(mut, obs) {
  461. $(".user-icons").eq(0).html("Stats");
  462.  
  463. updateWall();
  464. observeMutations($(".members-list")[0], ".members-list > .enemy", false, function(mut, obs) {
  465. debug("Member list got updated.")
  466. updateWall();
  467. });
  468. }, { childList: true, subtree: true });
  469. }
  470.  
  471. function updateWall() {
  472. let ignore = 0;
  473. $(".members-list > .enemy:not(:has(.estimate))").each(function(index) {
  474. var row = $(this);
  475. let id = row.find(".name").attr("href");
  476. id = id.substring(id.indexOf("XID=") + 4);
  477. let level = row.find(".level").html();
  478. debug(`Found ${id} at level ${level}`);
  479.  
  480. row.find(".member").addClass("estimate");
  481.  
  482. let delay = settings.apiDelay * (index - ignore);
  483.  
  484. if (shouldIgnore(level)){
  485. ignore++;
  486.  
  487. if (!settings.ignore.showEmpty) return;
  488. else delay = 0;
  489. }
  490.  
  491. updateUser(id, level, function(result) {
  492. if (result === EMPTY_CHAR) return;
  493.  
  494. var iconWrap = row.find(".user-icons");
  495.  
  496. $("<span class='level left' style='border-left: 0px solid transparent; width: 70px;'>" + result + "</p>").insertAfter(row.find(".level"));
  497. iconWrap.css("width", "175px");
  498. iconWrap.find("ul").css("width", "initial");
  499. }, delay);
  500. });
  501. }
  502.  
  503. function shouldLoad(page) {
  504. if (settings.pages.profile && page == "profiles") return true;
  505. if (settings.pages.search && page == "userlist" && hasSearchTag("step", "search")) return true;
  506. if (settings.pages.searchAdvanced && page == "userlist" && hasSearchTag("step", "adv")) return true;
  507. if (settings.pages.abroad && page == "index" && hasSearchTag("page", "people")) return true;
  508. if (settings.pages.hallOfFame && page == "halloffame") return true;
  509. if (settings.pages.bounties && page == "bounties") return true;
  510. if (settings.pages.blacklist && page == "blacklist") return true;
  511. if (page == "factions") {
  512. if (settings.pages.faction.wall && hasSearchTag("step", "your")) return true;
  513. if (settings.pages.faction.profile && hasSearchTag("step", "profile")) return true;
  514. }
  515. if (settings.pages.competition && page == "competition") return true;
  516.  
  517. return false;
  518. }
  519.  
  520. function shouldIgnore(level) {
  521. return settings.ignore.enabled && (settings.ignore.level <= level);
  522. }
  523.  
  524. function getCurrentPage() {
  525. var path = window.location.pathname;
  526. return path.substring(1, path.length - 4);
  527. }
  528.  
  529. function hasSearchTag(tag, value) {
  530. var params = new URL(window.location.href).searchParams;
  531.  
  532. return !value ? params.has(tag) : params.get(tag) == value;
  533. }
  534.  
  535. function hasSpecialTag(tag, value) {
  536. var params = new URLSearchParams(getSpecialSearch());
  537.  
  538. return !value ? params.has(tag) : params.get(tag) == value;
  539. }
  540.  
  541. function updateUser(id, lvl, callback, delay) {
  542. if (shouldIgnore(lvl)){
  543. debug(`Ignoring ${id} with level ${lvl}.`)
  544. if (settings.ignore.showEmpty) callback(EMPTY_CHAR);
  545. return;
  546. }
  547.  
  548. debug(`Estimating for ${id} with level ${lvl}.`)
  549.  
  550. let cached = getCachedStats(id);
  551. if (cached) {
  552. log(`Cached stats for ${id}! ${cached}`);
  553.  
  554. callback(cached);
  555. return;
  556. } else {
  557. debug(`NONE Cached stats for ${id}!`, cached);
  558. }
  559.  
  560. setTimeout(function(){
  561. sendAPIRequest("user", id, "profile,personalstats,crimes").then(function(oData) {
  562. debug("response", oData);
  563. if (!oData){
  564. debug("oData is not found")
  565. return callback("ERROR API (UNKNOWN)");
  566. }
  567. if (!oData.rank) {
  568. debug("api returned error")
  569. return callback("ERROR API (" + oData.error.code + ")");
  570. }
  571. debug("Loaded information from the api!");
  572.  
  573. var rankSpl = oData.rank.split(" ");
  574. var rankStr = rankSpl[0];
  575. if (rankSpl[1][0] === rankSpl[1][0].toLowerCase()) rankStr += " " + rankSpl[1];
  576.  
  577. var level = oData.level;
  578. var rank = ranks[rankStr];
  579. var crimes = oData.criminalrecord ? oData.criminalrecord.total : 0;
  580. var networth = oData.personalstats ? oData.personalstats.networth : 0;
  581.  
  582. var trLevel = 0, trCrime = 0, trNetworth = 0;
  583. for (let l in triggerLevel) {
  584. if (triggerLevel[l] <= level) trLevel++;
  585. }
  586. for (let c in triggerCrime) {
  587. if (triggerCrime[c] <= crimes) trCrime++;
  588. }
  589. for (let nw in triggerNetworth) {
  590. if (triggerNetworth[nw] <= networth) trNetworth++;
  591. }
  592.  
  593. var statLevel = rank - trLevel - trCrime - trNetworth - 1;
  594.  
  595. var estimated = estimatedStats[statLevel];
  596. if (!estimated) estimated = "N/A";
  597.  
  598. debug(`Estimated stats for ${id} with level ${lvl}.`)
  599.  
  600. cache[PREFIX_CACHE + id] = {};
  601. cache[PREFIX_CACHE + id].value = estimated;
  602. cache[PREFIX_CACHE + id].end = Date.now() + (estimated == estimatedStats[estimatedStats.length - 1] ? settings.cache.last : settings.cache.normal);
  603.  
  604. setCache("statestimate", cache, -1, true);
  605. callback(estimated);
  606. });
  607. }, delay);
  608. }
  609.  
  610. function getCachedStats(id) {
  611. let cached = cache[PREFIX_CACHE + id];
  612. if (cached) {
  613. debug(`Cached stats for ${id}?`);
  614.  
  615. let end = cached.end;
  616. if (end == -1 || end >= Date.now())
  617. return cached.value;
  618. else
  619. cache[PREFIX_CACHE + id] = undefined;
  620. }
  621. return undefined;
  622. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement