Sleazy Fork is available in English.

E-Hentai <-> ExHentai

Links between E-Hentai and ExHentai page, and also links user to ExHentai automatically if gallery is "removed" and adds "view later" function

Fra 02.07.2017. Se den seneste versjonen.

// ==UserScript==
// @name           E-Hentai <-> ExHentai
// @description    Links between E-Hentai and ExHentai page, and also links user to ExHentai automatically if gallery is "removed" and adds "view later" function
// @namespace      https://greasyfork.org/en/scripts/24342-e-hentai-exhentai
// @version        3.03.1
// @icon           https://e-hentai.org/favicon.ico

// @include        http*://e-hentai.org/*
// @include        https://upload.e-hentai.org/*
// @include        https://exhentai.org/*

// @require        https://code.jquery.com/jquery-3.1.1.min.js
// @author         Resuha
// @grant          GM_getValue
// @grant          GM_setValue
// ==/UserScript==

//Credit to developer of https://github.com/js-cookie/js-cookie

//Ver 3.00 added "view/read later" functionality
//Ver 2.00 added redirector and cookie remover

var extraCSS = document.createElement("style");
extraCSS.textContent = `
.link, .option {
cursor: pointer;
text-decoration: underline;
}

.option{
font-size: 125%;
}

.readLaterItem{
font-size: 125%;
}

.readLaterItem > .option{
font-size: 100%;
}

.divHeader{
font-size: 160%;
font-weight: bold;
}

.link.dark{
color:yellow
}

.option.dark{
color:plum
}

#fixedDiv.dark{
background-color:rgba(64, 64, 0, 0.6)
}

#readLaterDiv.dark,#mpvAddon.dark,#successDiv.dark{
background-color:rgba(64, 64, 0, 1)
}

.link.light{
color:blue
}

.option.light{
color:Red
}

#fixedDiv.light{
background-color:rgba(255, 255, 0, 0.6)
}

#readLaterDiv.light,#mpvAddon.light,#successDiv.light{
background-color:rgba(255, 255, 0, 1)
}

#successDiv{
font-size: 125%;
position: absolute;
transform: translate(-100%, -50%);
z-index:10;
padding: 8px 8px;
}

#linker{
font-size: 160%;
}

#fixedDiv{
text-align: left !important;
position: fixed;
top: 24px;
right: 24px;
align: left;
padding: 8px 8px;
}

#readLaterDiv{
text-align: left !important;
position:fixed;
bottom: 24px;right: 24px;
width: 55%;
align: left;
z-index:10;
padding: 8px 8px;
}

#optionDivUL, #readLaterUL, #readLaterOptionDivUL{
margin: 0; padding: 0px 0px 0px 20px;
}

#readLaterUL{
max-height: 160px;
overflow: auto;
}

.closeButton{
float:right;
cursor: pointer;
}
`;
document.head.appendChild(extraCSS);

var fixedDiv = `'
<div id="fixedDiv">
  <div class="divHeader">E<->Ex v`+GM_info.script.version+`</div><BR>
  <div id="linkerDiv">
    <label class="divHeader">Linker:</label>
  </div>
  <div id="readLaterOptionDiv"><BR>
    <label class="divHeader">Read Later:</label><BR><ul id="readLaterOptionDivUL"></ul>
  </div>
  <div id="optionDiv"><BR>
    <label class="divHeader">Option:</label><BR><ul id="optionDivUL"></ul>
  </div>
</div>'`;
$('body').append(fixedDiv);
fixedDiv = $('#fixedDiv');
linkerDiv = $('#linkerDiv');
optionDiv = $('#optionDiv');
optionDiv.hide();

var readLaterDiv = `'
<div id="readLaterDiv">
  <div class="divHeader"><label>Read Later List:</label><label class="closeButton" id="closeReadLaterButton">✖</label></div>
  <ul id="readLaterUL"></ul>
</div>'`;
$('body').append(readLaterDiv);
document.getElementById('closeReadLaterButton').addEventListener("click", function(){
    hide_rlList();
});
readLaterDiv = $('#readLaterDiv');
readLaterDiv.hide();

var targetWebsite;
if (document.location.href.indexOf('exhentai') != - 1) {
    link = 'https://e-hentai.org' + parse_gallery_identifier();
    targetWebsite = 'E-Hentai';
    fixedDiv.addClass("dark");
    readLaterDiv.addClass("dark");
} else {
    link = 'https://exhentai.org' + parse_gallery_identifier();
    targetWebsite = 'ExHentai';
    fixedDiv.addClass("light");
    readLaterDiv.addClass("light");
} // Determine if the current page is E-Hentai or ExHentai

var readLaterList = load_rlList();
populate_rlDiv();
window.addEventListener('focus', function() {
    readLaterList = load_rlList();
    populate_rlDiv();
});

var currentPageHref = window.location.href;

$(document).ready(function () {
    if (document.title == 'Gallery Not Available - E-Hentai Galleries'){ // Gallery is expunged in e-hentai
        document.location.href = 'https://exhentai.org' + parse_gallery_identifier();
    } else if(document.title == "exhentai.org (260×260)"){ // Got sadpanda
        var bYes = '<button id="yesButton" class="askButton">Yes';
        var bNo = '<button id="noButton" class="askButton">No';
        var askConfirm = '<div id="confirmDiv">Are you currently logged in at e-hentai.org forum?<label id="message"><br>'+bYes+bNo+'</div>';
        $('body').append(askConfirm);
        askConfirm = $('#confirmDiv');
        askConfirm.css({
            'align':'center',
            'color':'blue',
        });

        $('#yesButton').click(function(){ // Clear cookie and refresh
            $('#confirmDiv').text("This page will refresh. If you still see this page after the refresh, it is possible that your account is not old enough for exhentai");
            setTimeout(function() {
                // delete cookie
                Cookies.remove('yay', {domain:'.exhentai.org'});
                location.reload();
            }, 1000);
        });
        $('#noButton').click(function(){ // Redirect to forum
            $('#confirmDiv').text("Redirecting to E-Hentai login page");
            setTimeout(function() {
                document.location.href = 'https://forums.e-hentai.org/index.php?act=Login&CODE=00';
            }, 1000);
        });

    } else {
        if(currentPageHref.indexOf("/mpv/") === -1){
            var link;
            var linker;

            if (targetWebsite == 'ExHentai') {
                if(document.location.href == 'https://upload.e-hentai.org/manage.php'){
                    linker="https://exhentai.org/upload/manage.php";
                } else {
                    linker="https://exhentai.org"+parse_gallery_identifier();
                }
                linkerDiv.append(createLink("linker",linker,"To ExHentai"));
            } else {
                if(document.location.href == 'https://exhentai.org/upload/manage.php'){
                    linker="https://upload.e-hentai.org/manage.php";
                } else {
                    linker="https://e-hentai.org"+parse_gallery_identifier();
                }
                linkerDiv.append(createLink("linker",linker,"To E-Hentai"));
            } // Add option to switch between E-Hentai and ExHentai in the top bar of the page

            document.getElementById('linker').addEventListener("click",function(){
                document.location.href = linker;
            });

            // Setting page
            if(currentPageHref.indexOf("uconfig") > -1){
                optionDiv.show();
                var optionArray = [];
                optionArray.push(createOption("loadSettingOption","Load saved user setting"));
                optionArray.push(createOption("saveSettingOption","Save current user setting"));

                for (i=0;i<optionArray.length;i++){
                    $('#optionDivUL').append(optionArray[i]);
                }

                document.getElementById('loadSettingOption').addEventListener("click",function(){
                    var setting = GM_getValue("userSetting","");
                    if(setting !== ""){
                        if (document.location.href.indexOf('exhentai') != - 1) {
                            Cookies.set("uconfig",setting,{domain:".exhentai.org", expires:365});
                        } else {
                            Cookies.set("uconfig",setting,{domain:".e-hentai.org", expires:365});
                        }
                        alert("User setting loaded");
                        location.reload();
                    } else {
                        alert("Nothing to load");
                    }
                });
                document.getElementById('saveSettingOption').addEventListener("click",function(){
                    GM_setValue("userSetting", Cookies.get("uconfig"));
                    // Maybe have an option to save it to file
                    alert("User setting saved");
                });
            }

            // Gallery page
            if(currentPageHref.indexOf("/g/") > -1 || currentPageHref.indexOf("/s/") > -1){
                if(getIndex_rlList(parse_gallery_identifier()).index > -1 && getIndex_rlList(parse_gallery_identifier()).exactMatch === true){
                    $('#readLaterOptionDivUL').append(createOption("addReadLaterOption",'Already in "view later" list'));
                    $('#addReadLaterOption').css({
                        'text-decoration': 'none',
                        'cursor': 'default',
                    });
                } else {
                    $('#readLaterOptionDivUL').append(createOption("addReadLaterOption",'Add to "view later" list'));
                    document.getElementById('addReadLaterOption').addEventListener("click", add_rlEntryFunction);
                }

                if(currentPageHref.indexOf("/s/") > -1){
                    var oldLocation = location.href;
                    setInterval(function() {
                        if(location.href != oldLocation) {
                            oldLocation = location.href;
                            $('#addReadLaterOption').text('Add to "view later" list');
                            document.getElementById('addReadLaterOption').addEventListener("click", add_rlEntryFunction);
                            $('#addReadLaterOption').css({
                                'text-decoration': 'underline',
                                'cursor': 'pointer',
                            });
                        }
                    }, 2000); // check 2 seconds
                }
            }

            $('#readLaterOptionDivUL').append(createOption("seeReadLaterListOption",'Show "view later" list'));
            document.getElementById('seeReadLaterListOption').addEventListener("click",function(){
                if($('#seeReadLaterListOption').text().indexOf("Show")>-1){
                    show_rlList();
                } else {
                    hide_rlList();
                }
            });

            // If there is no option available, hide the optionDiv completely
            if ($('.option').length === 0){
                optionDiv.hide();
            }
        } else {
            var successDiv;
            if(targetWebsite === "E-Hentai"){
                $('#bar3').append('<div id="mpvAddon" class="dark"></div>');
                $('#mpvAddon').append('<img id="mpvSave_rl" src="http://i.imgur.com/rdXO8o2.png" title="Save this page to view later list (E<->Ex extension)" style="margin-top:10px; opacity:0.8">');
                $('#mpvAddon').append('<img id="mpvView_rl" src="http://i.imgur.com/ywCl5NP.png" title="Open view later list (E<->Ex extension)" style="margin-top:5px; opacity:0.8">');
                successDiv = '<div id="successDiv" class="dark">Added/updated "view later" list</div>';
            } else {
                $('#bar3').append('<div id="mpvAddon" class="light"></div>');
                $('#mpvAddon').append('<img id="mpvSave_rl" src="http://i.imgur.com/tWBUjde.png" title="Save this page to view later list (E<->Ex extension)" style="margin-top:10px; opacity:0.8">');
                $('#mpvAddon').append('<img id="mpvView_rl" src="http://i.imgur.com/XH8qCCi.png" title="Open view later list (E<->Ex extension)" style="margin-top:5px; opacity:0.8">');
                successDiv = '<div id="successDiv" class="light">Added/updated "view later" list</div>';
            }
            $('body').append(successDiv);
            successDiv = $('#successDiv');
            successDiv.hide();

            $('#mpvSave_rl').click(function(){
                var pos = getOffset(this);
                successDiv.css({
                    'top':pos.top+12,
                    'left':pos.left-12,
                });
                var currentPageNum = 0;
                var currentScrollLocation = $('#pane_images').scrollTop();
                var allImgDiv = $('#pane_images_inner').children('div');
                for(i=0;i<allImgDiv.length;i++){
                    currentScrollLocation -= allImgDiv[i].offsetHeight;
                    currentPageNum++;
                    if(currentScrollLocation <= 0){
                        break;
                    }
                }
                var lastPage = document.getElementById("pane_thumbs_inner").childElementCount;
                var title = document.title.substring(0, document.title.lastIndexOf(" - ")) +" {"+ currentPageNum +"/"+lastPage+"}";
                var link = parse_gallery_identifier();
                link = link.substring(0,link.lastIndexOf("/"))+"/#page"+currentPageNum;
                add_rlEntry(title, link);
                populate_rlDiv();
                $('#successDiv').fadeIn();
                setTimeout(function(){
                    $('#successDiv').fadeOut();
                }, 2000 );
            });
            $('#mpvView_rl').click(function(){
                if($('#readLaterDiv').is(":visible")){
                    hide_rlList();
                } else {
                    show_rlList();
                }
            });
            $('#fixedDiv').hide();
        }
    }
});

function getGalleryID(pageHref){
    var splitHref = pageHref.split("/");
    if(pageHref.indexOf("/g/") > -1 || pageHref.indexOf("/mpv/") > -1){
        return splitHref[2];
    } else {
        return splitHref[3].substring(0,splitHref[3].indexOf("-"));
    }
}

function populate_rlDiv(){
    $(".readLaterItem").remove(); // remove existing ones and repopulate the list

    for (i=0;i<readLaterList.length;i++){
        if(readLaterList[i].link !== undefined && readLaterList[i].link !== ""){
            if(targetWebsite === "E-Hentai"){
                $('#readLaterUL').append('<li class="readLaterItem"><label class="readLaterRemoveItem option dark">Remove</label> | '+ createLink("","https://e-hentai.org"+readLaterList[i].link,"E-Hentai") +' | '+ createLink("","https://exhentai.org"+readLaterList[i].link,"ExHentai") +' | '+readLaterList[i].title+'</li>');
            } else {
                $('#readLaterUL').append('<li class="readLaterItem"><label class="readLaterRemoveItem option light">Remove</label> | '+ createLink("","https://e-hentai.org"+readLaterList[i].link,"E-Hentai") +' | '+ createLink("","https://exhentai.org"+readLaterList[i].link,"ExHentai") +' | '+readLaterList[i].title+'</li>');
            }
        }
    }
    var removeItem = document.getElementsByClassName("readLaterRemoveItem");
    for (i=0;i<removeItem.length;i++){
        removeItem[i].addEventListener("click",function(){
            this.parentNode.remove(this);
            remove_rlEntry(parse_gallery_identifier(this.nextElementSibling.href));
        });
    }
}

function add_rlEntryFunction(){
    var title;
    if(window.location.href.indexOf("/g/") > -1){
        title = $('#gn').text();
    } else {
        title = $('#i1').children('h1').text() +" {"+ $('#i2').children('.sn').children('div').text().replace(/ /g,"")+"}";
    }
    add_rlEntry(title, parse_gallery_identifier());
    populate_rlDiv();
    $('#addReadLaterOption').text('Added to list');
    $('#addReadLaterOption').off();
    $('#addReadLaterOption').css({
        'text-decoration': 'none',
        'cursor': 'default',
    });
}

function show_rlList(){
    readLaterDiv.fadeIn("fast");
    $('#seeReadLaterListOption').text('Hide "view later" list');
}

function hide_rlList(){
    readLaterDiv.fadeOut("fast");
    $('#seeReadLaterListOption').text('Show "view later" list');
}

function createLink(id, link, text){
    if(targetWebsite === 'E-Hentai'){
        return '<a id="'+id+'" href="'+link+'" class="link dark">'+text+'</a>';
    } else {
        return '<a id="'+id+'" href="'+link+'" class="link light">'+text+'</a>';
    }
}

function createOption(id, text){
    if(targetWebsite === 'E-Hentai'){
        return '<li><label id="'+id+'" class="option dark">'+text+'</label></li>';
    } else {
        return '<li><label id="'+id+'" class="option light">'+text+'</label></li>';
    }
}

function rlStringToArray(string){
    var returnArray = [];
    var splitString = string.split(";");
    for (i=0;i<splitString.length;i++){
        var entrySplit = splitString[i].split("::");
        returnArray.push(create_rlEntry(entrySplit[0],entrySplit[1]));
    }
    return returnArray;
}

function rlArrayToString(array){
    var returnString = "";
    for (i=0;i<array.length;i++){
        returnString += getStringEntry(array[i]);
        if(i !== (array.length - 1)){
            returnString += ";";
        }
    }
    return returnString;
}

function create_rlEntry(title, link){
    return {title:title, link:link};
}

function getStringEntry(entry){
    return entry.title + "::" + entry.link;
}

function load_rlList(){
    var rlString = GM_getValue("readLater", "");
    return rlStringToArray(rlString);
}

function add_rlEntry(title, link){
    if(getIndex_rlList(link).index === -1){
        var entry = create_rlEntry(title, link);
        var entryString = title+"::"+link;
        // add to current saved list
        readLaterList.push(entry);
        // add to GM_saved list
        var newValue = GM_getValue("readLater", "");
        if(newValue !== ""){
            newValue += ";";
        }
        newValue += entryString;
        GM_setValue("readLater", newValue);
    } else {
        var replaceItemIndex = getIndex_rlList(link).index;
        // update current saved list
        readLaterList[replaceItemIndex].title = title;
        readLaterList[replaceItemIndex].link = link;
        // update current saved list
        var savedValue = GM_getValue("readLater", "");
        var array = rlStringToArray(savedValue);
        array[replaceItemIndex].title = title;
        array[replaceItemIndex].link = link;
        savedValue = rlArrayToString(array);
        GM_setValue("readLater", savedValue);
    }
}

function remove_rlEntry(link){
    var removeItemIndex = getIndex_rlList(link).index;
    // remove from current saved list
    readLaterList.splice(removeItemIndex,1);

    // remove from GM_saved list
    var savedValue = GM_getValue("readLater", "");
    var array = rlStringToArray(savedValue);
    array.splice(removeItemIndex,1);
    savedValue = rlArrayToString(array);
    GM_setValue("readLater", savedValue);

    if(location.href.indexOf(link)>-1){
        $('#addReadLaterOption').text('Add to "view later" list');
        if(currentPageHref.indexOf("/mpv/") === -1){
            document.getElementById('addReadLaterOption').addEventListener("click", add_rlEntryFunction);
        }
        $('#addReadLaterOption').css({
            'text-decoration': 'underline',
            'cursor': 'pointer',
        });
    }

    if(document.getElementsByClassName("readLaterItem").length === 0){
        hide_rlList();
    }
}

function getIndex_rlList(link){
    var galleryID = getGalleryID(link);
    for(i=0;i<readLaterList.length;i++){
        if (readLaterList[i].link !== undefined && readLaterList[i].link.indexOf(galleryID)>-1){
            if(readLaterList[i].link === link){
                return {index:i, exactMatch:true};
            } else {
                return {index:i, exactMatch:false};
            }
        }
    }
    return {index:-1, exactMatch:false};
}

// Parse the gallery link
function parse_gallery_identifier(link) {
    var identifier_start;
    var identifier_end;
    var identifier;
    if(link === undefined){
        if (location.href.indexOf('e-hentai.org') != - 1) {
            identifier_start = location.href.indexOf('e-hentai.org')+12;
        } else if (location.href.indexOf('exhentai.org') != - 1) {
            identifier_start = location.href.indexOf('exhentai.org')+12;
        }
        identifier_end = location.href.length;
        identifier = location.href.substr(identifier_start, identifier_end);
    } else {
        if (link.indexOf('e-hentai.org') != - 1) {
            identifier_start = link.indexOf('e-hentai.org')+12;
        } else if (link.indexOf('exhentai.org') != - 1) {
            identifier_start = link.indexOf('exhentai.org')+12;
        }
        identifier_end = link.length;
        identifier = link.substr(identifier_start, identifier_end);
    }
        return identifier;
}

// Credit to Adam Grant: http://stackoverflow.com/questions/442404/retrieve-the-position-x-y-of-an-html-element
function getOffset(el) {
    el = el.getBoundingClientRect();
    return {
        left: el.left + window.scrollX,
        top: el.top + window.scrollY
    };
}

/*!
 * JavaScript Cookie v2.1.3
 * https://github.com/js-cookie/js-cookie
 *
 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
 * Released under the MIT license
 */
;(function (factory) {
    var registeredInModuleLoader = false;
    if (typeof define === 'function' && define.amd) {
        define(factory);
        registeredInModuleLoader = true;
    }
    if (typeof exports === 'object') {
        module.exports = factory();
        registeredInModuleLoader = true;
    }
    if (!registeredInModuleLoader) {
        var OldCookies = window.Cookies;
        var api = window.Cookies = factory();
        api.noConflict = function () {
            window.Cookies = OldCookies;
            return api;
        };
    }
}(function () {
    function extend () {
        var i = 0;
        var result = {};
        for (; i < arguments.length; i++) {
            var attributes = arguments[ i ];
            for (var key in attributes) {
                result[key] = attributes[key];
            }
        }
        return result;
    }

    function init (converter) {
        function api (key, value, attributes) {
            var result;
            if (typeof document === 'undefined') {
                return;
            }

            // Write

            if (arguments.length > 1) {
                attributes = extend({
                    path: '/'
                }, api.defaults, attributes);

                if (typeof attributes.expires === 'number') {
                    var expires = new Date();
                    expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
                    attributes.expires = expires;
                }

                try {
                    result = JSON.stringify(value);
                    if (/^[\{\[]/.test(result)) {
                        value = result;
                    }
                } catch (e) {}

                if (!converter.write) {
                    value = encodeURIComponent(String(value))
                        .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
                } else {
                    value = converter.write(value, key);
                }

                key = encodeURIComponent(String(key));
                key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
                key = key.replace(/[\(\)]/g, escape);

                return (document.cookie = [
                    key, '=', value,
                    attributes.expires ? '; expires=' + attributes.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
                    attributes.path ? '; path=' + attributes.path : '',
                    attributes.domain ? '; domain=' + attributes.domain : '',
                    attributes.secure ? '; secure' : ''
                ].join(''));
            }

            // Read

            if (!key) {
                result = {};
            }

            // To prevent the for loop in the first place assign an empty array
            // in case there are no cookies at all. Also prevents odd result when
            // calling "get()"
            var cookies = document.cookie ? document.cookie.split('; ') : [];
            var rdecode = /(%[0-9A-Z]{2})+/g;
            var i = 0;

            for (; i < cookies.length; i++) {
                var parts = cookies[i].split('=');
                var cookie = parts.slice(1).join('=');

                if (cookie.charAt(0) === '"') {
                    cookie = cookie.slice(1, -1);
                }

                try {
                    var name = parts[0].replace(rdecode, decodeURIComponent);
                    cookie = converter.read ?
                        converter.read(cookie, name) : converter(cookie, name) ||
                        cookie.replace(rdecode, decodeURIComponent);

                    if (this.json) {
                        try {
                            cookie = JSON.parse(cookie);
                        } catch (e) {}
                    }

                    if (key === name) {
                        result = cookie;
                        break;
                    }

                    if (!key) {
                        result[name] = cookie;
                    }
                } catch (e) {}
            }

            return result;
        }

        api.set = api;
        api.get = function (key) {
            return api.call(api, key);
        };
        api.getJSON = function () {
            return api.apply({
                json: true
            }, [].slice.call(arguments));
        };
        api.defaults = {};

        api.remove = function (key, attributes) {
            api(key, '', extend(attributes, {
                expires: -1
            }));
        };

        api.withConverter = init;

        return api;
    }

    return init(function () {});
}));