您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds current pricing info from CheapShark for other stores to the Steam Store
// ==UserScript== // @name CheapShark Steam Integration // @description Adds current pricing info from CheapShark for other stores to the Steam Store // @version 0.3.0 // @author Phlebiac // @match https://store.steampowered.com/app/* // @connect www.cheapshark.com // @run-at document-end // @noframes // @license MIT; https://opensource.org/licenses/MIT // @namespace Phlebiac/CheapShark // @icon https://www.cheapshark.com/img/icons/round_114.png // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== ;(async () => { 'use strict' const BASE_URL = 'https://www.cheapshark.com'; const API_URL = `${BASE_URL}/api/1.0/`; const METACRITIC_BASE = 'https://www.metacritic.com'; let userPrefs = { open_in_new_tab: GM_getValue('open_in_new_tab', true), show_metacritic: GM_getValue('show_metacritic', true), store_info_cache: GM_getValue('store_info_cache', []), } const appId = getCurrentAppId(); if (!appId) { return; } injectCSS(); if (!userPrefs.store_info_cache.length) { log('Requesting store data...'); GM_xmlhttpRequest({ method: 'GET', url: `${API_URL}stores`, onload: buildStoreCache }); } else { //log(`Using cache of ${userPrefs.store_info_cache.length} stores`); } GM_xmlhttpRequest({ method: 'GET', url: `${API_URL}deals?steamAppID=${appId}&sortBy=Price`, onload: addDealsToStorePage }) function getCurrentAppId() { const urlPath = window.location.pathname; const appId = urlPath.match(/\/app\/(\d+)/); if (appId === null) { log('Unable to get AppId from URL path:', urlPath); return false; } return appId[1]; } function buildStoreCache(response) { if (response.status === 200) { try { var stores = JSON.parse(response.responseText); log(`Caching data for ${stores.length} stores`); stores.forEach(store => { userPrefs.store_info_cache[store.storeID] = store; }); GM_setValue('store_info_cache', userPrefs.store_info_cache); } catch (err) { log('Unable to parse CheapShark response as JSON:', response); log('Javascript error:', err); } } else { log('Got unexpected HTTP code from CheapShark:', response.status); } } function addDealsToStorePage(response) { if (response.status === 200) { try { var deals = JSON.parse(response.responseText); //log(`Found ${deals.length} deals`); } catch (err) { log('Unable to parse CheapShark response as JSON:', response); log('Javascript error:', err); } } else { log('Got unexpected HTTP code from CheapShark:', response.status); } let target = document.querySelector('.game_purchase_action'); if (target && deals.length > 0) { var bestDeal = deals[0]; let node = Object.assign(document.createElement('span'), { className: 'cheapshark_deals_row btnv6_blue_hoverfade btn_medium' }); if (userPrefs.show_metacritic && bestDeal.metacriticScore > 0) { node.appendChild(showMetaCritic(bestDeal)); } node.appendChild(lowestPrice(bestDeal)); if (deals.length > 1) { node.appendChild(listDeals(deals)); } target.insertBefore(node, target.firstChild); target.insertBefore(preferencesDialog(), node); } } function showMetaCritic(deal) { let node = Object.assign(document.createElement('a'), { className: 'cheapshark_metacritic', href: `${METACRITIC_BASE}${deal.metacriticLink}`, title: 'View on MetaCritic', target: userPrefs.open_in_new_tab ? '_blank' : '_self' }); node.appendChild(Object.assign(document.createElement('img'), { src: `${METACRITIC_BASE}/MC_favicon.png`, className: 'cheapshark_metacritic_img', height: 20 })); node.appendChild(Object.assign(document.createElement('span'), { textContent: `${deal.metacriticScore}`, className: `cheapshark_metacritic_score` })); return node; } function lowestPrice(deal) { var store = userPrefs.store_info_cache[deal.storeID]; let node = Object.assign(document.createElement('a'), { className: 'cheapshark_lowest', href: `${BASE_URL}/redirect?dealID=${deal.dealID}`, title: `$${deal.salePrice} on ${store.storeName}`, target: userPrefs.open_in_new_tab ? '_blank' : '_self' }); node.appendChild(Object.assign(document.createElement('span'), { textContent: `Lowest: $${deal.salePrice}`, className: `cheapshark_lowest_price`, })); node.appendChild(Object.assign(document.createElement('img'), { src: `${BASE_URL}${store.images.icon}`, className: 'cheapshark_lowest_img' })); return node; } function listDeals(deals) { // Build out a menu option for each store deal let dealOptions = ''; for (const deal of deals) { var store = userPrefs.store_info_cache[deal.storeID]; dealOptions = `${dealOptions} <div class="cheapshark_deal_option queue_menu_option"> <div class="cheapshark_valign queue_menu_option_label"> <a href="${BASE_URL}/redirect?dealID=${deal.dealID}" class="option_title"> <img class="cheapshark_valign" src="${BASE_URL}${store.images.icon}"> $${deal.salePrice} on ${store.storeName} </a> </div> </div>`; } return Object.assign(document.createElement('div'), { className: 'cheapshark_deals_dropdown queue_control_button queue_btn_menu', innerHTML: ` <div class="queue_menu_arrow"> <span><img src="https://store.cloudflare.steamstatic.com/public/images/v6/btn_arrow_down_padded.png"></span> </div> <div class="cheapshark_menu_flyout queue_menu_flyout"> <div class="queue_flyout_content">${dealOptions} </div> </div>` }); } function preferencesDialog() { const container = Object.assign(document.createElement('span'), { className: 'cheapshark_prefs_icon', title: 'Preferences for CheapShark Steam Integration', textContent: '⚙' }) container.addEventListener('click', () => { const html = ` <div class="cheapshark_prefs"> <div class="newmodal_prompt_description"> New preferences will only take effect after you refresh the page. </div> <blockquote> <div> <input type="checkbox" id="cheapshark_open_in_new_tab" ${ userPrefs.open_in_new_tab ? 'checked' : '' } /> <label for="cheapshark_open_in_new_tab">Open links in a new tab</label> </div> <div> <input type="checkbox" id="cheapshark_show_metacritic" ${ userPrefs.show_metacritic ? 'checked' : '' } /> <label for="cheapshark_show_metacritic">Show MetaCritic score and link</label> </div> </blockquote> </div>` unsafeWindow.ShowDialog('CheapShark on Steam Prefs', html); // Handle preferences changes const inputs = document.querySelectorAll('.cheapshark_prefs input'); for (const input of inputs) { input.addEventListener('change', event => { const target = event.target; const prefName = target.id.replace('cheapshark_', ''); switch (target.type) { case 'text': userPrefs[prefName] = target.value; GM_setValue(prefName, target.value); break; case 'checkbox': userPrefs[prefName] = target.checked; GM_setValue(prefName, target.checked); break; default: break; } }) } }) return container; } function injectCSS() { GM_addStyle(` .cheapshark_deals_row { border-style: solid; border-color: black; //padding: 0 0 2px 5px; padding: 5px 5px 5px 5px; background: #4d4b49; } .cheapshark_deals_row a:hover { color: white; } .cheapshark_metacritic { margin-right: 6px; } .cheapshark_metacritic_img { vertical-align: middle; margin-right: 4px; } .cheapshark_metacritic_score { font-size: 16px; vertical-align: middle; } .cheapshark_lowest { padding: 0 6px 0 6px; } .cheapshark_lowest_img { vertical-align: middle; } .cheapshark_lowest_price { font-size: 14px; vertical-align: middle; padding-right: 5px; } .cheapshark_deals_dropdown { //margin: -6px 0 -6px 0; } .cheapshark_menu_flyout { position: relative !important; width: unset !important; padding: 6px 6px; margin: -34px -6px -6px -240px; //position: absolute; //left: 0px; //margin-top: 5px; } .cheapshark_deal_option { padding: 2px !important; } .cheapshark_valign { vertical-align: middle; } .cheapshark_prefs_icon { font-size: 20px; padding: 0 2px; //vertical-align: top; cursor: pointer; } .cheapshark_prefs input[type="checkbox"], .cheapshark_prefs label { line-height: 20px; vertical-align: middle; display: inline-block; color: #66c0f4; cursor: pointer; } .cheapshark_prefs blockquote { margin: 15px 0 5px 10px; }`) } function log() { console.log('[CheapShark Steam Integration]', ...arguments) } })()