Sadpanda Save/Export All Favorites

Load all favorites to the page and save it or just copy the textbox contents. Works on exhentai and e-hentai.

As of 2020-04-28. See the latest version.

// ==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.2
// @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=623327
// @require     https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/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.

const pref = GM_webextPref({
    default: {
        inserttoTable: true,
        pageTimer: 3000
    },
    body: [{
            key: "inserttoTable",
            type: "checkbox",
            label: "Insert new pages into the current page. Disable this if your browser freezes."
        },
        {
            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");
    pageTimer = pref.get("pageTimer");
    getThisPage();
    if (pageNumber > 1) {
        $('#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() {
                        $('#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();
});