ExHentai Viewer

manage your favorite tags, enhance searching, improve comic page

As of 2019-02-11. See the latest version.

// ==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);
}