Steam New Queue AutoDiscover

auto run trough steam next fest discovery queue

  1. // ==UserScript==
  2. // @name Steam New Queue AutoDiscover
  3. // @version 0.2
  4. // @description auto run trough steam next fest discovery queue
  5. // @author gortik
  6. // @license MIT
  7. // @match https://store.steampowered.com/explore/
  8. // @icon https://store.steampowered.com/favicon.ico
  9. // @grant none
  10. // @require https://cdn.jsdelivr.net/npm/protobufjs@7.1.2/dist/light/protobuf.min.js
  11.  
  12. // @namespace https://greasyfork.org/users/968091
  13. // ==/UserScript==
  14.  
  15.  
  16. var access_token,
  17. skipDelay = 300, //in ms
  18. newDiscoveryQueueModal;
  19.  
  20.  
  21. var jsonGetQueue = {"nested":{"getQueue":{"fields":{"appids":{"rule":"repeated","type":"int32","id":1,"options":{"packed":false}},"b":{"rule":"required","type":"string","id":2},"c":{"rule":"required","type":"string","id":3},"d":{"rule":"required","type":"int32","id":4},"e":{"rule":"required","type":"int32","id":5},"f":{"rule":"required","type":"int32","id":6}}}}},
  22. jsonSkip = {"nested":{"skipAppid":{"fields":{"a":{"rule":"required","type":"int32","id":1},"appid":{"rule":"required","type":"int32","id":2},"in1":{"rule":"required","type":"In1","id":3}}},"In1":{"fields":{"in2":{"rule":"required","type":"In2","id":1}}},"In2":{"fields":{"a":{"rule":"required","type":"int32","id":1}}}}}
  23.  
  24.  
  25.  
  26. function sleep(ms) {
  27. return new Promise(resolve => {
  28. console.log('Sleep: ' + ms/1000 + 's.');
  29. setTimeout(resolve, ms)
  30. });
  31. }
  32.  
  33. function buffer2hex(buffer) {
  34. function i2hex(i) { return ('0' + i.toString(16)).slice(-2); }
  35. return Array.from(buffer).map(i2hex).join(' ');
  36. }
  37.  
  38. function buffer2base64(buffer) {
  39. let str = buffer.reduce((acc, char) => acc + String.fromCharCode(char) , '');
  40. return btoa(str);
  41. }
  42.  
  43. async function getAccessToken() {
  44. //document.querySelector('#application_config').dataset.loyalty_webapi_token
  45. /*if (window.location.href.indexOf('steampowered') > -1) {
  46. }
  47. else if(window.location.href.indexOf('steamcommunity') > -1) {
  48. }*/
  49. let response = await fetch('https://store.steampowered.com/points/shop');
  50. let text = await response.text();
  51. let match = text.match(/webapi_token":"([\d\w]+)&quot/);
  52. console.log('access_token: ' + match[1]);
  53. return match[1];
  54. }
  55.  
  56.  
  57. //arrGet = [8, 168, 219, 83, 8, 170, 243, 117, 8, 204, 243, 66, 8, 150, 176, 126, 8, 172, 169, 127, 8, 186, 169, 111, 8, 196, 129, 126, 8, 170, 242, 104, 8, 250, 195, 118, 8, 160, 232, 119, 8, 178, 170, 71, 8, 150, 196, 116, 18, 2, 83, 75, 26, 0, 32, 68, 40, 0, 48, 0]
  58. //arrGet = [8, 242, 255, 90, 8, 178, 162, 107, 8, 232, 155, 100, 8, 244, 198, 81, 8, 158, 208, 105, 8, 178, 238, 115, 8, 212, 205, 105, 8, 138, 202, 57, 8, 238, 162, 77, 8, 130, 194, 70, 8, 208, 134, 123, 8, 174, 231, 125, 18, 2, 83, 75, 26, 0, 32, 12, 40, 0, 48, 0]
  59.  
  60. //accepts base64 or Array or Uint8Array
  61. function decode(json, messageName, msg) {
  62. let root = protobuf.Root.fromJSON(json);
  63. let message = root.lookupType(messageName);
  64. let arr = [];
  65. //if msg is array or Uint8Array
  66. if (Array.isArray(msg) || ArrayBuffer.isView(msg))
  67. arr = msg;
  68. else
  69. protobuf.util.base64.decode(protobufMsg, arr, 0)
  70. //let arr = new Uint8Array(X) //X = bytes needed
  71. return message.decode(arr);
  72. }
  73.  
  74. //j = decode(jsonGetQueue, 'getQueue', arrGet)
  75.  
  76. function createPayload(appid) {
  77. return {
  78. a: 1,
  79. appid: appid,
  80. in1: {
  81. in2: {
  82. a: 1235711
  83. }
  84. }
  85. }
  86. }
  87.  
  88. function encode(json, messageName, payload) {
  89. let root = protobuf.Root.fromJSON(json),
  90. message = root.lookupType(messageName);
  91. //var payload = { a: 1, appid: 987654, in1: { in2: { a: 1235711 } } };
  92. let msg_to_send = message.create(payload);
  93. let buffer = message.encode(msg_to_send).finish();
  94. return buffer2base64(buffer);
  95. }
  96.  
  97. async function getQueue() {
  98. let body = {
  99. access_token: access_token,
  100. input_protobuf_encoded: 'CAESAlNLGAEwAWIGCgQI/7VL'
  101. },
  102. url = 'https://api.steampowered.com/IStoreService/GetDiscoveryQueue/v1?' + new URLSearchParams(body).toString(),
  103. options = {
  104. "credentials":"omit",
  105. "headers":{
  106. "accept":"application/json, text/plain, */*",
  107. "accept-language":"en-US,en;q=0.9",
  108. "sec-fetch-mode":"cors",
  109. "sec-fetch-site":"same-site"
  110. },
  111. "referrer":"https://store.steampowered.com/sale/nextfest",
  112. "referrerPolicy":"no-referrer-when-downgrade",
  113. "body": null,
  114. "method": "GET",
  115. "mode":"cors"
  116. }
  117. let response = await fetch(url, options);
  118. let arrBuff = await response.arrayBuffer();
  119. let uint8 = new Uint8Array(arrBuff);
  120. //let uint8 = Array.from(arrBuff);
  121. console.log(buffer2base64(uint8));
  122. let json = decode(jsonGetQueue, 'getQueue', uint8)
  123. return json;
  124. }
  125.  
  126.  
  127. async function postSkip(protobufBase64) {
  128. let query = {
  129. access_token: access_token
  130. },
  131. body = {
  132. input_protobuf_encoded: protobufBase64
  133. },
  134. url = 'https://api.steampowered.com/IStoreService/SkipDiscoveryQueueItem/v1?' + new URLSearchParams(query).toString();
  135.  
  136. let res = await fetch(url, {
  137. "headers": {
  138. "accept": "application/json, text/plain, */*",
  139. "accept-language": "en-US,en;q=0.9,sk;q=0.8,cs;q=0.7",
  140. // "content-type": "multipart/form-data; boundary=----WebKitFormBoundary5BetF1tNQduIif48",
  141. "content-type": "application/x-www-form-urlencoded",
  142. //"sec-ch-ua": "\";Not A Brand\";v=\"99\", \"Chromium\";v=\"88\"",
  143. //"sec-ch-ua-mobile": "?0",
  144. //"sec-fetch-dest": "empty",
  145. "sec-fetch-mode": "cors",
  146. "sec-fetch-site": "same-site"
  147. },
  148. //"referrer": "https://store.steampowered.com/",
  149. //"referrerPolicy": "strict-origin-when-cross-origin",
  150. //"body": "------WebKitFormBoundary5BetF1tNQduIif48\r\nContent-Disposition: form-data; name=\"input_protobuf_encoded\"\r\n\r\nCAEQsqpHGgYKBAj/tUs=\r\n------WebKitFormBoundary5BetF1tNQduIif48--\r\n",
  151. "body": new URLSearchParams(body).toString(),
  152. "method": "POST",
  153. "mode": "cors",
  154. "credentials": "omit"
  155. });
  156. let text = await res.text();
  157. if (text == '')
  158. console.log('OK');
  159. else
  160. console.log('')
  161. }
  162.  
  163. async function skipAppids(appids) {
  164. let i = 0;
  165. for (let appid of appids) {
  166. console.log(appid);
  167.  
  168. let payload = createPayload(appid);
  169. let payload_base64 = encode(jsonSkip, 'skipAppid', payload);
  170. await postSkip(payload_base64);
  171.  
  172. newDiscoveryQueueModal.Dismiss();
  173. newDiscoveryQueueModal = ShowBlockingWaitDialog('Exploring the queue...', 'Request ' + ++i + ' of ' + appids.length);
  174. await sleep(skipDelay);
  175. }
  176. console.log('Done');
  177. }
  178.  
  179. function showDoneDialog(queueTotal) {
  180. if (newDiscoveryQueueModal)
  181. newDiscoveryQueueModal.Dismiss();
  182. newDiscoveryQueueModal = ShowConfirmDialog('Done', 'Queue has been explored ' + queueTotal + ' times', 'Open badge page')
  183. .done(function() {
  184. window.open('https://steamcommunity.com/my/badges/62', '_blank');
  185. });
  186. }
  187.  
  188. function showGeneratingDialog(queueCount, queueTotal) {
  189. if (newDiscoveryQueueModal)
  190. newDiscoveryQueueModal.Dismiss();
  191. newDiscoveryQueueModal = ShowBlockingWaitDialog('Generating the new queue...', 'Generating new discovery queue ' + queueCount + ' of ' + queueTotal);
  192. }
  193.  
  194. async function skipQueues(queueTotal) {
  195. let queueCount = 0;
  196. access_token = access_token || await getAccessToken();
  197. for (let i = 0; i < queueTotal; i++) {
  198. queueCount++;
  199. console.log('Queue #' + queueCount);
  200. showGeneratingDialog(queueCount, queueTotal);
  201. let json = await getQueue();
  202. await sleep(1e3);
  203. await skipAppids(json.appids);
  204. }
  205. showDoneDialog(queueTotal);
  206. }
  207.  
  208. function addHTML() {
  209. let parentElem = document.querySelector('.discovery_queue_customize_ctn');
  210. parentElem.insertAdjacentHTML('afterend', '<div class="discovery_queue_customize_ctn"><div class="btnv6_blue_hoverfade btn_medium" id="js-new-queue-auto"><span>Auto discover new queue</span></div><span>Discover the queue 6 times to get the badge</span></div>')
  211. let button = document.getElementById('js-new-queue-auto');
  212. button.addEventListener('click', function() {
  213. skipQueues(6);
  214. }, false );
  215. }
  216.  
  217. (function() {
  218. 'use strict';
  219. addHTML();
  220. })();