NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @namespace https://openuserjs.org/users/Weinur2
// @name Gamebanana trashed files search
// @description https://gamebanana.com/search?mid=SearchResults&query=&game=*§ion=*
// @copyright 2021, Weinur2 (https://openuserjs.org/users/Weinur2)
// @license MIT
// @version 0.0.0
// @author Weinur
// @match https://gamebanana.com/search?mid=SearchResults&query=&game=*&vl[page]=*§ion=*
// @require https://code.jquery.com/jquery-3.5.1.min.js
// @run-at document-start
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_listValues
// ==/UserScript==
var saveItem = "gwitems";
var loadString = "";
var currentItems = {};
var usedFastMethod = false;
function toNumber(number, float = false)
{
var typeOfNumber = typeof number;
switch(typeOfNumber)
{
case "number": return number;
break;
case "string": return float ? parseFloat(number) : parseInt(number, 10);
break;
case "default": return -1;
break;
}
return -1;
}
function toInt(number)
{
return Math.round(toNumber(number));
}
function toFloat(number)
{
return toNumber(number, true);
}
function log(message, varName, debug)
{
if(varName)
{
message = varName + ": " + message;
}
if(debug) {
alert(message);
} else {
console.log(message);
}
}
function copyToClipboard (text) {
if (navigator.clipboard) { // default: modern asynchronous API
return navigator.clipboard.writeText(text);
} else if (window.clipboardData && window.clipboardData.setData) { // for IE11
window.clipboardData.setData('Text', text);
return Promise.resolve();
} else {
// workaround: create dummy input
var input = $('<input type="text" value="test">');
input.val(text);
document.body.append(input.get(0));
input.focus();
input.select();
document.execCommand('copy');
input.remove();
return Promise.resolve();
}
}
function startLoading(start = true)
{
$("body, html").toggleClass("loading", start);
}
function startProgress(start = true)
{
$("body, html").toggleClass("progress", start);
}
function getPercentValueFloat(loaded, total)
{
return loaded / total * 100;
}
function getPercentValue(loaded, total)
{
return Math.round(getPercentValueFloat(loaded, total));
}
function setProgressBarValue(value, start = false)
{
if(start) startProgress();
$(".progressSpinner").css("--progress-percent", value);
}
function getCurrentProgressBarValue()
{
return toInt($(".progressSpinner").css("--progress-percent"));
}
function addProgressBarValue(value, stop = false, stopTimeout = 0)
{
var currentPercent = getCurrentProgressBarValue();
var nextPercent = Math.round(currentPercent + value);
nextPercent = nextPercent >= 100 ? 100 : nextPercent;
setProgressBarValue(nextPercent);
if(stop && nextPercent == 100) {
setTimeout(function() {
startProgress(false);
}, stopTimeout);
}
}
function setProgressBarValueFloat(value)
{
$(".progressSpinner").css("--progress-percent-float", value);
}
function getCurrentProgressBarValueFloat()
{
return toFloat($(".progressSpinner").css("--progress-percent-float"));
}
function addProgressBarValueFloat(value, stop = false, stopTimeout = 0)
{
var currentPercent = getCurrentProgressBarValueFloat();
var nextPercent = currentPercent + value;
nextPercent = nextPercent >= 100 ? 100 : nextPercent;
var nextPercentRound = Math.round(nextPercent);
setProgressBarValueFloat(nextPercent);
setProgressBarValue(nextPercentRound);
if(stop && nextPercentRound == 100) {
setTimeout(function() {
startProgress(false);
setProgressBarValue(0);
setProgressBarValueFloat(0);
}, stopTimeout);
}
}
function deleteMe(percent, itemType, id)
{
var record = $(this).closest("record");
if(!record.length) {
var ele = "a.we" + itemType + "Id_" + id;
record = $(ele).closest("record");
}
if(record.length) {
record.remove();
}
addProgressBarValueFloat(percent, true, 1000);
log("buja");
}
function save(itemType, id, set)
{
var item = itemType + "_" + id;
currentItems[item] = set;
GM_setValue(item, set);
}
function saveItems()
{
var newItems = {};
var items = currentItems;
for (let key of Object.keys(items)) {
let value = currentItems[key];
if(value !== undefined) newItems[key] = value;
}
for (let key of GM_listValues()) {
let value = GM_getValue(key);
if(value !== undefined) newItems[key] = value;
}
currentItems = newItems;
var saveString = btoa(JSON.stringify(newItems));
localStorage.setItem(saveItem, saveString);
return saveString;
}
function load()
{
if(loadString !== "")
{
currentItems = JSON.parse(atob(loadString));
}
var saveString = saveItems();
console.log("saveThis (to clipboard):");
console.log(saveString);
copyToClipboard(saveString);
}
//load();
function getCurrentItem(itemType, id)
{
return currentItems[itemType + "_" + id];
}
function fetchURLEx(url, callbackTrue, callbackFalse, callbackError) {
const myInit = {
method: 'GET',
headers: {
'pragma': 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua': '"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
'origin': 'https://gamebanana.com',
'sec-ch-ua-mobile': '?0',
'sec-fetch-site': 'cross-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'font',
'referer': 'https://fonts.googleapis.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
'accept': '*/*',
'x-client-data': 'CIe2yQEIorbJAQjEtskBCKmdygEI0qDKAQj4x8oBCLKaywEI5JzLAQioncsB',
'accept-language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
'accept-encoding': 'gzip, deflate, br',
}
};
let myRequest = new Request(url, myInit);
fetch(myRequest).then(function(response) {
if(!response.ok)
{
throw Error(response.statusText);
}
return response.text();
}).then(function(text) {
var trashed = text.indexOf("TrashNoticeModule") >= 0;
var private = text.indexOf("PrivateAccessNoticeModule") >= 0;
if(trashed || private) {
callbackTrue(trashed, private);
} else {
callbackFalse();
}
}).catch(function(error) {
callbackError(error);
});
}
function callbackFileDownload(percent, itemType, id, itemTypes, trashed, private)
{
$(this).data("itemType", itemType)
.data("id", id)
.data("itemTypes", itemTypes)
.toggleClass("fileDownload", true)
.toggleClass("trashedFile", trashed)
.toggleClass("privateFile", private);
addProgressBarValueFloat(percent, true, 1000);
}
function downloadURLEx(url, fileName, mirror)
{
setProgressBarValue(0, true);
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onprogress = function(pe) {
console.log('progress');
if (pe.lengthComputable) {
var percent = getPercentValue(pe.loaded, pe.total);
setProgressBarValue(percent >= 99 ? 99 : percent);
}
};
xhr.onload = function(e) {
if (this.status == 200) {
addProgressBarValue(100, true, 1000);
var blob = this.response;
//TODO fallback needed for IE8 & IE9
if (navigator.appVersion.toString().indexOf('.NET') > 0) {
//IE 10+
window.navigator.msSaveBlob(blob, fileName);
} else {
//Firefox, Chrome
var a = document.createElement("a");
var blobUrl = window.URL.createObjectURL(new Blob([blob], {type: blob.type}));
document.body.appendChild(a);
a.style = "display: none";
a.href = blobUrl;
a.download = fileName;
a.click();
$(a).remove();
}
} else if(mirror) {
downloadURLEx(mirror, fileName);
} else {
addProgressBarValue(100, true, 1000);
}
};
xhr.send();
}
function callbackFiles(itemType, id, item, itemTypes)
{
$(Object.keys(item)).each(function() {
var downloadURL = item[this];
var downloadURL_ = "https://files.gamebanana.com/" + itemTypes + "/" + this;
downloadURLEx(downloadURL_, this, itemTypes, downloadURL);
});
}
function downloadFiles(itemType, id, itemTypes)
{
var item = getCurrentItem(itemType + "_files", id);
if(item !== undefined) {
if(item) callbackFiles(itemType, id, item, itemTypes);
return;
}
$.getJSON("https://api.gamebanana.com/Core/Item/Data", {
itemtype: itemType,
fields: "Files().aFiles()",
itemid: id,
}, function(response) {
var downloadLinks = {};
$(response).each(function(i, itemI) {
$(Object.keys(this)).each(function(j, itemJ) {
var that = itemI[itemJ];
downloadLinks[that._sFile] = that._sDownloadUrl;
});
});
item = downloadLinks;
save(itemType + "_files", id, item);
callbackFiles(itemType, id, item, itemTypes);
}).done(function() { log('getJSON request succeeded!'); })
.fail(function(jqXHR, textStatus, errorThrown) { log('getJSON request failed! ' + textStatus); usedFastMethod = false; })
.always(function() { log('getJSON request ended!');});
}
function isBan(percent, itemType, id, callback, callbackDownload, itemTypes)
{
var item = getCurrentItem(itemType, id);
if(item !== undefined) {
if(!item) {
callback(percent, itemType, id);
} else {
callbackDownload(percent, itemType, id, itemTypes ? itemTypes : itemType.toLowerCase() + "s");
}
return;
}
if(itemTypes) {
fetchURLEx("/" + itemTypes + "/" + id, function(trashed, private) {
save(itemType, id, true);
callbackDownload(percent, itemType, id, itemTypes, trashed, private);
}, function() {
save(itemType, id, false);
callback(percent, itemType, id);
}, function(error) {
addProgressBarValueFloat(percent, true, 1000);
});
return;
}
$.getJSON("https://api.gamebanana.com/Core/Item/Data", {
itemtype: itemType,
fields: "Trash().bIsTrashed()",
itemid: id,
}, function(response) {
log(response, "response");
var string = response.toString().toLowerCase();
var good = string.indexOf("true") >= 0;
save(itemType, id, good);
if(!good) {
callback(percent, itemType, id);
} else {
callbackDownload(percent, itemType, id, itemTypes ? itemTypes : itemType.toLowerCase() + "s", true, false);
}
}).done(function() { log('getJSON request succeeded!'); })
.fail(function(jqXHR, textStatus, errorThrown) { log('getJSON request failed! ' + textStatus); usedFastMethod = false; addProgressBarValueFloat(percent, true, 1000); })
.always(function() { log('getJSON request ended!');});
}
function getButtonHtml(id, title)
{
var html = `<div style="float: left; margin-left: 1em;" id="${id}Div"><button type="button" class="ExtendedContentButton" id="${id}Button"><spriteicon class="MiscIcon ShowContentIcon"></spriteicon><span>${title}</span></button></div>`;
return html;
}
function createButtons(cssStyles) {
$( ".InfiniteScroller" ).css(cssStyles).after( getButtonHtml("trashedFilesOnly", "Show trashed/private files only!") )
.after( getButtonHtml("autoScroll", "Show all elements!") );
$( "#trashedFilesOnlyDiv, #autoScrollDiv" ).css(cssStyles).css("margin-left", "1em");
}
function handler(cssStyles)
{
if( $( "#trashedFilesOnlyDiv" ).length ) return;
createButtons(cssStyles);
$(window).on("scroll", function() {
if( ! $( "#trashedFilesOnlyDiv" ).length ) createButtons(cssStyles);
var element = $( ".InfiniteScroller" );
if(element.length) {
element.css(cssStyles);
} else {
$( "#autoScrollDiv" ).remove();
$( "#trashedFilesOnlyDiv[style]" ).removeAttr("style");
}
});
}
function infiScroller() {
var infi = $(".InfiniteScroller");
if(infi.length) {
infi.get(0).scrollIntoView();
infi.find("button").trigger("click");
} else {
$("body, html").toggleClass("loading", false);
var element = $( "#trashedFilesOnlyDiv" );
if(element.length) element.get(0).scrollIntoView();
return;
}
window.setTimeout(infiScroller, 500);
}
function getCss() {
var style = document.createElement("style");
style.innerHTML = `
html.loading,
html.progress {
overflow-y: hidden;
pointer-events: none;
}
body.not(.loading) .loadingspinner,
body:not(.progress) .progressSpinner {
display: none;
}
body.loading,
body.progress {
height: 100vh;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
overflow-y: scroll;
display: block;
pointer-events: none;
}
body.loading:after,
body.progress:after {
display: block;
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: grey;
pointer-events: none;
z-index: 999999999999999;
opacity: 0.5;
}
body.loading .loadingspinner {
pointer-events: none;
width: 200px;
height: 200px;
border: 20px solid transparent;
border-color: #eee;
border-top-color: #3E67EC;
border-radius: 100%;
animation: loadingspin 1s linear infinite;
z-index: 10000000000000000000;
left: calc(50% - 100px);
top: calc(50% - 100px);
position: fixed;
box-sizing: border-box;
}
body.progress .progressSpinner {
pointer-events: none;
width: 250px;
height: 250px;
z-index: 10000000000000000000;
left: calc(50% - 125px);
top: calc(50% - 125px);
position: fixed;
box-sizing: border-box;
--progress-percent: 0;
--progress-percent-float: 0;
display: grid;
place-content: center;
transform: scale(1);
clip-path: circle(49%);
color: #ff4d4d;
width: 250px;
height: 250px;
}
body.progress .progressSpinner:before,
body.progress .progressSpinner:after {
grid-row: 1;
grid-column: 1;
font-size: 16px;
}
body.progress .progressSpinner:before {
border: solid 2em transparent;
padding: 6em;
border-radius: 50%;
box-shadow: inset 0 0 0 0.5em currentcolor;
--progress-slice: calc(360deg/16);
--progress-s-gap: calc(0.2*var(--progress-slice));
--progress-solid: calc((1 - 0.2)*var(--progress-slice));
background: repeating-conic-gradient(from calc(.5*var(--progress-s-gap)), currentcolor 0% var(--progress-solid), transparent 0% var(--progress-slice)) border-box;
filter: blur(0.5px);
--progress-mask: conic-gradient(red 0% calc(var(--progress-percent)*1%), rgba(255, 0, 0, .3) 0%), linear-gradient(red, red) border-box, radial-gradient(red 0% 5.5em, transparent calc(5.5em + 1px) calc(5.75em - 1px), red 5.75em calc(6em + 1px), transparent calc(6em + 2px));
-webkit-mask: var(--progress-mask);
-webkit-mask-composite: source-in, source-out;
mask: var(--progress-mask);
mask-composite: exclude;
content: '';
}
body.progress .progressSpinner:after {
place-self: center;
counter-reset: percent var(--progress-percent);
font: 3.75em consolas, monaco, ubuntu mono, monospace;
content: counter(percent) '%';
}
@keyframes progress {
90%, 100% {
--progress-percent: 100;
}
}
@keyframes loadingspin {
100% {
transform: rotate(360deg)
}
}
a.Name.fileDownload {
position: relative;
display: block;
}
a.Name.fileDownload:after {
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
content: "Download";
opacity: 0.8;
border-radius: 3px;
font-size: var(--ButtonFontSize);
font-family: var(--ButtonFontFamily);
outline: none;
background: var(--ButtonBackground);
color: var(--ButtonFontColor);
}
a.Name.fileDownload:hover:after {
opacity: 1.0;
}
a.Name.fileDownload.trashedFile:after {
content: "Download (trashed)";
}
a.Name.fileDownload.privateFile:after {
content: "Download (private)";
}
a.Name.fileDownload.trashedFile.privateFile:after {
content: "Download (trashed / private)";
}
`;
return $(style);
}
function getLoading()
{
return $('<div class="loadingspinner"></div>');
}
function getProgressBar()
{
return $('<div class="progressSpinner"></div>');
}
function getURLParams()
{
var params = $(location).attr("search").split("&");
var newParams = {};
$(params).each(function(i) {
var paramKeyValue = this.split("=");
newParams[paramKeyValue[0]] = paramKeyValue[1];
});
return newParams;
}
$(document).ready(function() {
var urlParams = getURLParams();
var section = urlParams["section"];
var sections = section + "s";
sections = sections.toLowerCase();
$("body").data("gwsection", section).data("gwsections", sections);
getCss().appendTo("body");
getLoading().appendTo("body");
getProgressBar().appendTo("body");
var cssStyles = {
"margin-top": "2em",
"margin-bottom": "2em",
"float": "left"
};
var buttonCss = {
"background": "#1c272e",
"color": "var(--DefaultBlueColor)"
};
handler(cssStyles);
$("body").on("click", ".Controls a[title]", function() {
$(".InfiniteScroller").triggerHandler("check");
});
$("body").on("mouseover touchmove touchend touchcancel check", ".InfiniteScroller", function(e) {
handler(cssStyles);
});
$("body").on("click", "#autoScrollDiv", function() {
$("body, html").toggleClass("loading", true);
infiScroller();
});
$("body").on("click", "#trashedFilesOnlyDiv", function() {
setProgressBarValueFloat(0);
setProgressBarValue(0, true);
var selector = 'records.List recordcell a.Name[href^="https://gamebanana.com/' + sections + '/"]';
var elements = $(selector);
var length = elements.length;
var percent = getPercentValueFloat(1, length);
elements.each(function(i) {
console.log("Element: " + i);
var that = this;
var id = $(that).attr("href").split(sections + "/");
id = parseInt(id[1], 10);
$(that).toggleClass("we" + section + "Id_" + id, true);
setTimeout(function() {
isBan(percent, section, id, deleteMe.bind(that), callbackFileDownload.bind(that), usedFastMethod ? false : sections);
}, usedFastMethod ? 3600 : 0);
});
var button = $("#trashedFilesOnlyButton").css(buttonCss);
setTimeout(function() { button.filter("[style]").removeAttr("style"); }, 700);
return false;
});
$("body").on("click", "a.Name.fileDownload", function(event) {
var element = $(this);
event.preventDefault();
setProgressBarValue(0, true);
downloadFiles(element.data("itemType"), element.data("id"), element.data("itemTypes"));
});
});