显示Steam游戏在线人数

在Steam商店页右侧信息面板增加在线人数, 便于观察游戏的实际热度

  1. // ==UserScript==
  2. // @name 显示Steam游戏在线人数
  3. // @description 在Steam商店页右侧信息面板增加在线人数, 便于观察游戏的实际热度
  4. // @icon https://store.steampowered.com/favicon.ico
  5. // @version 1.7
  6. // @author cweijan
  7. // @namespace cweijan/steam_online_players
  8. // @license MIT
  9. // @run-at document-start
  10. // @grant GM_xmlhttpRequest
  11. // @include *store.steampowered.com/app/*
  12. // ==/UserScript==
  13.  
  14. function makeElement(htmlString) {
  15. var div = document.createElement('div');
  16. div.innerHTML = htmlString.trim();
  17. return div.firstChild;
  18. }
  19.  
  20.  
  21. let onlineTextNode, onedayPeakTextNode;
  22. let initText = GM_xmlhttpRequest ? '数据加载中' : '无网络权限!', onedayInitText = initText
  23. const appId = location.href.match(/app\/(\d+)/)?.[1];
  24.  
  25. function colorization(msg, node) {
  26. let color = '#848683';
  27. if (Number.isNaN(parseInt(msg))) return color;
  28. if (msg > 100000) {
  29. color = '#e72424'
  30. } else if (msg > 50000) {
  31. color = '#ce3a3a'
  32. } else if (msg > 10000) {
  33. color = '#7cc53f'
  34. } else if (msg > 3000) {
  35. color = '#579227'
  36. }
  37. if (node) {
  38. node.setAttribute('style', `color: ${color}`)
  39. }
  40. return color;
  41. }
  42.  
  43. function fillText(msg, type) {
  44. if (type == 'peak') {
  45. if (onedayPeakTextNode) {
  46. onedayPeakTextNode.textContent = msg
  47. colorization(msg, onedayPeakTextNode)
  48. }
  49. else onedayInitText = msg
  50. return;
  51. }
  52. if (onlineTextNode) {
  53. onlineTextNode.textContent = msg
  54. colorization(msg, onlineTextNode)
  55. }
  56. else initText = msg
  57. }
  58.  
  59. if (GM_xmlhttpRequest) {
  60. // 接口参考: https://partner.steamgames.com/doc/webapi/ISteamUserStats#GetNumberOfCurrentPlayers
  61. GM_xmlhttpRequest({
  62. method: "GET",
  63. url: `https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=${appId}`,
  64. onload(response) {
  65. try {
  66. const playerCount = JSON.parse(response.responseText).response.player_count;
  67. fillText(playerCount || 0)
  68. } catch (error) {
  69. fillText(`解析API返回值失败:${response.responseText}`)
  70. }
  71. },
  72. onerror(response) {
  73. console.log(response)
  74. fillText("请求失败")
  75. }
  76. })
  77. GM_xmlhttpRequest({
  78. method: "GET",
  79. url: `https://steamcharts.com/app/${appId}`,
  80. onload(response) {
  81. try {
  82. const playerCount = response.responseText.match(/(?<="num">)(\d+)/g)[1];
  83. fillText(playerCount, 'peak')
  84. } catch (error) {
  85. fillText(`解析返回值失败`, 'peak')
  86. }
  87. },
  88. onerror(response) {
  89. console.log(response)
  90. fillText("请求失败", 'peak')
  91. }
  92. })
  93. }
  94.  
  95. let addedHistory = false;
  96. const observer = new MutationObserver(mutationList => {
  97. for (var mutation of mutationList) {
  98. for (var node of mutation.addedNodes) {
  99. if (!node.querySelectorAll) continue;
  100. if (node.getAttribute("class") == 'btn_addtocart' && !addedHistory) {
  101. addedHistory = true;
  102. // 增加历史价格记录
  103. const historyBtnHtml = `<div class="btn_addtocart"><a class="btn_blue_steamui btn_medium" href="https://steamdb.info/app/${appId}/#pricehistory" target="_blank"> <span>查看历史价格</span> </a></div>`
  104. node.parentNode.insertBefore(makeElement(historyBtnHtml), node)
  105. } else if (node.getAttribute("id") == 'userReviews') {
  106. // 增加查看所有评价的链接
  107. node.appendChild(makeElement(`<a style="padding-left: 104px;" target="_blank" href="https://steamcommunity.com/app/${appId}/reviews?browsefilter=toprated">浏览所有评测</a>`))
  108. // 当前正在玩
  109. const html = `<div class="user_reviews">
  110. <div class="user_reviews_summary_row">
  111. <div class="subtitle column">在玩人数:</div>
  112. <div class="summary column">
  113. <span id="onlinePlayers" style="color: ${colorization(initText)};">${initText}</span>
  114. </div>
  115. </div>
  116. <div class="user_reviews_summary_row">
  117. <div class="subtitle column">24小时峰值:</div>
  118. <div class="summary column">
  119. <span id="onedayPeakPlayers" style="color: ${colorization(onedayInitText)};">${onedayInitText}</span>
  120. </div>
  121. </div>
  122. </div>`
  123. // node.insertBefore(makeElement(html), node.firstChild)
  124. node.parentNode.insertBefore(makeElement(html), node)
  125. onlineTextNode = document.getElementById('onlinePlayers')
  126. onedayPeakTextNode = document.getElementById('onedayPeakPlayers')
  127. }
  128. }
  129. }
  130. });
  131.  
  132. observer.observe(document, { childList: true, subtree: true });

QingJ © 2025

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