显示游戏在各种商店中当前和历史最低价格及进包次数
// ==UserScript== // @name SteamHistoryLowestPrice // @namespace [email protected] // @description 显示游戏在各种商店中当前和历史最低价格及进包次数 // @include /^https?:\/\/store\.steampowered\.com\/(app|sub|bundle)\/\d+/ // @license GPL version 3 or any later version // @version 2017-7-8 // @grant GM_xmlhttpRequest // jshint esversion:6 // ==/UserScript== // 显示样式 // 0 = 显示在购买按钮上面 // 1 = 显示在购买信息框上面 const INFO_STYLE = 0; // 货币区域覆盖,两个字母的国家代号,大小写均可 // 空字符("")代表不覆盖,使用steam的cookie中steamCountry的值 // 见 https://zh.wikipedia.org/wiki/ISO_3166-1 或 https://en.wikipedia.org/wiki/ISO_3166-1 // 常用 美国USD:"us", ##CNY: "cn", 英国GBP: "uk", 日本JPY: "jp", 俄国RUS: "ru" const CC_OVERRIDE = ""; // 货币符号 const CURRENCY_SYMBOLS = { 'AED': 'DH', 'AUD': 'A$', 'BRL': 'R$', 'CAD': 'CDN$', 'CHF': 'CHF', 'CLP': 'CLP$', 'CNY': '¥', // Chines Yuan 'COP': 'COL$', 'CRC': '₡', // Costa Rican Colón 'EUR': '€', // Euro 'GBP': '£', // British Pound Sterling 'HKD': 'HK$', 'IDR': 'Rp', 'ILS': '₪', // Israeli New Sheqel 'INR': '₹', // Indian Rupee 'JPY': '¥', // Japanese Yen 'KRW': '₩', // South Korean Won 'MXN': 'Mex$', 'MYR': 'RM', 'NGN': '₦', // Nigerian Naira 'NOK': 'kr', 'NZD': 'NZ$', 'PEN': 'S/.', 'PHP': '₱', // Philippine Peso 'PLN': 'zł', // Polish Zloty 'PYG': '₲', // Paraguayan Guarani 'RUB': 'pуб', 'SAR': 'SR', 'SGD': 'S$', 'THB': '฿', // Thai Baht 'TRY': 'TL', 'TWD': 'NT$', 'UAH': '₴', // Ukrainian Hryvnia 'USD': '$', // US Dollar 'VND': '₫', // Vietnamese Dong 'ZAR': 'R ', }; // 查询历史低价包括的商店 const STORES = [ "steam", "amazonus", "impulse", "gamersgate", "direct2drive", "origin", "uplay", "indiegalastore", "gamesplanet", "indiegamestand", "gog", "nuuvem", "dlgamer", "humblestore", "squenix", "bundlestars", "fireflower", "humblewidgets", "newegg", "coinplay", "wingamestore", "macgamestore", "gamebillet", "silagames", "itchio", "gamejolt", "paradox" ]; // 在app页和愿望单页显示史低价格 let urlMatch = location.href.match(/(app|sub|bundle)\/(\d+)/); let appId = ""; let type = ""; let subIds = []; if(urlMatch && urlMatch.length == 3){ type = urlMatch[1] appId = urlMatch[2]; } // console.log('[史低]: ' + type + ' : ' + appId + ', requesting data info...'); // DEBUG // 获取subs document.querySelectorAll("input[name=subid]") .forEach(sub=>subIds.push(sub.value)); let cc = "cn"; if(CC_OVERRIDE.length > 0){ // 使用覆盖的货币区域 cc = CC_OVERRIDE; } else { // 使用默认的的货币区域 let ccMatch = document.cookie.match(/steamCountry=([a-z]{2})/i); if (ccMatch !== null && ccMatch.length == 2) { cc = ccMatch[1]; } } AddLowestPriceTag(appId, type, subIds, STORES.join(","), cc, location.protocol); // 在商店页添加史低信息 async function AddLowestPriceTag(appId, type = "app", subIds = [], stores = "steam", cc = "cn", protocol = "https"){ // 史低信息容器们 let lowestPriceNodes = {}; // 统计subid let findSubIds = []; if(type == "bundle"){ // bundle就一个, 视作subid findSubIds.push(appId); } else if (type == "app" || type == "sub"){ // app/sub 可能有好多 findSubIds = subIds.slice(); } // 寻找每一个subid的购买按钮,生成史低信息容器们 findSubIds.forEach(subId => { let gameWrapper = null; try{ gameWrapper = document.querySelector('.game_area_purchase_game input[value="' + subId + '"]'); switch (INFO_STYLE){ case 0: gameWrapper = gameWrapper.parentNode.parentNode.querySelector('.game_purchase_action'); break; case 1: gameWrapper = gameWrapper.parentNode.parentNode.parentNode; break; } } catch (ex) { gameWrapper = null; } if(gameWrapper){ let lowestInfo = document.createElement("div"); lowestInfo.className = "game_lowest_price"; lowestInfo.innerText = "正在读取历史最低价格..."; if(INFO_STYLE == 1){ lowestInfo.style.background = 'linear-gradient(to right, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.2) 100%)'; } gameWrapper.prepend(lowestInfo); lowestPriceNodes[subId] = lowestInfo; } }); // 获取sub们的数据 let data = null; try { data = JSON.parse( await GettingSteamDBAppInfo(appId, type, subIds, stores, cc, protocol) ); } catch (err) { console.log('[史低]: ' + err); } // console.log('[史低]: app ' + appId + ' data : %o', data); // DEBUG // 解析data let appInfos = []; let metaInfo = data ? data[".meta"] : null; // 如果是bundle, 除了.meta外只有一个bundle/xxx,否则是一大堆xxx if(type == "bundle"){ appInfos.push({Id:appId, Info:data["bundle/" + appId]}); } else if(type == "app" || type == "sub"){ for(let key in data){ if(!isNaN(key)){ appInfos.push({Id:key, Info:data[key]}); } } } // console.log('[史低]: app ' + appId + ' metaInfo: %o', metaInfo); // DEBUG // console.log('[史低]: app ' + appId + ' appInfos: %o', appInfos); // DEBUG // 如果查到info,塞到购买按钮上面去 if(metaInfo && appInfos.length > 0){ // 获取整体信息 let currencySymbol = metaInfo.currency in CURRENCY_SYMBOLS ? CURRENCY_SYMBOLS[metaInfo.currency] : metaInfo.currency; // 为每一个sub或bundle添加史低 appInfos.forEach( app => { let lowestInfo = lowestPriceNodes[app.Id]; if(lowestInfo){ lowestInfo.innerHTML = // 历史最低 '历史最低价是 ' + '<span style="cursor:help;text-decoration:underline;" title="' + app.Info.lowest.recorded_formatted + '">' + new Date(app.Info.lowest.recorded * 1e3).toLocaleDateString() + '</span> 时在 ' + '<a target="_blank" href="' + app.Info.lowest.url + '"> ' + app.Info.lowest.store + '</a> 中的 ' + '<span class="discount_pct">-' + app.Info.lowest.cut + '%</span>' + '<a target="_blank" title="查看价格历史" href="' + app.Info.urls.history + '"> ' + currencySymbol + ' ' + app.Info.lowest.price + '</a>' // 第二行 + '<br />' // 进包次数 + '进包 <a target="_blank" title="查看进包信息" href="' + app.Info.urls.bundles + '"' + (app.Info.bundles && app.Info.bundles.live.length > 0 ? ' style="color:#0d0" title="' + app.Info.bundles.live.length + ' 个正在销售的慈善包"' : '') +'> ' + app.Info.bundles.count + ' </a> 次,' // 当前最低 + (app.Info.price.price <= app.Info.lowest.price ? '<span class="game_purchase_discount_countdown">当前为历史最低价</span>,' : '<span>当前最低价是</span>' ) + '在 ' + '<a target="_blank" href="' + app.Info.price.url + '"> ' + app.Info.price.store + '</a> 中的 ' + '<span class="discount_pct">-' + app.Info.price.cut + '%</span>' + '<a target="_blank" title="查看价格信息" href="' + app.Info.urls.info + '"> ' + currencySymbol + ' ' + app.Info.price.price + '</a>'; } }); } else { // metaInfo为空,或者appInfos无内容 console.log('[史低]: get lowest price failed, data = %o', data); for(let id in lowestPriceNodes){ lowestPriceNodes[id].innerHTML = ""; } } // 返回史低info return Promise.resolve(lowestPriceNodes); } // 获取史低信息 async function GettingSteamDBAppInfo(appId, type = "app", subIds = [], stores = "steam", cc = "cn", protocol = "https"){ let requestPromise = null; let bundleId = ""; if(type == "bundle"){ bundleId = appId; } if(!isNaN(appId) && parseInt(appId) > 0){ let requestUrl = protocol + "//api.enhancedsteam.com/pricev3/?" + "bundleid=" + bundleId + "&subs=" + subIds.join(',') + "&appid=" + appId + "&stores=" + stores + "&cc=" + cc; // console.log('[史低]: requestUrl: ' + requestUrl); // DEBUG requestPromise = new Promise( (resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: requestUrl, onload: function (response) { resolve(response.response); }, onerror: function (error) { reject(error); } }); }); } else { requestPromise = Promise.reject("Invalid appid"); } return requestPromise; }