Bundle Helper

Add tools for many bundle sites.

目前為 2017-02-26 提交的版本,檢視 最新版本

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