Bundle Stars Keys Retrieve

Retrieve keys from Bundle Stars

  1. // ==UserScript==
  2. // @name Bundle Stars Keys Retrieve
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.3.1
  5. // @description Retrieve keys from Bundle Stars
  6. // @icon https://cdn.bundlestars.com/production/brand/apple-touch-icon-180x180.png
  7. // @author Bisumaruko
  8. // @include http*://*bundlestars.com/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. var $ = selector => document.querySelector(selector),
  16. $$ = selector => Array.from(document.querySelectorAll(selector)),
  17. BSRetrive = {};
  18.  
  19. BSRetrive.init = function () {
  20. var style = document.createElement('style');
  21.  
  22. style.type = 'text/css';
  23. style.innerHTML = `
  24. .BSRetrive {
  25. width: 100%;
  26. height: 200px;
  27. display: flex;
  28. flex-direction: column;
  29. box-sizing: border-box;
  30. border: 1px solid #424242;
  31. color: #999999;
  32. }
  33. .BSRetrive > textarea {
  34. width: 100%;
  35. height: 150px;
  36. border: none;
  37. background-color: #303030;
  38. color: #DDD;
  39. box-sizing: border-box;
  40. resize: none;
  41. }
  42. .BSRetrive > div {
  43. width: 100%;
  44. padding-top: 5px;
  45. box-sizing: border-box;
  46. }
  47. .BSRetrive button, .BSRetrive select {
  48. height: 34px;
  49. margin-right: 10px;
  50. padding: 6px 12px;
  51. border: 1px solid transparent;
  52. background-color: #262626;
  53. color: #DEDEDE;
  54. box-sizing: border-box;
  55. outline: none;
  56. cursor: pointer;
  57. }
  58. .BSRetrive button:hover, .BSRetrive select:hover {
  59. color: #A8A8A8;
  60. }
  61. .BSRetrive label {
  62. margin-right: 10px;
  63. color: #DEDEDE;
  64. }
  65. .BSRetrive select {
  66. max-width:200px;
  67. }
  68. .BSRetrive select, .BSRetrive span {
  69. margin-right: 0;
  70. margin-left: 10px;
  71. float: right;
  72. }
  73. .BSRetrive span {
  74. margin-top: 5px;
  75. }
  76. `;
  77.  
  78. document.head.appendChild(style);
  79. };
  80.  
  81. BSRetrive.setup = function () {
  82. if ($('.BSRetrive')) return;
  83.  
  84. var anchor = $('h2');
  85. if (!anchor || anchor.textContent.trim() !== 'Order Keys') return;
  86.  
  87. var BSContainer = document.createElement('div');
  88.  
  89. BSContainer.className = 'BSRetrive';
  90. BSContainer.innerHTML = `
  91. <textarea></textarea>
  92. <div>
  93. <button class="BSButtonReveal">Reveal</button>
  94. <button class="BSButtonRetrieve">Retrieve</button>
  95. <button class="BSButtonCopy">Copy</button>
  96. <button class="BSButtonReset">Reset</button>
  97. <label><input type="checkbox" class="BSCheckboxTitle">Include Game Title</label>
  98. <label><input type="checkbox" class="BSCheckboxJoin">Join Keys</label>
  99. <select class="BSSelectTo"></select>
  100. <span>to</span>
  101. <select class="BSSelectFrom"></select>
  102. </div>
  103. `;
  104.  
  105. anchor.parentNode.insertBefore(BSContainer, anchor);
  106.  
  107. $('.BSButtonReveal').addEventListener('click', () => {
  108. let keys = this.selector('.key-container a[ng-click^="redeemSerial"]');
  109.  
  110. if (keys) {
  111. for (let key of keys) {
  112. if (!key.closest('.ng-hide')) key.click();
  113. }
  114. } else msg.alert('Empty search, please select the correct options');
  115. });
  116.  
  117. $('.BSButtonRetrieve').addEventListener('click', () => {
  118. let containers = this.selector('.key-container');
  119.  
  120. if (containers) {
  121. let keys = [],
  122. includeTitle = $('.BSCheckboxTitle').checked,
  123. separator = $('.BSCheckboxJoin').checked ? ',' : "\n"
  124.  
  125. for (let container of containers) {
  126. let key = container.querySelector('input');
  127.  
  128. if (!key) continue;
  129. keys.push(
  130. includeTitle ?
  131. container.previousElementSibling.textContent + ', ' + key.value :
  132. key.value
  133. );
  134. }
  135.  
  136. $('.BSRetrive textarea').textContent = keys.join(separator);
  137. } else msg.alert('Empty search, please select the correct options');
  138. });
  139.  
  140. $('.BSButtonCopy').addEventListener('click', () => {
  141. $('.BSRetrive textarea').select();
  142. document.execCommand('copy');
  143. });
  144.  
  145. $('.BSButtonReset').addEventListener('click', () => {
  146. $('.BSRetrive textarea').textContent = '';
  147. });
  148.  
  149. this.baseElements = [document];
  150. var blocks = $$('hr ~ div > div:not(.ng-hide)'),
  151. selectFrom = $('.BSSelectFrom');
  152.  
  153. selectFrom.appendChild(new Option('All', 0));
  154.  
  155. for (let block of blocks) {
  156. let option,
  157. bundle = block.querySelector('h3'),
  158. tiers = Array.from(block.querySelectorAll('h4'));
  159.  
  160. if (tiers.length > 1) { //bundles (multiple tiers)
  161. for (let tier of tiers) {
  162. selectFrom.appendChild(new Option(
  163. bundle.textContent + ' ' + tier.textContent,
  164. this.baseElements.push(tier.parentNode) - 1
  165. ));
  166. }
  167. } else if (bundle) { //bundles (single tier)
  168. selectFrom.appendChild(new Option(
  169. bundle.textContent,
  170. this.baseElements.push(bundle.nextElementSibling) - 1
  171. ));
  172. } else { //individual games
  173. selectFrom.appendChild(new Option(
  174. block.querySelector('.title').textContent,
  175. this.baseElements.push(block) - 1
  176. ));
  177. }
  178. }
  179.  
  180. $('.BSSelectTo').innerHTML = selectFrom.innerHTML;
  181. };
  182.  
  183. BSRetrive.selector = function (selector) {
  184. var results = [],
  185. from = parseInt($('.BSSelectFrom').value),
  186. to = parseInt($('.BSSelectTo').value);
  187.  
  188. if (Number.isInteger(from) && Number.isInteger(to)) {
  189. if (from === 0 && to > 0) from = 1;
  190. if (from > 0 && to === 0) to = this.baseElements.length - 1;
  191.  
  192. for (var index = Math.min(from, to); index <= Math.max(from, to); index++) {
  193. let node = this.baseElements[index], result;
  194.  
  195. if (node) result = Array.from(node.querySelectorAll(selector));
  196. if (result) results = results.concat(result);
  197. }
  198. }
  199. return results;
  200. };
  201.  
  202. var msg = {
  203. box: null,
  204. init() {
  205. var style = document.createElement('style');
  206.  
  207. style.type = 'text/css';
  208. style.innerHTML = `
  209. .BSRetrive_msg {
  210. display: none;
  211. position: fixed;
  212. top: 50%;
  213. left: 50%;
  214. transform: translate(-50%, -50%);
  215. padding: 10px 20px;
  216. border: 1px solid #424242;
  217. background-color: rgb(32, 32, 32);
  218. color: #FFF;
  219. font-size: larger;
  220. }
  221. .BSRetrive_msg-show {
  222. display: block;
  223. }
  224. `;
  225. document.head.appendChild(style);
  226.  
  227. var BSRetrive_msg = document.createElement('div');
  228.  
  229. BSRetrive_msg.classList.add('BSRetrive_msg');
  230. document.body.appendChild(BSRetrive_msg);
  231. this.box = BSRetrive_msg;
  232. },
  233. alert(text) {
  234. this.box.textContent = text;
  235. this.box.classList.add('BSRetrive_msg-show');
  236. setTimeout(this.hide.bind(this), 3000);
  237. },
  238. hide() {
  239. this.box.classList.remove('BSRetrive_msg-show');
  240. }
  241. };
  242.  
  243. msg.init();
  244.  
  245. BSRetrive.init();
  246.  
  247. new MutationObserver(mutations => {
  248. for (let mutation of mutations) {
  249. if (!mutation.removedNodes.length) continue;
  250. if (mutation.removedNodes[0].id === 'loading-bar-spinner') BSRetrive.setup();
  251. }
  252. }).observe(document.body, {childList: true});
  253.  
  254. })();