Sleazy Fork is available in English.

NHentai Improved

Partially fade/remove non-english, HQ thumbnails, mark as read, subs, version grouping etc.

Устаревшая версия на 28.12.2023. Перейти к последней версии.

// ==UserScript==
// @name         NHentai Improved
// @namespace    Hentiedup
// @version      1.9.3
// @description  Partially fade/remove non-english, HQ thumbnails, mark as read, subs, version grouping etc.
// @author       Hentiedup
// @license      unlicense
// @match        https://nhentai.net/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_addStyle
// @icon         https://i.imgur.com/1lihxY2.png
// @noframes
// ==/UserScript==

(function() {
    'use strict';

    //YOU SHOULD NOT TOUCH THE SETTINGS HERE. THEY ARE NOW AVAILABLE ON THE SITE IN THE PROFILE SETTINGS

	//== non-english settings ==//
	var remove_non_english = GM_getValue("remove_non_english", false);
	var partially_fade_all_non_english = GM_getValue("partially_fade_all_non_english", true);
	var non_english_fade_opacity = GM_getValue("non_english_fade_opacity", 0.3);

	//== browse sections ==//
	var browse_thumbnail_width = GM_getValue("browse_thumbnail_width", 0);
	var browse_thumnail_container_width = GM_getValue("browse_thumnail_container_width", 0);
	var load_high_quality_browse_thumbnails = GM_getValue("load_high_quality_browse_thumbnails", true);
    var infinite_load = false; //WIP, not really ready to use

	//== comic pages view ==//
	var pages_thumbnail_width = GM_getValue("pages_thumbnail_width", 0);
	var pages_thumnail_container_width = GM_getValue("pages_thumnail_container_width", 0);
	var load_high_quality_pages_thumbnails = GM_getValue("load_high_quality_pages_thumbnails", true);

    var max_image_reload_attempts = 20;

	//== mark as read system ==//
	var mark_as_read_system_enabled = GM_getValue("mark_as_read_system_enabled", true);
	var marked_as_read_fade_opacity = GM_getValue("marked_as_read_fade_opacity", 0.3);
	var read_tag_font_size = GM_getValue("read_tag_font_size", 15);

	//== subscription system ==//
	var subscription_system_enabled = GM_getValue("subscription_system_enabled", true);

    //== version grouping system ==//
    var version_grouping_enabled = GM_getValue("version_grouping_enabled", true);
    var version_grouping_filter_brackets = GM_getValue("version_grouping_filter_brackets", false);
    var auto_group_on_page_comics = GM_getValue("auto_group_on_page_comics", true);
    var flagEn = "https://i.imgur.com/vSnHmmi.gif";
    var flagJp = "https://i.imgur.com/GlArpuS.gif";
    var flagCh = "https://i.imgur.com/7B55DYm.gif";

    //== comic reader system ==//
    var comic_reader_improved_zoom = GM_getValue("comic_reader_improved_zoom", true);
    var remember_zoom_level = GM_getValue("remember_zoom_level", true);
    var zoom_level = Number(GM_getValue("zoom_level", 1.0));

    //== tag blocking system ==//
    var tag_blocking_enabled = GM_getValue("tag_blocking_enabled", true);
    var tag_blocking_fade_only = GM_getValue("tag_blocking_fade_only", false);

    var banIcon = `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="ban" class="svg-inline--fa fa-ban fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.034 8 8 119.033 8 256s111.034 248 248 248 248-111.034 248-248S392.967 8 256 8zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676zM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676z"></path></svg>`;

	//================= Getting arrays ready =================//
	if(true) {
        var SubArray = [];
        var SubArrayString = GM_getValue("SubArrayString", null);
        if(SubArrayString == "null")
            SubArrayString = "[]";
        if(SubArrayString) { SubArray = JSON.parse(SubArrayString); }

        var MARArray = [];
        var MARArrayString = GM_getValue("MARArrayString", null);
        if(MARArrayString == "null")
            MARArrayString = "[]";
        if(MARArrayString) { MARArray = JSON.parse(MARArrayString); }

        var unreadImg = '<svg style="vertical-align: middle;" width="15" height="15" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="book-open" class="svg-inline--fa fa-book-open fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M542.22 32.05c-54.8 3.11-163.72 14.43-230.96 55.59-4.64 2.84-7.27 7.89-7.27 13.17v363.87c0 11.55 12.63 18.85 23.28 13.49 69.18-34.82 169.23-44.32 218.7-46.92 16.89-.89 30.02-14.43 30.02-30.66V62.75c.01-17.71-15.35-31.74-33.77-30.7zM264.73 87.64C197.5 46.48 88.58 35.17 33.78 32.05 15.36 31.01 0 45.04 0 62.75V400.6c0 16.24 13.13 29.78 30.02 30.66 49.49 2.6 149.59 12.11 218.77 46.95 10.62 5.35 23.21-1.94 23.21-13.46V100.63c0-5.29-2.62-10.14-7.27-12.99z"></path></svg>';
        var readImg = '<svg style="vertical-align: middle;" width="15" height="15" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="book" class="svg-inline--fa fa-book fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 360V24c0-13.3-10.7-24-24-24H96C43 0 0 43 0 96v320c0 53 43 96 96 96h328c13.3 0 24-10.7 24-24v-16c0-7.5-3.5-14.3-8.9-18.7-4.2-15.4-4.2-59.3 0-74.7 5.4-4.3 8.9-11.1 8.9-18.6zM128 134c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm0 64c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm253.4 250H96c-17.7 0-32-14.3-32-32 0-17.6 14.4-32 32-32h285.4c-1.9 17.1-1.9 46.9 0 64z"></path></svg>';

        var BlockTagArray = [];
        var BlockTagArrayString = GM_getValue("BlockTagArrayString", null);
        if(BlockTagArrayString == "null")
            BlockTagArrayString = "[]";
        if(BlockTagArrayString) { BlockTagArray = JSON.parse(BlockTagArrayString); }
	}
	//========================================================//

	//================== Adding stylesheets ==================//
	if(true) {
		if(remove_non_english) {
			GM_addStyle(`
				.gallery:not([data-tags~='12227']) {
					display: none;
				}
			`);
		}
		else if(!remove_non_english && partially_fade_all_non_english) {
			GM_addStyle(`
				.gallery:not([data-tags~='12227']) > .cover > img, .gallery:not([data-tags~='12227']) > .cover > .caption{
					opacity: ` + non_english_fade_opacity + `;
				}
			`);
		}

        if(mark_as_read_system_enabled)
        {
            GM_addStyle(`
                .marked-as-read > img, .marked-as-read > .caption {






                    opacity: `+marked_as_read_fade_opacity+`;
                }
            `);
        }

        if(tag_blocking_enabled) {
            let blockedTagsStylingString = "";
            for(let i = 0; i < BlockTagArray.length; i++)
            {
                blockedTagsStylingString += "html.theme-black a.tag.tag-" + BlockTagArray[i][0] + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":hover" + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":active" + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":focus" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":hover" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":active" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":focus" + " > span";

                if(i < BlockTagArray.length-1)
                    blockedTagsStylingString += ", ";
            }

			GM_addStyle(`
				`+blockedTagsStylingString+` {
					background-color: #500;
				}

				.blockTagButton
				{
					display: inline-block;
					width: 13px;
					height: 13px;
					vertical-align: middle;
					cursor: pointer;
					margin-left: 2px;
				}
				.blockTagButton > svg
				{
					vertical-align: top;
					color: #ff5454;
					width: 13px;
					height: 13px;
				}
				.blockTagButton:active > svg, .blockTagButton:hover > svg, .blockTagButton:focus > svg
				{
					color: #822B2B;
				}
			`);
        }

		//fixing too long cover images ==
		if(browse_thumbnail_width > 0) {
			GM_addStyle(`
				.gallery, .gallery > .cover {
					max-height: `+(browse_thumbnail_width*1.42)+`px;
				}
			`);
		}
		GM_addStyle(`
			.gallery > .cover {
				overflow: hidden;
				padding: 0 !important;
			}
			.gallery > .cover > img {
				position: relative;
				min-height: 100%;
			}
		`);
		// ==

		//browsing comics ==
		if(browse_thumnail_container_width > 0) {
			GM_addStyle(`
				/*browsing comics*/
				.container.index-container, #favcontainer {
					width: ` + browse_thumnail_container_width + `px;
				}
			`);
		}
		if(browse_thumbnail_width > 0) {
			GM_addStyle(`
				/*browsing comics*/
				.container.index-container > div.gallery, #favcontainer > .gallery-favorite {
					width: ` + browse_thumbnail_width + `px;
				}
			`);
		}
		if(browse_thumnail_container_width > 0) {
			GM_addStyle(`
				/*browsing comics*/
				.container.index-container, #favcontainer {
					max-width: 100%;
				}
			`);
		}
		GM_addStyle(`
			/*browsing comics*/
			.container.index-container, #favcontainer {
				text-align: center;
			}
			.gallery > .cover > img {
				width: 100%;
			}
		`);
		// ==

		//pages ==
		if(pages_thumnail_container_width > 0) {
			GM_addStyle(`
				/*view comic pages*/
				#thumbnail-container {
					max-width: 100%;
					width: ` + pages_thumnail_container_width + `px;
				}
			`);
		}
		if(pages_thumbnail_width > 0) {
			GM_addStyle(`
				/*view comic pages*/
				div.thumb-container img {
					width: ` + pages_thumbnail_width + `px;
				}
			`);
		}
		GM_addStyle(`
			/*view comic pages*/
			div.thumb-container {
				width: auto;
			}
			#thumbnail-container {
				text-align: center;
			}
		`);
		// ==

        if(version_grouping_enabled)
        {
            GM_addStyle(`
				.overlayFlag
				{
					position: absolute;
					display: inline-block;
					top: 3px;
					left: 3px;
					z-index: 3;
					width: 18px;
					height: 12px;
				}
				.numOfVersions {
					border-radius: 10px;
					padding: 5px 10px;
					position: absolute;
					background-color: rgba(0,0,0,.7);
					color: rgba(255,255,255,.8);
					top: 7.5px;
					left: 105px;
					font-size: 12px;
					font-weight: 900;
					opacity: 1;
					width: 40px;
					z-index: 2;
					display: none;
				}
				.findVersionButton {
					border-radius: 10px;
					padding: 5px 10px;
					position: absolute;
					background-color: rgba(0,0,0,.4);
					color: rgba(255,255,255,.8);
					bottom: 7.5px;
					left: 7.5px;
					font-size: 12px;
					font-weight: 900;
					opacity: 1;
					width: 125px;
					z-index: 2;
					cursor: pointer;
				}
				.versionNextButton {
					border-radius: 10px;
					padding: 5px 10px;
					position: absolute;
					background-color: rgba(0,0,0,.7);
					color: rgba(255,255,255,.8);
					top: 7.5px;
					right: 7.5px;
					font-size: 12px;
					font-weight: 900;
					opacity: 1;
					display: none;
					z-index: 2;
					cursor: pointer;
				}
				.versionPrevButton {
					border-radius: 10px;
					padding: 5px 10px;
					position: absolute;
					background-color: rgba(0,0,0,.7);
					color: rgba(255,255,255,.8);
					top: 7.5px;
					left: 7.5px;
					font-size: 12px;
					font-weight: 900;
					opacity: 1;
					z-index: 2;
					display: none;
					cursor: pointer;
				}

				.findVersionButton:focus, .findVersionButton:hover, .findVersionButton:active,
				.versionNextButton:focus, .versionNextButton:hover, .versionNextButton:active,
				.versionPrevButton:focus, .versionPrevButton:hover, .versionPrevButton:active
				{
					background-color: rgba(50,50,50,1);
				}
			`);
        }

		if(mark_as_read_system_enabled)
		{
			GM_addStyle(`
				.readTag {
					border-radius: 10px;
					padding: 5px 10px;
					position: absolute;
					background-color: rgba(0,0,0,.7);
					color: rgba(255,255,255,.8);
					bottom: 7.5px;
					right: 7.5px;
					font-size: `+read_tag_font_size+`px;
					font-weight: 900;
					opacity: 1;
				}

				#markAsRead, #markAsRead:visited {
					background-color: #3d9e48;
				}
				#markAsRead:active, #markAsRead:hover {
					background-color: #52bc5e;
				}

				#markAsUnRead, #markAsUnRead:visited {
					background-color: rgb(218, 53, 53);
				}
				#markAsUnRead:active, #markAsUnRead:hover {
					background-color: #e26060;
				}

				.gallery {
					position: relative;
				}
			`);
		}

		if(subscription_system_enabled) {
			GM_addStyle(`
				#tags .subbedTag, #tags .subbedTag:visited {
					background-color: #2c5030;
				}
				#tags .subbedTag:active, #tags .subbedTag:hover {
					background-color: #416144;
				}

				#subTo, #subTo:visited {
					background-color: #3d9e48;
				}
				#subTo:active, #subTo:hover {
					background-color: #52bc5e;
				}

				#unsubTo, #unsubTo:visited {
					background-color: rgb(218, 53, 53);
				}
				#unsubTo:active, #unsubTo:hover {
					background-color: #e26060;
				}

				#sub-content ul {
					text-align: left;
				}
				#sub-content li {
					box-sizing: border-box;
					display: inline-block;
					width: 25%;
					text-align: center;
					padding: 5px 20px;
				}

				#subTo, #unsubTo {
					height: auto;
					line-height: initial;
					cursor: pointer;
					font-size: 0.5em;
					padding: 6px 12px;
				}
                @media only screen and (max-width: 1345px) {
                    .menu.right a[href^='/logout/'] span { display: none; }
                }
                    @media only screen and (max-width: 1270px) {
                    .menu.right a[href^='/users/'] span { display: none; }
                }
                @media only screen and (max-width: 670px) {
                    .menu.right a[href='/favorites/'] span { display: none; }
                }
                @media only screen and (max-width: 600px) {
                    .menu.right a[href^='/logout/'] span { display: inline; }
                    .menu.right a[href^='/users/'] span { display: inline; }
                    .menu.right a[href='/favorites/'] span { display: inline; }
                }
			`);
		}
	}
	//========================================================//


	//================== On Comic info page ==================//
	if(window.location.href.match(/^https:\/\/nhentai\.net\/g\/\d+?\/(\?.*|\#.*|)$/g)) //if on the comic info page
	{
		//=== Mark as read system ===//
		if(mark_as_read_system_enabled) {
			var item = window.location.href.split("nhentai.net")[1].split("?")[0].split("#")[0]; //get item from url

			if(MARArray.includes(item)) //if item is marked as read
				$(".buttons").append('<a href="#" id="markAsUnRead" class="btn btn-secondary">'+unreadImg+' <span style="vertical-align: middle;">Mark as unread</span></a>'); //..add unmark button
			else
				$(".buttons").append('<a href="#" id="markAsRead" class="btn btn-secondary">'+readImg+' <span style="vertical-align: middle;">Mark as read</span></a>'); //...add mark button

			AddMARClickListeners();
		}
		//===========================//

		//==== Subscribe system =====//
		if(subscription_system_enabled) {
			let SubArraySelector = SubArray.join("'], .tag[href='");
			$(".tag[href='" + SubArraySelector + "']").addClass("subbedTag");
		}
		//===========================//

		//=== HQ thumbnail system ===//
		if(load_high_quality_pages_thumbnails && $("#thumbnail-container").length !== 0) {
			$("#thumbnail-container .thumb-container > .gallerythumb > img").on("load", OnLoadCoverReplaceHQ);
		}
		//===========================//
	}
	//========================================================//

	//============== On Artist/group info page ===============//
	else if(subscription_system_enabled && (window.location.href.match(/^.+?\/artist\/.+?\/(popular)?(\?.*?|\#.*?|)$/g) || window.location.href.match(/^.+?\/group\/.+?\/(popular)?(\?.*?|\#.*?|)$/g))) //in artist or group page
	{
		var subItem = window.location.href.split("nhentai.net")[1].split("popular")[0].split("?")[0].split("#")[0]; //get item from url
		if(SubArray.includes(subItem)) //if subscribed
			$("h1").append('<a href="#" id="unsubTo" class="btn btn-secondary"><span style="vertical-align: middle;">Unsubscribe</span></a>'); //...add unsub button
		else
			$("h1").append('<a href="#" id="subTo" class="btn btn-secondary"><span style="vertical-align: middle;">Subscribe</span></a>'); //...add sub button

		AddSubClickListeners();
	}
	//========================================================//

	//====================== Subs page =======================//
	else if(subscription_system_enabled && window.location.href.match(/^.+?\/subscriptions\/(\?.*|\#.*|)$/g)) //in subs page
	{
		$("head title").html('Subscriptions').prop("style", "font-size: 3.5em;");
		$("#content").prepend('<h1>Subscriptions</h1>');
		$("#content > .container").removeClass("error").addClass("artists-section").prop("id", "tag-container");
        $(".artists-section").before("<h2 style='font-size: 2em;'>Artists</h2>");
        $(".artists-section").after('<div class="container groups-section" id="tag-container"></div>');
        $(".groups-section").before("<h2 style='font-size: 2em; margin-top: 50px;'>Groups</h2>");

		var artists = [];
        var groups = [];
		for(let i = 0; i < SubArray.length; i++) {
            if(SubArray[i].split("/")[1].split("/")[0] == "artist")
                artists.push('<a class="tag" href="'+SubArray[i]+'"><span class="name">'+(SubArray[i].split("/")[2].split("/")[0].replace(/\-/g, " "))+'</span><span class="count">...</span></a>');
            else
                groups.push('<a class="tag" href="'+SubArray[i]+'"><span class="name">'+(SubArray[i].split("/")[2].split("/")[0].replace(/\-/g, " "))+'</span><span class="count">...</span></a>');
		}

        if(artists.length < 6)
            $(".container.artists-section").prop("style", "-webkit-columns: "+artists.length.toString()+"; columns: "+artists.length.toString()+";");
        if(groups.length < 6)
            $(".container.groups-section").prop("style", "-webkit-columns: "+groups.length.toString()+"; columns: "+groups.length.toString()+";");

		$(".artists-section").html(artists.join(""));
        $(".groups-section").html(groups.join(""));
        $(".tag > .count").each(function(i){
            let elem = $(this);
            SubsPageLoadTagCountWithDelay(elem, i*200);
        });
        $(".tag > .count").hover(function(){
            let elem = $(this);
            SubsPageLoadTagCountWithDelay(elem, 0);
        });
	}
	//========================================================//

    //====================== Reader Page =====================//
    else if(window.location.href.match(/^.+?\/g\/\d+?\/\d+\/$/g))
    {
        if(comic_reader_improved_zoom)
        {
            let prevVal = 1.0;
            if(remember_zoom_level)
                prevVal = zoom_level;
            let curVal = prevVal;
            SetReaderImageScale(curVal);

            $('body').on('keydown', function(e) {
                if(e.key == '+')
                {
                    curVal = prevVal+0.1;
                    if(curVal > 3)
                        curVal = 3;

                    SetReaderImageScale(curVal);
                    prevVal = curVal;
                }
                else if(e.key == '-')
                {
                    curVal = prevVal-0.1;
                    if(curVal < 0.1)
                        curVal = 0.1;

                    SetReaderImageScale(curVal);
                    prevVal = curVal;
                }
            });

            //make sure the current zoom-level stays between pages
            var observer = new MutationObserver(function( mutations ) {
                for(let i = 0; i < mutations.length; i++)
                    if(mutations[i].type == 'attributes')
                        SetReaderImageScale(curVal);
            });
            observer.observe($("#image-container > a")[0], {attributes: true, childList: false, characterData: false});

            $("section.reader-bar button.reader-zoom-out").click(function(e){
                e.preventDefault();
                e.stopPropagation();
                curVal = prevVal-0.1;
                if(curVal < 0.1)
                    curVal = 0.1;

                SetReaderImageScale(curVal);
                prevVal = curVal;
            });
            $("section.reader-bar button.reader-zoom-in").click(function(e){
                e.preventDefault();
                e.stopPropagation();
                curVal = prevVal+0.1;
                if(curVal > 3)
                    curVal = 3;

                SetReaderImageScale(curVal);
                prevVal = curVal;
            });
        }
    }
    //========================================================//

	//====================== all pages with lists of comics ====================//
	if($(".container.index-container, #favcontainer.container, #recent-favorites-container, #related-container").length !== 0)
	{
        //=== Tag blocking system ===//
        if(tag_blocking_enabled && BlockTagArray.length > 0)
        {
            let selector = "";
            for(let i = 0; i < BlockTagArray.length; i++)
            {
                if(tag_blocking_fade_only)
                    selector += ".gallery[data-tags*=" + BlockTagArray[i][0] + "] > .cover > img, .gallery[data-tags*=" + BlockTagArray[i][0] + "] > .cover > .caption";
                else
                    selector += ".gallery[data-tags*=" + BlockTagArray[i][0] + "]";

                if(i < BlockTagArray.length-1)
                    selector += ", ";
            }

            if(tag_blocking_fade_only)
                $(selector).css("opacity", non_english_fade_opacity);
            else
                $(selector).remove();
        }
        //===========================//

		//=== HQ thumbnail system ===//
		if(load_high_quality_browse_thumbnails) {
			$(".container.index-container > .gallery > .cover > img, #favcontainer.container > .gallery-favorite > .gallery > .cover > img, #related-container.container > .gallery > .cover > img").on("load", OnLoadCoverReplaceHQ);
		}
		//===========================//

		//=== Mark as read system ===//
		if(mark_as_read_system_enabled) {

            //possible problems with too long selectors? - splitting it up to chunks of 50
            let parts = [];
            for(let i = 0, count = MARArray.length; i < count; i += 50)
                parts.push(MARArray.slice(i, i+50));

            for(let i = 0, count = parts.length; i < count; i++)
            {
                let readPartSelector = parts[i].join("'], .cover[href='");
                $(".cover[href='" + readPartSelector + "']").addClass("marked-as-read").append("<div class='readTag'>READ</div>");
            }
		}
		//===========================//

        //=== Version Grouping system ===//
		if(version_grouping_enabled) {
            AddVersionGroupingButtonsToJQuerySelector($(".gallery"));

            if(auto_group_on_page_comics && !remove_non_english)
                GroupAltVersionsOnPage();
		}
		//===========================//

        //=== Infinite Load system ===//
        if(infinite_load) {
            setTimeout(() => {
                //if found paginator on page (also, specifically not enabled on favorites page for now)
                let paginator = $(".pagination > .page.current");
                if(paginator?.length && window.location.pathname != "/favorites/") {
                    let startingPageNum = parseInt(paginator.attr("href").split("page=")[1]);
                    let currentPageNum = startingPageNum;
                    //get query string and strip out the page part. Also if after the strip query starts with a "&", replace that with "?"
                    let queryWithNoPage = window.location.search.replace(/[\?\&]page=\d+/, "").replace(/^\&/, "?");
                    //build final url: path + original query + page property in correct format + pageNum
                    let getUrl = window.location.pathname + queryWithNoPage + (queryWithNoPage.length ? "&" : "?") + "page=" + (++currentPageNum);
                    $.get(getUrl, function(data) {
                        //returns invalid html so here's some custom handling...
                        //trim for starters
                        let filteredData = data.trim();
                        //take out everything before the section we want
                        filteredData = filteredData.split('<div class="container index-container">')[1];
                        //take out everything after the section we want starting at the paginator (also taking out the </div> left over from the container div)
                        filteredData = filteredData.split('</div><section class="pagination">')[0];
                        //wrapping final xml in a div for easier handling
                        filteredData = "<div>" + filteredData + "</div>";
                        //parse to HTML
                        let htmlData = $.parseHTML(filteredData);

                        //for each comic fetched
                        $(htmlData).find("div.gallery").each((i, el) => {

                            //if already on page (excluding the page 1 popular section), don't add again
                            if($(".container:not(.index-popular) .cover[href='" + $(el).find(".cover").attr("href") + "']").length)
                                return;

                            //if we are removing (normally actually just hiding via css) non-english anyways, might as well not insert them
                            if(remove_non_english && !$(el).data("tags").includes("12227"))
                                return;

                            //set thumbnail src = data-src
                            $(el).find("img").attr("src", $(el).find("img").data("src"));

                            //HQ thumbnail onLoad
                            if(load_high_quality_browse_thumbnails)
                                $(el).find(".cover > img").on("load", OnLoadCoverReplaceHQ);

                            //check if read, and mark as such
                            if(mark_as_read_system_enabled) {
                                let cover = $(el).find("a.cover");
                                let item = cover.attr("href");
                                if(MARArray.includes(item))
                                    cover.addClass("marked-as-read").append("<div class='readTag'>READ</div>");
                            }

                            //check if any of tags are blocked...
                            if(tag_blocking_enabled && BlockTagArray.length > 0) {
                                let tags = $(el).data("tags").split(" ");
                                if(BlockTagArray.some(blockedTag => tags.includes(blockedTag[0]))) {
                                    if(!tag_blocking_fade_only)
                                        return; //if not fade only, skip adding this comic entirely
                                    else
                                        $(el).find(".cover > img, .cover > .caption").css("opacity", non_english_fade_opacity); //if fade only, add fade
                                }
                            }

                            //add version grouping buttons
                            if(version_grouping_enabled)
                                AddVersionGroupingButtonsToJQuerySelector($(el));

                            /*TODO:
                            - replace [setTimeout -> Load next page once] with proper isAtBottom scroll detection + proper tracking of which page to load at that point
                            - Handle and retry on error
                            - Handle auto version grouping... Not sure how to handle... Might just disallow auto-grouping with infinite load
                            - Handle new comics on first page? With a filter in place to filter out comics already loaded, we could always check page 1 for new comics before whatever the next page would have been
                                - Where to put new comics found from page 1 -> Seems logical they would go at the top in their actual position, but the user wouldn't really notice that -> some kind of notification?
                            - Hide Paginator an enforce always using page 1? -> would technically work just fine if we allow manually going to other pages as well... The manually selected page should be considered "first" in the infinite load system
                            - Handle Favorites page -> infinite load disabled there for now
                            - Add additional highlighted numbers to the paginator beyound what is shown normally if pages beyond said page are loaded
                            - Handle last page
                            */

                            //finally add the modified comic on to page
                            $(".index-container:not(.advertisement, .index-popular)").first().append(el);
                        });

                        //after adding all comics from fetched page, mark that page as "current" in the paginator to clearly sow the user all the pages currently loaded
                        $(".pagination > .page[href$='page="+currentPageNum+"']").addClass("current");
                    }).fail(function() {
                        alert( "error" );
                    });
                }
            }, 3000);
        }
        //===========================//
	}
	//==========================================================================//

	//====================== Settings page ===================//
	if($("#settings-container").length !== 0)
	{
        //TODO: Sometimes changes aren't saved properly
        //this is actually needed here even if tag blocking is disabled (so that you can still remove tags properly). If it is enabled, then there is no need to add it again, thus: add it if it's NOT on
        if(!tag_blocking_enabled) {
            let blockedTagsStylingString = "";
            for(let i = 0; i < BlockTagArray.length; i++)
            {
                blockedTagsStylingString += "html.theme-black a.tag.tag-" + BlockTagArray[i][0] + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":hover" + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":active" + " > span" +
                    ", html.theme-black a.tag.tag-" + BlockTagArray[i][0] + ":focus" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":hover" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":active" + " > span" +
                    ", a.tag.tag-" + BlockTagArray[i][0] + ":focus" + " > span";

                if(i < BlockTagArray.length-1)
                    blockedTagsStylingString += ", ";
            }

			GM_addStyle(`
				`+blockedTagsStylingString+` {
					background-color: #500;
				}

				.blockTagButton
				{
					display: inline-block;
					width: 13px;
					height: 13px;
					vertical-align: middle;
					cursor: pointer;
					margin-left: 2px;
				}
				.blockTagButton > svg
				{
					vertical-align: top;
					color: #ff5454;
					width: 13px;
					height: 13px;
				}
				.blockTagButton:active > svg, .blockTagButton:hover > svg, .blockTagButton:focus > svg
				{
					color: #822B2B;
				}
			`);
        }

		GM_addStyle(`
			#settings-container .custom-settings {
				margin: 5px 5px 5px 20px;
			}

			#settings-container .custom-settings input[type="text"],
			#settings-container .custom-settings input[type="number"]{
				width: 70px;
				height: 25px;
				border-radius: 3px;
				text-align: center;
				padding: 0;
			}

			#settings-container .custom-settings.disabled-setting {
				color: RGBA(153, 153, 153, 1);
				opacity: 0.3;
			}

			#settings-container h2 {position: relative;}
			#settings-container #settings-saved-mark {
				color: green;
				font-size: 15px;
				position: absolute;
				right: 0;
				top: 10px;
				display: none;
			}

			#importexportdiv {
				position: fixed;
				top: 10%;
				left: 10%;
				width: 80%;
				height: 80%;
				background-color: #393939;
				padding: 3%;
				border-radius: 15px;
			}
			#importexportdiv > textarea {
				width: 100%;
				height: 90%;
			}
		`);

        let blockedTagsHTML = "";
        for(let i = 0; i < BlockTagArray.length; i++)
            blockedTagsHTML += "<a class='tag tag-"+BlockTagArray[i][0]+" href='#'><span class='name'>"+BlockTagArray[i][1]+"</span><span class='count'></span></a>";

		let settingsHTML = `<br>
			<div id="customSettingsContainer">
				<form class="form-horizontal" role="form">
					<h2>NHentai Improved Settings <span id="settings-saved-mark">Saved 🗸</span></h2>

					<h3>Non-English Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="remove_non_english" type="checkbox">
						Remove Non-English</label>
					</div></div>

					<div class="custom-settings"><div class="form-control">
						<label><input id="partially_fade_all_non_english" type="checkbox">
						Partially Fade Non-English</label>
					</div></div>

					<div class="custom-settings">
						<label>Non-English Fade Opacity
						<input id="non_english_fade_opacity" type="text" placeholder="0.0 - 1.0" autocomplete="off"></label>
					</div>


					<h3>Browse Section Settings</h3>
					<div class="custom-settings" title="0 = Use unmodified NHentai default. Height scales automatically">
						<label>Thumbnail Width
						<input id="browse_thumbnail_width" type="number" placeholder="0"> px</label>
					</div>

					<div class="custom-settings" title="0 = Use unmodified NHentai default. max-width = 100% of available space, meaning no need to worry about going too big">
						<label>Thumbnail Container Width
						<input id="browse_thumnail_container_width" type="number" placeholder="0"> px</label>
					</div>

					<div class="custom-settings"><div class="form-control">
						<label><input id="load_high_quality_browse_thumbnails" type="checkbox">
						HQ Thumbnails</label>
					</div></div>


					<h3>Comic Pages Section Settings</h3>
					<div class="custom-settings" title="0 = Use unmodified NHentai default. Height scales automatically">
						<label>Thumbnail Width
						<input id="pages_thumbnail_width" type="number" placeholder="0"> px</label>
					</div>

					<div class="custom-settings" title="0 = Use unmodified NHentai default. max-width = 100% of available space, meaning no need to worry about going too big">
						<label>Thumbnail Container Width
						<input id="pages_thumnail_container_width" type="number" placeholder="0"> px</label>
					</div>

					<div class="custom-settings"><div class="form-control">
						<label><input id="load_high_quality_pages_thumbnails" type="checkbox">
						HQ Thumbnails</label>
					</div></div>


					<h3>Comic Reader Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="comic_reader_improved_zoom" type="checkbox">
						Improved Zoom</label>
					</div></div>
					<div class="custom-settings"><div class="form-control">
						<label><input id="remember_zoom_level" type="checkbox">
						Remember Zoom Level</label>
					</div></div>


					<h3>Mark As Read Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="mark_as_read_system_enabled" type="checkbox">
						Enabled</label>
					</div></div>

					<div class="custom-settings">
						<label>Fade Opacity
						<input id="marked_as_read_fade_opacity" type="text" placeholder="0.0 - 1.0" autocomplete="off"></label>
					</div>

					<div class="custom-settings">
						<label>Read Tag Font Size
						<input id="read_tag_font_size" type="number" placeholder="15"> px</label>
					</div>


					<h3>Subscription Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="subscription_system_enabled" type="checkbox">
						Enabled</label>
					</div></div>

					<h3>Version Grouping Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="version_grouping_enabled" type="checkbox">
						Enabled</label>
					</div></div>

					<div class="custom-settings"><div class="form-control">
						<label><input id="version_grouping_filter_brackets" type="checkbox">
						Filter out normal brackets for version searches<br><sup>(square brackets are always filtered out regardless of this setting)</sup></label>
					</div></div>

					<div class="custom-settings"><div class="form-control">
						<label><input id="auto_group_on_page_comics" type="checkbox">
						Automatically group on-page comics<br><sup>(doesn't search the site, just current page)</sup><br><sup style="top: -1em;">(Currently does not properly work with "Remove Non-English")</sup></label>
					</div></div>

					<h3>Tag Blocking Settings</h3>
					<div class="custom-settings"><div class="form-control">
						<label><input id="tag_blocking_enabled" type="checkbox">
						Enabled</label>
					</div></div>

                    <div class="custom-settings"><div class="form-control">
						<label><input id="tag_blocking_fade_only" type="checkbox">
						Only partially fade blocked comics<br><sup>(blocked comics are removed otherwise)</sup></label>
					</div></div>

					<p>Currently Blocked Tags:</p>
					<span class="tags">`+(BlockTagArray.length > 0 ? blockedTagsHTML : "none")+`</span>

					<h3>Import/Export Data</h3>
					<button id="exportButt" style="line-height: 30px; height: 30px;" type="submit" class="btn btn-primary">Export</button>
					<button id="importButt" style="line-height: 30px; height: 30px;" type="submit" class="btn btn-primary">Import</button> <input id="NHIImportFile" type="file" style="display: none;">
					<br><br>
				</form>
				<br><br>
			</div>`;

		$("#settings-container").append(settingsHTML);
		InitialValuesForSettings();
		$("#settings-container form:last").change(function(){
			UpdateSettingsValues();
		});

        $("#importButt").click((e) => {
            e.preventDefault();
            e.stopPropagation();
            $("#NHIImportFile").animate({width:'toggle'},200);
        });

        $("#NHIImportFile").change((event) => {
            if (typeof window.FileReader !== 'function')
                throw ("The file API isn't supported on this browser.");
            let input = event.target;
            if (!input)
                throw ("The browser does not properly implement the event object");
            if (!input.files)
                throw ("This browser does not support the `files` property of the file input.");

            let file = input.files[0];
            let fr = new FileReader();
            fr.onload = (ev) => {
                let importedData = ev.target.result;
                if(importedData != null && confirm("File received. Import this file?"))
                {
                    let dataString = importedData;
                    dataString = dataString.replace(/(\r?\n|\r)/g, ""); //remove newlines
                    dataString.trim(); //remove whitespace around the string

					if(dataString.indexOf("|||||") < 0) {
						alert("invalid data");
						return;
					}

                    let dataArr = dataString.split("|||||");

                    if(dataArr.length > 0)
                    {
                        GM_setValue("SubArrayString", dataArr[0]);
                        console.log("NHI - SubArrayString imported");
                    }
                    if(dataArr.length > 1)
                    {
                        GM_setValue("MARArrayString", dataArr[1]);
                        console.log("NHI - MARArrayString imported");
                    }
                    if(dataArr.length > 2)
                    {
                        GM_setValue("BlockTagArrayString", dataArr[2]);
                        console.log("NHI - BlockTagArrayString imported");
                    }

                    if(dataArr.length > 3)
                    {
                        GM_setValue("remove_non_english", (String(dataArr[3]) == "true"));
                        console.log("NHI - remove_non_english imported");
                    }
                    if(dataArr.length > 4)
                    {
                        GM_setValue("partially_fade_all_non_english", (String(dataArr[4]) == "true"));
                        console.log("NHI - partially_fade_all_non_english imported");
                    }
                    if(dataArr.length > 5)
                    {
                        GM_setValue("non_english_fade_opacity", dataArr[5]);
                        console.log("NHI - non_english_fade_opacity imported");
                    }

                    if(dataArr.length > 6)
                    {
                        GM_setValue("load_high_quality_browse_thumbnails", (String(dataArr[6]) == "true"));
                        console.log("NHI - load_high_quality_browse_thumbnails imported");
                    }
                    if(dataArr.length > 7)
                    {
                        GM_setValue("browse_thumbnail_width", dataArr[7]);
                        console.log("NHI - browse_thumbnail_width imported");
                    }
                    if(dataArr.length > 8)
                    {
                        GM_setValue("browse_thumnail_container_width", dataArr[8]);
                        console.log("NHI - browse_thumnail_container_width imported");
                    }

                    if(dataArr.length > 9)
                    {
                        GM_setValue("load_high_quality_pages_thumbnails", (String(dataArr[9]) == "true"));
                        console.log("NHI - load_high_quality_pages_thumbnails imported");
                    }
                    if(dataArr.length > 10)
                    {
                        GM_setValue("pages_thumbnail_width", dataArr[10]);
                        console.log("NHI - pages_thumbnail_width imported");
                    }
                    if(dataArr.length > 11)
                    {
                        GM_setValue("pages_thumnail_container_width", dataArr[11]);
                        console.log("NHI - pages_thumnail_container_width imported");
                    }

                    if(dataArr.length > 12)
                    {
                        GM_setValue("max_image_reload_attempts", dataArr[12]);
                        console.log("NHI - max_image_reload_attempts imported");
                    }

                    if(dataArr.length > 13)
                    {
                        GM_setValue("mark_as_read_system_enabled", (String(dataArr[13]) == "true"));
                        console.log("NHI - mark_as_read_system_enabled imported");
                    }
                    if(dataArr.length > 14)
                    {
                        GM_setValue("marked_as_read_fade_opacity", dataArr[14]);
                        console.log("NHI - marked_as_read_fade_opacity imported");
                    }
                    if(dataArr.length > 15)
                    {
                        GM_setValue("read_tag_font_size", dataArr[15]);
                        console.log("NHI - read_tag_font_size imported");
                    }

                    if(dataArr.length > 16)
                    {
                        GM_setValue("subscription_system_enabled", (String(dataArr[16]) == "true"));
                        console.log("NHI - subscription_system_enabled imported");
                    }

                    if(dataArr.length > 17)
                    {
                        GM_setValue("version_grouping_enabled", (String(dataArr[17]) == "true"));
                        console.log("NHI - version_grouping_enabled imported");
                    }
                    if(dataArr.length > 18)
                    {
                        GM_setValue("version_grouping_filter_brackets", (String(dataArr[18]) == "true"));
                        console.log("NHI - version_grouping_filter_brackets imported");
                    }
                    if(dataArr.length > 19)
                    {
                        GM_setValue("auto_group_on_page_comics", (String(dataArr[19]) == "true"));
                        console.log("NHI - auto_group_on_page_comics imported");
                    }

                    if(dataArr.length > 20)
                    {
                        GM_setValue("comic_reader_improved_zoom", (String(dataArr[20]) == "true"));
                        console.log("NHI - comic_reader_improved_zoom imported");
                    }
                    if(dataArr.length > 21)
                    {
                        GM_setValue("remember_zoom_level", (String(dataArr[21]) == "true"));
                        console.log("NHI - remember_zoom_level imported");
                    }
                    if(dataArr.length > 22)
                    {
                        GM_setValue("zoom_level", Number(dataArr[22]));
                        console.log("NHI - zoom_level imported");
                    }
                    if(dataArr.length > 23)
                    {
                        GM_setValue("tag_blocking_enabled", (String(dataArr[23]) == "true"));
                        console.log("NHI - tag_blocking_enabled imported");
                    }
                    if(dataArr.length > 24)
                    {
                        GM_setValue("tag_blocking_fade_only", (String(dataArr[24]) == "true"));
                        console.log("NHI - tag_blocking_fade_only imported");
                    }
					location.reload();
                }
                else
                    $("#NHIImportFile").val('');
            };
            fr.readAsText(file);
        });

        $("#exportButt").click((e) => {
            e.preventDefault();
            e.stopPropagation();

            let data = SubArrayString + "|||||" +
                MARArrayString + "|||||" +
                BlockTagArrayString + "|||||" +

                remove_non_english + "|||||" +
                partially_fade_all_non_english + "|||||" +
                non_english_fade_opacity + "|||||" +

                load_high_quality_browse_thumbnails + "|||||" +
                browse_thumbnail_width + "|||||" +
                browse_thumnail_container_width + "|||||" +

                load_high_quality_pages_thumbnails + "|||||" +
                pages_thumbnail_width + "|||||" +
                pages_thumnail_container_width + "|||||" +

                max_image_reload_attempts + "|||||" +

                mark_as_read_system_enabled + "|||||" +
                marked_as_read_fade_opacity + "|||||" +
                read_tag_font_size + "|||||" +

                subscription_system_enabled + "|||||" +

                version_grouping_enabled + "|||||" +
                version_grouping_filter_brackets + "|||||" +
                auto_group_on_page_comics + "|||||" +

                comic_reader_improved_zoom + "|||||" +
                remember_zoom_level + "|||||" +
                zoom_level + "|||||" +
                tag_blocking_enabled + "|||||" +
                tag_blocking_fade_only;

            SaveToFile("NHI-Backup_" + new Date().toISOString().replace(/:/g, "-") + ".nhi", data);
        });

	}
    //========================================================//

    //====================== Own User Page ===================//
    if($("#user-container").length !== 0 && $(".user-info > h1").text().trim() == $("nav ul.menu.right a[href^='/users/']").text().replace(/<.+?>/g, "").trim())
    {
        $(".user-info > div").before(`<p><b>Comics marked as read: </b>`+MARArray.length+`</p>`); //add number of comics read to page
    }
	//========================================================//

	//====================== All pages =======================//
    if(true)
    {
        if(subscription_system_enabled) {
            $(".menu.right").prepend('<li title="Subscriptions"><a id="header-subs-button" href="/subscriptions/"><i class="fa fa-heartbeat"></i><span> Subscriptions</span></a></li>');
            let fi = $(".menu.right a[href='/favorites/'] i");
            $(".menu.right a[href='/favorites/']").html("");
            $(".menu.right a[href='/favorites/']").append(fi).append(`<span> Favorites</span>`).prop("title", "Favorites");
            let li = $(".menu.right a[href^='/logout/'] i");
            $(".menu.right a[href^='/logout/']").html("");
            $(".menu.right a[href^='/logout/']").append(li).append(`<span> Log out</span>`).prop("title", "Log out");
            let pi = $(".menu.right a[href^='/users/'] img");
            let pt = $(".menu.right a[href^='/users/']").html().split(">");
            pt = pt[pt.length-1].trim();
            $(".menu.right a[href^='/users/']").html("");
            $(".menu.right a[href^='/users/']").append(pi).append(`<span>` +pt+`</span>`);
        }

        //even if the system is disabled, we should have it on in the settings so we can remove tags from there. Also, don't run on the Subs page
        if(!window.location.href.match(/^.+?\/subscriptions\/(\?.*|\#.*|)$/g) && (tag_blocking_enabled || $("#settings-container").length !== 0))
        {
            if($("a.tag > .count").length > 0)
            {
                $("a.tag > .count").each(function(){
                    $(this).append(`<div class="blockTagButton" alt="block-tag" title="` +
                                   ($(this).css("background-color") == "rgb(85, 0, 0)" ||
                                    $(this).css("background-color") == "rgb(85,0,0)" ||
                                    $(this).css("background-color") == "#500" ||
                                    $(this).css("background-color") == "#550000"
                                    ? `un` : ``)+`block tag">`+banIcon+`</div>`);
                });

                $(".blockTagButton").click(function(e){
                    e.preventDefault();
                    e.stopPropagation();
                    ToggleTagFromBlockArray($(this).parent().parent().attr("class").split("tag-")[1].split(" ")[0], $(this).parent().parent().find(".name").text().trim());
                });
            }
        }
    }
	//========================================================//



    //====================== FUNCTIONS =======================//
    function OnLoadCoverReplaceHQ() {
        //TODO: Throws errors all over the place... Seems to works for most images though. if it fails the original lower res image remains so failing is okay-ish
        $(this).off("load");
        if($(this).attr("src").startsWith("http"))
        {
            //retry loading image
            $(this).on("error", function(){
                //count reload attempts
                let attempts = parseInt($(this).attr("img-reloads"));
                if(!attempts)
                    attempts = 0;
                else if(attempts >= max_image_reload_attempts) //after x attempts, give up
                {
                    $(this).off("error");
                    console.log("gave up on: " + $(this).attr("src"));
                    return;
                }

                $(this).attr("src", $(this).attr("src")); //reload
                attempts++;
                $(this).attr("img-reloads", attempts);
                console.log("image reload attempt " + attempts + " for: " + $(this).attr("src"));
            });

            let newsrc = $(this).attr("data-src").replace(/\/\/t\d*?\./g, "//i.").replace("thumb.jpg", "1.jpg").replace("thumb.png", "1.png").replace("t.jpg", ".jpg").replace("t.png", ".png");
            $(this).attr("src", newsrc);
        }
    }

    function SubsPageLoadTagCountWithDelay(elem, delay)
    {
        setTimeout(() => {
            if(!elem.hasClass("count-fetch-in-progress") && !elem.hasClass("count-fetched"))
            {
                elem.addClass("count-fetch-in-progress");
                $.ajax({
                    url: elem.parent().prop("href"),
                    method: "GET"
                }).done(function(data){
                    let found = $(data).find("h1 .tag > .count").text();
                    if(found != null && found.length > 0)
                        elem.text(found);
                    else
                        console.log("failed finding tag from: " + elem.parent().prop("href"));

                    elem.addClass("count-fetched");
                }).fail(function(){
                    console.log("failed getting page: " + elem.parent().prop("href"));
                }).always(function(){ elem.removeClass("count-fetch-in-progress"); });
            }
        }, delay);
    }

    function SetReaderImageScale(scale)
    {
        $("section.reader-bar .zoom-level > .value").html(scale.toFixed(1));
        $("#image-container img").css("width", 1280 * scale);
        GM_setValue("zoom_level", scale);
    }

    function ToggleTagFromBlockArray(tag, tagname)
    {
        //get the array again to make sure we have an up to date array (since other tabs could have modified it since loading this page)
        BlockTagArrayString = GM_getValue("BlockTagArrayString", null);
        if(BlockTagArrayString) { BlockTagArray = JSON.parse(BlockTagArrayString); }

        //console.log("operating on: " + tag + " - " + tagname);
        let tagObj = [tag, tagname];
        let tagObjString = JSON.stringify(tagObj);

        if(!!BlockTagArrayString && BlockTagArrayString.indexOf(tagObjString) >= 0) //remove from blocked
        {
            //console.log(BlockTagArrayString);
            BlockTagArrayString = BlockTagArrayString.replace(tagObjString+",", "").replace(","+tagObjString, "").replace(tagObjString, "");
            //console.log(BlockTagArrayString);
            BlockTagArray = JSON.parse(BlockTagArrayString);

            if($("#settings-container").length !== 0) //if on settings page, remove the tag from the list when unblocking
                $("a.tag.tag-"+tag).remove();
            else
            {
                $("a.tag.tag-"+tag+" .blockTagButton").attr("title", "block tag");
                $("a.tag.tag-"+tag+" > .name").css("background-color", "#4d4d4d");
                $("a.tag.tag-"+tag+" > .count").css("background-color", "#333");
                $("a.tag.tag-"+tag).hover(function(){
                    $("a.tag.tag-"+tag+" > .name").css("background-color", "#595959");
                    $("a.tag.tag-"+tag+" > .count").css("background-color", "#404040");
                }, function(){
                    $("a.tag.tag-"+tag+" > .name").css("background-color", "#4d4d4d");
                    $("a.tag.tag-"+tag+" > .count").css("background-color", "#333");
                });
            }
        }
        else //add to blocked
        {
            BlockTagArray.push(tagObj);
            $("a.tag.tag-"+tag+" .blockTagButton").attr("title", "unblock tag");
            $("a.tag.tag-"+tag+" > .name, a.tag.tag-"+tag+" > .count").css("background-color", "#500");
            $("a.tag.tag-"+tag).off();
        }

        BlockTagArrayString = JSON.stringify(BlockTagArray); //covert array to string
        GM_setValue("BlockTagArrayString", BlockTagArrayString); //save string
    }

    function GroupAltVersionsOnPage()
    {
        let i = 0;
        let found = $(".container > .gallery");
        while(!!found && i < found.length)
        {
            AddAltVersionsToThisFromPage(found[i]);
            i++;
            found = $(".container > .gallery");
        }
    }

    function AddVersionGroupingButtonsToJQuerySelector(JQSelector) {
        JQSelector.append([
            "<div class='findVersionButton'>Find Alt Versions</div>",
            "<div class='numOfVersions'>1/1</div>",
            "<div class='versionNextButton'>►</div>",
            "<div class='versionPrevButton'>◄</div>"
        ]);
        $(JQSelector).find(".findVersionButton").click(AddAltVersionsToThis);
        $(JQSelector).find(".versionPrevButton").click(PrevAltVersion);
        $(JQSelector).find(".versionNextButton").click(NextAltVersion);
    }

    function AddAltVersionsToThisFromPage(target)
    {
        let place = $(target);
        place.addClass("ignoreThis");
        let title = place.find(".cover > .caption").text();
        if(!title || title.length <= 0)
            return;
        let found = $(".container > .gallery:not(.ignoreThis)");
        let numOfValid = 0;
        for(let i = 0; i < found.length; i++) //loop through galleries
        {
            let cap = $(found[i]).find(".caption");
            if(cap.length == 1) //if the gallery includes just one item
            {
                if(IncludesAll(cap.text(), title)) //valid target
                {
                    if(partially_fade_all_non_english)
                        $(found[i]).find(".cover > img, .cover > .caption").css("opacity", non_english_fade_opacity);

                    if($(found[i]).attr("data-tags").includes("12227")) //en
                    {
                        $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagEn+`">`);
                        $(found[i]).find(".cover > img, .cover > .caption").css("opacity", "1");
                    }
                    else
                    {
                        if($(found[i]).attr("data-tags").includes("6346")) //jp
                            $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagJp+`">`);
                        else if($(found[i]).attr("data-tags").includes("29963")) //ch
                            $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagCh+`">`);

                        if(!partially_fade_all_non_english)
                           $(found[i]).find(".cover > img, .cover > .caption").css("opacity", "1");
                    }

                    if(mark_as_read_system_enabled) {
                        let MARArraySelector = MARArray.join("'], .cover[href='");
                        $(found[i]).find(".cover[href='" + MARArraySelector + "']").append("<div class='readTag'>READ</div>");
                        let readTag = $(found[i]).find(".readTag");
                        if(!!readTag && readTag.length > 0)
                            readTag.parent().parent().find(".cover > img, .cover > .caption").css("opacity", marked_as_read_fade_opacity);
                    }

                    place.append($(found[i]).find(".cover"));
                    $(found[i]).addClass("deleteThis");
                    numOfValid++;
                }
            }
            else //the gallery incvludes multiple items
            {
                let addThese = false;
                for(let j = 0; j < cap.length; j++) //loop through items in the gallery
                {
                    if(IncludesAll($(cap[j]).text(), title))
                    {
                        addThese = true; //if any of them match
                        break;
                    }
                }

                if(addThese) //if any matched
                {
                    for(let j = 0; j < cap.length; j++)
                        place.append($(cap[j]).parent()); //add all
                    $(found[i]).addClass("deleteThis");
                    numOfValid += cap.length;
                }
            }
        }
        numOfValid++;
        place.removeClass("deleteThis");
        place.removeClass("ignoreThis");
        $(".deleteThis").remove();
        if(numOfValid > 1)
        {
            place.find(".cover:not(:first)").css("display", "none");
            place.find(".versionPrevButton, .versionNextButton, .numOfVersions").show(200);
            place.find(".numOfVersions").text("1/" + numOfValid);
            //place.find(".findVersionButton").hide();
        }
    }

    function NextAltVersion(e) {SwitchAltVersion(e, this, true)}
    function PrevAltVersion(e) {SwitchAltVersion(e, this, false)}
    function SwitchAltVersion(ev, htmlEl, next) {
        ev.preventDefault();
        let toHide = $(htmlEl).parent().find(".cover").filter(":visible");
        let toShow = next ? toHide.next() : toHide.prev();
        if(!toShow || toShow.length <= 0)
            return;
        if(!toShow.is(".cover"))
            toShow = next ? toHide.nextUntil(".cover", ":last").next() : toHide.prevUntil(".cover", ":last").prev();
        if(!toShow || toShow.length <= 0)
            return;
        toHide.hide(100);
        toShow.show(100);
        let n = $(htmlEl).parent().find(".numOfVersions");
        n.text( (Number(n.text().split("/")[0])+(next ? 1 : -1)) + "/" + n.text().split("/")[1] );
    }

    function IncludesAll(string, search)
    {
        string = CleanupSearchString(string);
        search = CleanupSearchString(search);
        if(string.length == 0 || search.length == 0)
            return false;

        let searches = search.split(" ");
        //console.log(string + " ::: includes all::: " + searches);
        for(let i = 0; i < searches.length; i++)
            if(!!searches[i] && searches[i].length > 0 && !string.includes(searches[i]))
                return false
        //console.log(yes);
        return true;
    }

    function AddAltVersionsToThis(e)
    {
        e.preventDefault();
        let place = $(this);
        let title = place.parent().find(".cover:visible > .caption").text();
        $.get(BuildUrl(title), function(data){
            let found = $(data).find(".container > .gallery");
            if(!found || found.length <= 0)
            {
				alert("error reading data");
				return;
            }
            place.parent().find(".cover").remove();
            try
            {
                for(let i = 0; i < found.length; i++)
                {
                    if(partially_fade_all_non_english)
                            $(found[i]).find(".cover > img, .cover > .caption").css("opacity", non_english_fade_opacity);

                    if($(found[i]).attr("data-tags").includes("12227")) //en
                    {
                        $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagEn+`">`);
                        $(found[i]).find(".cover > img, .cover > .caption").css("opacity", "1");
                    }
                    else
                    {
                        if($(found[i]).attr("data-tags").includes("6346")) //jp
                            $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagJp+`">`);
                        else if($(found[i]).attr("data-tags").includes("29963")) //ch
                            $(found[i]).find(".caption").append(`<img class="overlayFlag" src="`+flagCh+`">`);

                        if(!partially_fade_all_non_english)
                           $(found[i]).find(".cover > img, .cover > .caption").css("opacity", "1");
                    }

                    if(mark_as_read_system_enabled) {
                        let MARArraySelector = MARArray.join("'], .cover[href='");
                        $(found[i]).find(".cover[href='" + MARArraySelector + "']").append("<div class='readTag'>READ</div>");
                        let readTag = $(found[i]).find(".readTag");
                        if(!!readTag && readTag.length > 0)
                            readTag.parent().parent().find(".cover > img, .cover > .caption").css("opacity", marked_as_read_fade_opacity);
                    }

                    let thumbnailReplacement;
                    if(!!$(found[i]).find(".cover > img").attr("data-src"))
                        thumbnailReplacement = $(found[i]).find(".cover > img").attr("data-src").replace(/\/\/.+?\.nhentai/g, "//i.nhentai").replace("thumb.jpg", "1.jpg").replace("thumb.png", "1.png");
                    else
                        thumbnailReplacement = $(found[i]).find(".cover > img").attr("src").replace(/\/\/.+?\.nhentai/g, "//i.nhentai").replace("thumb.jpg", "1.jpg").replace("thumb.png", "1.png");

                    $(found[i]).find(".cover > img").attr("src", thumbnailReplacement);
                    place.parent().append($(found[i]).find(".cover"));
                }
            }
            catch(er)
            {
                alert("error modifying data: " + er);
                return;
            }
            place.parent().find(".cover:not(:first)").css("display", "none");
            place.parent().find(".versionPrevButton, .versionNextButton, .numOfVersions").show(200);
            place.parent().find(".numOfVersions").text("1/" + (found.length));
            place.hide(200);
        }).fail(function(e){
            alert("error getting data: " + e);
        });
    }

    function CleanupSearchString(title)
    {
        title = title.replace(/\[.*?\]/g, "");
        title = title.replace(/\【.*?\】/g, "");
        if(version_grouping_filter_brackets)
            title = title.replace(/\(.*?\)/g, "");
        return title.trim();
    }

    function BuildUrl(title)
    {
        let url = CleanupSearchString(title);

		url = url.trim();
		url = url.replace(/(^|\s){1}[^\w\s\d]{1}(\s|$){1}/g, " "); //remove all instances of a lone symbol character
		url = url.replace(/\s+/g, '" "'); //wrap all terms with ""
		url = '"' + url + '"';

        url = encodeURIComponent(url);
        //alert(url);
        url = "https://nhentai.net/search/?q=" + url;
        return url;
    }

	function InitialValuesForSettings() {
		$("#remove_non_english").prop("checked", remove_non_english);
		$("#partially_fade_all_non_english").prop("checked", partially_fade_all_non_english);
		$("#non_english_fade_opacity").val(non_english_fade_opacity);
		$("#browse_thumbnail_width").val(browse_thumbnail_width);
		$("#browse_thumnail_container_width").val(browse_thumnail_container_width);
		$("#load_high_quality_browse_thumbnails").prop("checked", load_high_quality_browse_thumbnails);
		$("#pages_thumbnail_width").val(pages_thumbnail_width);
		$("#pages_thumnail_container_width").val(pages_thumnail_container_width);
		$("#load_high_quality_pages_thumbnails").prop("checked", load_high_quality_pages_thumbnails);
		$("#mark_as_read_system_enabled").prop("checked", mark_as_read_system_enabled);
		$("#marked_as_read_fade_opacity").val(marked_as_read_fade_opacity);
		$("#read_tag_font_size").val(read_tag_font_size);
		$("#subscription_system_enabled").prop("checked", subscription_system_enabled);
        $("#version_grouping_enabled").prop("checked", version_grouping_enabled);
        $("#version_grouping_filter_brackets").prop("checked", version_grouping_filter_brackets);
        $("#auto_group_on_page_comics").prop("checked", auto_group_on_page_comics);
        $("#tag_blocking_enabled").prop("checked", tag_blocking_enabled);
        $("#tag_blocking_fade_only").prop("checked", tag_blocking_fade_only);
        $("#comic_reader_improved_zoom").prop("checked", comic_reader_improved_zoom);
        $("#remember_zoom_level").prop("checked", remember_zoom_level);

        DisableEnableSettingsByValue();
	}

	function UpdateSettingsValues() {
		remove_non_english = $("#remove_non_english").is(':checked');
		partially_fade_all_non_english = $("#partially_fade_all_non_english").is(':checked');
		non_english_fade_opacity = $("#non_english_fade_opacity").val();
		browse_thumbnail_width = $("#browse_thumbnail_width").val();
		browse_thumnail_container_width = $("#browse_thumnail_container_width").val();
		load_high_quality_browse_thumbnails = $("#load_high_quality_browse_thumbnails").is(':checked');
		pages_thumbnail_width = $("#pages_thumbnail_width").val();
		pages_thumnail_container_width = $("#pages_thumnail_container_width").val();
		load_high_quality_pages_thumbnails = $("#load_high_quality_pages_thumbnails").is(':checked');
		mark_as_read_system_enabled = $("#mark_as_read_system_enabled").is(':checked');
		marked_as_read_fade_opacity = $("#marked_as_read_fade_opacity").val();
		read_tag_font_size = $("#read_tag_font_size").val();
		subscription_system_enabled = $("#subscription_system_enabled").is(':checked');
        version_grouping_enabled = $("#version_grouping_enabled").is(':checked');
        version_grouping_filter_brackets = $("#version_grouping_filter_brackets").is(':checked');
        auto_group_on_page_comics = $("#auto_group_on_page_comics").is(':checked');
        tag_blocking_enabled = $("#tag_blocking_enabled").is(':checked');
        tag_blocking_fade_only = $("#tag_blocking_fade_only").is(':checked');
        comic_reader_improved_zoom = $("#comic_reader_improved_zoom").is(':checked');
        remember_zoom_level = $("#remember_zoom_level").is(':checked');

		GM_setValue("remove_non_english", remove_non_english);
		GM_setValue("partially_fade_all_non_english", partially_fade_all_non_english);
		GM_setValue("non_english_fade_opacity", non_english_fade_opacity);
		GM_setValue("browse_thumbnail_width", browse_thumbnail_width);
		GM_setValue("browse_thumnail_container_width", browse_thumnail_container_width);
		GM_setValue("load_high_quality_browse_thumbnails", load_high_quality_browse_thumbnails);
		GM_setValue("pages_thumbnail_width", pages_thumbnail_width);
		GM_setValue("pages_thumnail_container_width", pages_thumnail_container_width);
		GM_setValue("load_high_quality_pages_thumbnails", load_high_quality_pages_thumbnails);
		GM_setValue("mark_as_read_system_enabled", mark_as_read_system_enabled);
		GM_setValue("marked_as_read_fade_opacity", marked_as_read_fade_opacity);
		GM_setValue("read_tag_font_size", read_tag_font_size);
		GM_setValue("subscription_system_enabled", subscription_system_enabled);
        GM_setValue("version_grouping_enabled", version_grouping_enabled);
        GM_setValue("version_grouping_filter_brackets", version_grouping_filter_brackets);
        GM_setValue("auto_group_on_page_comics", auto_group_on_page_comics);
        GM_setValue("tag_blocking_enabled", tag_blocking_enabled);
        GM_setValue("tag_blocking_fade_only", tag_blocking_fade_only);
        GM_setValue("comic_reader_improved_zoom", comic_reader_improved_zoom);
        GM_setValue("remember_zoom_level", remember_zoom_level);

		$("#settings-saved-mark").fadeIn(500, function() {
			setTimeout(function() {
				$("#settings-saved-mark").fadeOut(500);
			}, 1000);
		});

        DisableEnableSettingsByValue();
	}

    function DisableEnableSettingsByValue()
    {
        if(remove_non_english) {
			$("#partially_fade_all_non_english").prop("disabled", true);
			$("#non_english_fade_opacity").prop("disabled", true);
			$("#partially_fade_all_non_english").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
			$("#non_english_fade_opacity").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
		}
		else {
			$("#partially_fade_all_non_english").prop("disabled", false);
			$("#non_english_fade_opacity").prop("disabled", false);
			$("#partially_fade_all_non_english").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
			$("#non_english_fade_opacity").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
            $("#auto_group_on_page_comics").prop("disabled", false);
			$("#auto_group_on_page_comics").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");

			if(!partially_fade_all_non_english) {
				$("#non_english_fade_opacity").prop("disabled", true);
				$("#non_english_fade_opacity").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
			}
			else {
				$("#non_english_fade_opacity").prop("disabled", false);
				$("#non_english_fade_opacity").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
			}
		}

		if(mark_as_read_system_enabled) {
			$("#marked_as_read_fade_opacity, #read_tag_font_size").prop("disabled", false);
			$("#marked_as_read_fade_opacity, #read_tag_font_size").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
		}
		else {
			$("#marked_as_read_fade_opacity, #read_tag_font_size").prop("disabled", true);
			$("#marked_as_read_fade_opacity, #read_tag_font_size").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
		}

        if(version_grouping_enabled) {
			$("#version_grouping_filter_brackets").prop("disabled", false);
			$("#version_grouping_filter_brackets").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");

            if(remove_non_english)
            {
                $("#auto_group_on_page_comics").prop("disabled", true);
                $("#auto_group_on_page_comics").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
            }
            else
            {
                $("#auto_group_on_page_comics").prop("disabled", false);
                $("#auto_group_on_page_comics").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
            }
		}
		else {
			$("#version_grouping_filter_brackets").prop("disabled", true);
			$("#version_grouping_filter_brackets").parentsUntil(".custom-settings").parent().addClass("disabled-setting");

            $("#auto_group_on_page_comics").prop("disabled", true);
			$("#auto_group_on_page_comics").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
		}

        if(tag_blocking_enabled)
        {
            $("#tag_blocking_enabled").parent().parent().parent().next().show();
            $("#tag_blocking_enabled").parent().parent().parent().next().next().show();
            $("#tag_blocking_enabled").parent().parent().parent().next().next().next().show();
        }
        else
        {
            $("#tag_blocking_enabled").parent().parent().parent().next().hide();
            $("#tag_blocking_enabled").parent().parent().parent().next().next().hide();
            $("#tag_blocking_enabled").parent().parent().parent().next().next().next().hide();
        }

        if(comic_reader_improved_zoom)
        {
            $("#remember_zoom_level").prop("disabled", false);
            $("#remember_zoom_level").parentsUntil(".custom-settings").parent().removeClass("disabled-setting");
        }
        else
        {
            $("#remember_zoom_level").prop("disabled", true);
            $("#remember_zoom_level").parentsUntil(".custom-settings").parent().addClass("disabled-setting");
        }
    }

	function AddSubClickListeners() {
		$("#subTo").click(function(){

			//get the array again to make sure we have an up to date array (since other tabs could have modified it since loading this page)
			SubArrayString = GM_getValue("SubArrayString", null);
			if(SubArrayString) { SubArray = JSON.parse(SubArrayString); }

			SubArray.push(subItem); //add to array
			SubArrayString = JSON.stringify(SubArray); //convert array to string
			GM_setValue("SubArrayString", SubArrayString); //save string
			$(this).html('<span style="vertical-align: middle;">Unsubscribe</span>').prop("id", "unsubTo");
			$(this).off();
			AddSubClickListeners();
		});
		$("#unsubTo").click(function(){

			//get the array again to make sure we have an up to date array (since other tabs could have modified it since loading this page)
			SubArrayString = GM_getValue("SubArrayString", null);
			if(SubArrayString) { SubArray = JSON.parse(SubArrayString); }

			//do it mutiple times if needed (due to multiple tab fuckery)
			while(SubArray.indexOf(subItem) >= 0)
				SubArray.splice(SubArray.indexOf(subItem), 1); //remove from array

			SubArrayString = JSON.stringify(SubArray); //convert array to string
			GM_setValue("SubArrayString", SubArrayString); //save string
			$(this).html('<span style="vertical-align: middle;">Subscribe</span>').prop("id", "subTo");
			$(this).off();
			AddSubClickListeners();
		});
	}

	function AddMARClickListeners() {
		$("#markAsRead").click(function(){

			//get the array again to make sure we have an up to date array (since other tabs could have modified it since loading this page)
			MARArrayString = GM_getValue("MARArrayString", null);
			if(MARArrayString) { MARArray = JSON.parse(MARArrayString); }

			MARArray.push(item); //add to array
			MARArrayString = JSON.stringify(MARArray); //covert array to string
			GM_setValue("MARArrayString", MARArrayString); //save string
			$(this).html(unreadImg+' <span style="vertical-align: middle;">Mark as unread</span>').prop("id", "markAsUnRead");
			$(this).off();
			AddMARClickListeners();
		});

		$("#markAsUnRead").click(function(){

			//get the array again to make sure we have an up to date array (since other tabs could have modified it since loading this page)
			MARArrayString = GM_getValue("MARArrayString", null);
			if(MARArrayString) { MARArray = JSON.parse(MARArrayString); }

			//do it mutiple times if needed (due to multiple tab fuckery)
			while(MARArray.indexOf(item) >= 0)
				MARArray.splice(MARArray.indexOf(item), 1); //remove from array

			MARArrayString = JSON.stringify(MARArray); //covert array to string
			GM_setValue("MARArrayString", MARArrayString); //save string
			$(this).html(readImg+' <span style="vertical-align: middle;">Mark as read</span>').prop("id", "markAsRead");
			$(this).off();
			AddMARClickListeners();
		});
	}

    function SaveToFile(filename, data) {
        var blob = new Blob([data], {type: 'text/plain'});
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        }
        else{
            var elem = window.document.createElement('a');
            elem.href = window.URL.createObjectURL(blob);
            elem.download = filename;
            document.body.appendChild(elem);
            elem.click();
            document.body.removeChild(elem);
        }
    }
    //========================================================//
})();