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

As of 2017-07-01. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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.01
// @icon           https://e-hentai.org/favicon.ico

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

// @exclude        https://e-hentai.org/mpv/*
// @exclude        https://exhentai.org/mpv/*

// @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.light{
color:Red
}

.option.dark{
color:Plum
}

.link.light{
color:blue
}

#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;
min-width: 600px; width = 80%;
align: left;
z-index:10;
padding: 8px 8px;
}

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

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

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

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="optionDiv"><BR>
    <label class="divHeader">Option:</label><BR><ul id="optionDivUL"></ul>
  </div>
</div>'`;
$('body').append(fixedDiv);
fixedDiv = $('#fixedDiv');
linkerDiv = $('#linkerDiv');
optionDiv = $('#optionDiv');

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 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 {
        var link;
        var linker;

        if (targetWebsite == 'ExHentai') {
            fixedDiv.css({
                'background-color': 'rgba(255, 255, 0, 0.6)',
            });
            readLaterDiv.css({
                'background-color': 'rgba(255, 255, 0, 1)',
            });
            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 {
            fixedDiv.css({
                'background-color': 'rgba(128, 128, 0, 0.6)',
            });
            readLaterDiv.css({
                'background-color': 'rgba(128, 128, 0, 1)',
            });
            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){
            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){
                $('#optionDivUL').append(createOption("addReadLaterOption",'Already in "view later" list'));
                $('#addReadLaterOption').css({
                    'text-decoration': 'none',
                    'cursor': 'default',
                });
            } else {
                $('#optionDivUL').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
            }
        }

        $('#optionDivUL').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();
        }
    }
});

function getGalleryID(pageHref){
    var splitHref = pageHref.split("/");
    if(pageHref.indexOf("/g/") > -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');
        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;
}

/*!
 * 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 () {});
}));