// ==UserScript==
// @name NHentai Improved
// @namespace Hentiedup
// @version 1.10.1
// @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 = GM_getValue("infinite_load", true);
//== 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; }
}
`);
}
if(infinite_load) {
GM_addStyle(`
#NHI_loader_icon {
height: 355px;
line-height: 355px;
}
#NHI_loader_icon > div {
display: inline-flex;
}
.loader {
color: #ed2553;
font-size: 10px;
width: 1em;
height: 1em;
border-radius: 50%;
position: relative;
text-indent: -9999em;
animation: mulShdSpin 1.3s infinite linear;
transform: translateZ(0);
}
@keyframes mulShdSpin {
0%,
100% {
box-shadow: 0 -3em 0 0.2em,
2em -2em 0 0em, 3em 0 0 -1em,
2em 2em 0 -1em, 0 3em 0 -1em,
-2em 2em 0 -1em, -3em 0 0 -1em,
-2em -2em 0 0;
}
12.5% {
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em,
3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em,
-2em 2em 0 -1em, -3em 0 0 -1em,
-2em -2em 0 -1em;
}
25% {
box-shadow: 0 -3em 0 -0.5em,
2em -2em 0 0, 3em 0 0 0.2em,
2em 2em 0 0, 0 3em 0 -1em,
-2em 2em 0 -1em, -3em 0 0 -1em,
-2em -2em 0 -1em;
}
37.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em,
-2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
50% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em,
-2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
62.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0,
-2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
}
75% {
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em,
3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,
-2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
}
87.5% {
box-shadow: 0em -3em 0 0, 2em -2em 0 -1em,
3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,
-2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
}
}
`);
}
}
//========================================================//
//================== 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 ===//
/*TODO:
- Handle auto version grouping... Sometimes there are comics that are named something overly simple that causes tons of others to get grouped with it erroneously. Infinite load would make this issue way worse... How to handle this...
- Handle Favorites page -> infinite load disabled there for now
*/
if(infinite_load) {
//if found paginator on page (also, specifically not enabled on favorites page for now)
let paginator = $(".pagination");
if(paginator?.length && window.location.pathname != "/favorites/") {
//get pageNum
const startingPageNum = parseInt(paginator.find(".page.current").attr("href").split("page=")[1]);
let currentPageNum = startingPageNum;
const lastPage = parseInt(paginator.find(".last").attr("href").split("page=")[1]);
//build the fetch url without the page number
const queryWithNoPage = window.location.search.replace(/[\?\&]page=\d+/, "").replace(/^\&/, "?");
const finalUrlWithoutPageNum = window.location.pathname + queryWithNoPage + (queryWithNoPage.length ? "&" : "?") + "page=";
//setup some tracker varaibles
let isLoadingNextPage = false;
let retryCount = 0;
const giveUpAfterTries = 5;
//on scroll event,
$(window).scroll(function() {
//if we are near page bottom,
if($(window).scrollTop() + $(window).height() >= $(document).height() - 15) {
//aren't already loading, and aren't loading past the last page
if(!isLoadingNextPage && (currentPageNum + 1) <= lastPage) {
//Next page loader function (called in place and from within itself to retry load if needed)
(function LoadInNextPageComics() {
console.log("NHI: starting load");
isLoadingNextPage = true;
//add loader icon visual
$(".index-container:not(.advertisement, .index-popular)").first().append('<div id="NHI_loader_icon" class="gallery"><div><span class="loader"></span></div></div>');
$.get(finalUrlWithoutPageNum + (currentPageNum + 1), 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));
//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 show the user all the pages currently loaded
let paginatorItem = $(".pagination > .page[href$='page="+(currentPageNum + 1)+"']");
if(paginatorItem?.length)
paginatorItem.addClass("current");
else
$(".pagination > .next").before('<a href="'+finalUrlWithoutPageNum+(currentPageNum + 1)+'" class="page current">'+(currentPageNum + 1)+'</a>');
//reset values to allow load of next page and increment currentPageNum
retryCount = 0;
currentPageNum++;
isLoadingNextPage = false;
$("#NHI_loader_icon").remove();
}).fail(function(jqXHR, textStatus, errorThrown) {
if(retryCount < giveUpAfterTries) {
console.log("NHI: Infinite load - Failed loading page " + (currentPageNum + 1) + " - " + textStatus + " | " + errorThrown + " - retrying... (retry attempt "+(++retryCount)+")");
LoadInNextPageComics();
}
else {
$("#NHI_loader_icon").remove();
console.log("NHI: Infinite load - Failed loading page " + (currentPageNum + 1) + " - " + textStatus + " | " + errorThrown + " - Giving up.");
retryCount = 0;
isLoadingNextPage = false; //this lets user try again by simply moving the scroll to a triggering position again...
}
});
})();
}
}
});
}
}
//===========================//
}
//==========================================================================//
//====================== 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"><div class="form-control">
<label><input id="infinite_load" type="checkbox">
Dynamically load more comics as you scroll</label>
</div></div>
<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" or "Dynamically load more comics as you scroll" <a href="#" style="text-decoration: underline; color: #ed2553; " onclick="alert('This option only groups the appropiate comics from those loaded initially, but NOT those loaded in dynamically afterwards.'); return false;">?</a>)</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");
}
if(dataArr.length > 25)
{
GM_setValue("infinite_load", (String(dataArr[25]) == "true"));
console.log("NHI - infinite_load 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 + "|||||" +
infinite_load;
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();
//replace all instances of one or more consecutive symbol charactes padded by either whitespace or string start/end with a single space (except kanji)
url = url.replace(/(^|\s){1}([^\w\s\d\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\uFF00-\uFFEF\u4E00-\u9FAF\u2605-\u2606\u2190-\u2195\u203B]|\_)+?(\s|$){1}/g, " ");
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);
$("#infinite_load").prop("checked", infinite_load);
$("#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');
infinite_load = $("#infinite_load").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("infinite_load", infinite_load);
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);
}
}
//========================================================//
})();