您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tracks Keno random numbers and displays a heat map with light gray to dark red gradient
// ==UserScript== // @name Keno Heatmap // @namespace http://tampermonkey.net/ // @version 1.0.1 // @description Tracks Keno random numbers and displays a heat map with light gray to dark red gradient // @author Allenone[2033011] // @match https://www.torn.com/page.php?sid=keno // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; const win = (unsafeWindow || window); const TARGET_URL_BASE = "torn.com/page.php"; // Initialize frequency cache for numbers 1-80 function initializeFrequencyCache() { let frequency = GM_getValue('kenoNumberFrequency', null); if (!frequency) { frequency = {}; for (let i = 1; i <= 80; i++) { frequency[i] = 0; } GM_setValue('kenoNumberFrequency', frequency); } return frequency; } // Update frequency cache with new random numbers function updateFrequencyCache(randomNumbers) { let frequency = initializeFrequencyCache(); randomNumbers.forEach(num => { if (num >= 1 && num <= 80) { frequency[num] = (frequency[num] || 0) + 1; } }); GM_setValue('kenoNumberFrequency', frequency); updateHotspotMap(frequency); } // Interpolate between two RGB colors function interpolateColor(startColor, endColor, factor) { const result = startColor.slice(); for (let i = 0; i < 3; i++) { result[i] = Math.round(startColor[i] + (endColor[i] - startColor[i]) * factor); } return `rgb(${result[0]}, ${result[1]}, ${result[2]})`; } // Update the hotspot map with color gradient from light gray to dark red function updateHotspotMap(frequency) { const startColor = [211, 211, 211]; // Light gray (#D3D3D3) const endColor = [139, 0, 0]; // Dark red (#8B0000) const maxFrequency = Math.max(...Object.values(frequency), 1); // Avoid division by 0 const style = document.createElement('style'); style.textContent = ` #boardContainer span { border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; transition: background-color 0.3s; } `; document.head.appendChild(style); for (let i = 1; i <= 80; i++) { const element = document.getElementById(`keno_item_${i}`); if (element) { const freq = frequency[i] || 0; const factor = freq / maxFrequency; // Normalize frequency const color = interpolateColor(startColor, endColor, factor); element.style.backgroundColor = color; element.style.color = 'black'; } } } // Observe DOM for boardContainer and initialize hotspot map function initializeHotspotOnBoardLoad() { const targetNode = document.body; const observer = new MutationObserver((mutations, obs) => { const boardContainer = document.getElementById('boardContainer'); if (boardContainer) { updateHotspotMap(initializeFrequencyCache()); obs.disconnect(); // Stop observing once board is found } }); observer.observe(targetNode, { childList: true, subtree: true }); } // Start observing for boardContainer initializeHotspotOnBoardLoad(); const originalOpen = XMLHttpRequest.prototype.open; const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { this._url = url; return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { const isTargetUrl = this._url && this._url.includes(TARGET_URL_BASE); if (isTargetUrl) { const xhr = this; const handleResponse = function(event) { if (xhr.readyState === 4 && xhr.status === 200 && xhr.responseText) { try { const json = JSON.parse(xhr.responseText); if (json.matches !== undefined && json.winnings !== undefined) { //console.log(JSON.stringify(json, null, 2)); if (json.randomNumbers && Array.isArray(json.randomNumbers)) { updateFrequencyCache(json.randomNumbers); } } } catch (err) { } } }; xhr.addEventListener('load', handleResponse); } return originalSend.apply(this, arguments); }; })();