网易 buff 增强脚本

比例计算 成交量显示 销售价显示

  1. // ==UserScript==
  2. // @icon https://store.steampowered.com/favicon.ico
  3. // @name 网易 buff 增强脚本
  4. // @namespace out
  5. // @version 0.23
  6. // @description 比例计算 成交量显示 销售价显示
  7. // @author bluebird
  8. // @match *://buff.163.com/market/*
  9. // @match *://buff.163.com/goods/*
  10. // @grant GM_addStyle
  11. // @grant GM_openInTab
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_setValue
  14. // @grant GM_getValue
  15. // @require https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js
  16. // @connect steamcommunity.com
  17. // @supportURL https://steamcommunity.com/id/bluebird2333/
  18.  
  19. // ==/UserScript==
  20.  
  21. const $ = window.jQuery;
  22.  
  23.  
  24. (function () {
  25. 'use strict';
  26.  
  27. $(document).ready(function () {
  28. if (window.location.href.match("buff.163.com/goods/.+")) {
  29. run();
  30. } else if (window.location.href.match("buff.163.com/market/?.+")) {
  31. searchFilter()
  32. }
  33. });
  34.  
  35.  
  36. })();
  37.  
  38.  
  39. var volumeNum = 0
  40. var data
  41.  
  42. function run() {
  43. let marketUrl = $('div.detail-summ > a').attr("href")
  44. let detail = $("div.detail-summ")
  45. detail.prepend("<div><ul class='pricelist' id='infolist'><li id='tradenum' class='yellow'></li></ul></div>")
  46. detail.prepend("<div class='warn'> <ul id='warnlist'></ul></div>")
  47. getItemVolume(marketUrl, goodsGetPrice, steamError)
  48. getPriceData(marketUrl, calc, steamError)
  49. }
  50.  
  51. function searchShowError() {
  52. $("#error").html("<h2 style='color:red'>steam网络错误</h2>")
  53. }
  54.  
  55. function searchFilter() {
  56. GM_addStyle(` .new-Counter {min-width: 120px;} .fix-input {width: 160px}`);
  57. $(".l_Layout>.blank20").after('<div class="market-header "><div class="criteria black"><div class="l_Left"> <label>筛选:</label> \
  58. <div class="w-Counter new-Counter" id="taade_num"> <div class="w-Counter-input w-Counter-input3 fix-input"> 最低交易量<input type="text" class="i_Text" name="min_trade" placeholder="" pattened="true"> </div></div> \
  59. <div class="w-Counter new-Counter" id="radio_num"><div class="w-Counter-input w-Counter-input3 fix-input"> 最低比例<input type="text" class="i_Text" name="min_radio" placeholder="" pattened="true"></div></div> \
  60. <div class="w-Search" id="start"><a href="javascript:;" ></i>开始</a> <div id="error"></div></div> \
  61. </div></div></div>')
  62.  
  63.  
  64. $(document).on("click", "#start", function () {
  65. console.log("开始过滤")
  66. let tradeNum = $("input[name=min_trade]")[0].value
  67. let radioNum = $("input[name=min_radio]")[0].value
  68.  
  69. if (!tradeNum && !radioNum) {
  70. console.log("无过滤数据")
  71. return
  72. }
  73.  
  74. let arg = window.location.href.replace(/#tab=.+?&/, "&").split("?")[1]
  75. console.log("开始请求")
  76.  
  77. for (var i of $("#j_list_card>>li>a")) {
  78. let url = i.href
  79. let delli = $(i).parents("li")
  80. let name = i.title
  81. let price = parseFloat(delli.children("p").children("strong").text().split(" ")[1])
  82. GM_xmlhttpRequest({
  83. method: "get",
  84. url: url,
  85. responseType: "json",
  86. timeout: 5000,
  87. onload: function (result) {
  88. if (result.status === 200 && result.responseText !== "null") {
  89. let marketUrl = result.responseText.match("(https://steamcommunity.com/market/listings/.+?)\"")[1]
  90. console.log(marketUrl)
  91. if (!marketUrl) {
  92. return
  93. }
  94.  
  95. if (tradeNum) {
  96. getItemVolume(marketUrl, function (result) {
  97. result = result.response;
  98. if (!result) {
  99. return
  100. }
  101. let volumeNum
  102. if (result.volume) {
  103. volumeNum = parseInt(result.volume.replace(/\, ?/gi, ''))
  104. } else {
  105. volumeNum = 0
  106. }
  107. if (volumeNum < tradeNum) {
  108.  
  109. delli.remove();
  110.  
  111. }
  112. console.log(name+"交易量"+volumeNum.toString())
  113. }
  114. , searchShowError)
  115. }
  116. if (radioNum) {
  117. getPriceData(marketUrl, function (result) {
  118. if (!result.lowest_sell_order) {
  119. return
  120. }
  121. console.log(price)
  122. let sell_min_price = price
  123. let calcLow = calcfee(parseInt(result.lowest_sell_order)) / 100
  124. let lowRatio = (sell_min_price / calcLow).toFixed(2)
  125. console.log(lowRatio)
  126. if (lowRatio > radioNum) {
  127. try {
  128. delli.remove();
  129. } catch {
  130.  
  131. }
  132. return
  133.  
  134. }else{
  135.  
  136. }
  137. console.log(name+"比例"+lowRatio.toString())
  138.  
  139. }, searchShowError
  140. )
  141. }
  142.  
  143.  
  144.  
  145. }
  146.  
  147.  
  148. }
  149. })
  150.  
  151. }
  152.  
  153. })
  154. }
  155.  
  156.  
  157. function calc(data) {
  158.  
  159. console.log(data)
  160. if (data && data.success) {
  161. console.log("获取数据成功")
  162. GM_addStyle(` .detail-cont > div.blank20 { height:5px;}
  163. .detail-summ span { display:none; margin-right:0px; }
  164. ..detail-summ a { float:right }
  165. .pricelist {font-size: 0.9rem; float:left}
  166. .red {color:red}
  167. .warn {font-size: 0.75rem;float:right}
  168. .yellow {color:yellow}
  169. `);
  170.  
  171. if (!data.lowest_sell_order && !data.highest_buy_order) {
  172. return;
  173. }
  174.  
  175. console.log("开始获取buff价格")
  176. let siteprice = getFloat($("table a.i_Btn:first").attr('data-price'));
  177. if (!siteprice) {
  178. siteprice = getFloat($("table strong.f_Strong:first").text() + $("table strong.f_Strong:first small").text());
  179. }
  180. if (!siteprice) {
  181. return
  182. }
  183.  
  184. let lowest = 0
  185. let highest = 0
  186. let calcLow = 0
  187. let calcHigh = 0
  188. let lowRatio = 0
  189. let highRatio = 0
  190.  
  191. if (data.highest_buy_order) {
  192. console.log("开始计算收购比例")
  193. highest = parseInt(data.highest_buy_order) / 100
  194. calcHigh = calcfee(parseInt(data.highest_buy_order)) / 100
  195. highRatio = (siteprice / calcHigh).toFixed(2)
  196. $("#infolist").append("<li class='yellow'>最高收购价格" + highest.toString() + " 比例:<strong>" + highRatio.toString() + "</strong></li>")
  197.  
  198. }
  199. if (data.lowest_sell_order) {
  200. console.log("开始计算销售比例")
  201. lowest = parseInt(data.lowest_sell_order) / 100
  202. calcLow = calcfee(parseInt(data.lowest_sell_order)) / 100
  203. lowRatio = (siteprice / calcLow).toFixed(2)
  204. $("#infolist").append("<li class='yellow'>最低出售价格" + lowest.toString() + " 比例:<strong>" + lowRatio.toString() + "</strong></li>")
  205.  
  206. }
  207. console.log("开始计算稳定价格和价格区间数量")
  208. let priceRange = (siteprice / 20).toFixed(2)
  209. let buyPriceMap = {1: 0, 2: 0}
  210. let stableBuyPrice = 0
  211. let buy_order_graph = data.buy_order_graph
  212. var tmp = 0
  213. for (let i = 0; i < buy_order_graph.length; i++) {
  214. let spread = highest - buy_order_graph[i][0]
  215. let itemNum = buy_order_graph[i][1]
  216. let rangeNum = Math.trunc(spread / priceRange) + 1
  217. if (rangeNum > 3) {
  218. break
  219. }
  220. buyPriceMap[rangeNum] += (itemNum - tmp)
  221. if ((itemNum - tmp) >= 5 & stableBuyPrice === 0) {
  222. stableBuyPrice = buy_order_graph[i][0]
  223. }
  224. tmp = itemNum
  225.  
  226. }
  227. if (stableBuyPrice != 0) {
  228. $("#infolist").append("<li>最高稳定收购价格:" + stableBuyPrice.toString() + " 比例:<strong>" + (siteprice * 100 / calcfee(stableBuyPrice * 100)).toFixed(2) + "</strong></li>")
  229. }
  230. let sellPriceMap = {1: 0, 2: 0}
  231. let stableSellPrice = 0
  232. let sell_order_graph = data.sell_order_graph
  233. tmp = 0
  234. for (let i = 0; i < sell_order_graph.length; i++) {
  235. let spread = sell_order_graph[i][0] - lowest
  236. let itemNum = sell_order_graph[i][1]
  237. let rangeNum = Math.trunc(spread / priceRange) + 1
  238. if (rangeNum > 3) {
  239. break
  240. }
  241. sellPriceMap[rangeNum] += (itemNum - tmp)
  242. if ((itemNum - tmp) >= 5 & stableSellPrice === 0) {
  243. stableSellPrice = sell_order_graph[i][0]
  244. }
  245. tmp = itemNum
  246.  
  247. }
  248. if (stableSellPrice != 0) {
  249. $("#infolist").append("<li>最低稳定出售价格:" + stableSellPrice.toString() + " 比例:<strong>" + (siteprice * 100 / calcfee(stableSellPrice * 100)).toFixed(2) + "</strong></li>")
  250. }
  251.  
  252.  
  253. if (highRatio > 0.8) {
  254. // info = info + "<li class='red'>比例过低</li>"
  255. $("#warnlist").append("<li class='red'>比例过低</li>")
  256. }
  257.  
  258.  
  259. if (buy_order_graph.length !== 0 && buyPriceMap[1] < 5) {
  260. $("#warnlist").append("<li class='red'>目前最高收购价格区间(5%)仅有" + buyPriceMap[1].toString() + "件请谨慎购买</li>")
  261. }
  262.  
  263. if (sell_order_graph.length !== 0 && sellPriceMap[1] < 5) {
  264. $("#warnlist").append("<li class='red'>目前最低出售价格区间(5%)仅有" + sellPriceMap[1].toString() + "件请谨慎购买</li>")
  265. }
  266.  
  267.  
  268. }
  269.  
  270.  
  271. }
  272.  
  273.  
  274. function getItemVolume(marketUrl, onLoad, onError) {
  275. let oriLink = marketUrl.split('/');
  276. let appid = oriLink[oriLink.length - 2];
  277. oriLink = oriLink[oriLink.length - 1];
  278. GM_xmlhttpRequest({
  279. method: "get",
  280. url: `https://steamcommunity.com/market/priceoverview/?appid=${appid}&market_hash_name=${oriLink}`,
  281. responseType: "json",
  282. timeout: 5000,
  283. onload: onLoad,
  284. ontimeout: onError,
  285. onerror: onError
  286. });
  287. }
  288.  
  289. function goodsGetPrice(result) {
  290. if (result.status !== 200){
  291. $("#tradenum").attr("class","red")
  292. if(result.status === 429){
  293. $("#tradenum").html("api请求过多造成限制 推荐换个加速器或梯子")
  294. }else{
  295. $("#tradenum").html("请求销售量发生网络错误 错误码"+result.status)
  296. }
  297. return
  298. }
  299. result = result.response;
  300. if (result.volume) {
  301. volumeNum = parseInt(result.volume.replace(/\, ?/gi, ''))
  302. } else {
  303. volumeNum = 0
  304. }
  305. $("#tradenum").html("24小时出售量 :<strong>" + volumeNum.toString() + "</strong>")
  306. if (volumeNum < 100) {
  307. $("#warnlist").append("<li class='red'>每日销售量过低请谨慎购买</li>")
  308. }
  309.  
  310. }
  311.  
  312.  
  313. function getPriceData(marketUrl, precess, onError) {
  314. GM_xmlhttpRequest({
  315. method: "GET",
  316. url: marketUrl,
  317. timeout: 5000,
  318. onload: function (res) {
  319. console.log("req ok ")
  320. if (res.status === 200 && res.responseText !== "null") {
  321. console.log("req status ok ")
  322. var g_sessionID
  323. var g_strCountryCode
  324. var g_strLanguage
  325. var g_walletCurrency
  326.  
  327. try{
  328. g_sessionID = res.responseText.match(/g_sessionID = "([^"]+)"/)[1];
  329. g_walletCurrency = parseInt(res.responseText.match(/"wallet_currency":(\d+)/)[1]);
  330. g_strLanguage = res.responseText.match(/g_strLanguage = "([^"]+)"/)[1];
  331. g_strCountryCode = res.responseText.match(/g_strCountryCode = "([^"]+)"/)[1];
  332. }
  333. catch(err){
  334. g_strCountryCode = "CN"
  335. g_strLanguage = "schinese";
  336. g_walletCurrency = 23
  337. }
  338. try {
  339. var nameid = res.responseText.match(/Market_LoadOrderSpread\( (\d+)/)[1];
  340. } catch (err) {
  341. if (res.responseText.indexOf('market_listing_nav_container') != -1) {
  342. // steamxj();
  343. return;
  344. }
  345. }
  346. GM_xmlhttpRequest({
  347. timeout: 5000,
  348. method: "GET",
  349. url: "https://steamcommunity.com/market/itemordershistogram?country=CN&language=schinese&currency=23&item_nameid=" + nameid,
  350. responseType: "json",
  351. onload: function (data) {
  352. var obj = data.response;
  353. data = obj
  354. precess(data)
  355. }
  356. }
  357. )
  358. }
  359.  
  360. },
  361. ontimeout: onError,
  362. onerror: onError
  363. }
  364. )
  365. }
  366.  
  367. function steamError() {
  368. $("div.detail-summ").append("<h1>无法获取steam市场数据 可能是请求频率过高或无法连接steam</h1>");
  369. }
  370.  
  371.  
  372. function calcfee(price) {
  373. let p = Math.round(price)
  374. var pnofee = Math.max(Math.floor(p / 1.15), 1);
  375. var vfee = Math.max(Math.floor(pnofee * 0.1), 1);
  376. var pfee = Math.max(Math.floor(pnofee * 0.05), 1);
  377. while ((pnofee + vfee + pfee) != p) {
  378. if ((pnofee + vfee + pfee) > p) {
  379. pnofee--;
  380. }
  381. if ((pnofee + vfee + pfee) < p) {
  382. pnofee++;
  383. }
  384. vfee = Math.max(Math.floor(pnofee * 0.1), 1);
  385. pfee = Math.max(Math.floor(pnofee * 0.05), 1);
  386. }
  387. return pnofee;
  388. }
  389.  
  390.  
  391. function getFloat(str) {
  392. try {
  393. var f = parseFloat(str.match(/[\d]{1,}(\.\d+)?/)[0]);
  394. } catch (err) {
  395. return 0;
  396. }
  397. return f;
  398.  
  399. }