ExHentai Viewer

manage your favorite tags, enhance searching, improve comic page

As of 11. 02. 2019. 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 ExHentai Viewer
// @namespace Violentmonkey Scripts
// @description manage your favorite tags, enhance searching, improve comic page
// @match *://exhentai.org/*
// @match *://e-hentai.org/*
// @grant       GM_setValue
// @grant       GM_getValue
// @version 0.37
// ==/UserScript==
var custom_filter = GM_getValue('custom_filter', []);
custom_filter.forEach(function(v, i, a){
    if (v == undefined || v.tag == undefined || v.name == undefined){
        a.splice(i, 1);
        GM_setValue('custom_filter', custom_filter);
    }
})
if (window.location.href.includes("/s/")) {
    EhViewer();
} else if (window.location.href.includes("/g/")) {
	addNewStyle('input{margin:2px 2px!important;}');
    filterForGallery();
} else if (document.getElementById('searchbox') !== null) {
	addNewStyle('input{margin:2px 2px!important;}');
    addFilter(document.getElementsByClassName("nopm")[0]);
}

function addNewStyle(newStyle) {
    var styleElement = document.getElementById('styles_js');
    if (!styleElement) {
        styleElement = document.createElement('style');
        styleElement.type = 'text/css';
        styleElement.id = 'styles_js';
        document.getElementsByTagName('head')[0].appendChild(styleElement);
        styleElement.appendChild(document.createTextNode(newStyle));
    } else {
        styleElement.innerText = newStyle;
    }
}

function filterForGallery(){
    // var galleryFilter = document.getElementsByClassName('gm')[0].appendChild(document.createElement("form"));
    var galleryFilter = document.body.insertBefore(document.createElement('form'), document.getElementsByClassName('gm')[0]);
    galleryFilter.innerHTML = '<p id="galleryFilter" class="nopm"><input type="text" name="f_search" placeholder="Search Keywords" value="" size="50"><input type="submit" name="f_apply" value="Apply Filter"></p>';
    galleryFilter.setAttribute('style', 'display: none; width: 30%; text-align: center; margin: 10px auto; border: 2px ridge black; padding: 10px;');
    galleryFilter.setAttribute('action', 'https://exhentai.org/');
    galleryFilter.setAttribute('method', 'get');
    addFilter(document.getElementById('galleryFilter'));
    var tb = document.getElementById('taglist').firstElementChild.firstElementChild;
    tb.innerHTML += '<tr><td class="tc">EHV:</td><td><div id="show_filter" class="gt" style="cursor:pointer">show filter</div></td></tr>';
    document.getElementById('show_filter').addEventListener('click', function(e){
    	if (e.target.innerText === 'show filter'){
    		galleryFilter.style.display = "block";
    		e.target.innerText = 'hide filter'
    	} else {
    		galleryFilter.style.display = "none";
    		e.target.innerText = 'show filter'
    	}
    })
	for(var i=0; i<document.all.length; i++){
		if (document.all[i].id.slice(0, 3) === 'ta_') {
			document.all[i].addEventListener('contextmenu', addGalleryTag, false);
		}
	}

	function addGalleryTag(e) {
		e.preventDefault();
		var searchBox = galleryFilter.firstElementChild.firstElementChild;
		var tagValue = '"'+e.target.innerText+'"';
		if (searchBox.value.includes(tagValue)){
			console.log('del?');
			searchBox.value = searchBox.value.replace(tagValue, '');
		}else {
			searchBox.value += tagValue;
		}
	}
}

function addFilter(boxPos){
    var ipColor1;
    var ipColor2;
    if (window.location.host === 'e-hentai.org'){
        ipColor1 = 0xedeada;
        ipColor2 = ipColor1 - 0x202020;
    } else {
        ipColor1 = 0x34353b;
        ipColor2 = ipColor1 + 0x202020;
    }
    ipColor1 = '#' + ipColor1.toString('16');
    ipColor2 = '#' + ipColor2.toString('16');
    var search_box = boxPos.firstElementChild;
    var p = document.getElementById('custom_filter');
    if(p == null) {
    	boxPos.appendChild(document.createElement('br'));
        boxPos.appendChild(document.createElement('br'));
        p = boxPos.appendChild(document.createElement('p'));
        boxPos.appendChild(document.createElement('br'));
        p.setAttribute('class', 'nopm');
        p.setAttribute('id', 'custom_filter');
    } else {
        p.innerHTML = '';
    }
    for (var i in custom_filter) {
        var filter = custom_filter[i];
        var t = p.appendChild(document.createElement('input'));
        t.setAttribute('type', 'button');
        t.setAttribute('value', filter.name);
        t.setAttribute('tag', filter.tag);
        t.addEventListener('click', addTag, false);
        t.addEventListener('contextmenu', delTag, false);
        if (search_box.value.includes(filter.tag)){
            t.style.backgroundColor=ipColor2;
        } else {
            t.style.backgroundColor=ipColor1;
        }
    }
    t=p.appendChild(document.createElement('input'));
    t.setAttribute('type', 'button');
    t.setAttribute('value', "+");
    t.addEventListener('click', newTag, false);
    function addTag(e){
        var t = e.target;
        var tag = t.getAttribute('tag');
        if (search_box.value.includes(tag)){
            search_box.value = search_box.value.replace(('"'+tag+'"'), "");
            t.style.backgroundColor=ipColor1;
        } else {
            search_box.value += ('"'+tag+'"');
            t.style.backgroundColor=ipColor2;
        }
    }
    function delTag(e){
        e.preventDefault();
        if (window.confirm('Delete this tag?') === true){
            var t = e.target;
            var tag = t.getAttribute('tag');
            for (var i in custom_filter) {
                if(custom_filter[i].tag == tag){
                    custom_filter.splice(i, 1);
                    break;
                }
            }
            GM_setValue('custom_filter', custom_filter);
            addFilter(e.target.parentElement.parentElement);
        }
        return false;
    }
    function newTag(e){
    	var tagStr = window.prompt("Add filter like format below", "name@value").split("@");
    	if(tagStr.length == 2){
    	    custom_filter.push({'name':tagStr[0], 'tag':tagStr[1]});
    	    GM_setValue('custom_filter', custom_filter);
    	    addFilter(e.target.parentElement.parentElement);
    	} else {
    	    window.alert("Invalid value... :(");
    	}
	}
}
function EhViewer(){
    var isFirstRun = true;
    console.log('EhV start...');
    var zoomInterval;
    var oldSi = si;
    var firstPage = document.getElementsByClassName("sn")[0].firstChild.href;
    var lastPage = document.getElementsByClassName("sn")[0].lastChild.href;
    var float_icon = new Array([]);
    var float_link = new Array([]);
    var currentScale = 1;
    var float_list = document.createElement("ul");
    var newStyle = 'h1, #i2, #i5, #i6, #i7, .ip, .sn{display:none!important;}.float_list{display:block; position:fixed; bottom:10px; right:10px; list-style:none;z-index:1005;}.float_icon{user-select:none;background-color:btColor1; margin:5px; width:50px; height:50px; line-height:50px; font-size:12px; border-radius:50%; cursor:pointer;}.float_icon:hover{transition-duration:0.05s;font-size:13px; background-color:btColor2; box-shadow:0 0 3px 1px shadowColor;}.float_icon:active{box-shadow:0 0 3px 1px shadowColor inset; font-size:12px}::-webkit-scrollbar{display:none;}';
    var btColor1;
    var btColor2;
    var shadowColor;
    if (window.location.host === 'e-hentai.org'){
        btColor1 = 0xe3e0d1 - 0x101010;
        btColor2 = btColor1 - 0x050505;
        shadowColor = btColor1 + 0x080808;
    } else {
        btColor1 = 0x34353b + 0x101010;
        btColor2 = btColor1 + 0x050505;
        shadowColor = btColor1 - 0x080808;
    }
    newStyle = newStyle.replace('btColor1', '#'+btColor1.toString('16'));
    newStyle = newStyle.replace('btColor2', '#'+btColor2.toString('16'));
    newStyle = newStyle.replace('shadowColor', '#'+shadowColor.toString('16'));
    newStyle = newStyle.replace('shadowColor', '#'+shadowColor.toString('16'));
    document.body.appendChild(float_list);
    for(var i=0; i<5; i++){
        float_icon[i]=document.createElement("li");
        float_link[i]=document.createElement("a");
        float_list.appendChild(float_icon[i]);
        float_icon[i].appendChild(float_link[i]);
    }
    float_list.setAttribute("class", "float_list");
    float_icon[0].setAttribute("class", "float_icon prev_page");
    float_icon[1].setAttribute("class", "float_icon next_page");
    float_icon[2].setAttribute("class", "float_icon zoom_in");
    float_icon[3].setAttribute("class", "float_icon zoom_out");
    float_icon[4].setAttribute("class", "float_icon gallery");
    float_icon[0].innerText="➕";
    float_icon[1].innerText="➖";
    float_icon[2].innerText="👈";
    float_icon[3].innerText="👉";
    float_icon[4].innerText="📚";
    document.addEventListener("keydown", keyDown);
    float_icon[0].addEventListener('mousedown', zoomIn, false);
    float_icon[1].addEventListener('mousedown', zoomOut, false);
    float_icon[2].addEventListener('click', prevPage, false);
    float_icon[3].addEventListener('click', nextPage, false);
    document.addEventListener('mouseup', function(){clearInterval(zoomInterval);});
    float_icon[4].setAttribute("onclick", "window.open(document.getElementsByClassName('sb')[0].firstChild.href,'_self');");
    function keyDown(e) {
       var keycode = e.which;
        switch(keycode){
            case 37: {
                setNewPage();
                break;
            }
            case 39: {
                setNewPage();
                break;
            }
            case 187: {
                setScale("zoomIn");
                break;
            }
            case 189: {
                setScale("zoomOut");
                break;
            }
            case 188: {
                window.scrollBy(0, -window.innerHeight);
                break;
            }
            case 190: {
                window.scrollBy(0, window.innerHeight);
                break;
            }
            case 219: {
                window.scrollBy(0, -window.innerHeight*0.3);
                break;
            }
            case 221: {
                window.scrollBy(0, window.innerHeight*0.3);
                break;
            }
            default: {
                // console.log(keycode);
            }
        }
    }
    setNewPage(); // initial when user enter comic page from elsewhere;
    function setNewPage() {
                var listenChange = setInterval(function(){
                    if((oldSi != si) || isFirstRun){
                        isFirstRun = false;
                        var pic = document.getElementById("img");
                        var width = Number(pic.style.width.replace("px", ""));
                        var height = Number(pic.style.height.replace("px", ""));
                        var page = document.getElementsByTagName('span');
                        var footMark = document.getElementById('i4').firstChild;
                        var currentPage = page[0].innerText;
                        var totalPage = page[1].innerText;
                        footMark.innerHTML = currentPage +"P / "+ totalPage +"P :: "+ footMark.innerText +" :: ";
                        var originDlLink = document.getElementById('i7').lastChild;
                        if (originDlLink != null){
	                        var dlLink = document.createElement('a');
	                        dlLink.href = originDlLink.href;
	                        dlLink.innerText = originDlLink.innerText;
                        	footMark.appendChild(dlLink);
                        } else {
                        	footMark.innerHTML += 'No download';
                        }
                        width *= currentScale;
                        height *= currentScale;
                        pic.style.width = width + "px";
                        pic.style.height = height + "px";
                        oldSi = si;
                        clearInterval(listenChange);
                    }
                }, 200);
            }
    function setScale(scale){
        var pic = document.getElementById("img");
        var width = Number(pic.style.width.replace("px", ""));
        var height = Number(pic.style.height.replace("px", ""));
        switch(scale){
            case 'zoomIn': {
                var max_width = Number(pic.style.maxWidth.replace("px", ""));
                if (width < max_width){
                    width *= 1.1;
                    height *= 1.1;
                    currentScale *= 1.1;
                } else{
                }
                break;
            }
            case 'zoomOut': {
                if (height >= window.innerHeight){
                    width /= 1.1;
                    height /= 1.1;
                    currentScale /= 1.1;
                } else {
                }
                break;
            }
        }
        pic.style.width = width + "px";
        pic.style.height = height + "px";
    }
    function prevPage(e){
        e.preventDefault();
        if (window.location.href !== firstPage){
            document.getElementById('prev').onclick();
        } else {
            window.alert("The first page (⊙_⊙)")
        }
        setNewPage();
    }
    function nextPage(e){
        e.preventDefault();
        if (window.location.href !== lastPage){
            document.getElementById('next').onclick();
        } else {
            window.alert("The last page (⊙ω⊙)")
        }
        setNewPage();
    }
    function zoomIn(e){
        e.preventDefault();
        setScale('zoomIn');
        zoomInterval = setInterval(function(){
            setScale('zoomIn');
        }, 200);
    }
    function zoomOut(e){
        e.preventDefault();
        setScale('zoomOut');
        zoomInterval = setInterval(function(){
            setScale('zoomOut');
        }, 200);
    }
    addNewStyle(newStyle);
}