Show prices on Steam followedgames page

在Steam社区"已关注的游戏"页面显示游戏的价格

  1. // ==UserScript==
  2. // @name Show prices on Steam followedgames page
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description 在Steam社区"已关注的游戏"页面显示游戏的价格
  6. // @author lyzlyslyc
  7. // @match http*://steamcommunity.com/*/followedgames*
  8. // @icon https://store.steampowered.com/favicon.ico
  9. // @grant GM_xmlhttpRequest
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // Your code here...
  17.  
  18. let interval = 1000;
  19. let requestTimeout = 3e3;
  20. let cc="";
  21.  
  22. //查询账号区域
  23. console.log("Checking country.");
  24. getCountryCode();
  25. function getCountryCode(){
  26. GM_xmlhttpRequest({
  27. method: "get",
  28. url: `https://store.steampowered.com/api/getfundwalletinfo/`,
  29. responseType: "json",
  30. timeout: requestTimeout,
  31. onload: (result)=>{
  32. result = result.response;
  33. if(result.success){
  34. cc=result.country_code;
  35. console.log(`Country code:${cc}`);
  36. }
  37. setInterval(requestPrice,interval);
  38. },
  39. ontimeout:()=>{
  40. getCountryCode();
  41. console.log("Checking country timeout. Retrying.");
  42. },
  43. onerror:(e)=>{
  44. console.log("Checking country error.");
  45. console.log(e);
  46. }
  47. })
  48. }
  49.  
  50. function requestPrice(){
  51. //获取关注列表
  52. let apps = document.querySelector(".games_list_rows").children;
  53. let queryList = {};
  54. let appidString = "";
  55. for(let i=0;i<apps.length;i++){
  56. if(apps[i].hasPrice||apps[i].hasPrice=="loading")continue;
  57. //找到第一个没查询且在可视区域内的app
  58. if(isAppVisible(apps[i])){
  59. //前后查询50个
  60. let min = (i-25)<0?0:(i-25);
  61. let max = (i+25)>apps.length?apps.length:(i+25);
  62. for(let j = min;j<max&&j<apps.length;j++){
  63. if(apps[j].hasPrice||apps[j].hasPrice=="loading"){
  64. max++;
  65. continue;
  66. }
  67. let appUrl = apps[j].querySelector("a").href;
  68. if(appUrl){
  69. //获取appid
  70. let appId = appUrl.match(/app\/(\d+)/)[1];
  71. apps[j].hasPrice = "loading";
  72. queryList[appId] = apps[j];
  73. appidString+=appId+",";
  74. }
  75. }
  76. break;
  77. }
  78. }
  79.  
  80. if(appidString=="")return;
  81. //发送查询请求
  82. GM_xmlhttpRequest({
  83. method: "get",
  84. url: `https://store.steampowered.com/api/appdetails?appids=${appidString}&cc=${cc}&filters=price_overview`,
  85. responseType: "json",
  86. timeout: requestTimeout,
  87. onload: handleResult,
  88. ontimeout:handleTimeout
  89. })
  90. console.log(`Request:${appidString}`);
  91. function handleResult(result){
  92. try{
  93. result = result.response;
  94. let appId;
  95. //对每一个app
  96. for(appId in result){
  97. //获取app信息:success和data
  98. let appInfo = result[appId];
  99. let price = null;
  100. //应用已下架,success===false
  101. if(!appInfo.success){
  102. price = {
  103. discount_percent: 0,
  104. final : 0,
  105. final_formatted: "Not for Sale"
  106. };
  107. }
  108. //如果data为空,无法判断是免费或者还是未发售,需要继续请求
  109. else if(appInfo.data.length===0){
  110. //发送查询请求
  111. GM_xmlhttpRequest({
  112. method: "get",
  113. url: `https://store.steampowered.com/api/appdetails?appids=${appId}&cc=${cc}`,
  114. responseType: "json",
  115. timeout: requestTimeout,
  116. onload: handleResult,
  117. ontimeout:handleTimeout
  118. })
  119. console.log(`RequestDetail:${appId}`);
  120. continue;
  121. }
  122. //此处处理上面分支发送的请求
  123. else if(appInfo.data.name){
  124. //即将发售
  125. if(appInfo.data.release_date.coming_soon){
  126. price = {
  127. discount_percent: 0,
  128. final : 0,
  129. final_formatted: "Coming Soon"
  130. };
  131. }
  132. //免费
  133. else if(appInfo.data.is_free){
  134. price = {
  135. discount_percent: 0,
  136. final : 0,
  137. final_formatted: "Free to Play"
  138. };
  139. }
  140. }
  141. else price = appInfo.data.price_overview;
  142.  
  143. //添加结果
  144. let content = generatePrice(price);
  145. let span = queryList[appId].querySelector(".game_purchase_action_bg");
  146. if(!span)span = document.createElement("span");
  147. span.innerHTML = content;
  148. span.className = "game_purchase_action_bg";
  149. let a = queryList[appId].querySelector(".followed_game_actions a");
  150. a.parentElement.prepend(span);
  151. queryList[appId].hasPrice = true;
  152. }
  153. }
  154. catch(e){
  155. let content =
  156. `<span class="discount_block no_discount discount_block_inline" data-price-final="0">`+
  157. '<div class="discount_prices">'+
  158. `<div class="discount_final_price">Request Error</div>`+
  159. '</div>'+
  160. '</span>';
  161.  
  162. let appId;
  163. for(appId in queryList){
  164. if(queryList[appId].hasPrice==true)continue;
  165. let span = queryList[appId].querySelector(".game_purchase_action_bg");
  166. if(!span)span = document.createElement("span");
  167. span.innerHTML = content;
  168. span.className = "game_purchase_action_bg";
  169. let a = queryList[appId].querySelector(".followed_game_actions a");
  170. a.parentElement.prepend(span);
  171. queryList[appId].hasPrice = false;
  172. console.log(`Error:${appId}`);
  173. console.log(e);
  174. }
  175. }
  176. }
  177.  
  178. function handleTimeout(){
  179. let content =
  180. `<span class="discount_block no_discount discount_block_inline" data-price-final="0">`+
  181. '<div class="discount_prices">'+
  182. `<div class="discount_final_price">Request Timeout</div>`+
  183. '</div>'+
  184. '</span>';
  185.  
  186. let appId;
  187. for(appId in queryList){
  188. if(queryList[appId].hasPrice==true)continue;
  189. let span = queryList[appId].querySelector(".game_purchase_action_bg");
  190. if(!span)span = document.createElement("span");
  191. span.innerHTML = content;
  192. span.className = "game_purchase_action_bg";
  193. let a = queryList[appId].querySelector(".followed_game_actions a");
  194. a.parentElement.prepend(span);
  195. queryList[appId].hasPrice = false;
  196. console.log(`Timeout:${appId}`);
  197. }
  198. }
  199. }
  200.  
  201. function generatePrice(price){
  202. let content = "";
  203. let template = "";
  204. if(price.discount_percent==0){
  205. template =
  206. `<span class="discount_block no_discount discount_block_inline" data-price-final="${price.final}">`+
  207. '<div class="discount_prices">'+
  208. `<div class="discount_final_price">${price.final_formatted}</div>`+
  209. '</div>'+
  210. '</span>';
  211. }
  212. else {
  213. template =
  214. `<span class="discount_block discount_block_inline" data-price-final="${price.final}">`+
  215. `<div class="discount_pct">-${price.discount_percent}%</div>`+
  216. '<div class="discount_prices">'+
  217. `<div class="discount_original_price">${price.initial_formatted}</div>`+
  218. `<div class="discount_final_price">${price.final_formatted}</div>`+
  219. '</div>'+
  220. '</span>'
  221. }
  222. content+=template;
  223. return content;
  224. }
  225.  
  226. function isAppVisible(app){
  227. let s = app.offsetTop; // 元素相对于页面顶部的距离
  228. let x = app.offsetHeight; //元素自身高度
  229. let t = document.documentElement.scrollTop; // 页面在垂直方向上滚动的距离
  230. let y = document.documentElement.clientHeight; //窗口可视区域的高度
  231. let isHidden = (s+x) < t || (s > (t+y));
  232. return !isHidden
  233. }
  234. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址