Steam New Queue AutoDiscover

auto run trough steam next fest discovery queue

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Steam New Queue AutoDiscover
// @version      0.2
// @description  auto run trough steam next fest discovery queue
// @author       gortik
// @license      MIT
// @match        https://store.steampowered.com/explore/
// @icon         https://store.steampowered.com/favicon.ico
// @grant        none
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/light/protobuf.min.js

// @namespace https://greasyfork.org/users/968091
// ==/UserScript==


var	access_token,
	skipDelay = 300,		//in ms
	newDiscoveryQueueModal;


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}}}}},
	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}}}}}



function sleep(ms) {
        return new Promise(resolve => {
		console.log('Sleep: ' + ms/1000 + 's.');
		setTimeout(resolve, ms)
	});
}

function buffer2hex(buffer) {
	function i2hex(i) { return ('0' + i.toString(16)).slice(-2); }
	return Array.from(buffer).map(i2hex).join(' ');
}

function buffer2base64(buffer) {
	let str = buffer.reduce((acc, char) => acc + String.fromCharCode(char) , '');
	return btoa(str);
}

async function getAccessToken() {
	//document.querySelector('#application_config').dataset.loyalty_webapi_token
	/*if (window.location.href.indexOf('steampowered') > -1) {
	}
	else if(window.location.href.indexOf('steamcommunity') > -1) {
	}*/
	let response = await fetch('https://store.steampowered.com/points/shop');
	let text = await response.text();
	let match = text.match(/webapi_token":"([\d\w]+)&quot/);
	console.log('access_token: ' + match[1]);
	return match[1];
}


//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]
//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]

//accepts base64  or Array  or Uint8Array
function decode(json, messageName, msg) {
	let root = protobuf.Root.fromJSON(json);
	let message = root.lookupType(messageName);
	let arr = [];
	//if msg is array or Uint8Array
	if (Array.isArray(msg) || ArrayBuffer.isView(msg))
		arr = msg;
	else
		protobuf.util.base64.decode(protobufMsg, arr, 0)
	//let arr = new Uint8Array(X)	//X = bytes needed
	return message.decode(arr);
}

//j = decode(jsonGetQueue, 'getQueue', arrGet)

function createPayload(appid) {
	return {
		a: 1,
		appid: appid,
		in1: {
			in2: {
				a: 1235711
			}
		}
	}
}

function encode(json, messageName, payload) {
	let	root = protobuf.Root.fromJSON(json),
		message = root.lookupType(messageName);
	//var payload = { a: 1, appid: 987654, in1: { in2: { a: 1235711 } } };
	let msg_to_send = message.create(payload);
	let buffer = message.encode(msg_to_send).finish();
	return buffer2base64(buffer);
}

async function getQueue() {
	let	body = {
			access_token: access_token,
			input_protobuf_encoded: 'CAESAlNLGAEwAWIGCgQI/7VL'
		},
		url = 'https://api.steampowered.com/IStoreService/GetDiscoveryQueue/v1?' + new URLSearchParams(body).toString(),
		options = {
			"credentials":"omit",
			"headers":{
				"accept":"application/json, text/plain, */*",
				"accept-language":"en-US,en;q=0.9",
				"sec-fetch-mode":"cors",
				"sec-fetch-site":"same-site"
			},
			"referrer":"https://store.steampowered.com/sale/nextfest",
			"referrerPolicy":"no-referrer-when-downgrade",
			"body": null,
			"method": "GET",
			"mode":"cors"
		}
	let response  = await fetch(url, options);
	let arrBuff = await response.arrayBuffer();
	let uint8 = new Uint8Array(arrBuff);
	//let uint8 = Array.from(arrBuff);
	console.log(buffer2base64(uint8));
	let json = decode(jsonGetQueue, 'getQueue', uint8)
	return json;
}


async function postSkip(protobufBase64) {
	let	query = {
			access_token: access_token
		},
		body = {
			input_protobuf_encoded: protobufBase64
		},
		url = 'https://api.steampowered.com/IStoreService/SkipDiscoveryQueueItem/v1?' + new URLSearchParams(query).toString();

	let res = await fetch(url, {
		"headers": {
			"accept": "application/json, text/plain, */*",
			"accept-language": "en-US,en;q=0.9,sk;q=0.8,cs;q=0.7",
			// "content-type": "multipart/form-data; boundary=----WebKitFormBoundary5BetF1tNQduIif48",
			"content-type": "application/x-www-form-urlencoded",
			//"sec-ch-ua": "\";Not A Brand\";v=\"99\", \"Chromium\";v=\"88\"",
			//"sec-ch-ua-mobile": "?0",
			//"sec-fetch-dest": "empty",
			"sec-fetch-mode": "cors",
			"sec-fetch-site": "same-site"
		},
		//"referrer": "https://store.steampowered.com/",
		//"referrerPolicy": "strict-origin-when-cross-origin",
		//"body": "------WebKitFormBoundary5BetF1tNQduIif48\r\nContent-Disposition: form-data; name=\"input_protobuf_encoded\"\r\n\r\nCAEQsqpHGgYKBAj/tUs=\r\n------WebKitFormBoundary5BetF1tNQduIif48--\r\n",
		"body": new URLSearchParams(body).toString(),
		"method": "POST",
		"mode": "cors",
		"credentials": "omit"
	});
	let text = await res.text();
	if (text == '')
		console.log('OK');
	else
		console.log('')
}

async function skipAppids(appids) {
	let i = 0;
	for (let appid of appids) {
		console.log(appid);

		let payload = createPayload(appid);
		let payload_base64 = encode(jsonSkip, 'skipAppid', payload);
		await postSkip(payload_base64);

		newDiscoveryQueueModal.Dismiss();
		newDiscoveryQueueModal = ShowBlockingWaitDialog('Exploring the queue...', 'Request ' + ++i + ' of ' + appids.length);
		await sleep(skipDelay);
	}
	console.log('Done');
}

function showDoneDialog(queueTotal) {
	if (newDiscoveryQueueModal)
		newDiscoveryQueueModal.Dismiss();
	newDiscoveryQueueModal = ShowConfirmDialog('Done', 'Queue has been explored ' + queueTotal + ' times', 'Open badge page')
		.done(function() {
			window.open('https://steamcommunity.com/my/badges/62', '_blank');
		});
}

function showGeneratingDialog(queueCount, queueTotal) {
	if (newDiscoveryQueueModal)
		newDiscoveryQueueModal.Dismiss();
	newDiscoveryQueueModal = ShowBlockingWaitDialog('Generating the new queue...', 'Generating new discovery queue ' + queueCount + ' of ' + queueTotal);
}

async function skipQueues(queueTotal) {
	let queueCount = 0;
	access_token = access_token || await getAccessToken();
	for (let i = 0; i < queueTotal; i++) {
		queueCount++;
		console.log('Queue #' + queueCount);
		showGeneratingDialog(queueCount, queueTotal);
		let json = await getQueue();
		await sleep(1e3);
		await skipAppids(json.appids);
	}
	showDoneDialog(queueTotal);
}

function addHTML() {
	let parentElem = document.querySelector('.discovery_queue_customize_ctn');
	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>')
	let button = document.getElementById('js-new-queue-auto');
	button.addEventListener('click', function() {
		skipQueues(6);
	}, false );
}

(function() {
	'use strict';
	addHTML();
})();