- // ==UserScript==
- // @name Steam Wishlist Sorter
- // @namespace SWS
- // @version 1.0.1
- // @description Lets you sort your Steam wishlist by comparing two games at a time.
- // @author Anxeal
- // @license MIT
- // @match https://store.steampowered.com/wishlist/*
- // @grant GM_addStyle
- // @grant GM_setValue
- // @grant GM_getValue
- // @require https://code.jquery.com/jquery-3.3.1.min.js
- // ==/UserScript==
-
- GM_addStyle(`
- .sws-overlay {
- display:flex;
- flex-direction:column;
- justify-content:center;
- align-items:center;
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,.7);
- z-index:9999;
- }
- .sws-close-button {
- position:fixed;
- top:20px;
- right:40px;
- font-size:80px;
- cursor:pointer;
- text-align:center;
- }
- .sws-choice-button {
- box-shadow: 0px 0px 0px 5px #ccc;
- margin: 0.5em;
- width: 292px;
- height: 136px;
- cursor: pointer;
- transition: transform .3s ease, box-shadow .3s ease;
- }
- .sws-choice-button:hover {
- transform: scale(1.2);
- box-shadow: 0px 0px 0px 5px #09c;
- }
- .sws-choice-button:active {
- transform: none;
- }
- .sws-app-title-text {
- font-size: 20px;
- line-height: 60px;
- }
- .sws-sort-button {
- display:flex;
- justify-content:center;
- align-items:center;
- margin-left:15px;
- }
- .sws-progress-outer {
- border:5px solid #069;
- border-radius: 20px;
- background:#999;
- width:800px;
- height:20px;
- margin:30px;
- box-shadow: inset 0 0 5px #000;
- }
- .sws-progress-inner {
- border-radius: 10px;
- background-image: linear-gradient( -45deg, #09c 25%, #0cf 25%, #0cf 50%, #09c 50%, #09c 75%, #0cf 75%, #0cf );
- background-size: 20px 20px;
- animation:sws-progress 1s linear 0s infinite;
- height:100%;
- width:0;
- transition: width .5s ease-out;
- }
- @keyframes sws-progress {
- to {
- background-position: 0 20px;
- }
- }
- `);
-
- (function($, window) {
- 'use strict';
-
- // Class that does merge sort with manual comparisons from an older project
- class ManualSorter {
- constructor(array, $leftButton, $rightButton, callback) {
- var self = this;
- $leftButton.click(function() {
- if ($(this).is("[disabled]")) return;
- self.compare(-1);
- self.sendNext();
- });
- $rightButton.click(function() {
- if ($(this).is('[disabled]')) return;
- self.compare(1);
- self.sendNext();
- });
-
- this.arr = this.shuffleArray(array.slice());
- this.step = 1;
- this.index = 0;
- this.done = false;
-
- this.compCount = 0;
- // approx max comp count
- this.maxCompCount = this.arr.length * Math.ceil(Math.log2(this.arr.length));
-
- this.cleanVars();
- this.callback = callback;
- this.sendNext();
- }
-
- sendNext(){
- this.callback(this.getNext());
- }
-
- cleanVars() {
- this.headLeft = 0;
- this.headRight = 0;
- this.result = [];
- }
-
- compare(input) {
- if (this.done) return;
- var rightLimit = Math.min(this.step, this.arr.length-(this.index+1)*this.step);
- if (this.headLeft < this.step && this.headRight < rightLimit) {
- if (input < 0) {
- this.pushLeft();
- }
- else {
- this.pushRight();
- }
- }
- if (!(this.headLeft < this.step && this.headRight < rightLimit)) {
- while (this.headLeft < this.step) {
- this.pushLeft();
- }
- while (this.headRight < rightLimit) {
- this.pushRight();
- }
- for (var i = 0; i < this.result.length; i++) {
- this.arr[this.index * this.step + i] = this.result[i];
- }
- this.index += 2;
- if ((this.index + 1) * this.step + this.headRight >= this.arr.length) {
- this.step *= 2;
- this.index = 0;
- }
- if (this.step >= this.arr.length) {
- // We are done sorting
- this.done = true;
- }
- this.cleanVars();
- }
- }
-
- pushLeft() {
- this.result.push(this.arr[this.index * this.step + this.headLeft]);
- this.headLeft++;
- this.compCount++;
- }
-
- pushRight() {
- this.result.push(this.arr[(this.index + 1) * this.step + this.headRight]);
- this.headRight++;
- this.compCount++;
- }
-
- getNext() {
- if (!this.done) {
- return { left: this.arr[this.index * this.step + this.headLeft], right: this.arr[(this.index + 1) * this.step + this.headRight], done: false};
- } else {
- console.log("[SWS] Done sorting!");
- return { result: this.arr, done: true};
- }
- }
-
- shuffleArray(a) {
- var j, x, i;
- for (i = a.length - 1; i > 0; i--) {
- j = Math.floor(Math.random() * (i + 1));
- x = a[i];
- a[i] = a[j];
- a[j] = x;
- }
- return a;
- }
-
- serialize() {
- return JSON.stringify(this);
- }
-
- deserialize(json) {
- var obj = JSON.parse(json);
- console.log(obj);
- for(var val in obj) {
- this[val] = obj[val];
- }
- }
-
- get progress(){
- return this.compCount/this.maxCompCount*100;
- }
- };
-
- var waitForWishlist = $.Deferred();
-
- waitForWishlist.then(function(wl){
-
- // g_bCanEdit => if wishlist is editable
-
- // if it isn't our wishlist, don't bother running
- if(!window.g_bCanEdit){
- console.log("[SWS] Can't edit wishlist: Stopping.");
- return;
- }
-
- var $overlay = $("<div class='sws-overlay'></div>");
- var $closeButton = $("<a class='sws-close-button'>×</a>");
- var $appTitleText = $("<div class='sws-app-title-text '></div>");
- var $leftButton = $("<div class='sws-choice-button'></div>");
- var $rightButton = $leftButton.clone();
- var $progress = $("<div class='sws-progress-outer'><div class='sws-progress-inner'></div></div>");
-
-
- $(document.body).append($overlay);
- $overlay.append($closeButton).append($leftButton).append($appTitleText).append($rightButton).append($progress);
- $overlay.hide();
-
- $('.sws-choice-button').hover(function(){
- $appTitleText.text($(this).attr("data-app-title")).stop().animate({ opacity: 1 }, 200);
- }, function(){
- $appTitleText.stop().animate({ opacity: 0 }, 200);
- }).on("mousedown", function(e){
- if(e.which == 2) { // middleclick
- window.open('https://store.steampowered.com/app/'+$(this).attr("data-app-id")+'/', '_blank');
- }
- });
-
- // close button behavior
- $closeButton.click(function(){
- $overlay.fadeOut();
- });
-
- // main buttons
-
- var $sortButton = $("<div class='sws-sort-button'><div class='btnv6_blue_hoverfade btn_medium'><span>Sort!</span></div></div>");
- var $saveButton = $sortButton.clone();
- var $discardButton = $sortButton.clone();
- var $saveProgressButton = $sortButton.clone();
- var $loadProgressButton = $sortButton.clone();
-
- $sortButton.appendTo(".wishlist_header").children().click(function(){
- $overlay.fadeIn();
- $discardButton.fadeIn();
- $saveProgressButton.fadeIn();
- });
- $sortButton.hide().fadeIn();
-
- $saveButton.hide().children().children().text("Save");
- $saveButton.appendTo(".wishlist_header").children().click(function(){
- wl.SaveOrder();
- location.reload();
- });
-
- $discardButton.hide().children().children().text("Discard");
- $discardButton.appendTo(".wishlist_header").children().click(function(){
- location.reload();
- });
-
- $saveProgressButton.hide().children().children().text("Save Progress");
- $saveProgressButton.appendTo(".wishlist_header").children().click(function(){
- var data = sorter.serialize();
- GM_setValue("sws-sorter-data", data);
- alert("Progress Saved!");
- });
-
- $loadProgressButton.hide().children().children().text("Load Progress");
- $loadProgressButton.appendTo(".wishlist_header").children().click(function(){
- var data = GM_getValue("sws-sorter-data");
- sorter.deserialize(data);
- sorter.sendNext();
- $sortButton.children().click();
- });
- if(GM_getValue("sws-sorter-data")) $loadProgressButton.fadeIn();
-
- var fadeDuration = 100;
- var setChoiceData = function($button, side){
- var bgUrl = "url('"+window.g_rgAppInfo[side].capsule+"')";
- if($button.attr("data-app-id") == side){
- $button.attr("disabled", "disabled")
- .delay(2*fadeDuration)
- .removeAttr("disabled");
- return;
- }
- $button.attr("disabled", "disabled").fadeOut(fadeDuration, function(){
- $button.css("background-image", bgUrl);
- $button.attr("data-app-id", side);
- $button.attr("data-app-title", window.g_rgAppInfo[side].name);
- $button.trigger("mouseenter");
- }).fadeIn(fadeDuration, function(){
- $button.removeAttr("disabled");
- });
- }
-
-
- var sorter = new ManualSorter(wl.rgAllApps, $leftButton, $rightButton, function(next){
- if (next.done) {
- wl.rgAllApps = next.result;
- wl.Update();
- $overlay.fadeOut();
- $saveButton.fadeIn();
- alert("Done sorting! Please review your wishlist and save or discard.");
- } else {
- setChoiceData($leftButton, next.left);
- setChoiceData($rightButton, next.right);
- if(sorter) $progress.children().width((sorter.progress)+"%");
- }
- });
- });
-
- var checkWishlist = function(){
- if(!window.g_Wishlist || !window.g_Wishlist.rgAllApps){
- console.log("[SWS] Waiting for wishlist...");
- setTimeout(checkWishlist, 500);
- return;
- }
- console.log("[SWS] Wishlist loaded.");
- waitForWishlist.resolve(window.g_Wishlist);
- };
-
- checkWishlist();
-
- })(unsafeWindow.jQuery, unsafeWindow);