// ==UserScript==
// @name Sadpanda Save/Export All Favorites
// @namespace SaddestPanda
// @description Load all favorites to the page and save it or just copy the textbox contents. Works on exhentai and e-hentai.
// @include /^https?://e.hentai\.org/favorites.php.*/
// @homepage https://greasyfork.org/en/scripts/23406-sadpanda-save-export-all-favorites
// @supportURL https://greasyfork.org/en/scripts/23406-sadpanda-save-export-all-favorites/feedback
// @version 2.3.4
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM_addValueChangeListener
// @grant GM.addValueChangeListener
// @require https://greasyfork.org/scripts/371339-gm-webextpref/code/GM_webextPref.js?version=705415
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/he/1.2.0/he.min.js
// ==/UserScript==
//Top text box inspiration and its code from http://userscripts-mirror.org/scripts/show/173553. But this one won't have an import feature like that one.
//Using Jquery for jquery purposes and he.js for he.js purposes.
//Using GM_webextPref for the preferences menu. Many thanks to the author "eight" for the library. Greasyfork libraries use a specific version so they should be from malicious updates.
//Use the options menu to change these values.
var inserttoTable = true; //Disables inserting new pages to the table. Set this to false if your browser gets real slow. You can still use the textbox to save your favorites.
var pageTimer = 3000; //Waiting timer for each page in miliseconds. Default is 2500. Making it too short might prevent pages from loading.
var playemptyAudio = false; //Play empty audio while loading the pages. Enable this if you will be using your computer while waiting. It might prevent the tab from going into background mode and stop loading the pages.
//empty audio file and method borrowed from https://github.com/ccloli/E-Hentai-Downloader (Thank you)
var emptyAudio;
var emptyAudioFile = 'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU3LjcxLjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAEAAABVgANTU1NTU1Q0NDQ0NDUFBQUFBQXl5eXl5ea2tra2tra3l5eXl5eYaGhoaGhpSUlJSUlKGhoaGhoaGvr6+vr6+8vLy8vLzKysrKysrX19fX19fX5eXl5eXl8vLy8vLy////////AAAAAExhdmM1Ny44OQAAAAAAAAAAAAAAACQCgAAAAAAAAAVY82AhbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+MYxAALACwAAP/AADwQKVE9YWDGPkQWpT66yk4+zIiYPoTUaT3tnU487uNhOvEmQDaCm1Yz1c6DPjbs6zdZVBk0pdGpMzxF/+MYxA8L0DU0AP+0ANkwmYaAMkOKDDjmYoMtwNMyDxMzDHE/MEsLow9AtDnBlQgDhTx+Eye0GgMHoCyDC8gUswJcMVMABBGj/+MYxBoK4DVpQP8iAtVmDk7LPgi8wvDzI4/MWAwK1T7rxOQwtsItMMQBazAowc4wZMC5MF4AeQAGDpruNuMEzyfjLBJhACU+/+MYxCkJ4DVcAP8MAO9J9THVg6oxRMGNMIqCCTAEwzwwBkINOPAs/iwjgBnMepYyId0PhWo+80PXMVsBFzD/AiwwfcKGMEJB/+MYxDwKKDVkAP8eAF8wMwIxMlpU/OaDPLpNKkEw4dRoBh6qP2FC8jCJQFcweQIPMHOBtTBoAVcwOoCNMYDI0u0Dd8ANTIsy/+MYxE4KUDVsAP8eAFBVpgVVPjdGeTEWQr0wdcDtMCeBgDBkgRgwFYB7Pv/zqx0yQQMCCgKNgonHKj6RRVkxM0GwML0AhDAN/+MYxF8KCDVwAP8MAIHZMDDA3DArAQo3K+TF5WOBDQw0lgcKQUJxhT5sxRcwQQI+EIPWMA7AVBoTABgTgzfBN+ajn3c0lZMe/+MYxHEJyDV0AP7MAA4eEwsqP/PDmzC/gNcwXUGaMBVBIwMEsmB6gaxhVuGkpoqMZMQjooTBwM0+S8FTMC0BcjBTgPwwOQDm/+MYxIQKKDV4AP8WADAzAKQwI4CGPhWOEwCFAiBAYQnQMT+uwXUeGzjBWQVkwTcENMBzA2zAGgFEJfSPkPSZzPXgqFy2h0xB/+MYxJYJCDV8AP7WAE0+7kK7MQrATDAvQRIwOADKMBuA9TAYQNM3AiOSPjGxowgHMKFGcBNMQU1FMy45OS41VVU/31eYM4sK/+MYxKwJaDV8AP7SAI4y1Yq0MmOIADGwBZwwlgIJMztCM0qU5TQPG/MSkn8yEROzCdAxECVMQU1FMy45OS41VTe7Ohk+Pqcx/+MYxMEJMDWAAP6MADVLDFUx+4J6Mq7NsjN2zXo8V5fjVJCXNOhwM0vTCDAxFpMYYQU+RlVMQU1FMy45OS41VVVVVVVVVVVV/+MYxNcJADWAAP7EAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxOsJwDWEAP7SAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxPMLoDV8AP+eAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxPQL0DVcAP+0AFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV';
const pref = GM_webextPref({
default: {
inserttoTable: true,
playemptyAudio: false,
pageTimer: 3000
},
body: [
{
key: "inserttoTable",
type: "checkbox",
label: "Insert new pages into the current page. Disable this if your browser freezes."
},
{
key: "playemptyAudio",
type: "checkbox",
label: "Play empty audio while loading the pages. This might prevent the tab from going into background mode and stop loading the pages."
},
{
key: "pageTimer",
type: "number",
label: "Time (ms) to load each page. Keep this higher than 2000 especially if you set the thumbnails to load with the page."
}
]
});
var counter = 0,
showExport = 0,
pageNumber = "",
titlesBackup = "",
winlocsea = "?";
var displayMode = $("#dms [selected='selected']")[0].value; // m:minimal, p:minimal+, l:compact, e:extended, t:thumbnail
//console.log(displayMode);
if (window.location.search == "") {
winlocsea = "?";
} else {
winlocsea = window.location.search;
}
var PageUrl = "favorites.php" + winlocsea + "&page=";
function destroyBox() {
$('.uselessbr').each(function() { $(this).remove(); });
$('#exportFav').remove();
$('#exportStatus').remove();
}
function getPageNumber() {
var finalcell = $(".ptt")[0].rows[0].cells[$(".ptt")[0].rows[0].cells.length - 2];
pageNumber = finalcell.textContent;
}
function addRemoveButton(newbutton) {
if (newbutton) {
$('#exportFav').after("<div>");
$('#exportFav').next().append($('<input/>').attr('type', 'button').attr('value', 'Remove Titles').attr('id', 'removeTitles').attr('style', 'margin-top:5px;min-height:18px;'));
} else {
document.querySelector("#removeTitles").removeEventListener("click", restoreTitles, false);
document.querySelector("#removeTitles").value = "Remove Titles";
}
document.querySelector("#removeTitles").addEventListener("click", removeTitles, false);
}
function addRestoreButton() {
document.querySelector("#removeTitles").removeEventListener("click", removeTitles, false);
document.querySelector("#removeTitles").value = "Restore Titles";
document.querySelector("#removeTitles").addEventListener("click", restoreTitles, false);
}
function removeTitles() {
titlesBackup = $('#exportFav')[0].textContent;
$('#exportFav')[0].textContent = $('#exportFav')[0].textContent.replace(/( - .*)/g, "");
addRestoreButton();
}
function restoreTitles() {
$('#exportFav')[0].textContent = titlesBackup;
addRemoveButton(0);
}
function getText(thisa) {
var thetext = "";
if (displayMode == "e") {
thetext = he.encode(thisa.href + " - " + thisa.children[0].children[0].innerText);
} else if (displayMode == "l") {
thetext = he.encode(thisa.href + " - " + thisa.children[0].innerText);
} else {
thetext = he.encode(thisa.href + " - " + thisa.text);
}
$('#exportFav').append(thetext + '\n');
}
function getThisPage() {
var trlen, thislink, j = 0;
if (displayMode == "e") {
trlen = $(".glink").length;
for (j = 0; j < trlen; j++) {
thislink = $(".glink")[j].parentNode.parentNode;
getText(thislink);
}
} else {
trlen = $(".itg .glname").length;
for (j = 0; j < trlen; j++) {
thislink = $(".itg .glname a")[j];
getText(thislink);
}
}
}
function exportFavorites() {
if (showExport === 0) {
showExport = 1;
$('#nb').after('<br class="uselessbr"/>');
$('#nb').after($('<input/>').attr('type', 'button').attr('value', 'START').attr('id', 'startBut').attr('href', 'javascript:void(0)').attr('style', 'margin-left:5px;margin-top:5px;min-height:18px;'));
$('#startBut').click(getThePages);
$('#nb').after($('<input/>').attr('type', 'button').attr('value', 'Options').attr('id', 'optionsBut').attr('href', 'javascript:void(0)').attr('style', 'margin-top:5px;min-height:18px;'));
$('#optionsBut').click(pref.openDialog);
$('#nb').after('<br class="uselessbr"/>');
$('#nb').after('<textarea id="exportStatus" name="Text2" cols="80" rows="8" ... />');
$('#nb').after('<h2 class="uselessbr">Status');
$('#nb').after('<textarea id="exportFav" name="Text1" cols="80" rows="7" ... />');
$('#nb').after('<h2 class="uselessbr">Text List of Favorites');
$('#nb').after('<br class="uselessbr"/><br class="uselessbr"/>');
$('#exportStatus').append("Currently the website is not that slow but keep the delay between pages higher than 3000 or your pages & thumbnails might not load." + '\n\n');
$('#exportStatus').append("Chrome and some other browsers throttle background tabs so if you switch to another tab it might prevent you from loading all the pages." + '\n');
$('#exportStatus').append("To bypass that; turn this tab into its own window before you start and don't minimize it." + '\n');
if (pageNumber > 10) {
$('#exportStatus').append("You have more than 10 pages. If your browser crashes disable inserting to the page from the options." + '\n\n');
}
$('#exportStatus').append("Press START below to start loading the pages." + '\n');
} else {
//destroyBox();
//showExport = 0;
return;
}
if (window.location.search.indexOf("page=") != -1) {
$('#exportFav').append("GO TO THE FIRST PAGE AND TRY AGAIN" + '\n');
$('#exportStatus').append("GO TO THE FIRST PAGE AND TRY AGAIN" + '\n');
return;
}
}
function getThePages() {
inserttoTable = pref.get("inserttoTable");
playemptyAudio = pref.get("playemptyAudio");
pageTimer = pref.get("pageTimer");
getThisPage();
if (pageNumber > 1) {
if (playemptyAudio) {
emptyAudio = new Audio(emptyAudioFile);
emptyAudio.loop = true;
emptyAudio.play();
}
$('#exportStatus').append("Loading all pages will take " + (Math.ceil(pageTimer / 100) * (pageNumber)) / 10 + " seconds." + '\n');
//$('#exportStatus').append("NOTICE - If your browser completely freezes, try using the newest Firefox/Chrome with tampermonkey/violentmonkey or help me fix it." + '\n');
for (var ii = 1; ii < pageNumber; ii++) {
//console.log("Queued page: " + ii);
setTimeout(function() {
counter++;
//console.log("Current page: " + counter);
$('#exportStatus').append("Loading Page " + (counter + 1) + " of " + pageNumber + "..." + '\n');
if ((counter + 1) == pageNumber) {
setTimeout(function() {
if (playemptyAudio) {
emptyAudio.pause();
}
$('#exportStatus').append("Loading complete." + '\n' + "Copy above list, Ctrl+S to save the page or use an extension like SingleFile or Save Page WE." + '\n');
addRemoveButton(1);
$('#exportStatus').append("Confirmation: " + ($('#exportFav')[0].value.split("\n").length - 1) + " favorites in above text area, " + ($(".itg .glname a").length + $(".gl4e .glink").length) + " favorites in below page." + '\n');
if (pageNumber > 10) {
$('#exportStatus').append("If your gallery count doesn't add up, try again. You can load the pages faster now that you cached all the thumbnails." + '\n\n');
}
$('#exportStatus').scrollTop($('#exportStatus')[0].scrollHeight);
}, pageTimer + 2500);
}
$('#exportStatus').scrollTop($('#exportStatus')[0].scrollHeight);
$.ajax({
url: PageUrl + counter,
type: 'GET',
tryCount: 0,
retryLimit: 5,
success: function(sss) {
//do something
var trlen, thislink, j = 0;
trlen = (displayMode == "e") ? $(sss).find(".glink").length : $(sss).find(".itg .glname").length;
for (j = 0; j < trlen; j++) {
thislink = (displayMode == "e") ? $(sss).find(".glink")[j].parentNode.parentNode : $(sss).find(".itg .glname a")[j];
getText(thislink);
if (inserttoTable) {
if (displayMode != "t") {
$(".itg tbody")[0].append($(thislink).parents("tr:first")[0]);
} else {
$(".itg")[0].append($(thislink).parents(".gl1t")[0]);
}
}
}
},
error: function(xhr, textStatus, errorThrown) {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
$.ajax(this);
return;
}
return;
/*
if (textStatus == 'timeout') {
}
if (xhr.status == 500) {
//handle error
} else {
//handle error
}
*/
}
});
}, 200 + ii * pageTimer);
}
} else {
$('#exportStatus').append("Loading complete." + '\n' + "Copy above list, Ctrl+S to save the page or use an extension like SingleFile or Save Page WE." + '\n');
$('#exportStatus').append("Confirmation: " + ($('#exportFav')[0].value.split("\n").length - 1) + " favorites in above text area, " + ($(".itg .glname a").length + $(".gl4e .glink").length) + " favorites in below page." + '\n');
addRemoveButton(1);
}
}
$(document).ready(function() {
var topmenu = document.querySelector("#nb");
topmenu.style.justifyContent = "center";
topmenu.style.maxWidth = "1400px";
$('#nb').append($('<div/>').attr('id', 'exportFavsdiv'));
$('#exportFavsdiv').append($('<a/>').attr('href', 'javascript:void(0)').attr('id', 'exportFavorites').text('Load All Favorites'));
$('#exportFavorites').click(exportFavorites);
document.querySelector("#exportFavsdiv").style.marginLeft = "8px";
getPageNumber();
});