Bundle Helper

Add tools for many bundle sites.

目前为 2017-04-10 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Bundle Helper
  3. // @namespace iFantz7E.BundleHelper
  4. // @version 0.15
  5. // @description Add tools for many bundle sites.
  6. // @match *://www.hrkgame.com/*
  7. // @match *://www.bundlestars.com/*/bundle/*
  8. // @match *://www.bundlestars.com/*/promotions/*
  9. // @match *://www.reddit.com/r/*/comments/*
  10. // @match *://groupees.com/*
  11. // @match *://www.indiegala.com/*
  12. // @match *://cubicbundle.com/*
  13. // @match *://www.dailyindiegame.com/*
  14. // @match *://dailyindiegame.com/*
  15. // @match *://www.bundlekings.com/*
  16. // @match *://www.orlygift.com/*
  17. // @match *://otakumaker.com/*
  18. // @match *://www.otakumaker.com/*
  19. // @match *://www.superduperbundle.com/*
  20. // @match *://www.humblebundle.com/*
  21. // @match *://store.steampowered.com/widget/*
  22. // @match *://store.steampowered.com/app/*
  23. // @match *://store.steampowered.com/account/notinterested/*
  24. // @match *://steamcommunity.com/*/home*
  25. // @match *://steamcommunity.com/groups/*/announcements*
  26. // @match *://forums.steampowered.com/forums/showthread.php?*
  27. // @match *://www.gamebundle.com/*
  28. // @match *://steamcompanion.com/gifts/*
  29. // @match *://whosgamingnow.net/*
  30. // @match *://steamground.com/*
  31. // @match *://www.bunchkeys.com/*
  32. // @run-at document-start
  33. // @grant GM_addStyle
  34. // @grant GM_xmlhttpRequest
  35. // @connect store.steampowered.com
  36. // @connect www.hrkgame.com
  37. // @connect www.bundlestars.com
  38. // @connect www.steamgifts.com
  39. // @icon http://store.steampowered.com/favicon.ico
  40. // @copyright 2016, 7-elephant
  41. // ==/UserScript==
  42.  
  43. //// Connect to store.steampowered.com to get owner info
  44. //// Connect to www.hrkgame.com and www.bundlestars.com to get Steam ID of each products
  45. //// Connect to www.steamgifts.com to get bundle threads
  46.  
  47. (function ()
  48. {
  49. function attachOnLoad(callback)
  50. {
  51. window.addEventListener("load", function (e)
  52. {
  53. callback();
  54. });
  55. }
  56.  
  57. function attachOnReady(callback)
  58. {
  59. document.addEventListener("DOMContentLoaded", function (e)
  60. {
  61. callback();
  62. });
  63. }
  64.  
  65. function insertBeforeElement(newNode, referenceNode)
  66. {
  67. referenceNode.parentNode.insertBefore(newNode, referenceNode);
  68. }
  69.  
  70. function insertAfterElement(newNode, referenceNode)
  71. {
  72. referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  73. }
  74.  
  75. function reload()
  76. {
  77. var curHref = window.location.href;
  78. var posHashtag = curHref.indexOf("#");
  79. if (posHashtag > -1)
  80. {
  81. window.location = curHref.substr(0, posHashtag);
  82. }
  83. else
  84. {
  85. window.location = curHref;
  86. }
  87. }
  88. function getQueryByName(name, url)
  89. {
  90. if (url == null)
  91. {
  92. url = location == null ? "" : location.search;
  93. }
  94. name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
  95. var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
  96. var results = regex.exec(url);
  97. var retVal = "";
  98. if (results != null)
  99. {
  100. retVal = results[1].replace(/\+/g, " ");
  101. try
  102. {
  103. retVal = decodeURIComponent(retVal);
  104. }
  105. catch (ex)
  106. {
  107. console.error("getQueryByName", ex.message);
  108. }
  109. }
  110. return retVal;
  111. }
  112.  
  113. function clickToSelect(ele)
  114. {
  115. if (ele != null)
  116. {
  117. var range = document.createRange();
  118. range.setStartBefore(ele.firstChild);
  119. range.setEndAfter(ele.lastChild);
  120.  
  121. var sel = window.getSelection();
  122. sel.removeAllRanges();
  123. sel.addRange(range);
  124. }
  125. }
  126. function normalizeArray(arr)
  127. {
  128. arr = arr.filter(function(elem, index, self)
  129. {
  130. return index == self.indexOf(elem);
  131. });
  132. return arr;
  133. }
  134. function randNum(min, max)
  135. {
  136. return Math.round(Math.random() * (max - min) + min);
  137. }
  138. function markOwned(query, markOwnedCallback)
  139. {
  140. var rgxId = /[0-9]{3,}/g;
  141. var rgxApp = /:\/\/((store\.steampowered|steamcommunity)\.com\/app|cdn.akamai.steamstatic.com\/steam\/apps)\/[0-9]+/i;
  142. var rgxSub = /:\/\/store\.steampowered\.com\/sub\/[0-9]+/i;
  143. GM_xmlhttpRequest(
  144. {
  145. method: "GET",
  146. url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
  147. onload: function(response)
  148. {
  149. var dataRes = JSON.parse(response.responseText);
  150. var countOwned = [0, 0];
  151. var countAll = [0, 0];
  152. if (typeof dataRes["rgOwnedApps"] !== "undefined"
  153. && typeof dataRes["rgOwnedPackages"] !== "undefined"
  154. && typeof dataRes["rgIgnoredApps"] !== "undefined")
  155. {
  156. var eleApps = document.querySelectorAll(query);
  157. for (var i = 0; i < eleApps.length; i++)
  158. {
  159. var attrHref = eleApps[i].getAttribute("href") || eleApps[i].getAttribute("src");
  160. var ids = attrHref.match(rgxId);
  161. if (ids != null)
  162. {
  163. var valId = parseInt(ids[0]);
  164. if (rgxApp.test(attrHref))
  165. {
  166. if (dataRes["rgOwnedApps"].indexOf(valId) > -1)
  167. {
  168. markOwnedCallback(eleApps[i]);
  169. countOwned[0]++;
  170. }
  171. else
  172. {
  173. console.log("App: not owned - http://store.steampowered.com/app/" + valId + "/");
  174. }
  175. countAll[0]++;
  176. }
  177. else if (rgxSub.test(attrHref))
  178. {
  179. if (dataRes["rgOwnedPackages"].indexOf(valId) > -1)
  180. {
  181. markOwnedCallback(eleApps[i]);
  182. countOwned[1]++;
  183. }
  184. else
  185. {
  186. console.log("Sub: not owned - http://store.steampowered.com/sub/" + valId + "/");
  187. }
  188. countAll[1]++;
  189. }
  190. }
  191. }
  192. }
  193. var diff = countAll[0] - countOwned[0];
  194. console.log("App: " + countOwned[0] + "/" + countAll[0] + (diff > 10 ? " Diff: " + diff : ""));
  195. console.log("Sub: " + countOwned[1] + "/" + countAll[1]);
  196. } // End onload
  197. });
  198. }
  199. function markOwned_old(query, getLabelCallback)
  200. {
  201. var apps = [];
  202. var eleApps = document.querySelectorAll(query);
  203. for (var i = 0; i < eleApps.length; i++)
  204. {
  205. var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
  206. if (app != null)
  207. {
  208. apps.push(app[0]);
  209. }
  210. }
  211. apps = apps.filter(function(elem, index, self)
  212. {
  213. return index == self.indexOf(elem);
  214. });
  215. console.log("Apps: " + apps.length);
  216. var appAll = apps.join(",");
  217. GM_xmlhttpRequest(
  218. {
  219. method: "GET",
  220. headers:
  221. {
  222. "Cache-Control": "max-age=0"
  223. },
  224. url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
  225. onload: function(response)
  226. {
  227. var dataRes = JSON.parse(response.responseText);
  228. var countOwned = 0;
  229. var eleApps = document.querySelectorAll(query);
  230. for (var i = 0; i < eleApps.length; i++)
  231. {
  232. var appUrl = eleApps[i].getAttribute("href");
  233. if (appUrl.indexOf("http://store.steampowered.com/app/") > -1)
  234. {
  235. var app = /[0-9]+/.exec(appUrl);
  236. if (app != null)
  237. {
  238. if (typeof dataRes[app] !== "undefined")
  239. {
  240. if (dataRes[app].success)
  241. {
  242. if (dataRes[app].data.is_owned)
  243. {
  244. var eleLabel = getLabelCallback(eleApps[i]);
  245. eleLabel.classList.add("bh_owned");
  246. countOwned++;
  247. }
  248. else
  249. {
  250. console.log("App: not owned - http://store.steampowered.com/app/" + app + "/");
  251. }
  252. }
  253. else
  254. {
  255. console.log("App: not success - https://steamdb.info/app/" + app + "/");
  256. }
  257. }
  258. }
  259. }
  260. }
  261. console.log("Apps: owned - " + countOwned);
  262. } // End onload
  263. });
  264. }
  265.  
  266. function main()
  267. {
  268. // #8BC349
  269. // #6EA028
  270. // #2ECC71
  271. // #92B300
  272. GM_addStyle(
  273. " .bh_button { "
  274. + " border-radius: 2px; border: medium none; padding: 10px; display: inline-block; "
  275. + " cursor: pointer; background: #67C1F5 none repeat scroll 0% 0%; "
  276. + " width: 120px; text-align: center; } "
  277. + " .bh_button a { "
  278. + " text-decoration: none !important; color: #FFF !important; "
  279. + " padding: 0px 2px; } "
  280. + " .bh_button:hover a { "
  281. + " color: #0079BF !important; } "
  282. + " .bh_button, .bh_button a { "
  283. + " font-family: Verdana; font-size: 12px; "
  284. + " line-height: 16px; } "
  285. + " .bh_owned { background-color: #7CA156 !important; "
  286. + " transition: background 500ms ease 0s; } "
  287. + " #bh_markOwned { "
  288. + " position: fixed; right: 20px; bottom: 20px; z-index:3; } "
  289. + " #bh_OpenLib { "
  290. + " position: fixed; right: 20px; bottom: 65px; z-index:3; } "
  291. );
  292. var url = document.documentURI;
  293. if (url.indexOf("hrkgame.com") > -1)
  294. {
  295. if (window !== window.parent)
  296. return;
  297. GM_addStyle(
  298. " .bh_owned { background-color: #97BA22 !important; } "
  299. + " #bh_markOwned { bottom: 40px !important; } "
  300. );
  301. if (url.indexOf("/randomkeyshop/make-bundle") > -1)
  302. {
  303. // Add load button
  304. {
  305. var divButton = document.createElement("div");
  306. divButton.classList.add("bh_button");
  307. divButton.id = "bh_loadAll";
  308. divButton.setAttribute("style", "bottom: 86px;");
  309. divButton.setAttribute("onclick", " \
  310. this.firstElementChild.textContent = \"Loading...\"; \
  311. window.scrollTo(0,document.body.scrollHeight); \
  312. var countHidden = 5; \
  313. var idx = setInterval(function(ele) \
  314. { \
  315. var eleLoad = document.querySelector(\"#loader-icon\"); \
  316. if (eleLoad) \
  317. { \
  318. window.scrollTo(0,document.body.scrollHeight); \
  319. if (eleLoad.style.display == \"none\") \
  320. { \
  321. countHidden--; \
  322. } \
  323. else \
  324. { \
  325. countHidden = 5; \
  326. } \
  327. } \
  328. else \
  329. { \
  330. countHidden--; \
  331. } \
  332. if (countHidden < 0) \
  333. { \
  334. clearInterval(idx); \
  335. ele.style.display=\"none\"; \
  336. var eleRes = document.querySelector(\"#result\"); \
  337. if (eleRes) \
  338. { \
  339. eleRes.scrollIntoView(true); \
  340. window.scrollBy(0, -80); \
  341. } \
  342. } \
  343. }, 500, this); \
  344. return false; \
  345. ");
  346. divButton.innerHTML = "<a onclick='return false;'>Load All</a>";
  347. document.body.appendChild(divButton);
  348. }
  349. // Add mark button
  350. {
  351. var divButton = document.createElement("div");
  352. divButton.classList.add("bh_button");
  353. divButton.id = "bh_markOwned";
  354. var eleA = document.createElement("a");
  355. eleA.setAttribute("onclick", "return false;");
  356. eleA.textContent = "Mark Owned";
  357. divButton.appendChild(eleA);
  358. document.body.appendChild(divButton);
  359. divButton.addEventListener("click", function()
  360. {
  361. GM_xmlhttpRequest(
  362. {
  363. method: "GET",
  364. url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
  365. onload: function(response)
  366. {
  367. var dataResSteam = JSON.parse(response.responseText);
  368. if (typeof dataResSteam["rgOwnedApps"] == "undefined"
  369. || dataResSteam["rgOwnedApps"].length == 0)
  370. {
  371. console.log("not logged in");
  372. }
  373. else if (typeof dataResSteam["rgOwnedApps"] !== "undefined"
  374. && typeof dataResSteam["rgOwnedPackages"] !== "undefined"
  375. && typeof dataResSteam["rgIgnoredApps"] !== "undefined")
  376. {
  377. var parser = new DOMParser();
  378. var rgxId = /[0-9]+/;
  379. var rgxApp = /:\/\/store\.steampowered\.com\/app\/[0-9]+/i;
  380. var rgxSub = /:\/\/store\.steampowered\.com\/sub\/[0-9]+/i;
  381. var elesProduct = document.querySelectorAll("#result .content:not(.bh_owned)");
  382. var productCur = 0;
  383. var tmId = setInterval(function()
  384. {
  385. if (productCur >= elesProduct.length)
  386. {
  387. clearInterval(tmId);
  388. }
  389. else
  390. {
  391. var dataHref = elesProduct[productCur].firstElementChild.getAttribute("data-href");
  392. if (dataHref != null)
  393. {
  394. var fullHref = "https://www.hrkgame.com" + dataHref + "/";
  395. elesProduct[productCur].setAttribute("bh_href", fullHref);
  396. GM_xmlhttpRequest(
  397. {
  398. method: "GET",
  399. url: fullHref,
  400. onload: function(response)
  401. {
  402. var isOwned = false;
  403. var dataRes = parser.parseFromString(response.responseText, "text/html");
  404. var eleA = dataRes.querySelector(".storeside a.item[href*='store.steampowered.com/']");
  405. if (eleA != null)
  406. {
  407. var attrHref = eleA.href;
  408. var id = rgxId.exec(attrHref);
  409. if (id != null)
  410. {
  411. var valId = parseInt(id);
  412. if (rgxApp.test(attrHref))
  413. {
  414. if (dataResSteam["rgOwnedApps"].indexOf(valId) > -1)
  415. {
  416. isOwned = true;
  417. }
  418. else
  419. {
  420. console.log("App: not owned - http://store.steampowered.com/app/" + id + "/");
  421. }
  422. }
  423. else if (rgxSub.test(attrHref))
  424. {
  425. if (dataResSteam["rgOwnedPackages"].indexOf(valId) > -1)
  426. {
  427. isOwned = true;
  428. }
  429. else
  430. {
  431. console.log("Sub: not owned - http://store.steampowered.com/sub/" + id + "/");
  432. }
  433. }
  434. if (isOwned)
  435. {
  436. for (var i = 0; i < elesProduct.length; i++)
  437. {
  438. if (elesProduct[i].getAttribute("bh_href") == response.finalUrl)
  439. {
  440. elesProduct[i].classList.add("bh_owned");
  441. break;
  442. }
  443. }
  444. }
  445. }
  446. }
  447. else
  448. {
  449. console.log("Info: not found - " + response.finalUrl);
  450. }
  451. } // End onload
  452. });
  453. }
  454. }
  455. productCur++
  456. }, 200);
  457. }
  458. } // End onload
  459. });
  460. });
  461. }
  462. }
  463. else if (url.indexOf("/library") > -1)
  464. {
  465. var clientScript = ' \
  466. confirm = function() \
  467. { \
  468. return true; \
  469. }; \
  470. ';
  471.  
  472. var eleClientScript = document.createElement("script");
  473. eleClientScript.innerHTML = clientScript;
  474. document.head.appendChild(eleClientScript);
  475. }
  476. }
  477. else if (url.indexOf("bundlestars.com") > -1)
  478. {
  479. GM_addStyle(
  480. //" .bh_owned { background-color: #A7CC00 !important; } "
  481. " .bh_owned { background-color: #D0FE00 !important; } "
  482. + " .bh_owned:hover { background-color: #BBE500 !important; } "
  483. + " .bh_owned * { color: #444 !important; } "
  484. + " .bh_owned .was, .bh_owned .was * { color: #777 !important; } "
  485. + " .bh_owned .hide-checkbox + label span { color: #DDD !important; } "
  486. + " .bh_owned .hide-checkbox:checked + label span { color: #D0FE00 !important; } "
  487. + " #launcher { bottom: 100px !important; } "
  488. );
  489. if (url.indexOf("/bundle/") > -1)
  490. {
  491. // Add mark button
  492. {
  493. var divButton = document.createElement("div");
  494. divButton.classList.add("bh_button");
  495. divButton.id = "bh_markOwned";
  496. var eleA = document.createElement("a");
  497. eleA.setAttribute("onclick", "return false;");
  498. eleA.textContent = "Mark Owned";
  499. divButton.appendChild(eleA);
  500. document.body.appendChild(divButton);
  501. divButton.addEventListener("click", function()
  502. {
  503. markOwned(".bundle-accordian a.btn-bundle-more[href*='store.steampowered.com/']", function(ele)
  504. {
  505. ele.parentElement.parentElement
  506. .parentElement.parentElement.parentElement
  507. .parentElement.parentElement.parentElement
  508. .parentElement.firstElementChild
  509. .classList.add("bh_owned");
  510. });
  511. });
  512. }
  513. }
  514. else if (url.indexOf("/promotions/") > -1)
  515. {
  516. // Add mark button
  517. {
  518. var divButton = document.createElement("div");
  519. divButton.classList.add("bh_button");
  520. divButton.id = "bh_markOwned";
  521. var eleA = document.createElement("a");
  522. eleA.setAttribute("onclick", "return false;");
  523. eleA.textContent = "Mark Owned";
  524. divButton.appendChild(eleA);
  525. document.body.appendChild(divButton);
  526. divButton.param_promo = url.substr(url.indexOf("/promotions/") + 12)
  527. .replace(/\?.*/, "").replace(/#.*/, "");
  528. eleA.param_promo = divButton.param_promo;
  529. divButton.addEventListener("click", function(e)
  530. {
  531. var promo = e.target.param_promo;
  532. GM_xmlhttpRequest(
  533. {
  534. method: "GET",
  535. url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
  536. onload: function(response)
  537. {
  538. var dataResSteam = JSON.parse(response.responseText);
  539. if (typeof dataResSteam["rgOwnedApps"] == "undefined"
  540. || dataResSteam["rgOwnedApps"].length == 0)
  541. {
  542. console.log("not logged in");
  543. }
  544. else if (typeof dataResSteam["rgOwnedApps"] !== "undefined"
  545. && typeof dataResSteam["rgOwnedPackages"] !== "undefined"
  546. && typeof dataResSteam["rgIgnoredApps"] !== "undefined")
  547. {
  548. var elesProduct = document.querySelectorAll(".bs-card-body:not(.bh_owned)");
  549. for (var i = 0; i < elesProduct.length; i++)
  550. {
  551. var sref = elesProduct[i].firstElementChild.getAttribute("ui-sref");
  552. if (sref != null)
  553. {
  554. elesProduct[i].setAttribute("bh_slug"
  555. , sref.replace("base.game({ slug: '", "")
  556. .replace("base.dlc({ slug: '", "")
  557. .replace("' })", ""));
  558. }
  559. }
  560. GM_xmlhttpRequest(
  561. {
  562. method: "GET",
  563. url: "https://www.bundlestars.com/api/promotions/" + promo,
  564. onload: function(response)
  565. {
  566. var dataRes = JSON.parse(response.responseText);
  567. var slugs = [];
  568. var i = dataRes.length - 1;
  569. //for (var i = 0; i < dataRes.length; i++)
  570. {
  571. for (var j = 0; j < dataRes[i].products.length; j++)
  572. {
  573. if (dataRes[i].products[j].drm.steam)
  574. {
  575. slugs.push(dataRes[i].products[j].slug);
  576. }
  577. }
  578. }
  579. slugs = normalizeArray(slugs);
  580. var slugCur = 0;
  581. var tmId = setInterval(function()
  582. {
  583. if (slugCur >= slugs.length)
  584. {
  585. clearInterval(tmId);
  586. }
  587. else
  588. {
  589. GM_xmlhttpRequest(
  590. {
  591. method: "GET",
  592. url: "https://www.bundlestars.com/api/products/" + slugs[slugCur],
  593. onload: function(response)
  594. {
  595. var isOwned = false;
  596. var dataRes = JSON.parse(response.responseText);
  597. if (!dataRes.steam.sub)
  598. {
  599. if (dataResSteam["rgOwnedApps"].indexOf(dataRes.steam.id) > -1)
  600. {
  601. isOwned = true;
  602. }
  603. else
  604. {
  605. console.log("App: not owned - http://store.steampowered.com/app/" + dataRes.steam.id + "/ - " + dataRes.slug);
  606. }
  607. }
  608. else
  609. {
  610. if (dataResSteam["rgOwnedPackages"].indexOf(dataRes.steam.id) > -1)
  611. {
  612. isOwned = true;
  613. }
  614. else
  615. {
  616. console.log("Sub: not owned - http://store.steampowered.com/sub/" + dataRes.steam.id + "/ - " + dataRes.slug);
  617. }
  618. }
  619. if (isOwned)
  620. {
  621. for (var i = 0; i < elesProduct.length; i++)
  622. {
  623. if (elesProduct[i].getAttribute("bh_slug") == dataRes.slug)
  624. {
  625. elesProduct[i].classList.add("bh_owned");
  626. break;
  627. }
  628. }
  629. }
  630. } // End onload
  631. });
  632. }
  633. slugCur++;
  634. }, 200);
  635. } // End onload
  636. });
  637. }
  638. } // End onload
  639. });
  640. });
  641. }
  642. }
  643. }
  644. else if (url.indexOf("reddit.com") > -1)
  645. {
  646. GM_addStyle(
  647. " .bh_owned , .md .bh_owned code { background-color: #DFF0D8 !important; } "
  648. + " li > .bh_owned { padding: 0px 2px 0px 2px; } "
  649. );
  650. // Add mark button
  651. {
  652. var divButton = document.createElement("div");
  653. divButton.classList.add("bh_button");
  654. divButton.id = "bh_markOwned";
  655. var eleA = document.createElement("a");
  656. eleA.setAttribute("onclick", "return false;");
  657. eleA.textContent = "Mark Owned";
  658. divButton.appendChild(eleA);
  659. //document.body.appendChild(divButton);
  660. divButton.addEventListener("click", function()
  661. {
  662. markOwned("td > a[href*='store.steampowered.com/']", function(ele)
  663. {
  664. ele.parentElement.parentElement.classList.add("bh_owned");
  665. });
  666. });
  667. }
  668. setTimeout(function()
  669. {
  670. markOwned("td > a[href*='store.steampowered.com/']", function(ele)
  671. {
  672. ele.parentElement.parentElement.classList.add("bh_owned");
  673. });
  674. markOwned("li > a[href*='store.steampowered.com/']", function(ele)
  675. {
  676. ele.classList.add("bh_owned");
  677. });
  678. }, 1000);
  679. }
  680. else if (url.indexOf("groupees.com") > -1)
  681. {
  682. GM_addStyle(
  683. " .bh_owned { background-color: #DFF0D8 !important; } "
  684. + " #subscribe-form { display: none; } "
  685. + " input[name='search'] { position: fixed; z-index: 1099; left: 18%; top: 16px; } "
  686. + " button[role='show3dKeyModal'] { position: fixed; z-index: 1099; left: 72%; top: 16px; } "
  687. + " .cancel-spin { position: fixed !important; z-index: 1099 !important; left: 39.5% !important; top: 22px !important; } "
  688. + " .bh_owned_dark { background-color: rgba(140, 197, 63, 0.6) !important; } "
  689. );
  690. /*
  691. var a = document.querySelector("input[name='search']");
  692. var b = document.querySelector("#subscribe-form");
  693. b.parentElement.insertBefore(a,b);
  694. b.parentElement.removeChild(b);
  695. */
  696. // Add mark button
  697. {
  698. var divButton = document.createElement("div");
  699. divButton.classList.add("bh_button");
  700. divButton.id = "bh_markOwned";
  701. var eleA = document.createElement("a");
  702. eleA.setAttribute("onclick", "return false;");
  703. eleA.textContent = "Mark Owned";
  704. divButton.appendChild(eleA);
  705. document.body.appendChild(divButton);
  706. divButton.addEventListener("click", function()
  707. {
  708. var apps = [];
  709. var eleApps = document.querySelectorAll(".bundle > .products .info .description a[href*='store.steampowered.com/app/']"
  710. + ", .expanded .product-info a[href*='store.steampowered.com/app/']"
  711. + ", .product-details.hidden .external-links a[href*='store.steampowered.com/app/']");
  712. console.log("Apps: " + eleApps.length);
  713. for (var i = 0; i < eleApps.length; i++)
  714. {
  715. var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
  716. if (app != null)
  717. {
  718. apps.push(app[0]);
  719. }
  720. }
  721. apps = apps.filter(function(elem, index, self)
  722. {
  723. return index == self.indexOf(elem);
  724. });
  725. var appAll = apps.join(",");
  726. GM_xmlhttpRequest(
  727. {
  728. method: "GET",
  729. headers:
  730. {
  731. "Cache-Control": "max-age=0"
  732. },
  733. url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
  734. onload: function(response)
  735. {
  736. var dataRes = JSON.parse(response.responseText);
  737. var countOwned = 0;
  738. var elePurchases = null;
  739. var elePrds = document.querySelectorAll(".bundle > .products .product h3"
  740. + ", .expanded .details, .product-info");
  741. var eleApps = document.querySelectorAll(".bundle > .products .info"
  742. + ", .expanded .details, .product-details.hidden");
  743. for (var i = 0; i < eleApps.length; i++)
  744. {
  745. var eleApp = eleApps[i].querySelector(".description a[href*='store.steampowered.com/app/']"
  746. + ", .product-info a[href*='store.steampowered.com/app/']"
  747. + ", .external-links a[href*='store.steampowered.com/app/']");
  748. if (eleApp != null)
  749. {
  750. var app = /[0-9]+/.exec(eleApp.getAttribute("href"));
  751. if (app != null)
  752. {
  753. if (typeof dataRes[app] !== "undefined")
  754. {
  755. if (dataRes[app].success)
  756. {
  757. if (dataRes[app].data.is_owned)
  758. {
  759. var eleLabel = elePrds[i];
  760. if (eleLabel.classList.contains("product-info"))
  761. {
  762. eleLabel.classList.add("bh_owned_dark");
  763. // Mark game in build bundles
  764. {
  765. var eleName = eleLabel.querySelector("h4");
  766. if (eleName)
  767. {
  768. var name = eleName.textContent.trim();
  769. if (elePurchases == null)
  770. {
  771. elePurchases = document.querySelectorAll(".purchase-products > .bundle-product > .input > label");
  772. }
  773. if (elePurchases != null)
  774. {
  775. for (var j = 0; j < elePurchases.length; j++)
  776. {
  777. if (elePurchases[j].textContent.trim() == name)
  778. {
  779. elePurchases[j].parentElement.parentElement.classList.add("bh_owned_dark");
  780. }
  781. }
  782. }
  783. }
  784. }
  785. }
  786. else
  787. {
  788. eleLabel.classList.add("bh_owned");
  789. }
  790. countOwned++;
  791. }
  792. else
  793. {
  794. console.log("App: not owned - http://store.steampowered.com/app/" + app);
  795. }
  796. }
  797. else
  798. {
  799. console.log("App: not success - http://store.steampowered.com/app/" + app);
  800. }
  801. }
  802. }
  803. }
  804. }
  805. console.log("Apps: owned - " + countOwned);
  806. } // End onload
  807. });
  808. });
  809. }
  810. }
  811. else if (url.indexOf("indiegala.com") > -1)
  812. {
  813. GM_addStyle(
  814. " .bh_owned { background-color: rgba(125, 174, 45, 0.9) !important; } "
  815. + " .bh_owned .add-info-button-cont .left, .bh_owned .add-info-button-cont .palette-background-2 { "
  816. + " background-color: #7DAE2D !important; } "
  817. + " .bh_owned .add-info-button-cont .right .inner-info, .bh_owned .add-info-button-cont .right .palette-border-2 { "
  818. + " border-color: #7DAE2D !important; } "
  819. + " .bh_owned.medium-game .game-cover-medium { border: 3px solid #7DAE2D; background-color: rgba(125, 174, 45, 0.4); } "
  820. + " .bh_owned.game-data-cont { background-color: #76AD1C !important; } "
  821. + " .bundle-item-trading-cards-cont span { opacity: 0.7; } "
  822. + " .span-title .title_game, .span-title .title_drm, .span-title .title_music { "
  823. + " line-height: 43px !important; margin: 10px 0px 10px 15px !important; "
  824. + " padding-left: 10px !important; border-radius: 3px !important; } "
  825. );
  826. // Auto reload when error
  827. {
  828. setTimeout(function()
  829. {
  830. if (document.title == "500 Server Error")
  831. {
  832. console.log("Autorefresh: 500 Server Error");
  833. setTimeout(function()
  834. {
  835. reload();
  836. }, 5000);
  837. }
  838. }, 10000);
  839. }
  840. // Insert email to bundle section
  841. {
  842. var countRetryEmail = 10;
  843. var tmRetryEmail = setInterval(function()
  844. {
  845. var eleEmail = document.querySelector(".account-email");
  846. var eleInput = document.querySelector(".email-input");
  847. if (eleEmail && eleInput)
  848. {
  849. var email = eleEmail.textContent.trim();
  850. if (email != "")
  851. {
  852. eleInput.value = email;
  853. clearInterval(tmRetryEmail);
  854. }
  855. }
  856. if (countRetryEmail < 0)
  857. {
  858. clearInterval(tmRetryEmail);
  859. }
  860. countRetryEmail--;
  861. }, 3000);
  862. }
  863. // Add mark button
  864. if (url.indexOf("/store/product/") < 0)
  865. {
  866. var divButton = document.createElement("div");
  867. divButton.classList.add("bh_button");
  868. divButton.id = "bh_markOwned";
  869. var eleA = document.createElement("a");
  870. eleA.setAttribute("onclick", "return false;");
  871. eleA.textContent = "Mark Owned";
  872. divButton.appendChild(eleA);
  873. document.body.appendChild(divButton);
  874. divButton.addEventListener("click", function()
  875. {
  876. var rgxId = /[0-9]{3,}/g;
  877. var rgxApp = /:\/\/((store\.steampowered\.com|steamcommunity\.com)\/app|www.indiegala.com\/store\/product\/[^\/]+)\/[0-9]+/i;
  878. var rgxSub = /:\/\/(store\.steampowered\.com|steamcommunity\.com)\/sub\/[0-9]+/i;
  879. var rgxInvalidApp = /:\/\/store\.steampowered\.com\/[0-9]+\//i;
  880. var eleApps = document.querySelectorAll("a[href*='store.steampowered.com/']");
  881. for (var i = 0; i < eleApps.length; i++)
  882. {
  883. var attrHref = eleApps[i].getAttribute("href");
  884. if (rgxInvalidApp.test(attrHref))
  885. {
  886. eleApps[i].setAttribute("href", attrHref.replace("store.steampowered.com/", "store.steampowered.com/app/"));
  887. }
  888. }
  889. GM_xmlhttpRequest(
  890. {
  891. method: "GET",
  892. url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
  893. onload: function(response)
  894. {
  895. var dataRes = JSON.parse(response.responseText);
  896. var countOwned = 0;
  897. if (typeof dataRes["rgOwnedApps"] !== "undefined"
  898. && typeof dataRes["rgOwnedPackages"] !== "undefined"
  899. && typeof dataRes["rgIgnoredApps"] !== "undefined")
  900. {
  901. var elePrds = document.querySelectorAll(
  902. ".bundle-item-link, .in .in .in .game-steam-url"
  903. + ", #this_your_gift .game-steam-url");
  904. var eleApps = document.querySelectorAll(
  905. ".game-opened-switcher a[href*='store.steampowered.com/'].game-steam-url"
  906. + ", .game-opened-switcher a[href*='steamcommunity.com/'].game-steam-url"
  907. + ", .in .in .in .game-steam-url"
  908. + ", #this_your_gift .game-steam-url"
  909. + ", .game-cover-medium[href^='/store/product/']"
  910. + ", #game_list_div .game-data-cont a[href^='/store/product/']"
  911. + ", .search-page-store .game-data-cont a[href^='/store/product/']");
  912. var eleTitle = document.querySelector("#title-p");
  913. if (eleTitle && eleTitle.textContent.trim() === "Indiegala gift")
  914. {
  915. elePrds = document.querySelectorAll(
  916. "#steam-key-games .game-steam-url");
  917. eleApps = document.querySelectorAll(
  918. "#steam-key-games .game-steam-url");
  919. }
  920. for (var i = 0; i < eleApps.length; i++)
  921. {
  922. var attrHref = eleApps[i].href;
  923. var ids = attrHref.match(rgxId);
  924. if (ids != null)
  925. {
  926. var valId = parseInt(ids[ids.length - 1]);
  927. var eleLabel = null;
  928. if (eleApps[i].classList.contains("game-cover-medium"))
  929. {
  930. eleLabel = eleApps[i].parentElement;
  931. }
  932. else if (eleApps[i].parentElement.parentElement.classList.contains("game-data-cont"))
  933. {
  934. eleLabel = eleApps[i].parentElement.parentElement;
  935. }
  936. else
  937. {
  938. eleLabel = elePrds[i].parentElement;
  939. }
  940. if (rgxApp.test(attrHref))
  941. {
  942. if (dataRes["rgOwnedApps"].indexOf(valId) > -1)
  943. {
  944. eleLabel.classList.add("bh_owned");
  945. countOwned++;
  946. }
  947. else
  948. {
  949. console.log("App: not owned - http://store.steampowered.com/app/" + valId);
  950. }
  951. }
  952. else if (rgxSub.test(attrHref))
  953. {
  954. if (dataRes["rgOwnedPackages"].indexOf(valId) > -1)
  955. {
  956. eleLabel.classList.add("bh_owned");
  957. countOwned++;
  958. }
  959. else
  960. {
  961. console.log("Sub: not owned - http://store.steampowered.com/sub/" + valId);
  962. }
  963. }
  964. }
  965. }
  966. console.log("Apps: owned - " + countOwned);
  967. }
  968. } // End onload
  969. });
  970. });
  971. }
  972. // Change title
  973. {
  974. var countRetryTitle = 10;
  975. var tmRetryTitle = setInterval(function()
  976. {
  977. var elesPrice = document.querySelectorAll(".bundle-claim-phrase");
  978. for (var i = elesPrice.length - 1; i > -1; i--)
  979. {
  980. var elePrice = elesPrice[i].querySelector("span");
  981. if (elePrice)
  982. {
  983. var price = elePrice.textContent.trim();
  984. if (price.indexOf("$") == 0)
  985. {
  986. document.title = price + " " + document.title;
  987. clearInterval(tmRetryTitle);
  988. break;
  989. }
  990. }
  991. }
  992. if (countRetryTitle < 0)
  993. {
  994. clearInterval(tmRetryTitle);
  995. }
  996. countRetryTitle--;
  997. }, 3000);
  998. }
  999. // Load library
  1000. if (url.indexOf("/profile") > -1)
  1001. {
  1002. var clientScript = " \
  1003. function openBundleLibrary() \
  1004. { \
  1005. $.ajax({ \
  1006. type: 'GET', \
  1007. data: { user_id : '" + getQueryByName("user_id") + "' }, \
  1008. url: '/ajaxprofile_sale_tab', \
  1009. dataType: 'json', \
  1010. context: $( '#profile_bundle_section .accordion-toggle' ), \
  1011. \
  1012. beforeSend: function(){ \
  1013. console.log('Start: open bundle library' ); \
  1014. openBundleLibraryAjaxSemaphore = false; \
  1015. $('.spinner', $( '#profile_bundle_section .accordion-toggle' ) ).remove(); \
  1016. $( '#profile_bundle_section .accordion-toggle' ).append(\" <span class='spinner'><i class='fa fa-spinner fa-spin'></i></span>\"); \
  1017. }, \
  1018. success: function(data){ \
  1019. console.log('Success: open bundle library' ); \
  1020. $( '#collapseBundles .panel-body' ).html( data['html'] ); \
  1021. setTimeout(function() \
  1022. { \
  1023. $('#profile_bundle_section .accordion-toggle:not([aria-expanded=\"true\"])').click(); \
  1024. }, 500); \
  1025. }, \
  1026. error: function(){ \
  1027. console.log('Error: open bundle library' ); \
  1028. setTimeout(openBundleLibrary, 500); \
  1029. }, \
  1030. complete: function(){ \
  1031. openBundleLibraryAjaxSemaphore = false; \
  1032. $('.spinner', $( '#profile_bundle_section .accordion-toggle' ) ).remove(); \
  1033. }, \
  1034. }); \
  1035. } \
  1036. ";
  1037.  
  1038. var eleClientScript = document.createElement("script");
  1039. eleClientScript.innerHTML = clientScript;
  1040. document.head.appendChild(eleClientScript);
  1041. var divButton = document.createElement("div");
  1042. divButton.classList.add("bh_button");
  1043. divButton.id = "bh_OpenLib";
  1044. divButton.setAttribute("onclick", "openBundleLibrary()");
  1045. var eleA = document.createElement("a");
  1046. eleA.setAttribute("onclick", "return false;");
  1047. eleA.textContent = "Open Library";
  1048. divButton.appendChild(eleA);
  1049. document.body.appendChild(divButton);
  1050. }
  1051. if (url.indexOf("/successpay") > -1)
  1052. {
  1053. setTimeout(function()
  1054. {
  1055. var eleBtn = document.querySelector("#faang.fa-angle-down");
  1056. if (eleBtn)
  1057. {
  1058. eleBtn.click();
  1059. }
  1060. }, 5000);
  1061. }
  1062. }
  1063. else if (url.indexOf("orlygift.com") > -1)
  1064. {
  1065. if (window !== window.parent)
  1066. return;
  1067. // Add mark button
  1068. {
  1069. var divButton = document.createElement("div");
  1070. divButton.classList.add("bh_button");
  1071. divButton.id = "bh_markOwned";
  1072. var eleA = document.createElement("a");
  1073. eleA.textContent = "Mark Owned";
  1074. divButton.appendChild(eleA);
  1075. document.body.appendChild(divButton);
  1076. divButton.addEventListener("click", function()
  1077. {
  1078. var apps = [];
  1079. var eleApps = document.querySelectorAll("div[id^='game-detail-'] a.btn-primary[href^='http://store.steampowered.com/app/']");
  1080. console.log("Apps: " + eleApps.length);
  1081. for (var i = 0; i < eleApps.length; i++)
  1082. {
  1083. var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
  1084. if (app != null)
  1085. {
  1086. apps.push(app[0]);
  1087. }
  1088. }
  1089. apps = apps.filter(function(elem, index, self)
  1090. {
  1091. return index == self.indexOf(elem);
  1092. });
  1093. var appAll = apps.join(",");
  1094. GM_xmlhttpRequest(
  1095. {
  1096. method: "GET",
  1097. headers:
  1098. {
  1099. "Cache-Control": "max-age=0"
  1100. },
  1101. url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
  1102. onload: function(response)
  1103. {
  1104. var dataRes = JSON.parse(response.responseText);
  1105. var countOwned = 0;
  1106. var elePrds = document.querySelectorAll(".box-game");
  1107. var eleApps = document.querySelectorAll("div[id^='game-detail-']");
  1108. for (var i = 0; i < eleApps.length; i++)
  1109. {
  1110. var eleApp = eleApps[i].querySelector("a.btn-primary[href^='http://store.steampowered.com/app/']");
  1111. if (eleApp != null)
  1112. {
  1113. var app = /[0-9]+/.exec(eleApp.getAttribute("href"));
  1114. if (app != null)
  1115. {
  1116. if (typeof dataRes[app] !== "undefined")
  1117. {
  1118. if (dataRes[app].success)
  1119. {
  1120. if (dataRes[app].data.is_owned)
  1121. {
  1122. var eleLabel = elePrds[i];
  1123. eleLabel.classList.add("bh_owned");
  1124. countOwned++;
  1125. }
  1126. else
  1127. {
  1128. console.log("App: not owned - " + app);
  1129. }
  1130. }
  1131. else
  1132. {
  1133. console.log("App: not success - " + app);
  1134. }
  1135. }
  1136. }
  1137. }
  1138. }
  1139. console.log("Apps: owned - " + countOwned);
  1140. } // End onload
  1141. });
  1142. });
  1143. }
  1144. }
  1145. else if (url.indexOf("cubicbundle.com") > -1)
  1146. {
  1147. GM_addStyle(
  1148. " .bh_owned { background-color: #91BA07 !important; } "
  1149. );
  1150. // Add mark button
  1151. {
  1152. var divButton = document.createElement("div");
  1153. divButton.classList.add("bh_button");
  1154. divButton.id = "bh_markOwned";
  1155. var eleA = document.createElement("a");
  1156. eleA.setAttribute("onclick", "return false;");
  1157. eleA.textContent = "Mark Owned";
  1158. divButton.appendChild(eleA);
  1159. document.body.appendChild(divButton);
  1160. divButton.addEventListener("click", function()
  1161. {
  1162. markOwned(".price a[href*='store.steampowered.com/']", function(ele)
  1163. {
  1164. ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
  1165. });
  1166. });
  1167. }
  1168. }
  1169. else if (url.indexOf("dailyindiegame.com") > -1)
  1170. {
  1171. GM_addStyle(
  1172. " .bh_owned, .bh_owned a, .bh_owned a:not(:visited) .DIG2content { color: #202020 !important; } "
  1173. );
  1174. // Add mark button
  1175. {
  1176. var divButton = document.createElement("div");
  1177. divButton.classList.add("bh_button");
  1178. divButton.id = "bh_markOwned";
  1179. var eleA = document.createElement("a");
  1180. eleA.setAttribute("onclick", "return false;");
  1181. eleA.textContent = "Mark Owned";
  1182. divButton.appendChild(eleA);
  1183. document.body.appendChild(divButton);
  1184. divButton.addEventListener("click", function()
  1185. {
  1186. if (document.querySelectorAll(".DIG-content a[href*='store.steampowered.com/']").length > 0)
  1187. {
  1188. markOwned(".DIG-content a[href*='store.steampowered.com/']", function(ele)
  1189. {
  1190. ele.parentElement
  1191. .parentElement.parentElement
  1192. .parentElement.parentElement
  1193. .classList.add("bh_owned");
  1194. });
  1195. }
  1196. else
  1197. {
  1198. markOwned(".DIG2content a[href*='store.steampowered.com/']", function(ele)
  1199. {
  1200. ele.parentElement
  1201. .parentElement
  1202. .classList.add("bh_owned");
  1203. });
  1204. }
  1205. });
  1206. }
  1207. }
  1208. else if (url.indexOf("bundlekings.com") > -1)
  1209. {
  1210. // Add mark button
  1211. {
  1212. var divButton = document.createElement("div");
  1213. divButton.classList.add("bh_button");
  1214. divButton.id = "bh_markOwned";
  1215. var eleA = document.createElement("a");
  1216. eleA.setAttribute("onclick", "return false;");
  1217. eleA.textContent = "Mark Owned";
  1218. divButton.appendChild(eleA);
  1219. document.body.appendChild(divButton);
  1220. divButton.addEventListener("click", function()
  1221. {
  1222. markOwned(".content-wrap a[href*='store.steampowered.com/']", function(ele)
  1223. {
  1224. ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
  1225. });
  1226. });
  1227. }
  1228. }
  1229. else if (url.indexOf("otakumaker.com") > -1)
  1230. {
  1231. GM_addStyle(
  1232. " .bh_owned { background-color: #91BA07 !important; } "
  1233. );
  1234. // Add mark button
  1235. {
  1236. var divButton = document.createElement("div");
  1237. divButton.classList.add("bh_button");
  1238. divButton.id = "bh_markOwned";
  1239. var eleA = document.createElement("a");
  1240. eleA.setAttribute("onclick", "return false;");
  1241. eleA.textContent = "Mark Owned";
  1242. divButton.appendChild(eleA);
  1243. document.body.appendChild(divButton);
  1244. divButton.addEventListener("click", function()
  1245. {
  1246. markOwned(".gantry-width-spacer a[href*='store.steampowered.com/']", function(ele)
  1247. {
  1248. ele.parentElement.parentElement.classList.add("bh_owned");
  1249. });
  1250. });
  1251. }
  1252. }
  1253. else if (url.indexOf("superduperbundle.com") > -1)
  1254. {
  1255. // Add mark button
  1256. {
  1257. var divButton = document.createElement("div");
  1258. divButton.classList.add("bh_button");
  1259. divButton.id = "bh_markOwned";
  1260. var eleA = document.createElement("a");
  1261. eleA.setAttribute("onclick", "return false;");
  1262. eleA.textContent = "Mark Owned";
  1263. divButton.appendChild(eleA);
  1264. document.body.appendChild(divButton);
  1265. divButton.addEventListener("click", function()
  1266. {
  1267. markOwned("#gameslist a[href*='store.steampowered.com/']", function(ele)
  1268. {
  1269. ele.parentElement.parentElement.classList.add("bh_owned");
  1270. });
  1271. });
  1272. }
  1273. }
  1274. else if (url.indexOf("gamebundle.com") > -1)
  1275. {
  1276. GM_addStyle(
  1277. " .bh_owned { background-color: #A0CC41 !important; border-bottom: 45px solid rgba(233, 233, 233, 0.5); } "
  1278. + " .bh_owned .activebundle_game_bundle_debut_title { background-color: #A0CC41 !important; } "
  1279. );
  1280. // Add mark button
  1281. {
  1282. var divButton = document.createElement("div");
  1283. divButton.classList.add("bh_button");
  1284. divButton.id = "bh_markOwned";
  1285. var eleA = document.createElement("a");
  1286. eleA.setAttribute("onclick", "return false;");
  1287. eleA.textContent = "Mark Owned";
  1288. divButton.appendChild(eleA);
  1289. document.body.appendChild(divButton);
  1290. divButton.addEventListener("click", function()
  1291. {
  1292. markOwned(".activebundle_game_section_full a[href*='store.steampowered.com/']", function(ele)
  1293. {
  1294. ele.parentElement.classList.add("bh_owned");
  1295. });
  1296. });
  1297. }
  1298. }
  1299. else if (url.indexOf("humblebundle.com") > -1)
  1300. {
  1301. GM_addStyle(
  1302. " .game-box img { max-height: 180px !important; max-width: 130px !important; } "
  1303. );
  1304. var elePrice = document.querySelector(".section-heading.bta, h2.s-bta");
  1305. if (elePrice)
  1306. {
  1307. var price = elePrice.textContent.trim()
  1308. .replace("Pay more than the average of ", "")
  1309. .replace(" to also unlock!", "").trim();
  1310. if (price.indexOf("$") == 0)
  1311. {
  1312. document.title = price + " " + document.title;
  1313. }
  1314. }
  1315. var eleSold = document.querySelector(".heading-bundles-sold .mini-digit-holder");
  1316. if (eleSold != null)
  1317. {
  1318. var sold = eleSold.getAttribute("data-initial-value") || "";
  1319. eleSold.parentElement.parentElement.setAttribute("title", sold);
  1320. }
  1321. var countRetrySold = 10;
  1322. var tmRetrySold = setInterval(function()
  1323. {
  1324. var sold = "";
  1325. var elesSold = document.querySelectorAll(".mini-digit-holder .top-cutter .heading-num");
  1326. for (var i = 0; i < elesSold.length; i++)
  1327. {
  1328. sold = sold + "" + elesSold[i].textContent.trim();
  1329. }
  1330. if (sold !== "")
  1331. {
  1332. clearInterval(tmRetrySold);
  1333. var eleCount = document.querySelector(".hr-tagline-bundles-sold");
  1334. if (eleCount)
  1335. {
  1336. eleCount.textContent += " (" + sold.replace(/^0+/, "") + ")";
  1337. }
  1338. }
  1339. if (countRetrySold < 0)
  1340. {
  1341. clearInterval(tmRetrySold);
  1342. }
  1343. countRetrySold--;
  1344. }, 1000);
  1345.  
  1346. if (url.indexOf("/downloads") > -1)
  1347. {
  1348. GM_addStyle(
  1349. " #steam-tab .redeem-instructions, #steam-tab .recommend-this-game { display: none; } "
  1350. );
  1351. setTimeout(function()
  1352. {
  1353. var elesKey = document.querySelectorAll(".sr-redeemed-bubble");
  1354. for (var i = 0; i < elesKey.length; i++)
  1355. {
  1356. elesKey[i].addEventListener("click", function (e)
  1357. {
  1358. var ele = e.target;
  1359. clickToSelect(ele);
  1360. });
  1361. }
  1362. }, 3000);
  1363. }
  1364. }
  1365. else if (url.indexOf("steamcompanion.com") > -1)
  1366. {
  1367. GM_addStyle(
  1368. " .bh_owned.banner { margin-bottom: 5px !important; margin-top: 35px !important; "
  1369. + " padding-bottom: 15px !important; padding-top: 15px !important; } "
  1370. + " .bh_owned.giveaway-links { opacity: 0.75; } "
  1371. );
  1372. markOwned("#hero a[href*='store.steampowered.com/']", function(ele)
  1373. {
  1374. ele.classList.add("bh_owned");
  1375. });
  1376. // Mark
  1377. {
  1378. var query = ".giveaway-links img[src^='https://steamcdn-a.akamaihd.net/steam/apps/']";
  1379. var getLabelCallback = function(ele)
  1380. {
  1381. return ele.parentElement.parentElement.parentElement;
  1382. };
  1383. var apps = [];
  1384. var eleApps = document.querySelectorAll(query);
  1385. for (var i = 0; i < eleApps.length; i++)
  1386. {
  1387. var app = /[0-9]+/.exec(eleApps[i].getAttribute("src"));
  1388. if (app != null)
  1389. {
  1390. apps.push(app[0]);
  1391. }
  1392. }
  1393. apps = apps.filter(function(elem, index, self)
  1394. {
  1395. return index == self.indexOf(elem);
  1396. });
  1397. console.log("Apps: " + apps.length);
  1398. var appAll = apps.join(",");
  1399. GM_xmlhttpRequest(
  1400. {
  1401. method: "GET",
  1402. headers:
  1403. {
  1404. "Cache-Control": "max-age=0"
  1405. },
  1406. url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
  1407. onload: function(response)
  1408. {
  1409. var dataRes = JSON.parse(response.responseText);
  1410. var countOwned = 0;
  1411. var eleApps = document.querySelectorAll(query);
  1412. for (var i = 0; i < eleApps.length; i++)
  1413. {
  1414. var appUrl = eleApps[i].getAttribute("src");
  1415. if (appUrl.indexOf("https://steamcdn-a.akamaihd.net/steam/apps/") > -1)
  1416. {
  1417. var app = /[0-9]+/.exec(appUrl);
  1418. if (app != null)
  1419. {
  1420. if (typeof dataRes[app] !== "undefined")
  1421. {
  1422. if (dataRes[app].success)
  1423. {
  1424. if (dataRes[app].data.is_owned)
  1425. {
  1426. var eleLabel = getLabelCallback(eleApps[i]);
  1427. eleLabel.classList.add("bh_owned");
  1428. countOwned++;
  1429. }
  1430. else
  1431. {
  1432. //console.log("App: not owned - http://store.steampowered.com/app/" + app + "/");
  1433. }
  1434. }
  1435. else
  1436. {
  1437. //console.log("App: not success - https://steamdb.info/app/" + app + "/");
  1438. }
  1439. }
  1440. }
  1441. }
  1442. }
  1443. console.log("Apps: owned - " + countOwned);
  1444. } // End onload
  1445. });
  1446. }
  1447. }
  1448. else if (url.indexOf("store.steampowered.com") > -1)
  1449. {
  1450. if (url.indexOf("/widget/") > -1)
  1451. {
  1452. GM_addStyle(
  1453. " .bh_owned { background-color: transparent !important; } "
  1454. + " .bh_owned a { color: #71A034 !important; }"
  1455. );
  1456. markOwned(".main_text a[href*='store.steampowered.com/']", function(ele)
  1457. {
  1458. ele.parentElement.classList.add("bh_owned");
  1459. });
  1460. }
  1461. else if (url.indexOf("/app/") > -1)
  1462. {
  1463. GM_addStyle(
  1464. " .bh_owned { "
  1465. + " background-color: #6D8C1A !important; "
  1466. + " padding: 0px 2px 0px 2px; "
  1467. + " } "
  1468. );
  1469. markOwned(".glance_details p > a[href*='store.steampowered.com/']"
  1470. + ", .game_area_dlc_bubble a[href*='store.steampowered.com/']",
  1471. function(ele)
  1472. {
  1473. ele.classList.add("bh_owned");
  1474. });
  1475. }
  1476. else if (url.indexOf("/notinterested/") > -1)
  1477. {
  1478. GM_addStyle(
  1479. " .bh_owned { "
  1480. + " background-color: #6D8C1A !important; "
  1481. + " padding: 5px 100px 5px 5px !important; "
  1482. + " margin-left: -5px; margin-right: 50px; "
  1483. + " } "
  1484. );
  1485. markOwned(".ignoredapps > a[href*='store.steampowered.com/']", function(ele)
  1486. {
  1487. ele.classList.add("bh_owned");
  1488. });
  1489. }
  1490. }
  1491. else if (url.indexOf("steamcommunity.com") > -1)
  1492. {
  1493. GM_addStyle(
  1494. " .bh_owned { background-color: #71A034 !important; "
  1495. + " padding: 0px 2px 0px 2px; } "
  1496. + " .bh_owned.blotter_userstatus_game { padding: 0px; border-color: #71A034; } "
  1497. );
  1498. if (url.indexOf("/home") > -1)
  1499. {
  1500. var querySteamHome = ".blotter_gamepurchase_details a[href*='store.steampowered.com/']:not(.bh_owned) "
  1501. + ", .blotter_author_block a[href*='store.steampowered.com/']:not(.bh_owned) "
  1502. + ", .blotter_author_block a[href*='steamcommunity.com/app/']:not(.bh_owned) "
  1503. + ", .blotter_daily_rollup_line a[href*='steamcommunity.com/app/']:not(.bh_owned) ";
  1504. markOwned(querySteamHome, function(ele)
  1505. {
  1506. if (ele.classList.contains("blotter_userstats_game"))
  1507. {
  1508. ele.parentElement.classList.add("bh_owned");
  1509. }
  1510. else
  1511. {
  1512. ele.classList.add("bh_owned");
  1513. }
  1514. });
  1515. var targetObMark = document.getElementById("blotter_content");
  1516. if (targetObMark)
  1517. {
  1518. var tmObMark = -1;
  1519. var obMark = new MutationObserver(function(mutations)
  1520. {
  1521. mutations.forEach(function(mutation)
  1522. {
  1523. clearTimeout(tmObMark);
  1524. tmObMark = setTimeout(function(querySteamHome)
  1525. {
  1526. markOwned(querySteamHome, function(ele)
  1527. {
  1528. if (!ele.classList.contains("blotter_userstats_game"))
  1529. {
  1530. ele.classList.add("bh_owned");
  1531. }
  1532. });
  1533. }, 100, querySteamHome);
  1534. });
  1535. });
  1536.  
  1537. var configObMark = { childList: true };
  1538. obMark.observe(targetObMark, configObMark);
  1539. }
  1540. }
  1541. else if (url.indexOf("/announcements") > -1)
  1542. {
  1543. markOwned(".announcement_body a[href*='store.steampowered.com/']", function(ele)
  1544. {
  1545. ele.classList.add("bh_owned");
  1546. });
  1547. }
  1548. }
  1549. else if (url.indexOf("forums.steampowered.com") > -1)
  1550. {
  1551. GM_addStyle(
  1552. " .bh_owned { background-color: #71A034 !important; "
  1553. + " padding: 0px 2px 0px 2px;"
  1554. + " } "
  1555. );
  1556. markOwned("div[id^='post_message'] a[href*='store.steampowered.com/']", function(ele)
  1557. {
  1558. ele.classList.add("bh_owned");
  1559. });
  1560. }
  1561. else if (url.indexOf("whosgamingnow.net") > -1)
  1562. {
  1563. if (url.indexOf("/discussion") > -1)
  1564. {
  1565. GM_addStyle(
  1566. " .bh_owned { "
  1567. + " padding: 0px 2px 0px 2px;"
  1568. + " } "
  1569. );
  1570. markOwned(".MessageList a[href*='store.steampowered.com/']", function(ele)
  1571. {
  1572. ele.classList.add("bh_owned");
  1573. });
  1574. }
  1575. else if (url.indexOf("/redeem") > -1)
  1576. {
  1577. GM_addStyle(
  1578. " .bh_owned { "
  1579. + " border: 1px solid #FFF;"
  1580. + " } "
  1581. + " .bh_owned .BoxArt { "
  1582. + " border: 0px !important;"
  1583. + " } "
  1584. );
  1585. markOwned(".GameInfo a[href*='store.steampowered.com/']", function(ele)
  1586. {
  1587. ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
  1588. });
  1589. }
  1590. else if (url.indexOf("/giveaway") > -1)
  1591. {
  1592. GM_addStyle(
  1593. " .bh_owned { "
  1594. + " border: 5px solid #7CA156;"
  1595. + " } "
  1596. );
  1597. markOwned("img[src*='://cdn.akamai.steamstatic.com/steam/']", function(ele)
  1598. {
  1599. ele.classList.add("bh_owned");
  1600. });
  1601. }
  1602. }
  1603. else if (url.indexOf("steamground.com") > -1 && url.indexOf("/wholesale") > -1)
  1604. {
  1605. GM_addStyle(
  1606. " .bh_owned { background-color: #48B24B !important; } "
  1607. + " .bh_owned .wholesale-card_title { color: #373d41 !important; } "
  1608. + " .bh_steam { display: none; } "
  1609. );
  1610. var elesTitle = document.querySelectorAll(".wholesale-card_title");
  1611. if (elesTitle.length > 0)
  1612. {
  1613. GM_xmlhttpRequest(
  1614. {
  1615. method: "GET",
  1616. url: "https://www.steamgifts.com/discussion/iy081/steamground-wholesale-build-a-bundle",
  1617. onload: function(response)
  1618. {
  1619. var data = response.responseText;
  1620. var eleContainer = document.createElement("div");
  1621. eleContainer.innerHTML = data;
  1622. var eleComment = eleContainer.querySelector(".comment__description");
  1623. if (eleComment)
  1624. {
  1625. var elesGame = eleComment.querySelectorAll("table td:nth-child(1) a[href*='store.steampowered.com/']");
  1626. if (elesGame.length > 0)
  1627. {
  1628. var arrTitle = [];
  1629. for (var i = 0; i < elesTitle.length; i++)
  1630. {
  1631. arrTitle.push(elesTitle[i].textContent.trim());
  1632. }
  1633. for (var i = 0; i < elesGame.length; i++)
  1634. {
  1635. var isMatch = false;
  1636. var game = elesGame[i].textContent.trim().toLowerCase();
  1637. for (var j = 0; j < elesTitle.length; j++)
  1638. {
  1639. var title = elesTitle[j].textContent.trim().toLowerCase();
  1640. if (game === title
  1641. || (title.indexOf("|") > -1 && game === title.replace("|", ":"))
  1642. || (game === "ball of light" && title === "ball of light (journey)")
  1643. || (game === "its your last chance in new school" && title === "it is yоur last chance in new schооl")
  1644. || (game === "shake your money simulator 2016" && title === "shake your money simulator")
  1645. || (game === "spakoyno: back to the ussr 2.0" && title === "spakoyno back to the ussr 2.0")
  1646. || (game === "or" && title === "or!"))
  1647. {
  1648. isMatch = true;
  1649. arrTitle = arrTitle.filter(function(value)
  1650. {
  1651. return value !== elesTitle[j].textContent.trim()
  1652. });
  1653. }
  1654. if (isMatch)
  1655. {
  1656. var eleA = document.createElement("a");
  1657. eleA.classList.add("bh_steam");
  1658. eleA.href = elesGame[i].href;
  1659. elesTitle[j].parentElement.parentElement.appendChild(eleA);
  1660. break;
  1661. }
  1662. }
  1663. if (!isMatch)
  1664. {
  1665. console.log("Not match: " + elesGame[i].href + " " + elesGame[i].textContent);
  1666. }
  1667. }
  1668.  
  1669. if (arrTitle.length > 0)
  1670. {
  1671. console.log("Not match: " + arrTitle.length);
  1672. for (var i = 0; i < arrTitle.length; i++)
  1673. {
  1674. console.log("Not match: " + arrTitle[i]);
  1675. }
  1676. }
  1677. markOwned(".wholesale-card > a[href*='store.steampowered.com/']", function(ele)
  1678. {
  1679. ele.parentElement.classList.add("bh_owned");
  1680. });
  1681. }
  1682. }
  1683. } // End onload
  1684. });
  1685. }
  1686. }
  1687. else if (url.indexOf("bunchkeys.com") > -1)
  1688. {
  1689. GM_addStyle(
  1690. " .bh_owned { border: #B5D12E 3px solid !important; "
  1691. + " margin-left: -3px; margin-top: -3px; } "
  1692. );
  1693. // Add mark button
  1694. {
  1695. var divButton = document.createElement("div");
  1696. divButton.classList.add("bh_button");
  1697. divButton.id = "bh_markOwned";
  1698. var eleA = document.createElement("a");
  1699. eleA.setAttribute("onclick", "return false;");
  1700. eleA.textContent = "Mark Owned";
  1701. divButton.appendChild(eleA);
  1702. document.body.appendChild(divButton);
  1703. divButton.addEventListener("click", function()
  1704. {
  1705. markOwned("a[href*='store.steampowered.com/']", function(ele)
  1706. {
  1707. ele.parentElement.classList.add("bh_owned");
  1708. });
  1709. });
  1710. }
  1711. }
  1712. }
  1713.  
  1714. attachOnReady(main);
  1715. })();