您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Display total stat gained for selected period on the Log page.
// ==UserScript== // @name Total Gained // @namespace http://tampermonkey.net/ // @version 1.1.0 // @description Display total stat gained for selected period on the Log page. // @author Caspie [2794025] // @license MIT License // @match https://www.torn.com/page.php?sid=log&log=5300 // @match https://www.torn.com/page.php?sid=log&log=5300&* // @match https://www.torn.com/page.php?sid=log&log=5301 // @match https://www.torn.com/page.php?sid=log&log=5301&* // @match https://www.torn.com/page.php?sid=log&log=5302 // @match https://www.torn.com/page.php?sid=log&log=5302&* // @match https://www.torn.com/page.php?sid=log&log=5303 // @match https://www.torn.com/page.php?sid=log&log=5303&* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant none // ==/UserScript== (function(w, d) { 'use strict'; const activityLog = d.querySelector('.activity-log'); if (activityLog) { new MutationObserver((entries) => { for (const entry of entries) { const el = entry.target; if (el.className.includes('logWrapper')) { if (el.className.includes('tableView') && !el.querySelector('[class^=notFoundMsg]')) { setTimeout(updateTotalGained, 100); break; } else { d.querySelector('.total-gained')?.remove(); } } } }).observe(activityLog, {subtree: true, childList: true}); } const updateTotalGained = () => { const panelContainer = activityLog?.querySelector('.panel'); if (!d.querySelector('.total-gained')) { const totalGainedContainer = createElement( { nodeName: 'div', className: 'total-gained info-msg-cont green border-round m-top10 m-bottom10', }, activityLog?.querySelector('div:nth-child(1)'), 'after' ); const infoMsg = createElement( { nodeName: 'div', className: 'info-msg border-round', }, totalGainedContainer ); createElement( { nodeName: 'i', className: 'info-icon', }, infoMsg, true ); const delimiter = createElement( { nodeName: 'div', className: 'delimiter', }, infoMsg ); createElement( { nodeName: 'div', className: 'msg right-round', textContent: 'Calculating...' }, delimiter ); } const totalGainedStart = panelContainer?.querySelector('tbody tr:last-child td:nth-child(4)')?.textContent; const totalGainedEnd = panelContainer?.querySelector('tbody tr:first-child td:nth-child(5)')?.textContent; const statName = panelContainer?.querySelector('thead tr:first-child th:nth-child(4)')?.textContent.split('_')[0]; const totalEnergy = panelContainer?.querySelectorAll('tbody tr td:nth-child(3)'); const totalHappy = panelContainer?.querySelectorAll('tbody tr td:nth-child(7)'); const colorMode = d.body.classList.contains('dark-mode') ? 'dark' : 'light'; const statColors = { 'dark': { 'strength': '--default-base-navy-color', 'speed': '--default-base-royal-color', 'defense': '--default-base-brown-color', 'dexterity': '--default-base-purple-color', 'energy': '--default-green-dark-color', 'happy': '--default-base-gold-color' }, 'light': { 'strength': '--default-base-royal-color', 'speed': '--default-base-turq-color', 'defense': '--default-base-brown-color', 'dexterity': '--default-base-pink-color', 'energy': '--default-green-dark-color', 'happy': '--default-base-gold-color' } }; if (totalGainedStart && totalGainedEnd) { const totalGained = Math.round(convertToFloat(totalGainedEnd) - convertToFloat(totalGainedStart)).toLocaleString(); const energyUsed = calculateUsage(totalEnergy); const happyUsed = calculateUsage(totalHappy); d.querySelector('.total-gained .msg').innerHTML = `You gained a total of <strong style="color:var(${statColors[colorMode][statName]});">${totalGained}</strong> ${statName}. To achieve it, you used <strong style="color:var(${statColors[colorMode].energy});">${energyUsed}</strong> energy and <strong style="color:var(${statColors[colorMode].happy});">${happyUsed}</strong> happy. `; } }; const calculateUsage = (items) => { return Array.from(items).reduce((total, item) => total + parseInt(item.textContent), 0).toLocaleString(); } const convertToFloat = (number) => { if (!number) { return number; } let localeTest = 1000; localeTest = localeTest.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}); return parseFloat(number.replaceAll(localeTest[1], '').replace(localeTest[5], '.')) } const createElement = (el, parent, prepend = false) => { const { nodeName = 'div', ...attrs } = el; const element = d.createElement(nodeName); Object.entries(attrs).forEach(([attr, value]) => { element[attr] = value; }); if (prepend == 'after') { parent.parentNode.insertBefore(element, parent.nextSibling) } else if (prepend == true) { parent.prepend(element); } else { parent.append(element); } return element; }; })(window, document);