// ==UserScript==
// @name Reset Steam Workshop Subscriptions
// @name:nl Reset Steam Workshop Abonnementen
// @namespace https://timmy.ws
// @version 1.1.4
// @license MIT
// @supportURL hello@timmy.ws
// @description Unsubscribe from all Steam Workshop Addons with a single click.
// @description:nl Zeg al je Steam Workshop abonnementen op met één enkele klik.
// @author Timmy
// @compatible firefox
// @compatible chrome
// @compatible opera
// @compatible safari
// @match *://steamcommunity.com/id/*/myworkshopfiles/*mysubscriptions*
// @match *://steamcommunity.com/profiles/*/myworkshopfiles/*mysubscriptions*
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
/*jslint browser: true*/
(function () {
'use strict';
var addons = [], addonTotal, pageTotal, sessionId;
// Returns the number of addons the user is subscribed to
function getAddonTotal() {
var regex, workshopInfo;
regex = /([0-9]+)/g;
workshopInfo = document.getElementsByClassName('workshopBrowsePagingInfo')[0].innerHTML;
return parseInt(workshopInfo.match(regex)[2], 10);
}
// Return the number of pages we have to analyse
function getPageTotal(addonTotal) {
return Math.ceil(addonTotal / 30);
}
// Returns true if we are on a secured page
function usingSSL() {
return (document.location.protocol === 'https:') ? true : false;
}
// Returns query variable (https://css-tricks.com/snippets/javascript/get-url-variables/)
function getQueryVariable(variable) {
var query, vars, i, pair;
query = window.location.search.substring(1);
vars = query.split('&');
for (i = 0; i < vars.length; i = i + 1) {
pair = vars[i].split('=');
if (pair[0] === variable) { return pair[1]; }
}
return false;
}
// Returns the users' profile id
function getBaseURL() {
return document.querySelector(".user_avatar").href;
}
// Returns the users' session id
function getSessionId() {
return document.getElementById('PublishedFileUnsubscribe').getElementsByTagName('input')[2].value;
}
// Returns the appId and name of the game if a filter is applied, or false
function getAppFilter() {
var id, name;
id = getQueryVariable('appid');
if (!id || id === "0") { return false; }
name = document.getElementById('searchedForApp').childNodes[0].nodeValue;
return [ id, name ];
}
// Display feedback to user
function feedback(id, message) {
var element = document.getElementById(id);
if (!element) {
element = document.createElement('div');
element.id = id;
document.getElementById('unsub-progress').appendChild(element);
} else if (element.firstChild) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
element.appendChild(document.createTextNode(message));
}
// Unsubscribe from all addons
function processAllAddons(xmlhttp) {
if (addons.length < addonTotal) { return false; }
var i, j, handleStateChange, url;
feedback('ANALYSE_PROG', 'Analysing subscriptions... Done!');
j = 0;
handleStateChange = function (index) {
return function () {
if (xmlhttp[index].readyState === 4) {
j = j + 1;
feedback('UNSUB_PROGRESS', 'Unsubscribing from addons... (' + Math.round(j / addonTotal * 100) + '%)');
if (j === addonTotal) {
feedback('UNSUB_PROGRESS', 'Unsubscribing from addons... Done!');
feedback('END', 'Reloading page...');
setTimeout(function () {
window.location.reload();
}, 1000);
}
}
};
};
xmlhttp = [];
url = (usingSSL()) ? 'https' : 'http';
url += '://steamcommunity.com/sharedfiles/unsubscribe';
for (i = 0; i < addons.length; i = i + 1) {
xmlhttp[i] = new XMLHttpRequest();
xmlhttp[i].open('POST', url);
xmlhttp[i].setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp[i].onreadystatechange = handleStateChange(i);
xmlhttp[i].send('id=' + addons[i][0] + '&appid=' + addons[i][1] + '&sessionid=' + sessionId);
}
}
// Get subscribed addons for each page and add them to the addons array
function processSinglePage(xmlhttp, index) {
if (xmlhttp[index].status === 200) {
var container, unsubscribeItem, i, itemDetails;
container = document.implementation.createHTMLDocument().documentElement;
container.innerHTML = xmlhttp[index].responseText;
unsubscribeItem = container.querySelectorAll('a[id^="UnsubscribeItemBtn"]');
for (i = 0; i < unsubscribeItem.length; i = i + 1) {
itemDetails = decodeURI(unsubscribeItem[i].href).match(/[0-9]+/g); // Extract WorkshopID and AppID
addons.push([itemDetails[0], itemDetails[1]]);
}
processAllAddons(xmlhttp);
}
}
function getAddons() {
var url, appFilter, xmlhttp, handleStateChange, i;
appFilter = getAppFilter();
url = getBaseURL();
url += '/myworkshopfiles/?browsefilter=mysubscriptions';
url += appFilter ? '&appid=' + appFilter[0] : '';
url += '&numperpage=30&p=';
xmlhttp = [];
handleStateChange = function (index) {
return function () {
if (xmlhttp[index].readyState === 4) {
feedback('ANALYSE_PROG', 'Analysing subscriptions... (' + index + '/' + pageTotal + ')');
processSinglePage(xmlhttp, index);
}
};
};
for (i = 1; i <= pageTotal; i = i + 1) {
xmlhttp[i] = new XMLHttpRequest();
xmlhttp[i].onreadystatechange = handleStateChange(i);
xmlhttp[i].open('GET', url + i);
xmlhttp[i].send();
}
}
// Injects our element in the DOM
function injectUnsubscriber() {
if (document.getElementById('no_items')) {
return false;
}
addonTotal = getAddonTotal();
pageTotal = getPageTotal(addonTotal);
sessionId = getSessionId();
var reference, parent, wrap, appFilter, titleText, title, button, clear, leftContents, progress;
reference = document.getElementById('tabs_basebg_workshop');
parent = reference.parentNode;
wrap = document.createElement('div');
wrap.id = 'unsubscriber';
parent.insertBefore(wrap, reference);
appFilter = getAppFilter();
if (appFilter) {
titleText = 'Reset Workshop Subscriptions for ' + appFilter[1];
} else {
titleText = 'Reset ALL Workshop Subscriptions';
}
title = document.createElement('div');
title.className = 'title';
title.appendChild(document.createTextNode(titleText));
wrap.appendChild(title);
button = document.createElement('div');
button.className = 'button';
button.innerHTML = 'Unsubscribe All';
button.addEventListener('click', function () {
var confirm = window.confirm("Are you sure you want to " + titleText + "?");
if (confirm) {
button.style.pointerEvents = 'none';
leftContents = document.getElementById('leftContents');
while (leftContents.firstChild) {
leftContents.removeChild(leftContents.firstChild);
}
progress = document.createElement('div');
progress.id = 'unsub-progress';
progress.className = 'generic-block';
leftContents.appendChild(progress);
feedback("START", "Task: " + titleText);
getAddons();
}
});
wrap.appendChild(button);
clear = document.createElement('div');
clear.className = 'clear';
wrap.appendChild(clear);
GM_addStyle('#unsubscriber {font-size: 13px; width: 100%; margin-top: 12px; background: rgba(0, 0, 0, 0.4); color: rgb(143, 152, 160); padding: 10px; box-sizing: border-box;}');
GM_addStyle('#unsubscriber .title {color: #67c1f5; font-size: 16px; font-family: \'Motiva Sans Light\', Arial, Tahoma; float: left;}');
GM_addStyle('#unsubscriber .button {color: rgba(255, 255, 255, 0.8);background: rgba(231, 76, 60, 0.4); font-size: 13px; padding: 3px 9px; float: right; border-radius: 2px; cursor: pointer;}');
GM_addStyle('#unsubscriber .button:hover {color: #fff; background: rgba(231, 76, 60, 0.75);}');
GM_addStyle('#unsubscriber .clear {clear: both;}');
GM_addStyle('.generic-block {margin-top: 10px; padding: 10px; color: rgb(143, 152, 160); background: rgba(0, 0, 0, 0.4); width: 100%; font-size: 13px; box-sizing: border-box; line-height: 1.5em;}');
GM_addStyle('.disabled {pointer-events: none; background: rgba(0, 0, 0, 0.7);}');
}
injectUnsubscriber();
}());