您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Some games has just "on sale" tag, instead of percentage discount. This script brings it back to normal. Script is not downloading any info, it is using only the info buried on a page, so might not work everywhere. Yeah, Steam just complies with stupid EU law.
当前为
// ==UserScript== // @name Steam explicit discounts // @version 2024.7.9 // @namespace Jakub Marcinkowski // @description Some games has just "on sale" tag, instead of percentage discount. This script brings it back to normal. Script is not downloading any info, it is using only the info buried on a page, so might not work everywhere. Yeah, Steam just complies with stupid EU law. // @author Jakub Marcinkowski <kuba.marcinkowski on g mail> // @copyright 2023+, Jakub Marcinkowski <kuba.marcinkowski on g mail> // @license Zlib // @homepageURL https://gist.github.com/JakubMarcinkowski // @homepageURL https://github.com/JakubMarcinkowski // @run-at document-idle // @grant unsafeWindow // @icon https://help.steampowered.com/public/shared/images/responsive/share_steam_logo.png // @match *://store.steampowered.com/* // @exclude *://store.steampowered.com/explore/* // @exclude *://store.steampowered.com/adultonly* // @exclude *://store.steampowered.com/sale/nextfest* // @exclude *://store.steampowered.com/sale/steam_awards* // @exclude *://store.steampowered.com/steamawards* // @exclude *://store.steampowered.com/vrhardware* // @exclude *://store.steampowered.com/steamdeck* // @exclude *://store.steampowered.com/points* // @exclude *://store.steampowered.com/news* // @exclude *://store.steampowered.com/yearinreview* // @exclude *://store.steampowered.com/labs* // @exclude *://store.steampowered.com/charts* // @exclude *://store.steampowered.com/about* // ==/UserScript== (function() { 'use strict'; let priceChunks, toPadEnd; if (location.pathname === '/' || location.pathname.startsWith('/dlc/') ) { const observer = new MutationObserver ( function(mutationsList) { for (const mutation of mutationsList) { for (const node of mutation.addedNodes) { if (node.nodeType !== Node.ELEMENT_NODE || node.className.startsWith('discount') || [...node.classList].find(x => ['ds_options', 'ds_wishlist_flag'].includes(x)) || node.nodeName === 'VIDEO' ) continue; convertAllClassic(node); } } } ); const ids = ['content_more', 'RecommendationsRows']; for (const id of ids) { const node = document.getElementById(id); if (node) observer.observe(node, {childList: true}); } const mainContent = document.getElementsByClassName('main_content_ctn')[0]; if (mainContent) observer.observe(mainContent, {childList: true, subtree: true}); } if (location.pathname === '/' || location.pathname.startsWith('/bundle/') || location.pathname.startsWith('/sub/') || location.pathname.startsWith('/dlc/') || location.pathname.startsWith('/widget/') // embedded iframe strip with basic game info ) { convertAllClassic(document); return; } if (location.pathname.startsWith('/app/')) { const prices = document.getElementsByClassName('game_purchase_action'); for (const element of prices) { convertAllClassic(element); } const dlcs = document.getElementById('gameAreaDLCSection'); if (dlcs) { convertAllClassic(dlcs); } const idsSelector = '#recommended_block_content, #franchise_app_block_content, #moredlcfrombasegame_block_content'; for (const node of document.querySelectorAll(idsSelector)) { convertAllClassic(node); } return; } if (location.pathname.startsWith('/search/')) { [...document.getElementById('search_resultsRows').children].forEach(convertAllClassic); const observer = new MutationObserver ( function(mutationsList) { for (const mutation of mutationsList) { if (mutation.addedNodes.length !== 1 || !(mutation.addedNodes[0].nodeName && mutation.addedNodes[0].nodeName === 'A') ) continue; convertAllClassic(mutation.addedNodes[0]); }; } ); observer.observe(document.getElementById('search_resultsRows'), {childList: true}); return; } if (location.pathname.startsWith('/wishlist/')) { const observer = new MutationObserver ( function(mutationsList) { for (const mutation of mutationsList) { if (mutation.addedNodes.length === 0) continue; convertAllClassic(mutation.addedNodes[0]); }; } ); observer.observe(document.getElementById('wishlist_ctn'), {childList: true}); return; } // Modern Steam pages 2024 let exampleNonGeneric; const reactElem = document.getElementsByClassName('react_landing_background')[0]; if (reactElem) { const observerReact = new MutationObserver ( function() { const nodes = reactElem.getElementsByClassName('Discounted'); if (nodes.length !== 0 && !unsafeWindow.StoreItemCache) { observerReact.disconnect() return; } else if (nodes.length !== 0) { if (!exampleNonGeneric) exampleNonGeneric = document .querySelector('.Discounted > div:last-child > div:first-child') .parentElement.parentElement; const genericDiscounts = [...nodes].filter ( elem => elem.firstChild.firstChild.nodeName === 'svg' ); for (const elem of genericDiscounts) { convertPricesModern2024(elem); } } } ); observerReact.observe(reactElem, {childList: true, subtree: true}); return; } function convertPricesModern2024(priceContainer) { const id = findId(priceContainer); if (!id) return; const priceInfo = unsafeWindow.StoreItemCache.m_mapApps.get(id).m_BestPurchaseOption; const discountText = (-priceInfo.discount_pct / 100).toLocaleString(navigator.language, {style: 'percent'}); const cloned = exampleNonGeneric.cloneNode(true); priceContainer.replaceChildren(...cloned.children); priceContainer.firstChild.textContent = discountText; priceContainer.lastChild.firstChild.textContent = priceInfo.formatted_original_price; priceContainer.lastChild.lastChild.textContent = priceInfo.formatted_final_price; } function findId(node) { let testElem, id; testElem = node.closest('a'); if (testElem) { id = parseInt(testElem.href.split('/')[4]); } if (!id && node.parentElement && node.parentElement.previousElementSibling && node.parentElement.previousElementSibling.firstChild ) { testElem = node.parentElement.previousElementSibling.firstChild; if (testElem.nodeName === 'IMG') { id = parseInt(testElem.src.split('/')[5]); } } if (!id && node.closest('.Panel') && node.closest('.Panel').getElementsByTagName('a')[0] ) { testElem = node.closest('.Panel').getElementsByTagName('a')[0]; if (testElem.nodeName === 'A') { id = parseInt(testElem.href.split('/')[4]); } } return id; } function convertAllClassic(node) { const nodes = 'length' in node ? node : node.getElementsByClassName('generic_discount'); while (nodes.length !== 0) { convertPricesClassic(nodes[0]); } } function convertPricesClassic(generic) { if (!priceChunks) { const originalPrice = generic.getElementsByClassName('discount_final_price')[0].textContent.trim(); priceChunks = [...originalPrice.matchAll(/(.*?)([0-9]+[,.]*[0-9]+)(.*)/g)][0]; const priceSplit = priceChunks[2].split(/[,.]/); if (priceSplit[1]) toPadEnd = priceSplit[1].length } const discount_block = generic.parentElement; // div.discount_block const discount_prices = discount_block.getElementsByClassName('discount_prices')[0]; const discount_icon = discount_block.getElementsByClassName('discount_icon')[0]; discount_icon.style.display = 'none'; generic.classList.remove('generic_discount'); const discount_pct = document.createElement('div'); discount_pct.className = 'discount_pct'; discount_block.prepend(discount_pct); const discount_original_price = document.createElement('div'); discount_original_price.className = 'discount_original_price'; discount_prices.prepend(discount_original_price); const discount = discount_block.dataset.discount; const discountText = (-discount / 100).toLocaleString(navigator.language, {style: 'percent'}); const priceFinal = discount_block.dataset.priceFinal; const priceCalc = priceFinal / (100 - discount); let priceText = ''; priceText = unsafeWindow.GStoreItemData.fnFormatCurrency(priceCalc * 100); // priceText = Number(priceCalc.toFixed(2)).toLocaleString(); // let priceFinalSplit = priceText.split(/[,.]/); // if (priceFinalSplit[1] && priceFinalSplit[1].length < toPadEnd) // {console.log(priceText, generic); // while (priceFinalSplit[1].length < toPadEnd) // { // priceText += '0'; // priceFinalSplit = priceText.split(/[,.]/); // } // } // if (priceChunks && priceChunks[1]) priceText = priceChunks[1] + priceText; // else if (priceChunks && priceChunks[3]) priceText = priceText + priceChunks[3]; discount_pct.textContent = discountText; discount_original_price.textContent = priceText; } })();