NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Light Novel Loader // @namespace https://openuserjs.org/users/XDHx86/scripts // @version 4.3 // @description BEST novel loader for your favorite Light Novel site! Works on Android & IOS!! Supports: (www.lightnovelworld.com, www.readlightnovel.me, www.readwn.com, www.wuxiax.com, www.lnreader.org, novelonlinefull.com, www.novels.pl, novelfull.com, boxnovel.com, bestlightnovel.com) // @author XDHx86 // @icon https://i.imgur.com/HfGcZ5V.png // @updateURL https://openuserjs.org/meta/XDHx86/Light_Novel_Loader.meta.js // @downloadURL https://openuserjs.org/install/XDHx86/Light_Novel_Loader.user.js // @copyright 2020, XDHx86 (https://openuserjs.org/users/XDHx86) // @license MIT // @match http*://*/* // @connect fonts.gstatic.com // @connect fonts.googleapis.com // @connect www.lightnovelworld.com // @connect static.lightnovelworld.com // @connect avatar.novelonlinefree.com // @connect www.readlightnovel.me // @connect www.wuxiax.com // @connect www.lnreader.org // @connect lnreader.org // @connect www.novels.pl // @connect readlightnovel.me // @connect www.novelhall.com // @connect www.readwn.com // @connect novelonlinefull.com // @connect novels.pl // @connect novelfull.com // @connect boxnovel.com // @connect bestlightnovel.com // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.9.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_notification // @grant GM_listValues // @noframes // ==/UserScript== (function() { 'use strict'; { const version = GM_getValue('scriptversion', ''); if (!version || version != GM_info.script.version) { GM_setValue('scriptversion', GM_info.script.version); window.open('https://openuserjs.org/scripts/XDHx86/Light_Novel_Loader#changelog', '_blank'); } } const SITES = { 'www.lightnovelworld.com': { novel: '.titles a', chaptertitle: '.chapter-title', chapter: '.chapter-content', next: '.chnav.next', prev: '.chnav.prev', title: '.titles', annon: [0, ['div', 'script', 'p[class]', 'ins', 'button', 'sub', 'input']], namer: ['\n', ':'], name: [' - ', ''], othert: '', favobj: { noveltitle: '.novel-title.text2row', link: '/chapters', lastc: '.container p a', status: '' }, indexobj: { max: '.PagedList-skipToLast a', nav: '.pagination a', list: '.chapter-list', page: '/page-1', chapters: '.chapter-list a', }, search: { input: '#inputContent', link: 'https://www.lightnovelworld.com/search' } }, 'readlightnovel.me': { novel: '.black-link', chaptertitle: '.block-title h1', chapter: '.desc', next: '.next.next-link', prev: '.prev.prev-link', title: '.block-title h1', annon: [0, ['span', 'div', 'hr', 'small', 'a', 'script']], namer: '', name: '', othert: '', favobj: { noveltitle: '.block-title h1', link: '', lastc: '', status: '' }, indexobj: { max: '', nav: '', list: '.tab-content', page: '', chapters: '.tab-content a', }, search: { input: '.form-control.search-form', link: 'https://www.readlightnovel.me/' } }, 'www.readlightnovel.me': { novel: '.black-link', chaptertitle: '.block-title h1', chapter: '.desc', next: '.next.next-link', prev: '.prev.prev-link', title: '.block-title h1', annon: [0, ['span', 'div', 'hr', 'small', 'a', 'script']], namer: '', name: '', othert: '', favobj: { noveltitle: '.block-title h1', link: '', lastc: '', status: '' }, indexobj: { max: '', nav: '', list: '.tab-content', page: '', chapters: '.tab-content a', }, search: { input: '.form-control.search-form', link: 'https://www.readlightnovel.me/' } }, 'www.novelhall.com': { novel: '#bookname', chaptertitle: '.single-header h1', chapter: '#htmlContent', next: '.nav-single a:nth-of-type(3)', prev: '.nav-single a', title: '.single-header h1', annon: [0, ['div']], namer: '', name: '', othert: '', favobj: { noveltitle: '.book-info h1', link: '', lastc: '.book-catalog.inner.mt20 a', status: 'span:nth-of-type(2)' }, indexobj: { max: '', nav: '', list: '#morelist', page: '', chapters: '#morelist a', }, search: { input: '', link: 'https://www.novelhall.com/index.php?s=so&module=book&keyword=${term}' } }, 'novelonlinefull.com': { novel: '.lem_bem_top a', chaptertitle: '.name_chapter', chapter: '.vung_doc', next: '.LN_nextchbtn', prev: '.LN_prevchbtn', title: '.name_chapter', annon: [0, ['div']], namer: '', name: '', othert: '', favobj: { noveltitle: '.truyen_info_right h1', link: '', lastc: '.chapter-list a', status: '.truyen_info_right li:nth-of-type(4) a' }, indexobj: { max: '', nav: '', list: '.chapter-list', page: '', chapters: '.chapter-list a', }, search: { input: '', link: 'https://novelonlinefull.com/search_novels/${term}' } }, 'www.novels.pl': { novel: '.panel-title.pull-left a', chaptertitle: '', chapter: '.panel-body.article', next: '.next a', prev: '.previous a', title: '.panel-title.pull-left', annon: [0, ['a', 'div']], namer: '', name: '', othert: '', favobj: { noveltitle: '.panel-title.pull-left', link: '', lastc: '#chapters a', status: '' }, indexobj: { max: '', nav: '', list: '', page: '', chapters: '' }, search: { input: '', link: 'https://www.novels.pl/?search=${term}' } }, 'novels.pl': { novel: '.panel-title.pull-left a', chaptertitle: '', chapter: '.panel-body.article', next: '.next a', prev: '.previous a', title: '.panel-title.pull-left', annon: [0, ['a', 'div']], namer: '', name: '', othert: '', favobj: { noveltitle: '.panel-title.pull-left', link: '', lastc: '#chapters a', status: '' }, indexobj: { max: '', nav: '', list: '', page: '', chapters: '' }, search: { input: '', link: 'https://www.novels.pl/?search=${term}' } }, 'novelfull.com': { novel: '.truyen-title', chaptertitle: '.chapter-text', chapter: '#chapter-content', next: '#next_chap', prev: '#prev_chap', title: '.chapter-text', annon: [0, ['div', 'script', 'ins', 'hr', 'h2', 'ol']], namer: '', name: '', othert: '', favobj: { noveltitle: '.title', link: '', lastc: '.l-chapters a', status: '.info div:nth-of-type(5) a' }, indexobj: { max: '.pagination:nth-of-type(1) .last a', nav: '.pagination:nth-of-type(1) a', list: '.list-chapter', page: '?page=1', chapters: '.list-chapter a' }, search: { input: '', link: 'https://novelfull.com/search?keyword=${term}' } }, 'boxnovel.com': { novel: '.breadcrumb li:nth-of-type(2) a', chaptertitle: '.breadcrumb .active', chapter: '.text-left', next: '.next_page.btn', prev: '.prev_page.btn', title: '.breadcrumb .active', annon: [0, ['div', 'script', 'p[class]', 'ins', 'button', 'sub', 'input']], namer: '', name: '', othert: '', favobj: { noveltitle: '.post-title h1', link: '', lastc: '.wp-manga-chapter a', status: '.post-status .summary-content' }, indexobj: { max: '', nav: '', list: '.main.version-chap', page: '', chapters: '.main.version-chap a', }, search: { input: '', link: 'https://boxnovel.com/?s=${term}&post_type=wp-manga' } }, 'bestlightnovel.com': { novel: '.lem_bem_top a', chaptertitle: '.name_chapter', chapter: '.vung_doc', next: '.LN_nextchbtn', prev: '.LN_prevchbtn', title: '.name_chapter', annon: [0, ['div']], namer: '', name: '', othert: '', favobj: { noveltitle: '.truyen_info_right h1', link: '', lastc: '.chapter-list a', status: '.truyen_info_right li:nth-of-type(4) a' }, indexobj: { max: '', nav: '', list: '.chapter-list', page: '', chapters: '.chapter-list a', }, search: { input: '', link: 'https://bestlightnovel.com/search_novels/${term}' } }, 'www.wuxiax.com': { novel: '.titles a', chaptertitle: '.titles h2', chapter: '.chapter-content', next: '.chnav.next', prev: '.chnav.prev', title: '.titles', annon: [0, ['div', 'script', 'p[class]', 'ins', 'button', 'sub']], namer: ['\n', ':'], name: [' - ', ''], othert: '', search: '', favobj: { noveltitle: '.novel-title', link: '', lastc: '.intro a', status: '.header-stats strong[class]' }, indexobj: { max: '', nav: '', list: '', page: '', chapters: '' }, search: { input: '', link: '' } }, 'lnreader.org': { novel: '.section-header-title a', chaptertitle: '.section-header-title span', chapter: '#chapterText', next: '.cm-button:nth-of-type(2)', prev: '.cm-button:nth-of-type(1)', title: '.section-header-title', annon: [0, ['div', 'script', 'p[class]', 'ins', 'button', 'sub', 'center']], namer: ['\n', ':'], name: [' - ', ''], othert: '', search: '', favobj: { noveltitle: '.novel-title', link: '', lastc: '.novels-detail-chapters a', status: 'li:nth-of-type(2) .novels-detail-right-in-right' }, indexobj: { max: '', nav: '', list: '', page: '', chapters: '.novels-detail-chapters a' }, search: { input: '.search-boxx-input', link: 'http://lnreader.org/' } }, 'www.readwn.com': { novel: '.titles a', chaptertitle: '.titles h2', chapter: '.chapter-content', next: '.chnav.next', prev: '.chnav.prev', title: '.titles', annon: [0, ['div', 'script', 'p[class]', 'ins', 'button', 'sub']], namer: ['\n', ':'], name: [' - ', ''], othert: '', search: '', favobj: { noveltitle: '.novel-title', link: '', lastc: '.intro a', status: '.header-stats span:nth-of-type(2)' }, indexobj: { max: '', nav: '', list: '', page: '', chapters: '.chapter-list a', }, search: { input: '', link: '' } }, }; Object.defineProperty(Object.prototype, 'LN_search', { value: function(value, options) { let output = { found: false }, altv, checkit = (inp, opt) => { let output = false; if (opt) { if (opt instanceof RegExp && opt.test(inp)) output = true; else if (typeof opt == 'string' && inp && inp.includes && inp.includes(value)) output = true; } else if (inp == value) output = true; return output; }; if (Array.isArray(this)) { for (let i = 0; i < this.length; i++) { if (typeof this[i] == 'object') { let obj = this[i]; for (let w in obj) { if (checkit(obj[w], options)) { output = { found: true, obj: obj, child: w, index: i, value: obj[w] }; break; } } if (output.found) break; } else if (Array.isArray(this[i])) { let arr = this[i]; for (let j = 0; j < arr.length; j++) { if (checkit(arr[j], options)) { output = { found: true, array: arr, index: j, parentindex: i, value: arr[j] }; break; } } if (output.found) break; } else if (checkit(this[i], options)) { output = { found: true, array: this, index: i, value: this[i], obj: this }; break; } } } else { for (let e in this) { if (typeof this[e] == 'object') { let obj = this[e]; for (let w in obj) { if (checkit(obj[w], options)) { output = { found: true, obj: obj, sub: w, child: e, value: obj[w]}; break; } } if (output.found) break; } else if (Array.isArray(this[e])) { let arr = this[e]; for (let i = 0; i < arr.length; i++) { if (checkit(arr[i])) { output = { found: true, array: arr, index: i, child: e, value: arr[i] }; break; } } if (output.found) break; } else if (checkit(this[e], options)) { output = { found: true, obj: this, child: e, value: this[e] }; break; } } } return output; }, enumerable: false }); Object.defineProperty(Object.prototype, 'LN_deepSearch', { value: function(value) { let output = { found: false }; if (Array.isArray(this)) { for (let i = 0; i < this.length; i++) { if (this[i] == value) { output = { found: true, array: this, index: i }; break; } else if (typeof this[i] == 'object' || Array.isArray(this[i])) { let search = this[i].LN_deepSearch(value); if (search.found) { output = search; output.parentIndex = i; break; } } } } else if (typeof this == 'object') { for (let e in this) { if (this[e] == value) { output = { found: true, obj: this, child: e }; break; } else if (typeof this[e] == 'object' || Array.isArray(this[e])) { let search = this[e].LN_deepSearch(value); if (search.found) { output = search; output.parentObj = e; break; } } } } return output; }, enumerable: false }); Object.defineProperty(Object.prototype, 'LN_hasClass', { value: function(classes) { let output = false; if (!this.classList) return output; if (!Array.isArray(classes)) classes = [classes]; for (let i = 0; i < classes.length; i++) if (this.classList.contains(classes[i])) output = true; return output; }, enumerable: false }); Object.defineProperty(Object.prototype, 'LN_index', { value: function() { let el = this, i = 0; do { i++; if (i > 12) break; } while (el = el.previousElementSibling); return i - 1; }, enumerable: false }); Object.defineProperty(Object.prototype, 'getType', { value: function() { if (this.search('jpeg') > 0) return 'jpeg'; if (this.search('jpg') > 0) return 'jpeg'; if (this.search('png') > 0) return 'png'; if (this.search('webp') > 0) return 'webp'; }, enumerable: false }); Object.defineProperty(Object.prototype, 'replacer', { value: function() { return this.replace(/’/g, "'").replace(':', ' -').normalize('NFD').replace(/([\u0300-\u036f]|[^0-9a-zA-Z ()\-_!'])/g, '').replace(/[^\x00-\x7F]/g, ''); }, enumerable: false }); String.prototype.LN_platform = function() { if (this.includes('lightnovelworld')) return 'Light Novel World'; else if (this.includes('readlightnovel.me')) return 'Read Light Novel'; else if (this.includes('readwn')) return 'Read WN'; else if (this.includes('www.wuxiax.com')) return 'Wuxia X'; else if (this.includes('lnreader.org')) return 'Light Novel Reader'; else if (this.includes('novelonlinefull')) return 'Novel Online Full'; else if (this.includes('bestlightnovel')) return 'Best Light Novel'; else if (this.includes('novels.pl')) return 'Novels PL'; else if (this.includes('novelfull')) return 'Novel Full'; else if (this.includes('boxnovel')) return 'Box Novel'; else if (this.includes('novelhall')) return 'Novel Hall'; } String.prototype.LN_host = function() { if (this.includes('lightnovelworld')) return 'www.lightnovelworld.com'; else if (this.includes('www.readlightnovel.me')) return 'www.readlightnovel.me'; else if (this.includes('readlightnovel.me')) return 'readlightnovel.me'; else if (this.includes('readwn')) return 'www.readwn.com'; else if (this.includes('www.wuxiax.com')) return 'www.wuxiax.com'; else if (this.includes('www.lnreader.org')) return 'www.lnreader.org'; else if (this.includes('lnreader.org')) return 'lnreader.org'; else if (this.includes('novelonlinefull')) return 'novelonlinefull.com'; else if (this.includes('bestlightnovel')) return 'bestlightnovel.com'; else if (this.includes('novels.pl')) return 'novels.pl'; else if (this.includes('novelfull')) return 'novelfull.com'; else if (this.includes('boxnovel.com')) return 'boxnovel.com'; else if (this.includes('novelhall')) return 'www.novelhall.com'; } String.prototype.LN_fix = function(url) { let s = this.split('/'); s.shift(); s.shift(); s.shift(); s.unshift('https:', '', url.LN_host()); s = s.join('/'); return s; } String.prototype.LN_replaceAt = function(index, replacement) { let a = this.split(''); a[index] = replacement; return a.join(''); } String.prototype.LN_reverseString = function() { const a = this.split(''), b = a.reverse(), c = b.join(''); return c; } if (GM_getValue('firsttime', true)) { GM_setValue('next', 'KeyN'); GM_setValue('nexta', 'ArrowRight'); GM_setValue('nextaa', 'KeyD'); GM_setValue('prev', 'KeyB'); GM_setValue('preva', 'ArrowLeft'); GM_setValue('prevaa', 'KeyA'); GM_setValue('darkmode', 'KeyL'); GM_setValue('fullscreen', 'KeyF'); GM_setValue('autoscroll', 'KeyQ'); GM_setValue('removean', 'KeyE'); GM_setValue('download', 'KeyS'); GM_setValue('decfs', 'Minus'); GM_setValue('incfs', 'Equal'); GM_setValue('autonc', false); GM_setValue('autora', true); GM_setValue('autodl', true); GM_setValue('autoresume', true); GM_setValue('defaultv', false); GM_setValue('scrollt', false); GM_setValue('swipeg', true); GM_setValue('nnotfound', true); GM_setValue('autoch', false); GM_setValue('autodmode', false); GM_setValue('decensore', true); GM_setValue('allowconfirm', true); GM_setValue('uselastr', false); GM_setValue('checkcomp', false); GM_setValue('downloadt', true); GM_setValue('autoretry', true); GM_setValue('laststop', ['placeholder']); GM_setValue('autoncd', 40); GM_setValue('dmtime', 18); GM_setValue('lmtime', 9); GM_setValue('pmargin', 20); GM_setValue('lheight', 1.4); GM_setValue('autoscrolls', 90); GM_setValue('autoretryno', 20); GM_setValue('showfavs', 'Digit3'); GM_setValue('autodown', false); GM_setValue('defaultf', "'Comic Sans MS'"); GM_setValue('defaultfs', 18); GM_setValue('checkd', '09:00'); GM_setValue('lastcheck', ''); GM_setValue('autobackupp', 0); GM_setValue('bgc', '#c95'); GM_setValue('txc', '#000'); GM_setValue('dbgc', '#111'); GM_setValue('dtxc', '#550'); GM_setValue('CCSS', ''); GM_setValue('ECCSS', ''); GM_setValue('FAVS', ['placeholder']); GM_setValue('HISTORY', ['placeholder']); GM_setValue('RULES', ['placeholder']); GM_setValue('DHISTORY', ['placeholder']); GM_setValue('TIMES', ['placeholder']); GM_setValue('CHECKED', [new Date]); GM_setValue('firsttime', false); } let next = GM_getValue('next', 'KeyN'), nexta = GM_getValue('nexta', 'ArrowRight'), nextaa = GM_getValue('nextaa', 'KeyD'), prev = GM_getValue('prev', 'KeyB'), preva = GM_getValue('preva', 'ArrowLeft'), prevaa = GM_getValue('prevaa', 'KeyA'), darkmode = GM_getValue('darkmode', 'KeyL'), fullscreen = GM_getValue('fullscreen', 'KeyF'), autoscroll = GM_getValue('autoscroll', 'KeyQ'), showfavs = GM_getValue('showfavs', 'Digit3'), removean = GM_getValue('removean', 'KeyE'), download = GM_getValue('download', 'KeyS'), decfs = GM_getValue('decfs', 'Minus'), incfs = GM_getValue('incfs', 'Equal'), autonc = GM_getValue('autonc', false), autora = GM_getValue('autora', true), autodl = GM_getValue('autodl', true), autoresume = GM_getValue('autoresume', true), defaultv = GM_getValue('defaultv', false), scrollt = GM_getValue('scrollt', false), swipeg = GM_getValue('swipeg', true), nnotfound = GM_getValue('nnotfound', true), autoch = GM_getValue('autoch', false), autodmode = GM_getValue('autodmode', false), decensore = GM_getValue('decensore', true), allowconfirm = GM_getValue('allowconfirm', true), uselastr = GM_getValue('uselastr', false), checkcomp = GM_getValue('checkcomp', false), downloadt = GM_getValue('downloadt', true), autoretry = GM_getValue('autoretry', true), laststop = GM_getValue('laststop', ['placeholder']), autoncd = parseFloat(GM_getValue('autoncd', 40)), dmtime = parseFloat(GM_getValue('dmtime', 18)), lmtime = parseFloat(GM_getValue('lmtime', 9)), pmargin = parseFloat(GM_getValue('pmargin', 20)), lheight = parseFloat(GM_getValue('lheight', 1.4)), autoscrolls = parseFloat(GM_getValue('autoscrolls', 90)), autoretryno = GM_getValue('autoretryno', 20), autodown = GM_getValue('autodown', false), defaultf = GM_getValue('defaultf', '"Comic Sans MS"'), defaultfs = GM_getValue('defaultfs', 18), checkd = GM_getValue('checkd', '09:00'), lastcheck = GM_getValue('lastcheck', ''), autobackupp = parseFloat(GM_getValue('autobackupp', 0)), bgc = GM_getValue('bgc', '#c95'), txc = GM_getValue('txc', '#000'), dbgc = GM_getValue('dbgc', '#111'), dtxc = GM_getValue('dtxc', '#550'), CCSS = GM_getValue('CCSS', ''), ECCSS = GM_getValue('ECCSS', ''), HISTORY = GM_getValue('HISTORY', ['placeholder']), FAVS = GM_getValue('FAVS', ['placeholder']), RULES = GM_getValue('RULES', ['placeholder']), DHISTORY = GM_getValue('DHISTORY', ['placeholder']), TIMES = GM_getValue('TIMES', ['placeholder']), CHECKED = GM_getValue('CHECKED', [JSON.stringify(new Date()).replaceAll('"', '')]), KEY = { code: fullscreen, altKey: false, ctrlKey: false, shiftKey: false, metaKey: false, target: { tagName: 'DIV' } }; if (!Array.isArray(laststop)) { laststop = JSON.parse(laststop); GM_setValue('laststop', laststop); } if (!Array.isArray(HISTORY)) { HISTORY = JSON.parse(HISTORY); GM_setValue('HISTORY', HISTORY); } if (!Array.isArray(FAVS)) { FAVS = JSON.parse(FAVS); GM_setValue('FAVS', FAVS); } if (!Array.isArray(RULES)) { RULES = JSON.parse(RULES); GM_setValue('RULES', RULES); } if (!Array.isArray(DHISTORY)) { DHISTORY = JSON.parse(DHISTORY); GM_setValue('DHISTORY', DHISTORY); } if (!Array.isArray(TIMES)) { TIMES = JSON.parse(TIMES); GM_setValue('TIMES', TIMES); } { for (let i = 1; i < HISTORY.length; i++ ) if (typeof HISTORY[i] == 'string') HISTORY.splice(i, 1); for (let i = 1; i < DHISTORY.length; i++ ) if (typeof DHISTORY[i] == 'string') DHISTORY.splice(i, 1); for (let i = 1; i < laststop.length; i++ ) if (typeof laststop[i] == 'string') laststop.splice(i, 1); let o = 'lightnovelworld'; for (let i = 1; i < FAVS.length; i++) { FAVS[i].lastc.href = FAVS[i].lastc.href.replace('lightnovelpub', o); FAVS[i].url.href = FAVS[i].url.href.replace('lightnovelpub', o); } while (DHISTORY.LN_search('lightnovelpub', 'includes').found) DHISTORY[DHISTORY.LN_search('lightnovelpub', 'includes').index] = DHISTORY.LN_search('lightnovelpub', 'includes').value.replace('lightnovelpub', o); while (HISTORY.LN_search('lightnovelpub', 'includes').found) HISTORY[HISTORY.LN_search('lightnovelpub', 'includes').index] = HISTORY.LN_search('lightnovelpub', 'includes').value.replace('lightnovelpub', o); while (laststop.LN_search('lightnovelpub', 'includes').found) laststop[laststop.LN_search('lightnovelpub', 'includes').index] = laststop.LN_search('lightnovelpub', 'includes').value.replace('lightnovelpub', o); GM_setValue('FAVS', FAVS); GM_setValue('DHISTORY', DHISTORY); GM_setValue('HISTORY', HISTORY); GM_setValue('laststop', laststop); } if (SITES[location.host]) { FAVS.forEach((elm, id) => { if (id != 0) { let {novel, url, url: {href, text}, status, lastc} = elm if (!novel || !url || !href || !text || !status || !lastc) FAVS.splice(id, 1); } }); GM_setValue('FAVS', FAVS); rvals(); } const s = document.createElement('div'), d = document.createElement('div'), o = document.createElement('div'), m = document.createElement('div'), c = document.createElement('div'), f = document.createElement('div'), r = document.createElement('div'), n = document.createElement('aside'), a = document.createElement('div'), l = document.createElement('div'), svga = '<svg style="transform: rotate(-90deg); height: 22px; width: 22px; display: inline; transition: inherit;" fill="#090" viewBox="0 0 26 26"> <path d="M13,15.405l8.764-8.584c0.392-0.383,1.019-0.38,1.406,0.008l1.536,1.536c0.391,0.391,0.39,1.026-0.002,1.417L13.707,20.707 C13.512,20.902,13.256,21,13,21c-0.256,0-0.512-0.098-0.707-0.293L1.296,9.782c-0.393-0.39-0.394-1.025-0.002-1.417L2.83,6.829 c0.387-0.387,1.015-0.391,1.406-0.008L13,15.405z"></path> </svg>', svgs = '<svg style="height: 20px; width: 50px;" viewBox="0 0 48 48"> <circle style="fill:#F44336;" cx="24" cy="24" r="19"/> <rect x="22" y="14" transform="matrix(0.7071 0.7071 -0.7071 0.7071 24 -9.9411)" style="fill:#FFFFFF;" width="4" height="20"/> <rect x="22" y="14" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 57.9411 24)" style="fill:#FFFFFF;" width="4" height="20"/> </svg>', svgi = '<svg style="height: 20px; width: 50px; flex: 0 0 auto;" viewBox="0 0 48 48"> <circle style="fill:#FFCA28;" cx="24" cy="24" r="19"/> <rect x="22" y="21" style="fill:#37474F;" width="4" height="13"/> <circle style="fill:#37474F;" cx="24" cy="16" r="2"/> </svg>', svgreader = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 50 50"> <path d="M 6 4 L 6 39 L 7 39 C 16.733333 39 24.552734 42.894531 24.552734 42.894531 L 25 43.117188 L 25.447266 42.894531 C 25.447266 42.894531 33.266667 39 43 39 L 44 39 L 44 4 L 43 4 C 33.160341 4 25.642079 7.6218492 25 7.9355469 C 24.357921 7.6218492 16.839659 4 7 4 L 6 4 z M 8 6.0898438 C 16.244795 6.3254498 22.653699 9.0479802 24 9.65625 L 24 40.503906 C 21.872898 39.585697 15.887188 37.302104 8 37.087891 L 8 6.0898438 z M 42 6.0898438 L 42 37.087891 C 34.112812 37.302104 28.127102 39.585697 26 40.503906 L 26 9.65625 C 27.346301 9.0479802 33.755205 6.3254498 42 6.0898438 z M 2 9 L 2 43 L 3 43 C 15.794872 43 24.59375 46.914062 24.59375 46.914062 L 25 47.09375 L 25.40625 46.914062 C 25.40625 46.914062 34.205128 43 47 43 L 48 43 L 48 9 L 46 9 L 46 41.070312 C 33.798944 41.276157 25.556846 44.711648 25 44.953125 C 24.443154 44.711648 16.201056 41.276157 4 41.070312 L 4 9 L 2 9 z"/> </svg>', svgsettings = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 24 24"> <path d="M 12.0625 0 C 9.7745 -1.9428903e-16 9.8125 0.21875 9.8125 0.21875 C 9.5405 1.53775 9.2555 2.43275 9.0625 2.96875 C 7.8965 3.34975 6.82525 3.94775 5.90625 4.71875 C 5.35225 4.60975 4.45775 4.40675 3.21875 3.96875 C 3.21875 3.96875 3.052 3.8235 1.875 5.8125 C 0.696 7.7995 0.875 7.90625 0.875 7.90625 C 1.788 8.76425 2.387 9.426 2.75 9.875 C 2.593 10.559 2.5 11.268 2.5 12 C 2.5 12.663 2.5585 13.3125 2.6875 13.9375 C 2.3145 14.3785 1.70525 15.043 0.78125 15.875 C 0.78125 15.875 0.613 15.95675 1.75 17.96875 C 2.886 19.98075 3.03125 19.84375 3.03125 19.84375 C 4.28225 19.43075 5.193 19.25325 5.75 19.15625 C 6.666 19.95925 7.72925 20.56375 8.90625 20.96875 C 9.10025 21.49675 9.4065 22.41425 9.6875 23.78125 C 9.6875 23.78125 9.6505 24 11.9375 24 C 14.2215 24 14.21875 23.78125 14.21875 23.78125 C 14.49075 22.46325 14.7435 21.56625 14.9375 21.03125 C 16.1035 20.65025 17.17575 20.05225 18.09375 19.28125 C 18.64875 19.39025 19.54325 19.59225 20.78125 20.03125 C 20.78125 20.03125 20.944 20.1755 22.125 18.1875 C 23.302 16.1985 23.125 16.09375 23.125 16.09375 C 22.211 15.23575 21.613 14.573 21.25 14.125 C 21.406 13.439 21.5 12.732 21.5 12 C 21.5 11.337 21.4415 10.6875 21.3125 10.0625 C 21.6855 9.6225 22.29375 8.958 23.21875 8.125 C 23.21875 8.125 23.387 8.04425 22.25 6.03125 C 21.114 4.01825 20.96875 4.15625 20.96875 4.15625 C 19.71875 4.56925 18.807 4.74675 18.25 4.84375 C 17.334 4.04175 16.26975 3.43625 15.09375 3.03125 C 14.90075 2.50425 14.5945 1.58475 14.3125 0.21875 C 14.3125 0.21875 14.3465 0 12.0625 0 z M 12 4 C 16.418 4 20 7.582 20 12 C 20 16.418 16.418 20 12 20 C 7.582 20 4 16.418 4 12 C 4 7.582 7.582 4 12 4 z M 12 5 C 8.134 5 5 8.134 5 12 C 5 15.866 8.134 19 12 19 C 15.866 19 19 15.866 19 12 C 19 8.134 15.866 5 12 5 z M 12 8 C 14.209 8 16 9.791 16 12 C 16 14.209 14.209 16 12 16 C 9.791 16 8 14.209 8 12 C 8 9.791 9.791 8 12 8 z"/> </svg>', svgarrowr = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 26 26"> <path d="M2.72,11.023l13.28-1V6.874c0-0.328,0.16-0.574,0.48-0.82c0.32-0.082,0.64-0.082,0.88,0.082 c3.28,2.296,6.4,6.144,6.48,6.308c0.078,0.159,0.152,0.393,0.157,0.556c0,0.005,0.003,0.012,0.003,0.017c0,0,0,0,0,0s0,0,0,0 c0,0.164-0.08,0.41-0.16,0.492c-0.08,0.164-3.12,4.023-6.48,6.319c-0.32,0.164-0.64,0.246-0.88,0.082 c-0.32-0.164-0.48-0.41-0.48-0.738v-3.15l-13.28-1C2.32,14.703,2,13.897,2,13.017C2,12.217,2.24,11.343,2.72,11.023z"/> </svg>', svgarrowl = '<svg style="height: 20px; width: 20px; transform: rotate(180deg);" fill="#090" viewBox="0 0 26 26"> <path d="M2.72,11.023l13.28-1V6.874c0-0.328,0.16-0.574,0.48-0.82c0.32-0.082,0.64-0.082,0.88,0.082 c3.28,2.296,6.4,6.144,6.48,6.308c0.078,0.159,0.152,0.393,0.157,0.556c0,0.005,0.003,0.012,0.003,0.017c0,0,0,0,0,0s0,0,0,0 c0,0.164-0.08,0.41-0.16,0.492c-0.08,0.164-3.12,4.023-6.48,6.319c-0.32,0.164-0.64,0.246-0.88,0.082 c-0.32-0.164-0.48-0.41-0.48-0.738v-3.15l-13.28-1C2.32,14.703,2,13.897,2,13.017C2,12.217,2.24,11.343,2.72,11.023z"/> </svg>', svgdarkm = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 24 24"> <path d="M 11.09375 0 C 11.070976 0.018366465 11.053905 0.043928916 11.03125 0.0625 C 4.8826005 0.56284675 0 5.7281066 0 12 C 0 18.271893 4.8826005 23.437153 11.03125 23.9375 C 11.053905 23.956071 11.070976 23.981634 11.09375 24 L 12 24 C 14.475 24 16.771484 23.234766 18.6875 21.9375 C 19.006836 21.721289 19.328369 21.495068 19.625 21.25 C 22.294678 19.044385 24 15.7125 24 12 C 24 11.5875 23.978662 11.18335 23.9375 10.78125 C 23.567041 7.1623535 21.561523 4.0083984 18.6875 2.0625 C 18.368164 1.8462891 18.05874 1.6540527 17.71875 1.46875 C 16.358789 0.72753906 14.827148 0.22714844 13.21875 0.0625 C 12.81665 0.021337891 12.4125 0 12 0 L 11.09375 0 z M 8.8125 2.53125 C 7.0677963 5.031543 6 8.3197873 6 12 C 6 15.680213 7.0677963 18.968457 8.8125 21.46875 C 4.8662498 20.128313 2 16.38442 2 12 C 2 7.6155795 4.8662498 3.8716869 8.8125 2.53125 z"/> </svg>', svgsh = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 50 50"> <path d="M 5 6 C 3.346 6 2 7.346 2 9 L 2 41 C 2 42.654 3.346 44 5 44 L 45 44 C 46.654 44 48 42.654 48 41 L 48 9 C 48 7.346 46.654 6 45 6 L 5 6 z M 5 8 L 29 8 L 29 42 L 5 42 C 4.448 42 4 41.552 4 41 L 4 9 C 4 8.448 4.448 8 5 8 z M 13.917969 18.990234 A 1.0001 1.0001 0 0 0 13.232422 19.296875 L 7.59375 25 L 13.232422 30.703125 A 1.0001 1.0001 0 1 0 14.654297 29.296875 L 11.394531 26 L 23.943359 26 A 1.0001 1.0001 0 1 0 23.943359 24 L 11.394531 24 L 14.654297 20.703125 A 1.0001 1.0001 0 0 0 13.917969 18.990234 z" /> </svg>', svgfd = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 50 50"> <path d="M 17.84375 10 C 17.43175 10 17.05525 10.27225 16.90625 10.65625 L 4.125 43.5 C 4.005 43.809 4.03275 44.13425 4.21875 44.40625 C 4.40575 44.67925 4.7325 44.84375 5.0625 44.84375 L 9.5 44.84375 C 9.918 44.84375 10.2915 44.5795 10.4375 44.1875 L 13.875 34.96875 L 26.375 34.96875 L 29.71875 44.1875 C 29.86175 44.5825 30.2665 44.84375 30.6875 44.84375 L 35.5 44.84375 L 35.53125 44.84375 C 36.08425 44.84375 36.53025 44.39675 36.53125 43.84375 C 36.53125 43.64675 36.474 43.4675 36.375 43.3125 L 23.59375 10.65625 C 23.44375 10.27225 23.06825 10 22.65625 10 L 17.84375 10 z M 20.1875 17.78125 L 24.28125 29.28125 L 16 29.28125 L 20.1875 17.78125 z M 37 24 C 36.447 24 36 24.448 36 25 C 36 25.552 36.447 26 37 26 L 47 26 C 47.553 26 48 25.552 48 25 C 48 24.448 47.553 24 47 24 L 37 24 z"/> </svg>', svgfi = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 50 50"> <path d="M 18.4375 4.28125 C 18.0255 4.28125 17.649 4.5535 17.5 4.9375 L 2.46875 43.5 C 2.34875 43.809 2.40775 44.13425 2.59375 44.40625 C 2.78075 44.67925 3.07625 44.84375 3.40625 44.84375 L 8.65625 44.84375 C 9.07425 44.84375 9.44775 44.5795 9.59375 44.1875 L 13.65625 33.25 L 28.5625 33.25 L 32.5625 44.1875 C 32.7055 44.5825 33.079 44.84375 33.5 44.84375 L 39.15625 44.84375 L 39.1875 44.84375 C 39.7395 44.84375 40.1875 44.39675 40.1875 43.84375 C 40.1875 43.64675 40.13025 43.4675 40.03125 43.3125 L 25.03125 4.9375 C 24.88125 4.5535 24.50575 4.28125 24.09375 4.28125 L 18.4375 4.28125 z M 21.15625 12.75 L 26.25 26.90625 L 16.03125 26.90625 L 21.15625 12.75 z M 42 19 C 41.447 19 41 19.448 41 20 L 41 24 L 37 24 C 36.447 24 36 24.448 36 25 C 36 25.552 36.447 26 37 26 L 41 26 L 41 30 C 41 30.553 41.447 31 42 31 C 42.553 31 43 30.553 43 30 L 43 26 L 47 26 C 47.553 26 48 25.552 48 25 C 48 24.448 47.553 24 47 24 L 43 24 L 43 20 C 43 19.448 42.553 19 42 19 z"/> </svg>', svgscroll = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 24 24"> <path d="M 12 2 C 7.5700855 2 4 5.5700855 4 10 L 4 14 C 4 18.429915 7.5700855 22 12 22 C 16.429915 22 20 18.429915 20 14 L 20 10 C 20 5.5700855 16.429915 2 12 2 z M 12 4 C 15.370085 4 18 6.6299145 18 10 L 18 14 C 18 17.370085 15.370085 20 12 20 C 8.6299145 20 6 17.370085 6 14 L 6 10 C 6 6.6299145 8.6299145 4 12 4 z M 12 6 L 9 9 L 11 9 L 11 11 L 9 11 L 12 14 L 15 11 L 13 11 L 13 9 L 15 9 L 12 6 z" /> </svg>', svgrema = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 32 32"> <path d="M 4 5 L 4 6 L 4 26 L 4 27 L 5 27 L 19 27 L 19 25 L 6 25 L 6 11 L 26 11 L 26 17 L 28 17 L 28 6 L 28 5 L 27 5 L 5 5 L 4 5 z M 6 7 L 26 7 L 26 9 L 6 9 L 6 7 z M 9 14 L 9 16 L 11 16 L 11 14 L 9 14 z M 13 14 L 13 16 L 23 16 L 23 14 L 13 14 z M 9 18 L 9 20 L 11 20 L 11 18 L 9 18 z M 13 18 L 13 20 L 19 20 L 19 18 L 13 18 z M 25 19 C 24.448 19 24 19.448 24 20 L 20 20 L 20 22 L 32 22 L 32 20 L 28 20 C 28 19.448 27.552 19 27 19 L 25 19 z M 21 23 L 21 30 C 21 31.093063 21.906937 32 23 32 L 29 32 C 30.093063 32 31 31.093063 31 30 L 31 23 L 29 23 L 29 30 L 23 30 L 23 23 L 21 23 z"/> </svg>', svgcontent = '<svg style="height: 20px; width: 20px;" fill="#090" viewBox="0 0 50 50"> <path d="M 43 7 C 42.448 7 42 7.447 42 8 L 42 12 C 42 12.553 42.448 13 43 13 L 47 13 C 47.552 13 48 12.553 48 12 L 48 8 C 48 7.447 47.552 7 47 7 L 43 7 z M 4 8 A 2.0002 2.0002 0 1 0 4 12 L 36 12 A 2.0002 2.0002 0 1 0 36 8 L 4 8 z M 43 17 C 42.448 17 42 17.447 42 18 L 42 22 C 42 22.553 42.448 23 43 23 L 47 23 C 47.552 23 48 22.553 48 22 L 48 18 C 48 17.447 47.552 17 47 17 L 43 17 z M 4 18 A 2.0002 2.0002 0 1 0 4 22 L 36 22 A 2.0002 2.0002 0 1 0 36 18 L 4 18 z M 43 27 C 42.448 27 42 27.448 42 28 L 42 32 C 42 32.552 42.448 33 43 33 L 47 33 C 47.552 33 48 32.552 48 32 L 48 28 C 48 27.448 47.552 27 47 27 L 43 27 z M 4 28 A 2.0002 2.0002 0 1 0 4 32 L 36 32 A 2.0002 2.0002 0 1 0 36 28 L 4 28 z M 43 37 C 42.448 37 42 37.448 42 38 L 42 42 C 42 42.552 42.448 43 43 43 L 47 43 C 47.552 43 48 42.552 48 42 L 48 38 C 48 37.448 47.552 37 47 37 L 43 37 z M 4 38 A 2.0002 2.0002 0 1 0 4 42 L 36 42 A 2.0002 2.0002 0 1 0 36 38 L 4 38 z"/> </svg>', svgdd = '<svg viewBox="0 0 60 60" style="height: 20px; width: 20px; margin: 0 2px 0 0; animation: LN_rotate 2s linear infinite;"><path d="M46.03,32c0,-2.751 2.233,-4.985 4.985,-4.985c2.751,0 4.985,2.234 4.985,4.985c0,2.751 -2.234,4.985 -4.985,4.985c-2.752,0 -4.985,-2.234 -4.985,-4.985Z" style="fill: #030;"></path> <path d="M41.92,41.92c1.946,-1.945 5.105,-1.945 7.051,0c1.945,1.946 1.945,5.105 0,7.051c-1.946,1.945 -5.105,1.945 -7.051,0c-1.945,-1.946 -1.945,-5.105 0,-7.051Z" style="fill: #060;"></path> <circle cx="32" cy="51.015" r="4.985" style="fill: #090;"></circle><path d="M22.08,41.92c1.945,1.946 1.945,5.105 0,7.051c-1.946,1.945 -5.105,1.945 -7.051,0c-1.945,-1.946 -1.945,-5.105 0,-7.051c1.946,-1.945 5.105,-1.945 7.051,0Z" style="fill: #090b;"></path> <path d="M17.97,32c0,2.751 -2.233,4.985 -4.985,4.985c-2.751,0 -4.985,-2.234 -4.985,-4.985c0,-2.751 2.234,-4.985 4.985,-4.985c2.752,0 4.985,2.234 4.985,4.985Z" style="fill: #0909;"></path> <path d="M22.08,22.08c-1.946,1.945 -5.105,1.945 -7.051,0c-1.945,-1.946 -1.945,-5.105 0,-7.051c1.946,-1.945 5.105,-1.945 7.051,0c1.945,1.946 1.945,5.105 0,7.051Z" style="fill: #0906;"></path><circle cx="32" cy="12.985" r="4.985" style="fill: #0903;"></circle></svg>', BOTCHECK = B => { if (B.innerText.includes('Cloudflare') || B.innerText.includes('cloudflare') || B.innerText.includes('Verifying that you are not a robot...') || B.innerText.includes('Your access to this site has been limited by the site owner')) return true; else return false; }; let sch, pch, och, dch, nch, bch, fch, tah, etah, portcss, CSS, ccss, fontcss, liningcss, CS; if (SITES[location.host]) CS = SITES[location.host]; let LF = 'https://fonts.googleapis.com/css2?family=Asap&family=Berkshire+Swash&family=Comic+Neue&family=Dosis&family=Nunito+Sans&family=Maven+Pro&family=Quicksand&family=Squada+One&family=Ubuntu&display=swap', fonts = ['comic sans ms', 'comic neue', 'squada one', 'maven pro', 'berkshire swash', 'dosis', 'cursive', 'ubuntu', 'asap', 'helvetiva', 'quicksand', 'verdana'], NLF = document.createElement('link'); NLF.rel = 'stylesheet'; NLF.href = LF; document.head.appendChild(NLF); a.classList.add('LN_alert'); document.body.appendChild(a); GM_addStyle(` .LN_alert { line-height: initial; position: fixed; z-index: 2147483647; background-color: #000; color: #090; font-size: 14px; font-family: 'Nunito Sans', sans-serif; transition: all 0.5s ease; user-select: none; } .LN_alert { bottom: 3%; margin: 0 auto; width: 500px; height: fit-content; height: -moz-fit-content; border-radius: 20px; border: 1px #090 solid; display: none; opacity: 0; user-select: none; cursor: default; text-align: center; padding: 25px; font-size: 25px; font-weight: 700; } `); { const arr1 = ['』', '」', '〉', '『', '「', '〈', '♬', '☆', '⑨', 'ē', '[email protected]', '→', '←', '↔',], arr2 = [']', ']', ']', '[', '[', '[', '', '', '', 'e', '@', ' > ', ' < ', ' <-> ']; if (!RULES.LN_search('&.{0,5};').found) { const obj = { word: '&.{0,5};', replaced: '', type: 'contains', cond: 'word' }; RULES.push(obj); } for (let i = 0; i < arr1.length; i++) { if (!RULES.LN_search(arr1[i]).found) { const obj = { word: arr1[i], replaced: arr2[i], type: 'equals', cond: 'word' }; RULES.push(obj); } } GM_setValue('RULES', RULES); } function ui() { GM_addStyle(` .LN_swiper { height: 0; width: 100%; overflow: hidden; background-color: inherit; color: inherit; transition: inherit; } .LN_swiper span { background-color: inherit; color: inherit; transition: inherit; display: block; font-size: 30px; text-align: center; height: 250px; width: 400px; margin: auto; font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; } .LN_icob:hover, .LN_icob2:hover { opacity: 0.3; } .LN_icob, .LN_icob2 { background-color: transparent !important; border: none; padding: 10px 0; margin: 30px 0; display: block ruby; width: 40px; cursor: pointer; outline: 0; font-family: sans-serif; font-weight: bolder; text-align: center; color: #090 !important; } .LN_icob2 { display: none !important; } .LN_sidebar { margin-left: -200px; margin-bottom: -200px; cursor: default !important; background-color: #000 !important; color: #090 !important; border-radius: 0 20px 20px 0; } .LN_filter h4 { color: #090; font-size: 18px; font-family: 'Nunito Sans', sans-serif; display: inline; } .LN_btn[disabled] { opacity: 0.6 !important; cursor: not-allowed !important; color: #000 !important; background-color: #090 !important; } .LN_note { align-content: center; display: flex; text-transform: none; } .LN_current { border: 1px dashed #090; padding: 2px; cursor: pointer; } .LN_styler:not(input), .LN_filter:not(input), .LN_menu:not(input, span) { text-transform: capitalize; } .LN_menu input, .LN_menu select, { appearance: auto; font-family: 'Nunito Sans', sans-serif; display: inline; width: auto; } .LN_help { cursor: help; border-bottom: 2px #aaa dotted; margin-bottom: 2px; display: inline-block; } .LN_sidebar *, .LN_settings *, .LN_downloadCounter *, .LN_menu *, .LN_overlay *, .LN_chapter *, .LN_styler *, .LN_filter *, .LN_chapterin * { transition: inherit; } .LN_settings, .LN_sidebar, .LN_menu, .LN_overlay, .LN_chapter, .LN_styler, .LN_filter, .LN_chapterin, .LN_downloadCounter { line-height: initial; position: fixed; z-index: 9999999999999999999; background-color: #000; color: #090; font-size: 14px; font-family: 'Nunito Sans', sans-serif; transition: all 0.5s ease; user-select: none; } .LN_settings, .LN_downloadCounter { bottom: 0; right: 0; padding: 5px; border-top-left-radius: 7px; cursor: pointer; border-right: 7px #090 solid; opacity: 0.7; font-family: cursive; font-weight: 700; } .LN_downloadCounter { right: -600px; cursor: default;} .LN_settings:hover, .LN_downloadCounter:hover { opacity: 1; } .LN_menu::-webkit-resizer, .LN_menu::-webkit-scrollbar-corner, .LN_menu::-webkit-scrollbar-button, .LN_chapterin::-webkit-resizer, .LN_chapterin::-webkit-scrollbar-corner, .LN_chapterin::-webkit-scrollbar-button { transition: all 0.5s; width: 0; height: 0; display: none; } .LN_menu::-webkit-scrollbar-thumb, .LN_chapterin::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: #090; } .LN_menu::-webkit-scrollbar-track, .LN_menu::-webkit-scrollbar, .LN_chapterin::-webkit-scrollbar-track, .LN_chapterin::-webkit-scrollbar { transition: all 0.5s; background-color: #000; width: 10px; } .LN_menu { top: 2%; right: 0; padding: 20px; width: 500px; height: -moz-fit-content; height: fit-content; margin-right: -600px; border-radius: 15px 0px 0px 15px; scrollbar-color: #090 #000; scrollbar-width: thin; } .LN_menu h2, .LN_styler h2, .LN_filter h2 { font-size: 22px; margin: 0; display: inline-block; line-height: 30px; transition: inherit; color: #090; cursor: pointer; font-weight: bolder; font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; } .LN_menu input[type=radio] { display: inline-block; appearance: radio; } .LN_menu input[type=number], .LN_menu input[type=text], .LN_filter input[type=text], .LN_menu input[type=time], .LN_styler input { width: auto; min-width: 100px; margin: 2px; outline: 0; background-color: #111; color: #777; border: none; padding: 2px; margin-left: 15px; text-align: center; font-weight: bolder; outline: 0; transition: inherit; appearance: auto; display: inline; } .LN_menu input[type=number]:focus, .LN_menu input[type=text]:focus, .LN_menu input[type=time]:focus, .LN_styler input:focus, .LN_filter input:focus { box-shadow: 0 0 5px 2px #090; padding: 3px; margin: 5px 1px 5px 10px; outline: 0; border: 1px solid #090; } .LN_menu input:invalid, .LN_filter input:invalid, .LN_styler input:invalid, .LN_main textarea:invalid { box-shadow: 0 0 5px 2px #900; outline: 0; border: 1px solid #900; } .LN_menu select, .LN_filter select { border: 1px solid #090; margin: 2px; background-color: #000; color: #090; outline: 0; cursor: pointer; font-size: 20px; padding: 3px 10px; appearance: auto; width: auto; height: auto; display: inline; } .LN_s, .LN_p, .LN_o, .LN_d, .LN_n, .LN_b, .LN_f { overflow-y: scroll; height: 0px; transition: inherit; } .LN_btn:hover { color: #090; background-color: #000; } .LN_cancel { display: inline-flex; vertical-align: middle; cursor: pointer; } .LN_btn { transition: inherit; border: none; color: #000; background-color: #090; outline: 0; font-family: sans-serif; cursor: pointer; padding: 5px 20px; font-weight: bolder; margin-left: 10px; margin-top: 10px; } .LN_overlay { z-index: 2147483640 !important; top: 0; right: 0; position: fixed; background-color: #000; opacity: 0.7; display: none; height: 100%; width: 100%; } .LN_chapter { user-select: text; display: none; top: 0; left: 0; width: 100%; height: 100%; z-index: 2147483635 !important; overflow: scroll; scroll-behavior: smooth; scrollbar-color: #000 #090; scrollbar-width: thin; } .LN_chapter div { background-color: #090; color: #000; padding: 50px 250px; border: none; } .LN_chapter::-webkit-resizer, .LN_chapter::-webkit-scrollbar-corner, .LN_chapter::-webkit-scrollbar-button { transition: all 0.5s; width: 0; height: 0; display: none; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: #000; } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: #090; width: 10px; } .LN_styler, .LN_filter, .LN_chapterin { box-shadow: 0 0 20px 20px #090; top: 20px; display: none; padding: 20px; margin: 20px auto; border-radius: 20px; height: -moz-fit-content; width: -moz-fit-content; height: fit-content; width: fit-content; } .LN_styler textarea { color: #090; background-color: #222; border: none; outline: 0; padding: 2px; width: 500px; height: 300px; font-family: roboto; } .LN_styler h2, .LN_filter h2 { cursor: default; } .LN_b input[type=file] { cursor: pointer; background-color: #000; color: #090; padding: 3px; border: 1px solid #090; } .LN_loading { width: 50px; height: 50px; text-align: center; margin: auto; border-radius: 50%; border: 8px #000 solid; border-color: #090 transparent; animation: LN_rotate 2s linear infinite; } .LN_chapterin { width: -moz-fit-content; width: fit-content; height: 70%; margin: auto; overflow-y: scroll; display: none; z-index: 2147483646 !important; background-color: #000; top: 30px; padding: 20px; border-radius: 15px; scrollbar-color: #090 #000; scrollbar-width: thin; align-self: center; scroll-behavior: smooth; } .LN_chapteran { border: 1px #090 solid; margin: 10px 0; width: 100%; text-align: center; color: #090; transition: all 0.3s; padding: 5px 50px; box-sizing: border-box; } .LN_chapteran:hover { color: #ccc !important; text-decoration: underline; border: 1px #ccc solid !important; } .LN_chapteran:visited { color: #c83; border: 1px #c83 solid; } @keyframes LN_rotate { from {transform: rotate(0deg);} to {transform:rotate(360deg);} `); portcss = GM_addStyle(` .LN_cmob { width: 100% !important; right: 0 !important; left: 0 !important; } .LN_fmob { width: 100% !important; right: 0 !important; left: 0 !important; } .LN_cmob textarea { width: 100% !important; } .LN_amob { font-size: 14px !important; max-width: 300px !important; margin: 0 ${(window.innerWidth - 300) / 2}px !important; } .LN_mob { padding: 20px !important; } .LN_bot { border-radius: 20px 20px 0 0 !important; } .LN_bot .LN_icob, .LN_bot .LN_icob2 { display: inline; padding: 0; margin: 10px 0; } `); CSS = GM_addStyle(` .LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${bgc} !important; color: ${txc} !important; scrollbar-color: ${txc} ${bgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${txc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${bgc}; width: 10px; }`); fontcss = GM_addStyle(` .LN_chapter, .LN_chapter div, .LN_chapter p { font-size: ${defaultfs}px !important; font-family: ${defaultf} !important; }`); liningcss = GM_addStyle(` .LN_chapter * { line-height: ${lheight}; } .LN_chapter p { margin: ${pmargin}px 0; text-align: start; }`); ccss = GM_addStyle(CCSS); s.className = 'LN_settings'; d.className = 'LN_downloadCounter'; o.className = 'LN_overlay'; m.className = 'LN_menu'; c.className = 'LN_styler'; f.className = 'LN_filter'; r.className = 'LN_chapter'; n.className = 'LN_sidebar'; l.className = 'LN_chapterin'; s.innerHTML = 'XDHx86 - LN Loader v4.3 | Settings'; d.innerHTML = svgdd + ' Downloading Chapters: 1'; m.innerHTML = `<h2> ${svga} Shortcuts: </h2> <div class="LN_s"> Reader Mode: <input type="text"> <br> Next Chapter: <input type="text"> <br> Next Chapter: <input type="text"> <br> Next Chapter: <input type="text"> <br> Prev Chapter: <input type="text"> <br> Prev Chapter: <input type="text"> <br> Prev Chapter: <input type="text"> <br> Dark Mode: <input type="text"> <br> Increase Font Size: <input type="text"> <br> Decrease Font Size: <input type="text"> <br> Remove Annoyances: <input type="text"> <br> Download: <input type="text"> <br> Auto Scroll: <input type="text"> <br> Show Favorites: <input type="text"> <br> </div> <h2> ${svga} Switches: </h2> <div class="LN_p"> <span title="What is this? Click to see notes." class="LN_help"> Auto Remove Annoyances: </span> <br> Yes <input type="radio" name="rn"> No <input type="radio" name="rn"> <br> Auto Next Chapter: <br> Yes <input type="radio" name="nc"> No <input type="radio" name="nc"> <br> <span title="What is this? Click to see notes." class="LN_help"> Use Dynamic Loading: </span> <br> Yes <input type="radio" name="dl"> No <input type="radio" name="dl"> <br> Download Type: <br> EPUB <input type="radio" name="ep"> PDF <input type="radio" name="ep"> <br> Auto Resume from Last Stop: <br> Yes <input type="radio" name="ar"> No <input type="radio" name="ar"> <br> Default Reader Mode: <br> Dark Mode <input type="radio" name="dr"> Light Mode <input type="radio" name="dr"> <br> Auto Scroll Type: <br> Page-Like <input type="radio" name="st"> Continuous <input type="radio" name="st"> <br> <span class="LN_help" title="What is this? click to see notes"> Swipe gestures: </span> <br> Yes <input type="radio" name="sg"> No <input type="radio" name="sg"> <br> Dynamic light-dark mode: <br> Yes <input type="radio" name="ld"> No <input type="radio" name="ld"> <br> decensore words: <br> Yes <input type="radio" name="uc"> No <input type="radio" name="uc"> <br> Confirm on auto download: <br> Yes <input type="radio" name="ca"> No <input type="radio" name="ca"> <br> Auto Download updates from: <br> Last read chapter <input type="radio" name="du"> Last downloaded chapter <input type="radio" name="du"> <br> Check Completed Novels: <br> Yes <input type="radio" name="cn"> No <input type="radio" name="cn"> <br> Auto Retry: <br> Yes <input type="radio" name="rr"> No <input type="radio" name="rr"> </div> <h2> ${svga} General: </h2> <div class="LN_o"> Default Font: <br> <select class="LN_dfs"> <option value="'Comic Sans MS'">Comic Sans MS</option> <option value="'Comic Neue'">Comic Neue</option> <option value="'Squada One'">Squada One</option> <option value="'Maven Pro'">Maven Pro</option> <option value="'Berkshire Swash'">Berkshire Swash</option> <option value="Dosis">Dosis</option> <option value="Cursive">Cursive</option> <option value="Ubuntu">Ubuntu</option> <option value="Asap">Asap</option> <option value="Helvetica">Helvetica</option> <option value="Quicksand">Quicksand</option> <option value="Verdana">Verdana</option> <option value="Custom">Custom</option> </select> <input class="LN_dft" style="display: none;" type="text"> <span class="LN_cancel" title="Cancel" style="display: none;"> ${svgs} </span> <span class="LN_note" style="display: none;"> ${svgi} Note that: <br> - The value has to be inbetween quotes and capitalized to work. <br> - The font has to be from Google Fonts. </span> <br> Auto Scroll Speed: <br> <select class="LN_ass"> <option value="60">Fastest</option> <option value="70">Faster</option> <option value="80">Fast</option> <option value="90">Medium</option> <option value="100">Slow</option> <option value="110">Slower</option> <option value="120">Slowest</option> <option value="Custom">Custom</option> </select> <input class="LN_ast" style="display: none;" type="number" min="10" max="200" step="1"> <span class="LN_cancel" title="Cancel" style="display: none;"> ${svgs} </span> <span class="LN_note" style="display: none;"> ${svgi} Notes: <br> - The lower the value the faster the speed. <br> - If you're using page-like scroll, then this represents seconds to wait before scrolling.</span> <br> Default Font Size: <input type="number" min="8" max="30"> <span class="LN_current"> Current Size </span> <br> Space between each paragraph: <input type="number" min="10" max="60"> <br> Line height: <input type="number" min="1" max="3" step="0.01"> <br> <span title="What is this? Click to see notes." class="LN_help"> Auto Next Chapter Delay: </span> <input type="number" min="20" max="100" step="1"> <br> Auto dark-mode hour: <input type="number" min="0" max="24" step="1"> <br> <span title="Click to see important note!" class=LN_help> Auto light-mode hour: </span> <input type="number" min="0" max="24" step="1"> <br> Auto retry times: <input type="number" min="0" max="1000" step="1"> <br> <br> Customize Styles: <button class="LN_btn"> Open Styler </button> <br> <span title="What is this? Click to see notes." class="LN_help"> Word Filtering: </span> <button class="LN_btn"> Open Filter </button> </div> <h2> ${svga} Download: </h2> <div class="LN_d"> Download <input type="number" min="1" max="10000" step="1"> chapter(s) <br> <button style="margin-top: 10px" class="LN_btn"> Download </button> <br> <span class=LN_note style="margin: 5px 0;"> ${svgi} Please note that: <br> - If you see random letters or incomprehensible words in a downloaded chapter, then you need to filter the letter that caused this issue such as:『 』「 」〈 〉 and other similar non-ASCII characters. </span> <br> Cancel current download: <button style="margin-top: 10px" class="LN_btn"> Cancel </button> <br> Cancel auto download: <button style="margin-top: 10px" class="LN_btn"> Cancel </button> </div> <h2> ${svga} Notifications & Favorites: </h2> <div class="LN_n"> Add this novel to favorites: <button class="LN_btn"> Add </button> <br> Notify when no chapters found: <br> Yes <input type="radio" name="nf"> No <input type="radio" name="nf"> <br> Auto check for updates: <br> Enabled <input type="radio" name="nn"> Disabled <input type="radio" name="nn"> <br> <span class=LN_help title="Not sure of something? Click to see notes"> Auto download updates: </span> <br> Yes <input type="radio" name="ad"> No <input type="radio" name="ad"> <br> <span class=LN_help> Auto check updates after: </span> <input type="time"> <br> Check for updates now: <button class="LN_btn"> Check </button> <br> Cancel current check: <button class="LN_btn"> Cancel </button> <br> Favorite novels list: <button class="LN_btn"> Show </button> <br> <span class="LN_note"> ${svgi} Please note that: <br> - If the window is already open it won't open again. <br> - You need to allow popups to use this. </span> </div> <h2> ${svga} Backup & Restore: </h2> <div class="LN_b"> Backup: <button class="LN_btn"> Backup </button> <br> Restore: <input type="file"> <button class="LN_btn"> Restore </button> <br> <br> Auto backup period: <input type=number min=0 max=20 step=1> <span class=LN_note> ${svgi} Notes: <br> - Set to zero to disable. <br> - This value determines the days before an auto backup. </span> </div> <h2> ${svga} Feedback: </h2> <div class="LN_f"> <button class=LN_btn> Send an email </button> </div> <br> <br> <button class="LN_btn"> Save </button> <button class="LN_btn"> Reset </button> `; c.innerHTML = 'Reader Text Color: <input type="text"> <br> Reader Background Color: <input type="text"> <br> Reader Text Color (Dark Mode): <input type="text"> <br> Reader Background Color (Dark Mode): <input type="text"> <br> <br> <h2>' + svga + ' Advanced Styling: </h2> <br> <textarea spellcheck="false" placeholder="Type CSS Code">' + CCSS + '</textarea> <br> <h2>' + svga + ' EPUB Styling: </h2> <br> <textarea spellcheck="false" placeholder="Type CSS Code">' + ECCSS + '</textarea> <br> <br> <button class="LN_btn"> Save </button>'; f.innerHTML = '<div> <h4> Replace </h4> <select> <option value="line"> Whole Line </option> <option value="word"> Word Only </option> </select> <h4> That </h4> <select> <option value="contains"> Contains </option> <option value="equals"> Equals </option> </select> <h4> This Value: </h4> <input type="text"> <h4> With: </h4> <input type="text" placeholder="Leave Empty to Remove"> <span class="LN_note"> ' + svgi + 'Note: <br> - Replaced word and the to be replaced word are both case-sensitive. <br> - "Word only" replacer with modifier "contains" uses RegExp. <br> - "Word only" replacer with modifier "equals" can contain HTML code, such as "< BR >". </span> </div> <h2> Rules: </h2> <br> <select size="6" style="width: 100%; padding: 0px;"> </select> <div style="display: inline-block;height: 50px;"> <button class="LN_btn" style="margin: 10px 2px;"> Add Rule </button> <button class="LN_btn" disabled="" style="right: 20px;position: absolute; margin: 10px -2px;"> Remove </button> </div>'; n.innerHTML = `<button class="LN_icob" title="Reader mode"> ${svgreader} </button> <button class="LN_icob" title="Settings"> ${svgsettings} </button> <button class="LN_icob" title="Previous Chapter"> ${svgarrowl} </button> <button class="LN_icob" title="Dark/Light Mode"> ${svgdarkm} </button> <button class="LN_icob" title="Next Chapter"> ${svgarrowr} </button> <button class="LN_icob" title="Extra actions"> ${svgsh} </button> </button> <button class="LN_icob2" title="Increase font size"> ${svgfi} </button> </button> <button class="LN_icob2" title="Decrease font size"> ${svgfd} </button> </button> <button class="LN_icob2" title="Auto scroll"> ${svgscroll} </button> </button> <button class="LN_icob2" title="Remove annoyances"> ${svgrema} </button> <button class="LN_icob2" title="Show novel's chapter index"> ${svgcontent} </button> `; l.innerHTML = '<div class=LN_loading></div>'; r.appendChild(document.querySelector(CS.chapter).cloneNode(true)); document.body.appendChild(s); document.body.appendChild(d); document.body.appendChild(m); document.body.appendChild(o); document.body.appendChild(c); document.body.appendChild(f); document.body.appendChild(r); document.body.appendChild(n); document.body.appendChild(l); if (location.host == 'www.lightnovelworld.com') document.querySelector('.navigation-bar').style.zIndex = 2, document.querySelector('.control-action').style.zIndex = 5; { let p = 50; m.querySelector('.LN_s').style.height = '-moz-fit-content'; m.querySelector('.LN_s').style.height = 'fit-content'; sch = m.querySelector('.LN_s').offsetHeight + p; m.querySelector('.LN_s').style.height = '0'; pch = 400; m.querySelector('.LN_p').style.height = '0'; m.querySelector('.LN_o').style.height = '-moz-fit-content'; m.querySelector('.LN_o').style.height = 'fit-content'; och = m.querySelector('.LN_o').offsetHeight + 130; m.querySelector('.LN_o').style.height = '0'; m.querySelector('.LN_d').style.height = '-moz-fit-content'; m.querySelector('.LN_d').style.height = 'fit-content'; dch = m.querySelector('.LN_d').offsetHeight + p; m.querySelector('.LN_d').style.height = '0'; m.querySelector('.LN_n').style.height = '-moz-fit-content'; m.querySelector('.LN_n').style.height = 'fit-content'; nch = m.querySelector('.LN_n').offsetHeight + p; m.querySelector('.LN_n').style.height = '0'; m.querySelector('.LN_b').style.height = '-moz-fit-content'; m.querySelector('.LN_b').style.height = 'fit-content'; bch = m.querySelector('.LN_b').offsetHeight + p; m.querySelector('.LN_b').style.height = '0'; m.querySelector('.LN_f').style.height = '-moz-fit-content'; m.querySelector('.LN_f').style.height = 'fit-content'; fch = m.querySelector('.LN_f').offsetHeight + p; m.querySelector('.LN_f').style.height = '0'; c.querySelector('textarea').style.height = '-moz-fit-content'; c.querySelector('textarea').style.height = 'fit-content'; tah = c.querySelector('textarea').offsetHeight || 200; c.querySelector('textarea').style.height = '0'; c.querySelector('textarea').style.display = 'none'; c.querySelectorAll('textarea')[1].style.height = '-moz-fit-content'; c.querySelectorAll('textarea')[1].style.height = 'fit-content'; etah = c.querySelectorAll('textarea')[1].offsetHeight || 200; c.querySelectorAll('textarea')[1].style.height = '0'; c.querySelectorAll('textarea')[1].style.display = 'none'; } document.body.onclick = document.body.ontouchstart = e => { let path = e.target; for (let i = 0; i < 6; i++) { if (path.LN_hasClass(['LN_menu', 'LN_alert', 'LN_styler', 'LN_overlay', 'LN_settings', 'LN_filter', 'LN_sidebar', 'LN_decincfs', 'LN_chapterin', '.LN_downloadCounter'])) return; else if (path.parentElement && path.parentElement.classList) path = path.parentElement; if (i == 5) { sh('sf'); sh('pf'); sh('of'); sh('df'); sh('nf'); sh('bf'); sh('ff'); sh('stf'); sh('cif'); sh('wff'); sh('menuf'); sh('etahf'); sh('tahf'); } } } s.onclick = () => { if (m.style.marginRight == '0' || m.style.marginRight == '0px') { sh('menuf'); sh('sf'); sh('of'); sh('df'); sh('nf'); sh('bf'); sh('ff'); sh('stf'); sh('wff'); } else sh('menut'); } m.querySelectorAll('h2')[0].onclick = () => { if (m.querySelector('.LN_s').style.height == '0' || m.querySelector('.LN_s').style.height == '0px') { sh('st'); sh('pf'); sh('of'); sh('df'); sh('nf'); sh('bf'); sh('ff'); } else sh('sf'); } m.querySelectorAll('h2')[1].onclick = () => { if (m.querySelector('.LN_p').style.height == '0' || m.querySelector('.LN_p').style.height == '0px') { sh('sf'); sh('pt'); sh('of'); sh('df'); sh('nf'); sh('bf'); sh('ff'); } else sh('pf'); } m.querySelectorAll('h2')[2].onclick = () => { if (m.querySelector('.LN_o').style.height == '0' || m.querySelector('.LN_o').style.height == '0px') { sh('sf'); sh('pf'); sh('ot'); sh('df'); sh('nf'); sh('bf'); sh('ff'); } else sh('of'); } m.querySelectorAll('h2')[3].onclick = () => { if (m.querySelector('.LN_d').style.height == '0' || m.querySelector('.LN_d').style.height == '0px') { sh('sf'); sh('pf'); sh('of'); sh('dt'); sh('nf'); sh('bf'); sh('ff'); } else sh('df'); } m.querySelectorAll('h2')[4].onclick = () => { if (m.querySelector('.LN_n').style.height == '0' || m.querySelector('.LN_n').style.height == '0px') { sh('sf'); sh('pf'); sh('of'); sh('df'); sh('nt'); sh('bf'); sh('ff'); } else sh('nf'); } m.querySelectorAll('h2')[5].onclick = () => { if (m.querySelector('.LN_b').style.height == '0' || m.querySelector('.LN_b').style.height == '0px') { sh('sf'); sh('pf'); sh('of'); sh('df'); sh('nf'); sh('bt'); sh('ff'); } else sh('bf'); } m.querySelectorAll('h2')[6].onclick = () => { if (m.querySelector('.LN_f').style.height == '0' || m.querySelector('.LN_f').style.height == '0px') { sh('sf'); sh('pf'); sh('of'); sh('df'); sh('nf'); sh('bf'); sh('ft'); } else sh('ff'); } m.querySelector('.LN_btn').onclick = () => { if (c.style.display == 'block') { sh('wff'); sh('stf'); sh('cif'); } else { sh('wff'); sh('cif'); sh('stt'); } } m.querySelectorAll('.LN_btn')[1].onclick = () => { if (f.style.display == 'block') { sh('wff'); sh('stf'); sh('cif'); } else { sh('stf'); sh('cif'); sh('wft'); } } c.querySelectorAll('h2')[0].onclick = () => { if (c.querySelectorAll('textarea')[0].style.display == 'block') sh('tahf'); else { sh('etahf'); sh('taht'); } } c.querySelectorAll('h2')[1].onclick = () => { if (c.querySelectorAll('textarea')[1].style.display == 'block') sh('etahf'); else { sh('tahf'); sh('etaht'); } } m.querySelector('.LN_dfs').style.fontFamily = m.querySelector('.LN_dfs').value; m.querySelector('.LN_dfs').addEventListener('change', function() { this.style.fontFamily = this.value; if (this.value == 'Custom') sh('dft'); m.querySelector('.LN_cancel').onclick = () => sh('dfs'); }); m.querySelector('.LN_ass').addEventListener('change', function() { if (this.value == 'Custom') sh('ast'); m.querySelectorAll('.LN_cancel')[1].onclick = () => sh('ass'); }); o.onclick = e => { sh('stf'); sh('wff'); sh('cif'); sh('tahf'); sh('etahf'); } let idlc = 0; r.addEventListener('click', () => { idlc = 0; r.querySelector(CS.chapter).style.cursor = 'text'; r.style.cursor = 'text'; }); r.addEventListener('mousemove', () => { idlc = 0; r.querySelector(CS.chapter).style.cursor = 'text'; r.style.cursor = 'text'; }); window.setInterval(() => { idlc++; if (idlc >= 5) { r.querySelector(CS.chapter).style.cursor = 'none'; r.style.cursor = 'none'; } }, 1000); window.addEventListener('click', e => { let found, elm = e.target; for (let i = 0; i < 6; i++) { if (elm.LN_hasClass(['LN_menu', 'LN_alert', 'LN_styler', 'LN_overlay', 'LN_settings', 'LN_filter', 'LN_sidebar', 'LN_decincfs', '.LN_chapterin', '.LN_downloadCounter'])) { found = true; break; } if (elm.parentElement) elm = elm.parentElement; } if (!found) sh('sidebar'); }); let currentfont = defaultf.replace(/'|"/g, ''); if (!fonts.includes(currentfont.toLowerCase())) { NLF.href = 'https://fonts.googleapis.com/css2?family=' + currentfont.replace(' ', '+') + '&display=swap'; let sl = m.querySelector('select'); document.head.appendChild(NLF); sl.lastElementChild.remove(); sl.options.add(new Option(currentfont, defaultf)); sl.options.add(new Option('Custom', 'Custom')); } let mobcss, mobcssf = () => { portcss.innerHTML = ` .LN_cmob { width: 100% !important; right: 0 !important; left: 0 !important; } .LN_fmob { width: 100% !important; right: 0 !important; left: 0 !important; } .LN_cmob textarea { width: 100% !important; } .LN_amob { font-size: 14px !important; max-width: 300px !important; margin: 0 ${(window.innerWidth - 300) / 2}px !important; } .LN_mob { padding: 20px !important; } .LN_bot { border-radius: 20px 20px 0 0 !important; } .LN_bot .LN_icob, .LN_bot .LN_icob2 { display: inline; padding: 0; margin: 10px 0; } `; if (!mobcss) mobcss = GM_addStyle(` .LN_menu { width: 300px !important; font-size: 14px !important; } .LN_menu .LN_s, .LN_menu h2:first-child, .LN_menu br:first-of-type { display: none !important; } .LN_menu h2 { font-size: 18px !important; } .LN_menu select { font-size: 16px; } `); }, inputsizes = (mode) => { if (mode) { for (let e of m.querySelectorAll('input')) e.size = 1; for (let e of c.querySelectorAll('input')) e.size = 1; for (let e of f.querySelectorAll('input')) e.size = 1; } else { for (let e of m.querySelectorAll('input')) e.size = 20; for (let e of c.querySelectorAll('input')) e.size = 20; for (let e of f.querySelectorAll('input')) e.size = 20; } }, robserver = new ResizeObserver(e => { let aside = n; if (window.innerWidth < window.innerHeight) { inputsizes(true); mobcssf(); r.querySelector(CS.chapter).classList.add('LN_mob'); a.classList.add('LN_amob'); c.classList.add('LN_cmob'); f.classList.add('LN_fmob'); aside.classList.remove('LN_side'); aside.classList.add('LN_bot'); s.style = 'display: none !important;'; aside.style = `bottom: 0; left: ${(r.offsetWidth - aside.offsetWidth) / 2}px;`; } else { inputsizes(false); r.querySelector(CS.chapter).classList.remove('LN_mob'); a.classList.remove('LN_amob'); c.classList.remove('LN_cmob'); f.classList.remove('LN_fmob'); aside.classList.add('LN_side'); aside.classList.remove('LN_bot'); s.style = 'display: block !important;'; aside.style = `top: ${(r.offsetHeight - aside.offsetHeight) / 2}px; left: 0;`; if (mobcss) { mobcss.remove(); mobcss = false; } } }); robserver.observe(r); if (window.innerWidth < window.innerHeight) { inputsizes(true); mobcssf(); r.querySelector(CS.chapter).classList.add('LN_mob'); a.classList.add('LN_amob'); c.classList.add('LN_cmob'); f.classList.add('LN_fmob'); n.classList.remove('LN_side'); n.classList.add('LN_bot'); s.style = 'display: none !important;'; setTimeout(() => { n.style = `bottom: 0; left: ${(window.innerWidth - n.offsetWidth) / 2}px;` }, 1000); } else { inputsizes(false); r.querySelector(CS.chapter).classList.remove('LN_mob'); a.classList.remove('LN_amob'); c.classList.remove('LN_cmob'); f.classList.remove('LN_fmob'); n.classList.add('LN_side'); n.classList.remove('LN_bot'); s.style = 'display: block !important;'; setTimeout(() => { n.style = `top: ${(window.innerHeight - n.offsetHeight) / 2}px; left: 0;` }, 1000); if (mobcss) { mobcss.remove(); mobcss = false; } } window.onresize = () => { if (window.innerWidth < window.innerHeight) { inputsizes(true); mobcssf(); r.querySelector(CS.chapter).classList.add('LN_mob'); a.classList.add('LN_amob'); c.classList.add('LN_cmob'); f.classList.add('LN_fmob'); n.classList.remove('LN_side'); n.classList.add('LN_bot'); s.style = 'display: none !important;'; n.style = `bottom: 0; left: ${(window.innerWidth - n.offsetWidth) / 2}px;`; } else { inputsizes(false); r.querySelector(CS.chapter).classList.remove('LN_mob'); a.classList.remove('LN_amob'); c.classList.remove('LN_cmob'); f.classList.remove('LN_fmob'); n.classList.add('LN_side'); n.classList.remove('LN_bot'); s.style = 'display: block !important;'; n.style = `top: ${(window.innerHeight - n.offsetHeight) / 2}px; left: 0;`; if (mobcss) { mobcss.remove(); mobcss = false; } } } fsbtn(); } function fsbtn() { if (!document.querySelectorAll('#LN_decincfs button')[0]) { const div = document.createElement('div'); r.querySelector(CS.chapter).style = ''; div.id = 'LN_decincfs'; div.classList.add('LN_decincfs'); div.style.display = 'none'; div.innerHTML = '<button>inc</button><button>dec</button>'; document.body.appendChild(div); const btn1 = div.querySelector('button'), btn2 = div.querySelectorAll('button')[1]; r.style.fontSize = defaultfs + 'px'; document.querySelector(CS.chapter).style.fontSize = defaultfs + 'px'; btn1.onclick = () => { document.querySelector(CS.chapter).style.fontSize = parseInt(document.querySelector(CS.chapter).style.fontSize) + 2 + 'px'; r.querySelector(CS.chapter).style = ''; fontcss.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { font-size: ${parseInt(getComputedStyle(r).fontSize) + 2}px !important; font-family: ${defaultf} !important; }`; } btn2.onclick = () => { document.querySelector(CS.chapter).style.fontSize = parseInt(document.querySelector(CS.chapter).style.fontSize) - 2 + 'px'; r.querySelector(CS.chapter).style = ''; fontcss.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { font-size: ${parseInt(getComputedStyle(r).fontSize) - 2}px !important; font-family: ${defaultf} !important; }`; } } else { r.querySelector(CS.chapter).style = ''; r.style.fontSize = defaultfs + 'px'; document.querySelector(CS.chapter).style.fontSize = defaultfs + 'px'; } } function sh(w) { switch (w) { case 'rt': r.style.display = 'block'; break; case 'rf': r.style.display = 'none'; break; case 'menut': m.style.marginRight = '0'; break; case 'menuf': m.style.marginRight = '-600px'; break; case 'st': m.querySelector('.LN_s').style.height = sch + 'px'; m.querySelectorAll('h2 svg')[0].style.transform = 'rotate(0deg)'; break; case 'sf': m.querySelector('.LN_s').style.height = '0'; m.querySelectorAll('h2 svg')[0].style.transform = 'rotate(-90deg)'; break; case 'pt': m.querySelector('.LN_p').style.height = pch + 'px'; m.querySelectorAll('h2 svg')[1].style.transform = 'rotate(0deg)'; break; case 'pf': m.querySelector('.LN_p').style.height = '0'; m.querySelectorAll('h2 svg')[1].style.transform = 'rotate(-90deg)'; break; case 'ot': m.querySelector('.LN_o').style.height = och + 'px'; m.querySelectorAll('h2 svg')[2].style.transform = 'rotate(0deg)'; break; case 'of': m.querySelector('.LN_o').style.height = '0'; m.querySelectorAll('h2 svg')[2].style.transform = 'rotate(-90deg)'; break; case 'dt': m.querySelector('.LN_d').style.height = dch + 'px'; m.querySelectorAll('h2 svg')[3].style.transform = 'rotate(0deg)'; break; case 'df': m.querySelector('.LN_d').style.height = '0'; m.querySelectorAll('h2 svg')[3].style.transform = 'rotate(-90deg)'; break; case 'nt': m.querySelector('.LN_n').style.height = nch + 'px'; m.querySelectorAll('h2 svg')[4].style.transform = 'rotate(0deg)'; break; case 'nf': m.querySelector('.LN_n').style.height = '0'; m.querySelectorAll('h2 svg')[4].style.transform = 'rotate(-90deg)'; break; case 'bt': m.querySelector('.LN_b').style.height = bch + 'px'; m.querySelectorAll('h2 svg')[5].style.transform = 'rotate(0deg)'; break; case 'bf': m.querySelector('.LN_b').style.height = '0'; m.querySelectorAll('h2 svg')[5].style.transform = 'rotate(-90deg)'; break; case 'ft': m.querySelector('.LN_f').style.height = fch + 'px'; m.querySelectorAll('h2 svg')[6].style.transform = 'rotate(0deg)'; break; case 'ff': m.querySelector('.LN_f').style.height = '0'; m.querySelectorAll('h2 svg')[6].style.transform = 'rotate(-90deg)'; break; case 'stt': c.style.display = 'block'; o.style.display = 'block'; c.style.right = (document.body.offsetWidth - c.offsetWidth) / 2 + 'px'; break; case 'stf': c.style.display = 'none'; o.style.display = 'none'; break; case 'wft': f.style.display = 'block'; o.style.display = 'block'; f.style.right = (document.body.offsetWidth - f.offsetWidth) / 2 + 'px'; break; case 'wff': f.style.display = 'none'; o.style.display = 'none'; break; case 'dct': d.style.right = '0px'; d.style.bottom = s.offsetHeight + 'px'; break; case 'dcf': d.style.right = '-600px'; d.style.bottom = s.offsetHeight + 'px'; break; case 'taht': c.querySelectorAll('h2 svg')[0].style.transform = 'rotate(0deg)'; c.querySelectorAll('textarea')[0].style.display = 'block'; c.querySelectorAll('textarea')[0].style.height = tah + 'px'; break; case 'tahf': c.querySelectorAll('h2 svg')[0].style.transform = 'rotate(-90deg)'; c.querySelectorAll('textarea')[0].style.display = 'none'; c.querySelectorAll('textarea')[0].style.height = '0'; break; case 'etaht': c.querySelectorAll('h2 svg')[1].style.transform = 'rotate(0deg)'; c.querySelectorAll('textarea')[1].style.display = 'block'; c.querySelectorAll('textarea')[1].style.height = etah + 'px'; break; case 'etahf': c.querySelectorAll('h2 svg')[1].style.transform = 'rotate(-90deg)'; c.querySelectorAll('textarea')[1].style.display = 'none'; c.querySelectorAll('textarea')[1].style.height = '0'; break; case 'cit': sh('wff'); sh('stf'); l.style.display = 'grid'; o.style.display = 'block'; l.style.left = (document.body.offsetWidth - l.offsetWidth) / 2 + 'px'; for (let e of l.querySelectorAll('a')) { let h = location.href.LN_fix(location.href); if (h.endsWith('/')) h = h.substr(0, h.length-1); if (e.href.LN_fix(location.href) == h) { l.scrollTo(0, e.offsetTop - e.offsetHeight); break; } } break; case 'cif': l.style.display = 'none'; o.style.display = 'none'; break; case 'dfs': m.querySelector('.LN_dfs').style.display = 'block'; m.querySelectorAll('.LN_note')[0].style.display = 'none'; m.querySelector('.LN_dfs').value = 'block'; m.querySelector('.LN_cancel').style.display = 'none'; m.querySelector('.LN_dft').style.display = 'none'; setTimeout(() => { for (let e of m.querySelector('.LN_dfs').options) { if (e.value == defaultf){ e.selected = true; m.querySelector('.LN_dfs').style.fontFamily = e.value; } } }, 100); break; case 'dft': m.querySelector('.LN_dfs').style.display = 'none'; m.querySelectorAll('.LN_note')[0].style.display = 'flex'; m.querySelector('.LN_cancel').style.display = 'inline-flex'; m.querySelector('.LN_dft').style.display = 'inline'; m.querySelector('.LN_dft').value = defaultf; break; case 'ass': m.querySelector('.LN_ass').style.display = 'block'; m.querySelectorAll('.LN_note')[1].style.display = 'none'; m.querySelectorAll('.LN_cancel')[1].style.display = 'none'; m.querySelector('.LN_ast').style.display = 'none'; setTimeout(() => { for (let e of m.querySelector('.LN_ass').options) if (e.value == autoscrolls) e.selected = true; }, 100); break; case 'ast': m.querySelector('.LN_ass').style.display = 'none'; m.querySelectorAll('.LN_note')[1].style.display = 'flex'; m.querySelectorAll('.LN_cancel')[1].style.display = 'inline-flex'; m.querySelector('.LN_ast').style.display = 'inline'; m.querySelector('.LN_ast').value = autoscrolls; break; case 'sidebar': if ((n.LN_hasClass('LN_side') && (n.style.marginLeft == '0' || n.style.marginLeft == '0px')) || (n.LN_hasClass('LN_bot') && (n.style.marginBottom == '0' || n.style.marginBottom == '0px'))) { if (n.LN_hasClass('LN_bot')) { n.style.marginLeft = '0px'; n.style.marginBottom = '-200px'; } else { n.style.marginBottom = '0px'; n.style.marginLeft = '-200px'; } } else { if (n.LN_hasClass('LN_bot')) { n.style.marginLeft = '0px'; n.style.marginBottom = '0px'; } else { n.style.marginBottom = '0px'; n.style.marginLeft = '0px'; } } break; } } function alt(msg, time=3000) { a.innerText = msg; a.style.cursor = 'default'; a.style.margin = '0 ' + (document.body.offsetWidth - 500) / 2 + 'px'; a.style.display = 'block'; setTimeout(() => { a.style.opacity = '1'; }, 100); setTimeout(() => { a.style.opacity = '0'; }, time); setTimeout(() => { a.style.display = 'none'; }, time + 600); } function getcontent(url, PL=CS, OBJ) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { try { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); OBJ.BODY = doc.body; OBJ.CHAPTER = OBJ.BODY.querySelector(PL.chapter); OBJ.NOVEL = OBJ.BODY.querySelector(PL.novel).innerText; if (url.includes('readlightnovel.me')) OBJ.CHAPTERTITLE = OBJ.BODY.querySelector('.block-title h1').lastChild.data; else if (url.includes('novelonlinefull') || url.includes('bestlightnovel')) OBJ.CHAPTERTITLE = OBJ.BODY.querySelector('.rdfa-breadcrumb p').lastChild.data; else if (url.includes('novels.pl')) OBJ.CHAPTERTITLE = OBJ.BODY.querySelector('.panel-title.pull-left').lastChild.data; else OBJ.CHAPTERTITLE = OBJ.BODY.querySelector(PL.chaptertitle).innerText; let title = OBJ.BODY.querySelector(PL.title).innerText; if (url.includes('novelfull.com') || url.includes('boxnovel.com')) title = OBJ.BODY.querySelector(PL.novel).innerText + ' - ' + OBJ.BODY.querySelector(PL.title).innerText; if (PL.othert != '') title = OBJ.BODY.querySelector(PL.othert).innerText + ' - ' + title; if (PL.name != '') for (let i = 0; i < PL.namer; i++) title = title.replace(PL.namer[i], PL.name[i]); OBJ.TITLE = [doc.title, OBJ.BODY.querySelector(PL.title).innerText, title]; } catch (e) { if (!OBJ.BODY) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Please try again later.\nReason: Might be request timeout, bad internet connection, spammed requests in a small time frame.', 10000); console.error(e); } else if (BOTCHECK(OBJ.BODY)) { if (confirm('Caught by bot verification.\nOpen url (' + url + ') in new tab?')) window.open(url, '_blank'); } else { alt('Error:\nDetails: Unexpected error has occured. Please try again later.\nReason: Might be request timeout, bad internet connection, another unexpected reason.', 10000); console.error(e); } } } }); } let oldtitle, oldurl, firsttitle, AUTHOR, IMAGE = {}, FONT = {}, NURL, CCC = 0, Dgetcover = async url => { GM_xmlhttpRequest({ method: 'GET', responseType: 'blob', url: url, onload: r => { IMAGE.code = new Blob([r.response], {type: 'image/' + IMAGE.link.getType()}); IMAGE.blob = window.URL.createObjectURL(IMAGE.code); } }) }, Dgetauthor = (url, PL) => { if (url.includes('lightnovelworld')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = doc.querySelector(PL.novel).href.LN_fix(url); let s = doc.querySelector('#chapter'), j = JSON.parse(s.innerHTML); for (let e in j) { for (let ee in j[e]) { for (let eee in j[e][ee]) if (eee == 'schema:author') AUTHOR = j[e][ee][eee]; } } } }); } else if (url.includes('wuxiax.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR = doc.querySelector('[itemprop="author"]').innerText; } }); } else if (url.includes('www.readwn.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR = doc.querySelector('[itemprop="author"]').innerText; } }); } else if (url.includes('lnreader.org')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc= new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR = doc.querySelector('a[href*=author]').innerText; } }); } else if (url.includes('readlightnovel.me')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; doc.querySelectorAll('.novel-detail-body a').forEach(item => { if (item.href.search('author') > 1) AUTHOR = item.innerText; }); } }); } else if (url.includes('novels.pl')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR = doc.querySelector('a[href*=author]').innerText; } }); } else if (url.includes('novelhall')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR = doc.querySelector('#author').innerText; } }); } else if (url.includes('novelfull.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR.link = doc.body.getAttribute('.info a'); } }); } else if (url.includes('novelonlinefull.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR.link = doc.body.querySelector('.truyen_info_right li:nth-of-type(2) a').innerText; } }); } else if (url.includes('bestlightnovel.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; AUTHOR.link = doc.body.querySelector('.truyen_info_right li:nth-of-type(2) a').innerText; } }); } }, Dlink = (url, PL) => { if (url.includes('lightnovelworld')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = doc.querySelector('[itemprop="image"]').href; } }); } if (url.includes('wuxiax')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = "https://www.wuxiax.com" + doc.querySelector('.cover img').getAttribute('data-src'); } }); } if (url.includes('readwn')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = "https://www.readwn.com" + doc.querySelector('.cover img').getAttribute('data-src'); } }); } if (url.includes('readlightnovel.me')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = doc.querySelector('[property="og:image"]').content; } }); } if (url.includes('lnreader.org')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = doc.querySelector('.novels-detail-left img').src.LN_fix(url); } }); } if (url.includes('novels.pl')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); IMAGE.link = doc.querySelector('[property="og:image"]').content; } }); } if (url.includes('novelhall')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; IMAGE.link = doc.body.getAttribute('.article-thumb'); } }); } if (url.includes('novelfull.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; IMAGE.link = doc.querySelector('.book img').src.LN_fix(url); } }); } if (url.includes('novelonlinefull.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; IMAGE.link = doc.querySelector('[property="og:image"]').content; } }); } if (url.includes('bestlightnovel.com')) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); NURL = url; IMAGE.link = doc.querySelector('[property="og:image"]').content; } }); } }, getfont = () => { GM_xmlhttpRequest({ url: 'https://fonts.googleapis.com/css2?family='+defaultf.replaceAll(' ', '+').replaceAll("'", ''), method: 'GET', onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), body = doc.body; let a = body.innerText.substr(body.innerText.search('latin ') + 9), b = a.substr(a.search('url')+4, a.search('format') - 6 - a.search('url')); GM_xmlhttpRequest({ url: b, method: 'GET', responseType: 'blob', onload: r => { FONT.font = defaultf.replace("'", ''); FONT.code = new Blob([r.response], {type: 'font/woff2'}); FONT.blob = window.URL.createObjectURL(new Blob([r.response], {type: 'font/woff2'})); } }); } }); }, Dcont = [], Dalt = false; function genEPUB(options, content, url, auto=false, index, single, title, OBJ) { let NOVEL = OBJ.NOVEL, zip = new JSZip(), metainf = zip.folder('META-INF'), oeb = zip.folder('OEBPS'), chapters = oeb.folder('Chapters'), images = oeb.folder('Images'), fonts = oeb.folder('Fonts'), styles = oeb.folder('Styles'), printMeta = () => { let text = ''; content.forEach((obj, i) => { text += `<navPoint id="body${i}" playOrder="${i}"><navLabel><text>${obj.title}</text></navLabel><content src="Chapters/Section_${i}.xhtml"/></navPoint>`; }); return text; }, items = () => { let text = ''; content.forEach((obj, i) => { text += `<item id="xhtml${i}" href="Chapters/Section_${i}.xhtml" media-type="application/xhtml+xml"/>`; }); return text; }, spine = () => { let text = ''; content.forEach((obj, i) => { text += `<itemref idref="xhtml${i}"/>`; }); return text; }, list = () => { let text = ''; content.forEach((obj, i) => { text += `<li> <a href="../Chapters/Section_${i}.xhtml">${obj.title}</a> </li>`; }); return text; }, date = () => { let bdate = new Date; bdate.setMilliseconds(0); return bdate.toISOString().replace('.000', ''); }, xmls = { container: `<?xml version="1.0" encoding="utf-8"?> <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"> <rootfiles> <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/> </rootfiles> </container>`, contentopf: `<?xml version="1.0" encoding="utf-8"?> <package version="3.0" unique-identifier="BookId" xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/"> <metadata> <dc:creator>EPUB generated by XDHx86 script LN LOADER check it out on https://openuserjs.org/users/XDHx86/</dc:creator> <dc:source>${NURL}</dc:source> <dc:title id="title">${options.title.replaceAll('\n', '')}</dc:title> <dc:language>en-US</dc:language> <dc:identifier id="BookId">urn:uuid:${options.uid}</dc:identifier> <dc:creator id="creator">XDHx86</dc:creator> <meta refines="#title" property="title-type">main</meta> <meta refines="#creator" property="file-as">${options.author || 'Unknown'}</meta> <meta property="dcterms:modified">${date()}</meta> <meta name="calibre:series" content="${NOVEL}"/> <meta name="calibre:series_index" content="00"/> <meta name="cover" content="cover.${options.cover.type}"/> </metadata> <manifest> <item id="css" href="Styles/css.css" media-type="text/css"/> ${options.font ? `<item id="font" href="Fonts/font.woff2" media-type="font/woff2"/>` : ''} <item id="cover.${options.cover.type}" href="Images/Cover.${options.cover.type}" media-type="image/${options.cover.type}" properties="cover-image"/> ${items()} <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/> <item id="cover.xhtml" href="Chapters/cover.xhtml" media-type="application/xhtml+xml"/> <item id="nav" href="Chapters/toc.xhtml" media-type="application/xhtml+xml" properties="nav"/> </manifest> <spine toc="ncx"> <itemref idref="cover.xhtml"/> ${spine()} </spine> <guide> <reference type="cover" title="Cover" href="Chapters/cover.xhtml"/> </guide> </package>`, tocncx: `<?xml version="1.0" encoding="utf-8"?> <ncx version="2005-1" xml:lang="en-US" xmlns="http://www.daisy.org/z3986/2005/ncx/"> <head> <meta content="urn:uuid:${options.uid}" name="dtb:uid"/> <meta content="2" name="dtb:depth"/> <meta content="0" name="dtb:totalPageCount"/> <meta content="0" name="dtb:maxPageNumber"/> </head> <docTitle> <text>${NOVEL}</text> </docTitle> <navMap>${printMeta()}</navMap> </ncx>`, tocxml: `<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" xmlns:epub="http://www.idpf.org/2007/ops" lang="en-US"> <head> <title>Table of Contents</title> </head> <body> <nav epub:type="toc" id="toc"> <h1>Table of Contents</h1> <ol> ${list()} </ol> </nav> <nav epub:type="landmarks" id="landmarks" hidden=""> <h1>Landmarks</h1> <ol> <li> <a epub:type="cover" href="../Chapters/cover.xhtml">Cover</a> </li> </ol> </nav> </body> </html>`, cover: `<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"> <head> <title> Cover </title> </head> <body> <img src="../Images/Cover.${options.cover.type}"/> </body> </html>`, css: `${options.font ? `@font-face {font-family: '${options.font}'; src: url('../Fonts/font.woff2') format('woff2'); } p {font-family: '${options.font}'; }` : ''} p { text-indent: 3%; }` }, down = (f, n) => { const a = document.createElement('a'); a.href = window.URL.createObjectURL(f); a.download = n + '.epub'; document.body.appendChild(a); a.click(); setTimeout(() => { a.remove(); }, 10000); } zip.file('mimetype', 'application/epub+zip', { compression: 'STORE', compressionOptions: { level: 0 } }); oeb.file('content.opf', xmls.contentopf); oeb.file('toc.ncx', xmls.tocncx); chapters.file('toc.xhtml', xmls.tocxml); chapters.file('cover.xhtml', xmls.cover); metainf.file('container.xml', xmls.container); styles.file('css.css', xmls.css); options.font ? fonts.file('font.woff2', options.woff2) : ''; content.forEach((obj, i) => { let text = `<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link href="../Styles/css.css" type="text/css" rel="stylesheet"/> <title> ${obj.title} </title> </head> <body> <h1> ${obj.title} </h1> <hr /> ${obj.content} </body> </html>`; chapters.file('Section_' + i + '.xhtml', text); }); images.file('Cover.' + options.cover.type, options.cover.code); zip.generateAsync({ type: 'blob', mimeType: 'application/epub+zip', compression: 'DEFLATE', compressionOptions: { level: 9 } }).then(function(file) { setTimeout(() => { GM_notification('EPUB generating is complete (' + NOVEL +'), Enjoy!\nIf you encountered any issues feedback is very appreciated! EPUB downloading is still in experimental phase.', 'EPUB generating is complete (' + NOVEL + '), Enjoy!') window.LN_downloading = false; if (m.querySelectorAll('.LN_btn')[2]) { m.querySelectorAll('.LN_btn')[3].disabled = false; m.querySelectorAll('.LN_btn')[2].disabled = false; m.querySelectorAll('.LN_btn')[2].innerText = 'Download'; } down(file, options.title); d.innerHTML = 'Download complete. Enjoy!' setTimeout(() => { sh('dcf'); }, 4000); setTimeout(() => { if (!auto) { if (location.href != url) { if (confirm('Download complete.\nRedirecting to last chapter downloaded (' + title.replace(/\n|\t|«/gm, '') + ')')) window.open(url, '_self'); } else alert('Download compelete.'); } else if (!single) downnew(index); else alert('Download compelete.'); }, 10000); }, 10000); }); } let downchp = 0, warned, epubsups = ['www.readlightnovel.me', 'readlightnovel.me', 'www.lightnovelworld.com', 'www.wuxiax.com', 'lnreader.org', 'www.lnreader.org', 'novels.pl', 'www.readwn.com', 'www.novelhall.com', 'novelfull.com', 'novelonlinefull.com', 'bestlightnovel.com']; let ogn; function Download(url, n=1, retries=0, auto=false, index, PL=CS, single, OBJ={}) { let allowbtn = () => { m.querySelectorAll('.LN_btn')[2].disabled = false; m.querySelectorAll('.LN_btn')[2].innerText = 'Download'; m.querySelectorAll('.LN_btn')[3].disabled = false; m.querySelectorAll('.LN_btn')[4].disabled = false; }, cancel = () => { window.LN_downloading = false; window.LN_canceldownload = false; alt('Download canceled.'); if (auto && !single && !window.LN_cancelauto) downnew(index + 1); window.LN_cancelauto = false; if (m.querySelector('.LN_btn')) allowbtn(); warned = false; } if (url.includes('lightnovelworld') && !warned && document.querySelector('.login-wrap-nav').innerText.toUpperCase() == 'SIGN IN') { warned = true; if (!confirm('To download from LNW you have to be logged in since many chapters are only avialable to the signed-in user\nTo continue press OK else sign in and try again')) { cancel(); return; } } window.LN_downloading = true; if (window.LN_canceldownload) { cancel(); return; } if (!ogn) ogn = n; n--; if (CCC < 10) Dgetcover(IMAGE.link), CCC++; getcontent(url, PL, OBJ); downchp++; if (d) sh('dct'), d.innerHTML = svgdd + ' Downloading Chapters: ' + downchp + '/' + ogn; if (downchp%100 == 0 && downloadt && epubsups.includes(url.LN_host())) alt(downchp+' chapters finished, it\'s not stuck. Don\'t worry.'); const action = setTimeout(() => { try { let NOVEL = OBJ.NOVEL, BODY = OBJ.BODY, CHAPTER = OBJ.CHAPTER, TITLE = OBJ.TITLE, CHAPTERTITLE = OBJ.CHAPTERTITLE; const down = () => { if (downloadt && epubsups.includes(url.LN_host())) { GM_notification('Chapters Loading is complete (' + NOVEL + ')\nGenerating EPUB this may take up to 5 minutes depending on the number of chapters downloaded.\nJust Wait for the download to begin.', 'Chapters loading is complete. (' + url.LN_platform() + ')'); let Dopts = { author: AUTHOR, cover: { link: IMAGE.link, type: IMAGE.link.getType(), code: IMAGE.code }, uid: ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)), title: `${NOVEL.replacer()} (${firsttitle.replace(NOVEL, '').replace('-', '')} - ${title.replace(NOVEL, '').replace('-', '')})`, font: FONT.font.replaceAll("'", ''), woff2: FONT.code } OBJ.url = a; genEPUB(Dopts, Dcont, url, auto, index, single, title, OBJ); d.innerHTML = svgdd + ' Generating EPUB' } else { if (downloadt && !confirm('EPUB downloading isn\'t supported for this site, it will be downloaded as PDF. Continue?')) { cancel(); return; } pdf.save(title.replaceAll('«', '') + '.pdf'); setTimeout(() => { window.LN_downloading = false; if (m.querySelectorAll('.LN_btn')[2]) allowbtn(); setTimeout(() => { if (!auto) { if (location.href != url) { if (confirm('Download complete.\nRedirecting to last chapter downloaded (' + title.replace(/\n|\t|«/gm, '') + ')')) window.open(url, '_self'); } else alert('Download compelete.'); } else if (!single) downnew(index); else alert('Download compelete.'); }, 5000); }, 3000); } } if (TITLE) { if (TITLE[2].includes('Teaser')) { window.LN_downloading = false; window.LN_canceldownload = false; window.LN_cancelauto = false; if (m.querySelector('.LN_btn')) allowbtn(); if (!auto) { if (location.href != url) { if (confirm('Download complete.\nRedirecting to last chapter downloaded (' + oldtitle.replace(/\n|\t|«/gm, '') + ')')) window.open(BODY.querySelector(PL.prev).href, '_self'); } else alert('Download compelete.'); } else if (!single) downnew(index); else alert('Download compelete.'); return; } if (TITLE[2] == oldtitle && n >= 0) { alt('Network latency high or server denied access, retrying...'); retry({ callback: Download, url: url, n: n, auto: auto, dindex: index, PL: PL, single: single, retries: retries + 1, origin: url, OBJ: OBJ }); return; } } let body = BODY, chapter = CHAPTER, title = TITLE[2]; oldtitle = title; oldurl = url; if (!firsttitle) firsttitle = title; removeannon(chapter, true, PL); record('', body, PL, url, true); let content = chapter.innerText, econtent = chapter.innerHTML, pdf = new jsPDF(); if (!downloadt || !epubsups.includes(url.LN_host())) { if (content.search(/\w+/gm) > 2) content = content.substr(content.search(/\w+/gm)); function wrap(text, textWidth, doc, fontSize = 10, fontType = 'normal', lineSpacing = 7, xPosition = 10, initialYPosition = 20, pageWrapInitialYPosition = 20) { let textLines = doc.splitTextToSize(text, textWidth), pageHeight = doc.internal.pageSize.height, cursorY = initialYPosition; doc.setFontType(fontType); doc.setFontSize(fontSize); textLines.forEach(lineText => { if (cursorY > pageHeight) { doc.addPage(); cursorY = pageWrapInitialYPosition; } doc.text(xPosition, cursorY, lineText); cursorY += lineSpacing; }); } wrap(content, 210 - 10 - 10, pdf, 16); } else { let t = n*2, m = (t/60).toFixed(), s = ((t/60 % 1) * 60).toFixed(); if (downloadt && !Dalt && epubsups.includes(url.LN_host())) { setTimeout(() => alt('Please wait, downloading chapters then generating Epub. This will take approximately ' + m + ' minute(s) ' + s + ' seconds. (Time is calculated based on number of chapters requested to be downloaded (' + parseInt(n + 1) +') NOT how many chapters the novel has.)\nIt will notify when it\'s done.', 10000), 6000); let url2; if (url.includes('wuxiax') || url.includes('lnreader') || url.includes('novels.pl') || url.includes('www.readwn.com') || url.includes('novelfull.com')) url2 = BODY.querySelector(PL.novel).href.LN_fix(url); Dgetauthor(url2 || url, PL); if (url.includes('readlightnovel') || url.includes('novels.pl')) url2 = undefined; Dlink(url2 || url); getfont(); } Dalt = true; let fcontent = econtent; if (url.includes('readlightnovel.me')) { let b = document.createElement('div'); for (let e of chapter.childNodes) { if (e.nodeName != '#text') e.remove(); else { let p = document.createElement('p'); p.innerText = e.data; b.appendChild(p); } } b.innerHTML = b.innerHTML.replaceAll('<br>', ''); for (let e of b.childNodes) if (e.innerText.search(/\w/) == -1) e.remove(); fcontent = b.innerHTML; } Dcont.push({ title: CHAPTERTITLE.replacer(), content: fcontent }); } if (n == 0) down(); if (n >= 1) { let nurl = body.querySelector(PL.next); if (url.includes('novelonlinefull') || url.includes('bestlightnovel')) { let nn; for (let e of body.querySelectorAll('a')) if (/NEXT CHAPTER/ig.test(e.innerText) || e.innerText == 'Next »') nn = e; nurl = nn; } if (nurl && nurl.href) nurl.href = nurl.href.LN_fix(url); if (nurl && nurl.href && (!(nurl.href.endsWith('#') && nurl.href.includes(url))) && (nurl.href.split(url.LN_host())[1] && nurl.href.split(url.LN_host())[1].split('/')[1].toLowerCase() == url.split(url.LN_host())[1].split('/')[1].toLowerCase()) && nurl.href != url) { nurl = nurl.href; Download(nurl, n, 0, auto, index, PL, single); } else down(); } } catch (e) { console.error(e); clearTimeout(action); if (!OBJ.BODY) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Retrying...', 10000); retry({ callback: Download, url: url, n: n, auto: auto, index: index, PL: PL, single: single, retries: retries + 1, origin: url, OBJ: OBJ }); } else if (BOTCHECK(OBJ.BODY)) { if (m.querySelector('.LN_btn')) allowbtn(); if (confirm('Caught by bot verification.\nClick OK to open url (' + url + ') in new tab, the script will try again in 5 seconds.\nYou can also press cancel to cancel the download.')) { window.open(url, '_blank'); Download(url, n, auto, index, PL, single, retries, OBJ) } } else { alt('Error:\nDetails: Unexpected error has occured. Retrying...', 10000); retry({ callback: Download, url: url, n: n, auto: auto, index: index, PL: PL, single: single, retries: retries + 1, origin: url, OBJ: OBJ }); } } }, 2000); } function set() { let inputst = m.querySelectorAll('.LN_s input[type=text]'), inputsr = m.querySelectorAll('input[type=radio]'), inputsn = m.querySelectorAll('input[type=number]:not([max="10000"])'), current = m.querySelector('.LN_current'), selects = m.querySelectorAll('select'), down = m.querySelectorAll('.LN_btn')[2], canceldown = m.querySelectorAll('.LN_btn')[3], cancelauto = m.querySelectorAll('.LN_btn')[4], addtof = m.querySelectorAll('.LN_btn')[5], updates = m.querySelectorAll('.LN_btn')[6], cancelupdate = m.querySelectorAll('.LN_btn')[7], fav = m.querySelectorAll('.LN_btn')[8], backup = m.querySelectorAll('.LN_btn')[9], restore = m.querySelectorAll('.LN_btn')[10], feba = m.querySelectorAll('.LN_btn')[11], save = m.querySelectorAll('.LN_btn')[12], reset = m.querySelectorAll('.LN_btn')[13], mreader = n.querySelectorAll('button')[0], msettings = n.querySelectorAll('button')[1], mprev = n.querySelectorAll('button')[2], mdarkm = n.querySelectorAll('button')[3], mnext = n.querySelectorAll('button')[4], msh = n.querySelectorAll('button')[5], mif = n.querySelectorAll('button')[6], mdf = n.querySelectorAll('button')[7], mas = n.querySelectorAll('button')[8], mra = n.querySelectorAll('button')[9], mdn = n.querySelectorAll('button')[10], inputsc = c.querySelectorAll('input'), savec = c.querySelector('.LN_btn'), textc = c.querySelectorAll('textarea')[0], etextc = c.querySelectorAll('textarea')[1], selectl = f.querySelectorAll('select')[0], selectt = f.querySelectorAll('select')[1], selectr = f.querySelectorAll('select')[2], word = f.querySelectorAll('input')[0], rword = f.querySelectorAll('input')[1], addwf = f.querySelectorAll('.LN_btn')[0], remwf = f.querySelectorAll('.LN_btn')[1], radios = [autora, autonc, autodl, downloadt, autoresume, defaultv, scrollt, swipeg, autodmode, decensore, allowconfirm, uselastr, checkcomp, autoretry, nnotfound, autoch, autodown], radiosn = ['autora', 'autonc', 'autodl', 'downloadt', 'autoresume', 'defaultv', 'scrollt', 'swipeg', 'autodmode', 'decensore', 'allowconfirm', 'uselastr', 'checkcomp', 'autoretry', 'nnotfound', 'autoch', 'autodown'], valst = [fullscreen, next, nexta, nextaa, prev, preva, prevaa, darkmode, incfs, decfs, removean, download, autoscroll, showfavs], valstn = ['fullscreen', 'next', 'nexta', 'nextaa', 'prev', 'preva', 'prevaa', 'darkmode', 'incfs', 'decfs', 'removean', 'download', 'autoscroll', 'showfavs'], valsn = [autoscrolls, defaultfs, pmargin, lheight, autoncd, dmtime, lmtime, autoretryno, autobackupp], valsnn = ['autoscrolls', 'defaultfs', 'pmargin', 'lheight', 'autoncd', 'dmtime', 'lmtime', 'autoretryno', 'autobackupp'], valsc = [txc, bgc, dtxc, dbgc], valscn = ['txc', 'bgc', 'dtxc', 'dbgc'], help = m.querySelectorAll('.LN_help'), downinput = m.querySelector('input[max="10000"]'), checktinput = m.querySelector('input[type=time]'); downinput.onkeydown = function(e) { if (e.key != 'Enter') return; this.blur(); down.click(); } checktinput.value = checkd; checktinput.setAttribute('ln-name', 'checkd'); checktinput.onchange = checktinput.onblur = function() { if (!this.value) { this.value = checkd; alt('Invalid value!'); this.setCustomValidity('Invalid value!'); this.reportValidity(); } } checktinput.onfocus = function() { this.setCustomValidity(''); } for (let i = 0; i < inputst.length; i++) { inputst[i].value = valst[i]; inputst[i].setAttribute('ln-og', inputst[i].value); inputst[i].setAttribute('ln-name', valstn[i]); inputst[i].onkeydown = e => { if ((e.shiftKey && e.code != 'Tab') || /tab/i.test(e.code)) return; else e.preventDefault(); } inputst[i].onkeyup = function(e) { if (/enter|capslock|f[0-9]|home|end|pageup|pagedown|insert|numlock|backquote/i.test(e.code)) alt('No special characters allowed!'); else if (e.ctrlKey || e.altKey || e.metaKey || (e.shiftKey && e.code != 'Tab')) alt('No special characters allowed!'); else if (e.code == 'Delete' || e.code == 'Backspace') this.value = this.getAttribute('ln-og'); else if (e.code == 'Escape') this.blur(); else if (!/control|shift|alt|meta|osl|osr/i.test(e.code) && e.code != 'Tab') this.value = e.code; } inputst[i].onblur = function() { if (!/digit|numpad|key|space|bracket|semi|comma|period|slash|(^quote)|minus|arrow|equal/i.test(this.value)) { alt('No special characters allowed!'); this.value = this.getAttribute('ln-og'); } let v = this.value.toLowerCase(), a = inputst, c = []; for (let e of a) c.push(e.value.toLowerCase()); if (c.indexOf(v) != c.lastIndexOf(v)) { alt('This value is already assigned!'); this.value = this.getAttribute('ln-og'); } } } for (let i = 0; i < inputsn.length; i++) { inputsn[i].value = valsn[i]; inputsn[i].setAttribute('ln-og', inputsn[i].value); inputsn[i].setAttribute('ln-name', valsnn[i]); inputsn[i].onblur = function() { if (isNaN(parseInt(this.value)) || this.value > parseInt(this.max) || this.value < parseInt(this.min) || (!this.step && this.value % 1 != 0) || (this.step && this.value / this.step % 1 != 0)) { this.blur(); this.onfocus = function() { this.onfocus = null; this.setCustomValidity(''); } alt(`Invalid value! No more than ${this.max} nor less than ${this.min} ${this.step ? `and is divisible by ${this.step}` : 'and no decimals'}.`, 7000); this.value = this.getAttribute('ln-og'); } } } { for (let i = 0; i < radios.length; i++) { if (radios[i] === true) inputsr[i*2].checked = true; else inputsr[i*2+1].checked = true; } let search = selects[0].options.LN_search(defaultf); if (search.found) { search.obj.selected = true; selects[0].style.fontFamily = search.obj.value; } search = selects[1].options.LN_search(autoscrolls); if (search.found) search.obj.selected = true; else { selects[1].lastElementChild.remove(); selects[1].options.add(new Option(autoscrolls, autoscrolls)); selects[1].options.add(new Option('Custom', 'Custom')); search = selects[1].options.LN_search(autoscrolls); search.obj.selected = true; } for (let i = 1; i < RULES.length; i++) selectr.add(new Option(RULES[i].word, RULES[i].word), selectr[0]); } for (let i = 0; i < inputsc.length; i++) { inputsc[i].value = valsc[i]; inputsc[i].setAttribute('ln-og', inputsc[i].value); inputsc[i].setAttribute('ln-name', valscn[i]); } for (let elm of help) elm.onclick = () => window.open('https://openuserjs.org/scripts/XDHx86/Light_Novel_Loader#notes'); current.onclick = () => { current.previousElementSibling.value = getComputedStyle(r).fontSize.split('px')[0]; } savec.onclick = () => { let a = [], validate = c => { let img = document.createElement('img'); img.style = 'background: rgb(0, 0, 0)'; img.style = 'background: ' + c; if (img.style.background != 'rgb(0, 0, 0)' && img.style.background != '') return true; img.style = 'background: rgb(255, 255, 255)'; img.style = 'background: ' + c; return (img.style.background != 'rgb(255, 255, 255)' && img.style.background != ''); }; for (let e of inputsc) { if (!validate(e.value)) { e.setCustomValidity('Invalid value!'); e.reportValidity(); e.onfocus = function() { this.setCustomValidity('Invalid value!'); this.reportValidity(); } e.onchange = function() { this.onchange = null; this.onfocus = null; this.setCustomValidity(''); } } else a.push(e.value); } if (a.length == 4) { for (let e of inputsc) GM_setValue(e.getAttribute('ln-name'), e.value); GM_setValue('CCSS', textc.value); GM_setValue('ECCSS', etextc.value); rvals(); ucss(0); alt('Settings will take effect immediately!'); } } feba.onclick = feedback; save.onclick = () => { if (m.querySelector(':invalid')) { alt('There are some invalid values, cannot save settings. Please check the values again.'); return; } for (let e of inputst) if (e.getAttribute('ln-name')) GM_setValue(e.getAttribute('ln-name'), e.value); for (let e of inputsn) if (e.getAttribute('ln-name')) GM_setValue(e.getAttribute('ln-name'), e.value); for (let i = 0; i < radios.length; i++) { if (inputsr[i*2].checked) GM_setValue(radiosn[i], true); else GM_setValue(radiosn[i], false); } if (selects[0].style.display == '' || selects[0].style.display == 'block') GM_setValue('defaultf', selects[0].value); else GM_setValue('defaultf', m.querySelector('.LN_dft').value); if (selects[1].style.display == '' || selects[1].style.display == 'block') GM_setValue('autoscrolls', selects[1].value); else GM_setValue('autoscrolls', parseInt(m.querySelector('.LN_ast').value)); rvals(); let currentfont = defaultf.replace(/'|"/g, ''); if (!fonts.includes(currentfont.toLowerCase())) { NLF.href = 'https://fonts.googleapis.com/css2?family=' + currentfont.replace(' ', '+') + '&display=swap'; document.head.appendChild(NLF); const search = selects[0].options.LN_search(defaultf); if (!search.found) { selects[0].lastElementChild.remove(); selects[0].options.add(new Option(currentfont, defaultf)); selects[0].options.add(new Option('Custom', 'Custom')); } } liningcss.innerHTML = ` .LN_chapter * { line-height: ${lheight}; } .LN_chapter p { margin: ${pmargin}px 0; text-align: start; }`; ucss(2); alt('Settings will take effect immediately!'); } down.onclick = () => { let link; if (CS.novel != '') link = document.querySelector(CS.novel).href; else { link = location.href.split('/'); if (link[link.length - 1] == '') { link.pop(); link.pop(); } else link.pop(); link = link.join('/'); } if (!FAVS.LN_deepSearch(link).found) { if (confirm('This novel is not in favorites, do you want to add it?')) addtof.click(); } if (!isNaN(parseInt(downinput.value)) && downinput.value >= 1 && downinput.value <= 10000 && downinput.value % 1 == 0) { alt('Download started.\nYou can still read from this page while downloading.'); down.disabled = true; down.innerText = 'Downloading..'; Dcont = []; Dalt = false; Download(location.href, downinput.value); } else { downinput.setCustomValidity('Invalid value!'); downinput.reportValidity(); downinput.onfocus = function() { downinput.onfocus = null; downinput.setCustomValidity(''); } alt(`Invalid value! No more than ${downinput.max} nor less than ${downinput.min} and NO decimals.`, 7000); return; } } canceldown.onclick = () => { window.LN_canceldownload = true; window.LN_cancelauto = false; alt('Please wait.'); canceldown.disabled = true; } cancelauto.onclick = () => { window.LN_canceldownload = true; window.LN_cancelauto = true; alt('Please wait.'); cancelauto.disabled = true; } reset.onclick = () => { if (confirm('Are you sure you want to reset the script? This will reset ALL the settings and records!')) { GM_setValue('firsttime', true); if (confirm('Settings will take effect after reload.\nReload now?')) location.reload(); } } window.addEventListener('keyup', e => { if (e.code == 'Escape') dofull(true); }); let swiperhp = false; r.onscroll = () => { { let a = r.scrollTop, b = r.scrollHeight - r.clientHeight - 100, c = { pos: a, link: location.href }; const search = laststop.LN_search(location.href); if (a > 100) { if (!search.found) { laststop.push(c); GM_setValue('laststop', laststop); } else { laststop[search.index].pos = a; GM_setValue('laststop', laststop); } } else { if (search.found) { laststop.splice(search.index, 1); GM_setValue('laststop', laststop); } } if (a >= b) { laststop.splice(laststop.indexOf(c), 1); GM_setValue('laststop', laststop); setTimeout(() => { KEY.code = next; if (autonc) handler(KEY); }, (autoncd * 1000)); } } { let swiper = r.querySelector('.LN_swiper'); if (!swiper && !swiperhp) { let d = document.createElement('div'); d.className = 'LN_swiper'; d.innerHTML = `<span> Scroll down to go to next chapter </span>`; r.appendChild(d); return; } if (swipeg) { if (autonc) autonc = false; if (r.firstElementChild.LN_hasClass('LN_swiper')) r.appendChild(swiper); const swiperh = n => { if (swiperhp) return; let h = swiper.offsetHeight; swiper.style.height = (h + n) + 'px'; } if ((r.scrollHeight - r.clientHeight) - r.scrollTop <= 5 && !swiperhp) swiperh(40); if (swiper && (swiper.offsetHeight / r.clientHeight) > 0.45) { swiper.remove(); swiperhp = true; alt('Loading the next chapter.', 1000); KEY.code = next; handler(KEY); setTimeout(() => { swiperhp = false; }, 5000); } } } } addtof.onclick = () => { let link; if (CS.novel != '') link = document.querySelector(CS.novel).href; else { link = location.href.split('/'); if (link[link.length - 1] == '') { link.pop(); link.pop(); } else link.pop(); link = link.join('/'); } favthis(link); alt('Please Wait.'); } fav.onclick = favs; updates.onclick = () => { alt('Please wait while the script searches for new chapters.', 5000); updates.innerText = 'Checking...'; updates.disabled = true; notify(); } cancelupdate.onclick = () => { window.LN_cancelcheck = true; alt('Please wait.'); cancelupdate.disabled = true; } backup.onclick = () => br(0); restore.onclick = () => br(1); mreader.onclick = () => dofull(); msettings.onclick = () => s.click(); mprev.onclick = () => { KEY.code = prev; handler(KEY); } mdarkm.onclick = () => { KEY.code = darkmode; handler(KEY); } mnext.onclick = () => { KEY.code = next; handler(KEY); } msh.onclick = () => { if (msh.querySelector('svg').style.transform == 'rotate(180deg)') { msh.querySelector('svg').style.transform = 'rotate(0deg)'; mdf.classList.remove('LN_icob'); mif.classList.remove('LN_icob'); mas.classList.remove('LN_icob'); mra.classList.remove('LN_icob'); mdn.classList.remove('LN_icob'); mdf.classList.add('LN_icob2'); mif.classList.add('LN_icob2'); mas.classList.add('LN_icob2'); mra.classList.add('LN_icob2'); mdn.classList.add('LN_icob2'); mreader.classList.add('LN_icob'); msettings.classList.add('LN_icob'); mprev.classList.add('LN_icob'); mdarkm.classList.add('LN_icob'); mnext.classList.add('LN_icob'); mreader.classList.remove('LN_icob2'); msettings.classList.remove('LN_icob2'); mprev.classList.remove('LN_icob2'); mdarkm.classList.remove('LN_icob2'); mnext.classList.remove('LN_icob2'); } else { msh.querySelector('svg').style.transform = 'rotate(180deg)'; mdf.classList.add('LN_icob'); mif.classList.add('LN_icob'); mas.classList.add('LN_icob'); mra.classList.add('LN_icob'); mdn.classList.add('LN_icob'); mdf.classList.remove('LN_icob2'); mif.classList.remove('LN_icob2'); mas.classList.remove('LN_icob2'); mra.classList.remove('LN_icob2'); mdn.classList.remove('LN_icob2'); mreader.classList.remove('LN_icob'); msettings.classList.remove('LN_icob'); mprev.classList.remove('LN_icob'); mdarkm.classList.remove('LN_icob'); mnext.classList.remove('LN_icob'); mreader.classList.add('LN_icob2'); msettings.classList.add('LN_icob2'); mprev.classList.add('LN_icob2'); mdarkm.classList.add('LN_icob2'); mnext.classList.add('LN_icob2'); } } mdf.onclick = () => { KEY.code = decfs; handler(KEY); } mif.onclick = () => { KEY.code = incfs; handler(KEY); } mas.onclick = () => { KEY.code = autoscroll; handler(KEY); sh('sidebar'); } mra.onclick = () => { KEY.code = removean; handler(KEY); } mdn.onclick = () => { if (!window.LN_indexslow) { getindex(); if (!l.style.display || l.style.display == 'none') sh('cit'); else sh('cif'); } else alt('Novel index is loading, please wait'); } record(); addwf.onclick = () => { let value = word.value, replaced = rword.value, type = selectt.value, condition = selectl.value, search = RULES.LN_search(value), obj = { word: value, replaced: replaced.includes('\\n') ? replaced.replaceAll('\\n', '\n') : replaced, type: type, cond: condition }; if (search.found && search.child == 'word' && selectr.value != value) { if (!word.value || word.value == '') { alt('Invalid rule configurations!'); return; } selectr.options.LN_search(value).obj.selected = true; selectt.options.LN_search(search.obj.type).obj.selected = true; selectl.options.LN_search(search.obj.condition).obj.selected = true; word.value = search.obj.word; rword.value = search.obj.replaced; remwf.disabled = false; alt('Rule already exist!'); } else if (search.found && search.child == 'word' && selectr.value == value) { if (!word.value || word.value == '') { alt('Invalid rule configurations!'); return; } search.obj.type = selectt.value; search.obj.condition = selectl.value; search.obj.word = word.value; search.obj.replaced = rword.value; GM_setValue('RULES', RULES); rvals(); alt('Rule edited successfully.'); } else if (!search.found || search.child != 'word') { if (!word.value || word.value == '') { alt('Invalid rule configurations!'); return; } selectr.add(new Option(word.value, word.value), selectr[0]); RULES.push(obj); GM_setValue('RULES', RULES); rvals(); alt('Rule added successfully.'); } } remwf.onclick = () => { if (selectr.selectedIndex > -1) { if (confirm('Are you sure you want to remove this filter rule?')) { RULES.splice(RULES.LN_search(selectr.value).index, 1); GM_setValue('RULES', RULES); rvals(); selectr.selectedOptions[0].remove(); } } } selectr.onchange = () => { let search = RULES.LN_search(selectr.value); selectt.options.LN_search(search.obj.type).obj.selected = true; selectl.options.LN_search(search.obj.cond).obj.selected = true; word.value = search.obj.word; rword.value = search.obj.replaced; remwf.disabled = false; } } let asked = false, dloldtitle; function dynamicload(url, retries=0, OBJ={}) { window.LN_loading = true; getcontent(url, CS, OBJ); if (location.href != url) asked = false; if (timers) { clearInterval(timers); timers = 'on'; } setTimeout(() => { try { const body = OBJ.BODY, chapter = OBJ.CHAPTER, title = OBJ.TITLE, cp = document.querySelector(CS.chapter).parentElement, c = document.querySelector(CS.chapter); let next = body.querySelector(CS.next), prev = body.querySelector(CS.prev), cpos = ''; if (title[2] == dloldtitle) { window.LN_loading = false; alt('Network latency high or server denied access, retrying...'); retry({ callback: dynamicload, url: url, retries: retries + 1, origin: url, OBJ: OBJ }); return; } dloldtitle = title[2]; if (location.host.includes('novelonlinefull') || location.host.includes('bestlightnovel')) { let nn, pp; for (let e of body.querySelectorAll('a')) { if (/NEXT CHAPTER/ig.test(e.innerText) || e.innerText == 'Next »') nn = e; if (/PREV CHAPTER/ig.test(e.innerText) || e.innerText == '« Previous') pp = e; } next = nn || null; prev = pp || null; } if (next !== null) next = next.href; if (prev !== null) prev = prev.href; cp.insertBefore(chapter.cloneNode(true), Array.from(cp.children)[c.LN_index()]); r.appendChild(chapter.cloneNode(true)); r.querySelector(CS.chapter).remove(); c.remove(); if (location.host.includes('readlightnovel.me')) document.querySelector('.block-title h1').lastChild.data = OBJ.CHAPTERTITLE; else if (location.host.includes('novelonlinefull') || location.host.includes('bestlightnovel')) document.querySelector('.rdfa-breadcrumb p').lastChild.data = OBJ.CHAPTERTITLE; else if (location.host.includes('novels.pl')) document.querySelector('.panel-title.pull-left').lastChild.data = OBJ.CHAPTERTITLE; else document.querySelector(CS.chaptertitle).innerText = OBJ.CHAPTERTITLE; if (document.querySelector(CS.next)) document.querySelector(CS.next).href = next; else if (document.querySelector('.LN_nextchbtn')) document.querySelector('.LN_nextchbtn').href = next; else { let a = document.createElement('a'); a.className = CS.next.replace(/\.|\#/, '').replace('.', ' '); a.id = CS.next.replace(/\.|\#/, '').replace('.', ' '); a.href = next; a.classList.add('LN_nextchbtn'); a.style.display = 'none'; document.body.appendChild(a); } if (document.querySelector(CS.prev)) document.querySelector(CS.prev).href = prev; else if (document.querySelector('.LN_prevchbtn')) document.querySelector('.LN_prevchbtn').href = prev; else { let a = document.createElement('a'); a.className = CS.prev.replace(/\.|\#/, '').replace('.', ' '); a.id = CS.prev.replace(/\.|\#/, '').replace('.', ' '); a.href = prev; a.classList.add('LN_prevchbtn'); a.style.display = 'none'; document.body.appendChild(a); } document.title = title[0]; alt(title[1].replace(/\n|\t|«/gm, '')); if (CS.title && (location.host.includes('novelonlinefull') || location.host.includes('bestlightnovel'))) document.querySelector(CS.title).innerText = title[2]; fsbtn(); try { history.pushState('', title[0], url); } catch (e) { url = url.LN_fix(location.href); history.pushState('', title[0], url); } if (autora) removeannon(); let ls = laststop.LN_search(location.href); if (ls.found) resume(); else r.scrollTo(0, 0); if (window.innerWidth < window.innerHeight) { r.querySelector(CS.chapter).classList.add('LN_mob'); a.classList.add('LN_amob'); n.classList.remove('LN_side'); n.classList.add('LN_bot'); s.style = 'display: none !important;'; n.style = `bottom: 0; left: ${(window.innerWidth - n.offsetWidth) / 2}px;`; } else { r.querySelector(CS.chapter).classList.remove('LN_mob'); a.classList.remove('LN_amob'); n.classList.add('LN_side'); n.classList.remove('LN_bot'); s.style = 'display: block !important;'; n.style = `top: ${(window.innerHeight - n.offsetHeight) / 2}px; left: 0;`; } dynamicmode(); record(); window.LN_loading = false; setTimeout(() => { if (timers == 'on') { timers = false; doautoscroll(); } }, 3000); } catch (e) { window.LN_loading = false; console.error(e); if (!OBJ.BODY) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Retrying...', 10000); retry({ callback: dynamicload, retries: retries + 1, url: url, origin: url, OBJ: OBJ }); } else if (BOTCHECK(OBJ.BODY)) { if (confirm('Caught by bot verification.\nOpen url (' + url + ') in new tab?')) window.open(url, '_blank'); } else { alt('Error:\nDetails: Unexpected error has occured. Retrying...', 10000); retry({ callback: dynamicload, retries: retries + 1, url: url, origin: url, OBJ: OBJ }); } } }, 3000); } function removeannon(c, m=false, PL=CS) { let chapter; if (c) chapter = c; else chapter = r; let replaced, replacew, list = PL.annon[1]; if (PL.annon[0]) { replaced = PL.annon[0][0]; replacew = PL.annon[0][1]; } if (replacew) chapter.innerHTML = chapter.innerHTML.replace(replaced, replacew); if (list && chapter.querySelector(PL.chapter)) for (let e of chapter.querySelector(PL.chapter).querySelectorAll(list)) e.remove(); else if (list && chapter.querySelector(list)) for (let e of chapter.querySelectorAll(list)) e.remove(); if (chapter.querySelectorAll('p').length > 25 && PL.chapter != SITES['novels.pl'].chapter) { chapter.innerHTML = chapter.innerHTML.replaceAll('<\/p>', '</p>\n\n'); for (let e of chapter.querySelectorAll('br')) e.remove(); } if (decensore) { while (chapter.innerHTML.search(/[a-zA-Z](\.[a-zA-Z]){1,}/) > -1) { let a = chapter.innerHTML, b = a.substr(a.search(/[a-zA-Z](\.[a-zA-Z]){1,}/)), c = b.substr(0, b.indexOf(' ')), i1 = a.search(/[a-zA-Z](\.[a-zA-Z]){1,}/), i2 = c.length; for (let i = i1; i < i1 + c.length; i++) a = a.LN_replaceAt(i1, ''); a = a.LN_replaceAt(i1, c.replaceAll('.', '') + ' '); chapter.innerHTML = a; } } if (chapter.querySelector('br') && m) chapter.innerHTML = chapter.innerHTML.replaceAll('<br>', '\n'); if (chapter.querySelector(PL.chapter)) filter(chapter.querySelector(PL.chapter)); else filter(chapter); } let timers = false; function doautoscroll() { let del, scrolly; if (scrollt) { del = (autoscrolls / 2) * 1000; let div = document.createElement('div'); div.style = 'display: block; z-index: -1; position: fixed; top: 0; left: 0; width: 100%; height: 100%;'; document.body.appendChild(div); scrolly = div.clientHeight - 120; div.remove(); } else { del = autoscrolls; scrolly = 2; } if (!timers) timers = setInterval(() => r.scrollBy(0, scrolly), del); else { clearInterval(timers); timers = false; } r.ontouchstart = r.onclick = r.onauxclick = () => { if (timers) { clearInterval(timers); timers = false; } } let cond = false; window.onblur = () => { if (timers) { cond = true; clearInterval(timers); timers = false; } window.onfocus = () => { if (!timers && cond) { cond = false; timers = setInterval(() => r.scrollBy(0, scrolly), del); } } } } let darked = false; function ucss(u=1) { if (u == 0) { ccss.innerHTML = CCSS; if (darked) CSS.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${dbgc} !important; color: ${dtxc} !important; scrollbar-color: ${dtxc} ${dbgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${dtxc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${dbgc}; width: 10px; }`; else CSS.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${bgc} !important; color: ${txc} !important; scrollbar-color: ${txc} ${bgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${txc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${bgc}; width: 10px; }`; } else if (u == 1) { if (!darked) { CSS.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${dbgc} !important; color: ${dtxc} !important; scrollbar-color: ${dtxc} ${dbgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${dtxc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${dbgc}; width: 10px; }`; darked = true; } else { CSS.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${bgc} !important; color: ${txc} !important; scrollbar-color: ${txc} ${bgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${txc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${bgc}; width: 10px; }`; darked = false; } } else if (u == 5) { CSS.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { background-color: ${dbgc} !important; color: ${dtxc} !important; scrollbar-color: ${dtxc} ${dbgc}; } .LN_chapter::-webkit-scrollbar-thumb { transition: all 0.5s; background-color: ${dtxc} } .LN_chapter::-webkit-scrollbar-track, .LN_chapter::-webkit-scrollbar { transition: all 0.5s; background-color: ${dbgc}; width: 10px; }`; darked = true; } else fontcss.innerHTML = `.LN_chapter, .LN_chapter div, .LN_chapter p { font-size: ${defaultfs}px !important; font-family: ${defaultf} !important; }`; } function rvals() { next = GM_getValue('next', 'KeyN'); nexta = GM_getValue('nexta', 'ArrowRight'); nextaa = GM_getValue('nextaa', 'KeyD'); prev = GM_getValue('prev', 'KeyB'); preva = GM_getValue('preva', 'ArrowLeft'); prevaa = GM_getValue('prevaa', 'KeyA'); darkmode = GM_getValue('darkmode', 'KeyL'); fullscreen = GM_getValue('fullscreen', 'KeyF'); autoscroll = GM_getValue('autoscroll', 'KeyQ'); showfavs = GM_getValue('showfavs', 'Digit3'); removean = GM_getValue('removean', 'KeyE'); download = GM_getValue('download', 'KeyS'); decfs = GM_getValue('decfs', 'Minus'); incfs = GM_getValue('incfs', 'Equal'); autonc = GM_getValue('autonc', true); autora = GM_getValue('autora', true); autodl = GM_getValue('autodl', true); autoresume = GM_getValue('autoresume', true); defaultv = GM_getValue('defaultv', false); scrollt = GM_getValue('scrollt', false); swipeg = GM_getValue('swipeg', true); nnotfound = GM_getValue('nnotfound', true); autoch = GM_getValue('autoch', false); autodmode = GM_getValue('autodmode', false); decensore = GM_getValue('decensore', true); allowconfirm = GM_getValue('allowconfirm', true); uselastr = GM_getValue('uselastr', false); checkcomp = GM_getValue('checkcomp', false); downloadt = GM_getValue('downloadt', true); autoretry = GM_getValue('autoretry', true); laststop = GM_getValue('laststop', ['placeholder']); dmtime = parseFloat(GM_getValue('dmtime', 18)); lmtime = parseFloat(GM_getValue('lmtime', 9)); pmargin = parseFloat(GM_getValue('pmargin', 20)); lheight = parseFloat(GM_getValue('lheight', 1.4)); autoncd = parseFloat(GM_getValue('autoncd', 40)); autoscrolls = parseFloat(GM_getValue('autoscrolls', 90)); autoretryno = GM_getValue('autoretryno', 20); autodown = GM_getValue('autodown', false); defaultf = GM_getValue('defaultf', '"Comic Sans MS"'); defaultfs = GM_getValue('defaultfs', 18); checkd = GM_getValue('checkd', '09:00'); lastcheck = GM_getValue('lastcheck', ''); autobackupp = parseFloat(GM_getValue('autobackupp', 3)); bgc = GM_getValue('bgc', '#c95'); txc = GM_getValue('txc', '#000'); dbgc = GM_getValue('dbgc', '#111'); dtxc = GM_getValue('dtxc', '#550'); CCSS = GM_getValue('CCSS', ''); ECCSS = GM_getValue('ECCSS', ''); FAVS = GM_getValue('FAVS', ['placeholder']); HISTORY = GM_getValue('HISTORY', ['placeholder']); RULES = GM_getValue('RULES', ['placeholder']); DHISTORY = GM_getValue('DHISTORY', ['placeholder']); TIMES = GM_getValue('TIMES', ['placeholder']); CHECKED = GM_getValue('CHECKED', [JSON.stringify(new Date()).replaceAll('"', '')]); } let alreadyc = false; function dofull(exit) { let isfull = (document.fullscreenElement && document.fullscreenElement !== null) || (document.webkitFullscreenElement && document.webkitFullscreenElement !== null) || (document.mozFullScreenElement && document.mozFullScreenElement !== null) || (document.msFullscreenElement && document.msFullscreenElement !== null), docElm = document.documentElement, exitf = () => { sh('rf'); document.querySelector('html').style.cssText = document.body.style.cssText = ''; if (!isfull) return; if (document.exitFullscreen) document.exitFullscreen(); else if (document.webkitExitFullscreen) document.webkitExitFullscreen(); else if (document.mozCancelFullScreen) document.mozCancelFullScreen(); else if (document.msExitFullscreen) document.msExitFullscreen(); }, gof = () => { document.querySelector('html').style.cssText = document.body.style.cssText = 'min-height: 0px !important; height: 0px !important; overflow: hidden !important;'; if (docElm.requestFullscreen) docElm.requestFullscreen(); else if (docElm.mozRequestFullScreen) docElm.mozRequestFullScreen(); else if (docElm.webkitRequestFullScreen) docElm.webkitRequestFullScreen(); else if (docElm.msRequestFullscreen) docElm.msRequestFullscreen(); } if (exit) exitf(); else if (!isfull) { sh('rt'); if (autora) removeannon(); if (defaultv && !alreadyc) { ucss(5); alreadyc = true; } resume(); dynamicmode(); gof(); } else exitf(); } function resume() { if (!asked) { let ls = laststop.LN_search(location.href); if (ls.found) { if (autoresume) r.scrollTo(0, ls.obj.pos); else if (confirm('Continue from last stop?')) { r.scrollTo(0, ls.obj.pos); if (confirm('Don\'t ask again?')) { GM_setValue('autoresume', true); m.querySelectorAll('input[type=radio]')[6].checked = true; } } } asked = true; } } function handler(e) { if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey || e.target.tagName == 'INPUT' || e.target.tagName == 'TEXTAREA') return; let ncb = document.querySelector(CS.next), pcb = document.querySelector(CS.prev), key = e.code, inc = document.querySelectorAll('#LN_decincfs button')[0], dec = document.querySelectorAll('#LN_decincfs button')[1]; if (location.host.includes('novelonlinefull') || location.host.includes('bestlightnovel')) { let nn, pp; for (let e of document.querySelectorAll('a')) { if (/NEXT CHAPTER/ig.test(e.innerText) || e.innerText.includes('Next »')) nn = e; if (/PREV CHAPTER/ig.test(e.innerText) || e.innerText.includes('« Previous')) pp = e; } ncb = document.querySelector('.LN_nextchbtn') || nn || null; pcb = document.querySelector('.LN_prevchbtn') || pp || null; } if (key == next || key == nexta || key == nextaa) { if (!ncb || !ncb.href || ncb.href.endsWith('null') || (ncb.href.endsWith('#') && ncb.href.includes(location.href)) || !ncb.href.split(location.host)[1] || ncb.href.split(location.host)[1].split('/')[1].toLowerCase() != location.href.split(location.host)[1].split('/')[1].toLowerCase() || ncb.href == location.href) alt('Last Chapter.'); else { if (autodl) dynamicload(ncb.href); else ncb.click(); } } else if (key == prev || key == preva || key == prevaa) { if (!pcb || !pcb.href || pcb.href.endsWith('null') || (pcb.href.endsWith('#') && pcb.href.includes(location.href)) || !pcb.href.split(location.host)[1] || pcb.href.split(location.host)[1].split('/')[1].toLowerCase() != location.href.split(location.host)[1].split('/')[1].toLowerCase() || pcb.href == location.href) alt('No chapter Found!'); else { if (autodl) dynamicload(pcb.href); else pcb.click(); } } else if (key == fullscreen) dofull(); else if (key == autoscroll) doautoscroll(); else if (key == showfavs) { if (WIN === undefined) favs(); else { WIN.close(); WIN = undefined; } } else if (key == removean) removeannon(); else if (key == darkmode) ucss(); else if (key == download) { sh('menut'); sh('sf'); sh('pf'); sh('of'); sh('dt'); sh('nf'); sh('bf'); sh('stf'); sh('wff'); m.querySelector('input[max="10000"]').focus(); } else if (key == 'Escape') { sh('stf'); sh('wff'); } else if (key == incfs) inc.click(); else if (key == decfs) dec.click(); } let URL, LASTC, STATUS, lasturl, WIN; function favs() { rvals(); WIN = window.open('', 'LN_favs', 'menubar=no,status=no,titlebar=no,location=no,top=0,left=0,height=' + window.innerHeight + 'width=' + (window.innerWidth / 10) * 8); const b = WIN.document.body, h = WIN.document.head; h.innerHTML = `<style> body { color: #090; background-color: #111; } table, th, td { border: 1px solid #090; text-align: center; } th { width: 200px; height: 30px; font-family: 'Nunito Sans', sans-serif; } a { color: #00f; text-decoration: none; transition: color 0.5s; } a:hover { text-decoration: underline; } body { color: #090; background-color: #111; } .main { width: -moz-fit-content; width: fit-content; margin: 50px auto; } h1 { width: -moz-fit-content; width: fit-content; margin: 50px auto; font-size: 35px; font-weight: bolder; font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; } td { height: 50px; font-family: Helvetica; } td svg { cursor: pointer } a:visited { color: #d2f !important; } h4 { font-family: arial; margin: 0px; } h2 { font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; font-size: 22px; margin: 0 25px 30px; } .notes { padding: 0 40px; } .updates { font-family: Helvetica Neue, Segoe UI, Helvetica, Arial, sans-serif; font-size: 22px; margin: 0 25px 30px; display: inline; } button:hover { color: #090; background-color: #111; } button { transition: all 0.5s; border: none; color: #111; background-color: #090; outline: 0; font-family: sans-serif; cursor: pointer; padding: 5px 20px; font-weight: bolder; margin-left: 10px; margin-top: 10px; } :disabled { opacity: 0.6 !important; cursor: not-allowed !important; color: #000 !important; background-color: #090 !important; } .picker { top: 0; left: 0; position: fixed; width: 100%; height: 100%; background: #0009; display: flex; } .pbody { margin: auto; align-self: center; padding: 40px; background-color: #111; width: 50%; border-radius: 15px; user-select: none; font-family: arial; font-weight: 700; font-size: 20px; } .source { border: 1px solid #090; margin: 2px; background-color: #111; color: #090; cursor: pointer; font-size: 20px; padding: 3px 10px; appearance: auto; width: auto; height: auto; display: inline; } .LN_help { cursor: help; border-bottom: 2px #aaa dotted; margin-bottom: 2px; display: inline-block; } input[type="time"]:focus { box-shadow: 0 0 5px 2px #090; outline: 0; border: 1px solid #090; } input[type=time] { background-color: #111; border: none; color: #090; cursor: pointer; transition: all 0.5s; padding: 3px; } </style>`; b.innerHTML = `<div class="main"> <h1> Favorites </h1> <table> <tbody> <tr> <th> Novel </th> <th> URL </th> <th> Last Chapter </th> <th> Last Read </th> <th> Last Downloaded </th> <th> Status </th> <th> <span class=LN_help title="If auto check is enabled, the script checks daily at this time for each novel individually" onclick="javascript:window.open('https://openuserjs.org/scripts/XDHx86/Light_Novel_Loader#notes')"> Update Time </th> <th> Migrate </th> <th> Download </th> <th> Check </th> <th> Remove </th> </tr> </tbody> </table> <br> <br> <h2 class="updates"> Check for Updates: </h2> <button class="check"> Check </button> <br> <h2 class=updates> Save updates times: </h2> <button class=savetime> Save </button> <br> <h2> Notes: </h2> <div class="notes"> <h4> - Press CTRL+Z to undo removal. </h4> <br> <h4> - Press CTRL+R to show new changes. </h4> <br> <h4> - Press Escape to close the window. </h4> <br> <h4> - All novels in favorites will receive notifications, to disable notifications go to "Notifications & Favorites" in settings menu. </h4> <br> <h4> - If the window is already open it won't open again. </h4> </div> </div>`; const table = b.querySelector('table'); if (WIN.innerWidth < (window.innerWidth / 10) * 8) { try { WIN.innerWidth = (window.innerWidth / 10) * 8; } catch (e) { } } for (let i = 1; i < FAVS.length; i++) { let fav = FAVS[i], novel = fav.novel.replace(/\n|\t|«/gm, ''), url = fav.url, status = fav.status, lastc = fav.lastc, lastr = HISTORY.LN_search(url.href).obj, lastd = DHISTORY.LN_search(url.href).obj, time = TIMES.LN_search(url.href).obj || '', svgs = '<div title="Remove from favorites"> <svg class="remove" style="height: 20px; width: 20px;" viewBox="0 0 48 48"> <circle style="fill:#F44336;" cx="24" cy="24" r="19"/> <rect x="22" y="14" transform="matrix(0.7071 0.7071 -0.7071 0.7071 24 -9.9411)" style="fill:#FFFFFF;" width="4" height="20"/> <rect x="22" y="14" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 57.9411 24)" style="fill:#FFFFFF;" width="4" height="20"/> </svg> </div>', svgd = '<div title="Download to latest chapter"> <svg class="download" style="height: 20px; width: 20px; fill: #ccc;" viewBox="0 0 26 26"> <path d="M 11 0 C 9.344 0 8 1.343 8 3 L 8 11 L 4.75 11 C 3.34 11 3.043 11.2265 4.25 12.4375 L 10.84375 19.03125 C 13.04475 21.23125 13.01375 21.23725 15.21875 19.03125 L 21.78125 12.4375 C 22.98925 11.2275 22.5855 11 21.3125 11 L 18 11 L 18 3 C 18 1.343 16.656 0 15 0 L 11 0 z M 0 19 L 0 23 C 0 24.656 1.344 26 3 26 L 23 26 C 24.656 26 26 24.656 26 23 L 26 19 L 24 19 L 24 23 C 24 23.551 23.552 24 23 24 L 3 24 C 2.448 24 2 23.551 2 23 L 2 19 L 0 19 z"/> </svg> </div>', svgc = '<div title="Check this novel for updates"> <svg class="update" style="height: 20px; width: 20px; fill: #ccc;" viewBox="0 0 24 24"> <path d="M 7.59375 3 L 9.0625 5 L 12 5 L 13 5 C 16.325562 5 19 7.674438 19 11 L 19 15 L 16 15 L 20 20.46875 L 24 15 L 21 15 L 21 11 C 21 6.593562 17.406438 3 13 3 L 12 3 L 7.59375 3 z M 4 3.53125 L 0 9 L 3 9 L 3 13 C 3 17.406438 6.593562 21 11 21 L 12 21 L 14 21 L 16.40625 21 L 14.9375 19 L 14 19 L 12 19 L 11 19 C 7.674438 19 5 16.325562 5 13 L 5 9 L 8 9 L 4 3.53125 z"/> </svg> </div>', svgm = '<div title="Migrate this novel to another source"> <svg class="migrate" style="height: 20px; width: 20px; fill: #ccc;" viewBox="0 0 50 50"> <path d="M 2 2 L 2 3 L 2 39 L 2 40 L 3 40 L 19 40 L 19 47 L 19 48 L 20 48 L 47 48 L 48 48 L 48 47 L 48 22 L 48 21.59375 L 47.71875 21.28125 L 36.71875 10.28125 L 36.40625 10 L 36 10 L 27.4375 10 L 19.71875 2.28125 L 19.40625 2 L 19 2 L 3 2 L 2 2 z M 4 4 L 18 4 L 18 14 L 18 15 L 19 15 L 29 15 L 29 32 L 29 34 L 29 38 L 4 38 L 4 4 z M 20 5.4375 L 26 11.40625 L 26 11.4375 A 1.0043849 1.0043849 0 0 0 26.03125 11.5 A 1.0043849 1.0043849 0 0 0 26.375 11.84375 A 1.0043849 1.0043849 0 0 0 26.46875 11.90625 L 27.5625 13 L 20 13 L 20 5.4375 z M 29.4375 12 L 35 12 L 35 22 L 35 23 L 36 23 L 46 23 L 46 46 L 21 46 L 21 40 L 30 40 L 31 40 L 31 39 L 31 36.4375 L 33.28125 38.71875 L 34.71875 37.28125 L 31.4375 34 L 41 34 L 41 32 L 31.4375 32 L 34.71875 28.71875 L 33.28125 27.28125 L 31 29.5625 L 31 14 L 31 13.59375 L 30.71875 13.28125 L 29.4375 12 z M 37 13.4375 L 44.5625 21 L 37 21 L 37 13.4375 z M 17.71875 20.28125 L 16.28125 21.71875 L 19.5625 25 L 10 25 L 10 27 L 19.5625 27 L 16.28125 30.28125 L 17.71875 31.71875 L 22.71875 26.71875 L 23.40625 26 L 22.71875 25.28125 L 17.71875 20.28125 z"/> </svg> </div>'; if (!lastr) lastr = { href: '', text: 'No Record Yet', target: '_self' }; else lastr.target = '_blank'; if (!lastd) lastd = { href: '', text: 'No Record Yet', target: '_self' }; else lastd.target = '_blank'; let timecode = ` <input type=time value="${time.time}">`; if (status.toLowerCase().includes('complete')) timecode = '<span style="cursor: default;"> Completed </span>'; let code = `<tr data="${i}"> <td> ${novel} </td> <td> <a href="${url.href}" target="_blank"> ${url.text} </a> </td> <td> <a href="${lastc.href}" target="_blank"> ${lastc.text} </a> </td> </td> <td> <a href="${lastr.href}" target="${lastr.target}"> ${lastr.text} </a> </td> <td> <a href="${lastd.href}" target="${lastd.target}"> ${lastd.text} </a> </td> <td style="text-transform: capitalize;"> ${status.toLowerCase()} </td> <td> ${timecode} </td> <td> ${svgm} </td> <td> ${svgd} </td> <td> ${svgc} </td> <td> ${svgs} </td> </tr>`; table.innerHTML += code; } let ROW, DATA; for (let i = 1; i < FAVS.length; i++) { let svg = b.querySelectorAll('svg.remove')[i-1]; svg.onclick = function() { let p = this.parentElement.parentElement.parentElement, d = p.getAttribute('data'); ROW = p.cloneNode(true); DATA = FAVS[d]; FAVS.splice(d, 1); GM_setValue('FAVS', FAVS); rvals(); p.remove(); } svg = b.querySelectorAll('svg.migrate')[i-1]; if (svg) { svg.onclick = function() { let tr = this.parentElement.parentElement.parentElement, d = tr.getAttribute('data'), novel = FAVS[d], div = document.createElement('div'); div.className = 'picker'; div.innerHTML = `<div class="pbody"> <h2> How It Works: </h2> <ul> <li> After clicking migrate the script will attempt to search for the novel in the specified source for the user to select </li> <br> <li> After selecting the novel, add it to favorites. FIRST novel added will be the target to migrate to - Whether it's already favored or not - and the script won't check for names </li> <br> <li> Migrating a novel doesn't delete the old one </li> <br> <li> Migrating a novel doesn't delete records of the old one but only adds the current records to the new source</li> </ul> Migrating novel: ${novel.novel} <br> From: ${novel.url.href.LN_host()} <br> To: <select class="source"> </select> <br> <button> Migrate </button> </div>`; for (let e in SITES) { let s = div.querySelector('select'); if (e != 'www.readlightnovel.me' && e != 'www.novels.pl' && e != novel.url.href.LN_host()) s.options.add(new Option(e, e)); } WIN.document.body.appendChild(div); div.querySelector('button').onclick = () => { let site = div.querySelector('.source').value; search(novel.novel, site); GM_setValue('migrated', novel.url.href); } div.onclick = e => { if (e.target.className == 'picker') div.remove(); } } } svg = b.querySelectorAll('svg.download')[i-1]; svg.onclick = () => downnew(i, true); svg = b.querySelectorAll('svg.update')[i-1]; svg.onclick = () => notify(i, 0, true); } b.querySelector('.check').onclick = function() { notify(); this.disabled = true; this.innerText = 'Checking...'; setTimeout(() => { b.querySelector('.check').disabled = false; b.querySelector('.check').innerText = 'Check'; }, 10000); } b.querySelector('.savetime').onclick = function() { let ins = b.querySelectorAll('[type=time]'); for (let i = 0; i < ins.length; i++) { if (ins[i].value) { let h = FAVS[ins[i].parentElement.parentElement.getAttribute('data')].url.href, obj = { href: h, time: ins[i].value } if (TIMES.LN_search(h).obj) TIMES.LN_search(h).obj.time = ins[i].value; else TIMES.push(obj); GM_setValue('TIMES', TIMES); } } } WIN.onkeyup = e => { if (e.code == 'KeyZ' && e.ctrlKey && ROW) { let t = b.querySelector('table'); ROW.setAttribute('data', FAVS.length); t.appendChild(ROW); FAVS.push(DATA); GM_setValue('FAVS', FAVS); rvals(); favs(); } else if (e.code == 'KeyR' && e.ctrlKey) { e.preventDefault(); favs(); } else if (e.code == 'Escape' || (e.code == showfavs && e.target.tagName != 'INPUT')) { WIN.close(); WIN = undefined; } } } let FNOVEL function favthis(url, mode=0, PL=CS) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: r => { try { let BODY, CHAPTER, TITLE, CHAPTERTITLE; const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, getdata = () => { for (let e of b.querySelectorAll('script')) { if (e.innerHTML.includes('function load(page)')) { let str = e.innerHTML; str = str.substr(str.indexOf('data: {')); let id = str.substr(10, 4); id = id.trim(); if (id.endsWith(',')) id = id.substr(0, id.length-1); str = str.substr(str.indexOf(',')+2); let novel = str.substr(6, str.indexOf(',')-6); novel = novel.replace(/'|"'/g, ''); str = str.substr(str.indexOf(',')+2); let max = str.substr(4,4); max = max.trim(); if (max.endsWith(',')) max = max.substr(0, max.length-1); let string = `id=${id}&novel=${novel}&max=${max}&page=1`; return string; } } }, lastcnovels = () => { GM_xmlhttpRequest({ method: 'POST', url: 'https://www.novels.pl/ajax/ajaxGetChapters.php', data: getdata(), headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body; LASTC = { href: b.querySelector('a').href.LN_fix(url), text: b.querySelector('a').innerText } } }); }, adding = () => { let index = { novel: FNOVEL, url: URL, status: STATUS.toLowerCase(), lastc: LASTC }, err, {novel, url, status, lastc} = index; if (!novel || !url || !status || !lastc) { setTimeout(() => { alt('Error retreving data, can’t add favorite. Please report this via Email to xdhx86@gmail.com', 5000) }, 5000); err = true; } if (err) return; FAVS.push(index); GM_setValue('FAVS', FAVS); rvals(); alt('Added to favorites!'); setTimeout(() => { if (GM_getValue('migrated')) { migrate(GM_getValue('migrated'), url); GM_setValue('migrated', false); } }, 7000); } if (mode == 0 || mode == 2) { if (mode == 0 && FAVS.LN_deepSearch(url).found) { if (GM_getValue('migrated')) { migrate(GM_getValue('migrated'), url); GM_setValue('migrated', false); } else alt('This novel is already in favorites!'); return; } URL = { href: url, text: url.LN_platform() }; let link; if (url.includes('lightnovelworld')) { FNOVEL = b.querySelector(PL.favobj.noveltitle).innerText; STATUS = b.querySelectorAll('.header-stats span')[3].querySelector('strong').innerText; link = url + PL.favobj.link; } else if (url.includes('readlightnovel.me')) { FNOVEL = b.querySelector(PL.favobj.noveltitle).innerText; let t = b.querySelectorAll('.novel-detail-item'); for (let e of t) { if (e.innerText.includes('Status')) STATUS = e.querySelector('li').innerText; else if (e.innerText.includes('Latest Chapters')) LASTC = { href: e.querySelector('a').href.LN_fix(url), text: e.querySelector('a').innerText }; } } else if (url.includes('novels.pl')) { FNOVEL = b.querySelector(PL.favobj.noveltitle).innerText; STATUS = ' - '; lastcnovels(); } else { FNOVEL = b.querySelector(PL.favobj.noveltitle).innerText.replaceAll(/\n|HOT|NEW/gm, ''); if (PL.favobj.status) STATUS = b.querySelector(PL.favobj.status).innerText; else STATUS = ' - '; LASTC = { href: b.querySelector(PL.favobj.lastc).href.LN_fix(url), text: b.querySelector(PL.favobj.lastc).innerText }; } if (link && mode == 0) favthis(link, 1); else if (link && mode == 2) favthis(link, 3, PL); else if (!link && mode == 0) { if (url.includes('novels.pl')) setTimeout(adding, 3000); else adding(); } } else if (mode == 1 || mode == 3) { if (url.includes('novels.pl')) lastcnovels(); else { LASTC = { href: b.querySelector(PL.favobj.lastc).href.LN_fix(url), text: b.querySelector(PL.favobj.lastc).innerText }; } if (mode == 3) return; if (url.includes('novels.pl')) setTimeout(adding, 3000); else adding(); } } catch (e) { const doc = new DOMParser().parseFromString(r.responseText, "text/html"), b = doc.body; if (!b) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Please try again later.\nReason: Might be request timeout, bad internet connection, spammed requests in a small time frame.', 10000); console.error(e); } else if (BOTCHECK(b)) { if (confirm('Caught by bot verification.\nOpen url (' + url + ') in new tab?')) window.open(url, '_blank'); } else { alt('Error:\nDetails: Unexpected error has occured. Please try again later.\nReason: Might be request timeout, bad internet connection, another unexpected reason.', 10000); console.error(e); } } } }); } function notify(index, retries=0, single=false, allowdown=false) { if (window.LN_checking) { alt('The script is already checking for updates, please wait patiently or cancel it in notifications menu.'); return; } if (window.LN_cancelcheck) { window.LN_cancelcheck = false; if (m.querySelectorAll('.LN_btn')[5]) { m.querySelectorAll('.LN_btn')[5].disabled = false; m.querySelectorAll('.LN_btn')[5].innerText = 'Check'; m.querySelectorAll('.LN_btn')[6].disabled = false; } alt('Checking canceled.'); return; } window.LN_checking = true; let i = index || 1, curl, checkc = obj => { let c = [], output = false; for (let i = 1; i < FAVS.length; i++) c.push({lastc: FAVS[i].lastc, novel: FAVS[i].novel}); for (let i = 0; i < c.length; i++) { let e = c[i]; if (obj.lastc.text == e.lastc.text && obj.lastc.href == e.lastc.href && obj.novel != e.novel) { output = true; break; } } return output; }, clear = () => { if (notification) clearInterval(notification); window.LN_checking = false; if (allowdown) setTimeout(() => downnew(index, single), 7000); if (m.querySelectorAll('.LN_btn')[5]) { m.querySelectorAll('.LN_btn')[5].disabled = false; m.querySelectorAll('.LN_btn')[5].innerText = 'Check'; m.querySelectorAll('.LN_btn')[6].disabled = false; } }, notification = setInterval(() => { try { if (!FAVS[i]) { clear(); setTimeout(downnew, 3000); return; } if (window.LN_cancelcheck) { window.LN_cancelcheck = false; clear(); alt('Checking canceled.'); return; } let obj = FAVS[i], PL = SITES[obj.url.href.LN_host()]; curl = obj.url.href; if (obj.status.toLowerCase().includes('complete') && !checkcomp && !single) { clear(); alt('Novel is complete, skipping.'); notify(i+1); return; } favthis(obj.url.href, 2, PL); let action = setTimeout(() => { if ((!LASTC || obj.url.href.LN_host() != LASTC.href.LN_host() || checkc({lastc: LASTC, novel: obj.novel}))) { alt('Network latency high or server denied access, retrying...'); clear(); retry({ callback: notify, index: i, single: single, retries: retries + 1, origin: obj.url.href }); return; } if (LASTC.text != obj.lastc.text) { if (STATUS != obj.status && STATUS.toLowerCase().includes('complete')) { GM_notification({ title: 'Novel is completed!', text: `${obj.novel.replace(/\n|\t|«/gm, '')}\nIs completed!\nLast chapter: ${LASTC.text}.\nClick to show favorites.`, onclick: favs }); obj.lastc = LASTC; obj.status = STATUS; GM_setValue('FAVS', FAVS); rvals(); } else { GM_notification({ title: 'New chapter found!', text: `${obj.novel.replace(/\n|\t|«/gm, '')}\n\nHas new chapter: ${LASTC.text}.\nClick to show favorites.`, onclick: favs }); obj.lastc = LASTC; GM_setValue('FAVS', FAVS); rvals(); } } else { if (nnotfound) { GM_notification({ title: 'No chapter found!', text: `${obj.novel.replace(/\n|\t|«/gm, '')}\n\nHas no new chapter.\nClick to show favorites.`, onclick: favs }); } } }, 6500); if (!single) i++; else clear(); } catch (e) { window.LN_checking = false; console.error(e); if (!OBJ.BODY) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Retrying...', 10000); retry({ callback: notify, index: i, single: single, retries: retries + 1, origin: FAVS[i].url.href }); } else if (BOTCHECK(OBJ.BODY)) { if (m.querySelectorAll('.LN_btn')[5]) { m.querySelectorAll('.LN_btn')[5].disabled = false; m.querySelectorAll('.LN_btn')[5].innerText = 'Check'; m.querySelectorAll('.LN_btn')[6].disabled = false; } if (confirm('Caught by bot verification.\nOpen url (' + FAVS[i].url.href + ') in new tab?')) window.open(FAVS[i].url.href, '_blank'); } else { alt('Error:\nDetails: Unexpected error has occured. Retrying...', 10000); retry({ callback: notify, index: i, single: single, retries: retries + 1, origin: FAVS[i].url.href }); } } }, 7000); } function check() { if (autoch && (new Date).toTimeString().substr(0, 5) > checkd && (!lastcheck || lastcheck != (new Date).getDate())) { alt('Auto checking for updates..'); lastcheck = (new Date).getDate(); GM_setValue('lastcheck', lastcheck); notify(); } } let aurcc = 0; function retry(obj) { let callback = obj.callback, retries = obj.retries, origin = obj.origin, single = obj.single, index = obj.index, auto = obj.auto, OBJ = obj.OBJ, url = obj.url, PL = obj.PL, n = obj.n; if (retries < 3) { if (callback.name == 'notify') callback(index, retries, single); else if (callback.name == 'Download') callback(url, n, retries, auto, index, PL, single, OBJ); else if (callback.name == 'dynamicload') callback(url, retries, OBJ); } else { if (autoretry && aurcc <= autoretryno) { setTimeout(() => { aurcc++; obj.retries = 0; retry(obj); }, 5000); } else if (!autoretry || aurcc > autoretryno) { if (confirm('Refused to connect to (' + origin + ') after ' + (autoretry ? autoretryno : '3') + ' retries.\nClick ok to open the url in a new tab.\nThe script will retry after 5 seconds after you click ok.')) { window.open(origin, '_blank'); setTimeout(() => { aurcc = 0; obj.retries = 0; retry(obj); }, 5000); } else if (!confirm('Are you sure you want to cancel? Press OK to cancel')) { window.open(origin, '_blank'); setTimeout(() => { aurcc = 0; obj.retries = 0; retry(obj); }, 5000); } else if (callback.name == 'notify') { window.LN_checking = false; m.querySelectorAll('.LN_btn')[5].disabled = false; m.querySelectorAll('.LN_btn')[6].disabled = false; m.querySelectorAll('.LN_btn')[5].innerText = 'Check'; } else if (callback.name == 'Download') { window.LN_downloading = false; Dalt = false; m.querySelectorAll('.LN_btn')[2].disabled = false; m.querySelectorAll('.LN_btn')[3].disabled = false; m.querySelectorAll('.LN_btn')[2].innerText = 'Download'; } else if (callback.name == 'dynamicload') window.LN_loading = false; } } } function downnew(index=1, single=false) { if (!autodown && !single) return; let obj = FAVS[index]; if (!obj) { alt('Auto download finished.'); return; } let lastr = HISTORY.LN_search(obj.url.href), lastd = DHISTORY.LN_search(obj.url.href), PL = SITES[obj.url.href.LN_host()], con = () => { if (allowconfirm) return (confirm('Attempting to download following chapters from (' + TITLE[2].replace(/\n|«/gm, '') + ') to last chapter uploaded.\nConfirm?')); else return true; }, lastm = () => { if (uselastr) return lastr; else return lastd; }, lastt = () => { if (lastm() == lastr) return 'read'; else return 'downloaded'; }; if (!lastm().found && !single) { alt('Last '+ lastt() +' chapter not found, skipping.'); downnew(index + 1); } else if (!lastm().found && single) alt('Last '+ lastt() +' chapter not found!'); else if (obj.lastc.href == lastm().obj.href && !single) { alt('Last '+ lastt() +' chapter is last the chapter, skipping.'); downnew(index + 1); } else { const OBJ = {}; getcontent(lastm().obj.href, PL, OBJ); setTimeout(() => { let NOVEL = OBJ.NOVEL, BODY = OBJ.BODY, CHAPTER = OBJ.CHAPTER, TITLE = OBJ.TITLE, CHAPTERTITLE = OBJ.CHAPTERTITLE; let current = BODY.querySelector(PL.next); if (obj.lastc.href.includes('novelonlinefull') || obj.lastc.href.includes('bestlightnovel')) { let nn; for (let e of BODY.querySelectorAll('a')) if (/NEXT CHAPTER/ig.test(e.innerText) || e.innerText == 'Next »') nn = e; current = nn; } if (current && current.href) current.href = current.href.LN_fix(obj.lastc.href); if (current && current.href && (!(current.href.endsWith('#') && current.href.includes(obj.lastc.href))) && (current.href.split(obj.url.href.LN_host())[1] && current.href.split(obj.url.href.LN_host())[1].split('/')[1].toLowerCase() == obj.lastc.href.split(obj.url.href.LN_host())[1].split('/')[1].toLowerCase())) { current = current.href; if (con()) { let int = setInterval(() => { if (!window.LN_checking) { Dcont = []; Dalt = false; Download(current, 9999, 0, true, index, PL, single); clearInterval(int); } }, 1000); } else if (!single) downnew(index + 1); } else { alt('Last '+ lastt() +' chapter is last the chapter, skipping.'); if (!single) downnew(index + 1); } }, 5000); } } function br(mode) { let fr = new FileReader(), res; if (!fr) alt('File API not supported!'); else if (mode == 0) { const a = document.createElement('a'), date = (new Date).toDateString().split(' '), time = date[2] + '-' + date[1], names = GM_listValues(), values = [], parsed = []; names.forEach(e => values.push(GM_getValue(e))); parsed.push(names); parsed.push(values); a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(parsed)); a.download = '(' + time + ').XDHx86_LightNovelLoader.data.txt'; a.click(); a.remove(); GM_setValue('lastbackup', JSON.stringify(new Date).replace('"', '')); } else if (mode == 1) { const i = document.querySelector('.LN_b input'), f = i.files[0]; if (!f) { alt('Please select a file!'); return; } fr.onload = () => { res = fr.result; } fr.readAsText(f); setTimeout(() => { let arr = JSON.parse(res), g = arr[0], v = arr[1]; if (!g || !g.LN_search('firsttime').found) alt('This is not a backup file, please check the uploaded file.'); else { for (let i = 0; i < g.length; i++) GM_setValue(g[i], v[i]); if (confirm('Settings will take effect after reload.\nReload now?')) location.reload(); } }, 1500); } } function record(e, doc = document, PL=CS, url, download=false) { rvals(); let novel, chapter; url = url || doc.URL || location.href; if (PL.novel != '') novel = doc.querySelector(PL.novel).href.LN_fix(url); else { novel = location.href.LN_fix(url).split('/'); if (novel[novel.length - 1] == '') { novel.pop(); novel.pop(); } else novel.pop(); novel = novel.join('/'); } if (url.includes('readlightnovel.me')) chapter = doc.querySelector('.block-title h1').lastChild.data.replace(' - ', ''); else if (url.includes('novelonlinefull') || url.includes('bestlightnovel')) chapter = doc.querySelector('.rdfa-breadcrumb p').lastChild.data; else if (url.includes('novels.pl')) chapter = doc.querySelector('.panel-title.pull-left').lastChild.data; else chapter = doc.querySelector(PL.chaptertitle).innerText; let result1 = HISTORY.LN_search(novel), result2 = DHISTORY.LN_search(novel); if (!download) { if (result1.found) { let obj = result1.obj; if (chapter != obj.text) { obj.text = chapter; obj.href = url; GM_setValue('HISTORY', HISTORY); rvals(); } } else { let obj = { novel: novel, href: url, text: chapter }; HISTORY.push(obj); GM_setValue('HISTORY', HISTORY); rvals(); } } else { if (result2.found) { let obj = result2.obj; if (chapter != obj.text) { obj.text = chapter; obj.href = url; GM_setValue('DHISTORY', DHISTORY); rvals(); } } else { let obj = { novel: novel, href: url, text: chapter }; DHISTORY.push(obj); GM_setValue('DHISTORY', DHISTORY); rvals(); } } } let cleanedr = false; function filter(c) { let clean = () => { let tbr = c.querySelectorAll('*'), elements = []; for (let e of tbr) if (e.parentElement == c && e.parentElement.tagName == 'P' && e.tagName == 'P') elements.push(e); for (let i = 0; i < elements.length; i++) { let e = elements[i]; if (e.children.length > 0) { do e.parentElement.appendChild(e.children[0]); while (e.children.length > 0); } } }; if (!cleanedr || window.LN_downloading) { clean(); clean(); if (!window.LN_downloading) cleanedr = true; } for (let i = 1; i < RULES.length; i++) { let obj = RULES[i]; if (obj.cond == 'line') { if (obj.type == 'contains') { for (let e of c.childNodes) { if (e.data) { if (obj.replaced == '' && e.data.includes(obj.word)) { if (e.previousSibling && e.previousSibling.tagName == 'BR') e.previousSibling.remove(); if (e.previousSibling && e.previousSibling.tagName == 'BR') e.previousSibling.remove(); e.data = ''; } else if (e.data.includes(obj.word)) e.data = obj.replaced; } else if (e.childNodes[0]) { for (let m of e.childNodes) { if (m.data) { if (obj.replaced == '' && m.data.includes(obj.word)) { m.data = ''; if (m.parentElement.tagName == 'P') m.parentElement.remove(); } else if (m.data.includes(obj.word)) m.data = obj.replaced; } } } } } else { for (let e of c.childNodes) { if (e.data) { if (obj.replaced == '' && e.data == (obj.word)) { if (e.previousSibling && e.previousSibling.tagName == 'BR') e.previousSibling.remove(); if (e.previousSibling && e.previousSibling.tagName == 'BR') e.previousSibling.remove(); e.data = ''; } else if (e.data.includes(obj.word)) e.data = obj.replaced; } else if (e.childNodes[0]) { for (let m of e.childNodes) { if (m.data) { if (obj.replaced == '' && m.data == (obj.word)) { m.data = ''; if (m.parentElement.tagName == 'P') m.parentElement.remove(); } else if (m.data.includes(obj.word)) m.data = obj.replaced; } } } } } } else { if (obj.type == 'equals') c.innerHTML = c.innerHTML.replaceAll(obj.word, obj.replaced); else c.innerHTML = c.innerHTML.replaceAll(new RegExp(obj.word, 'gmi'), obj.replaced); } } } let chapters = [], confirmed = false, pagecc = 1, wxpage = 0; function novelindex(url, maximum, elm) { let nurl = url; GM_xmlhttpRequest({ url: url, method: 'GET', onload: r => { try { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, PL = SITES[url.LN_host()], getmax = () => { let anc; if (b.querySelector(PL.indexobj.max)) anc = b.querySelector(PL.indexobj.max); else if (b.querySelectorAll(PL.indexobj.nav).length > 0) anc = b.querySelectorAll(PL.indexobj.nav)[b.querySelectorAll(PL.indexobj.nav).length-2]; else return 1; let x = new window.URL(anc.href); if (x.search) { let y = x.search.substr(x.search.indexOf('page=')), z = y; if (y.indexOf('&') > -1) z = y.substr(0, y.indexOf('&')); return parseInt(z.substr(z.indexOf('=') + 1)); } else return parseInt(x.href.substr(x.href.indexOf('page')+5)); }, getpage = () => { let x = new window.URL(url); if (x.search) { let y = x.search.substr(x.search.indexOf('page=')), z = y; if (y.indexOf('&') > -1) z = y.substr(0, y.indexOf('&')); return parseInt(z.substr(z.indexOf('=') + 1)); } else return parseInt(x.href.substr(x.href.indexOf('page')+5)); }, add = (elms=chapters) => { let addto = elm || l; if (addto.querySelector('div')) addto.querySelector('div').remove(); if (!Array.isArray(elms)) elms = Array.from(elms); if (!url.includes('lightnovelworld') && !url.includes('readlightnovel') && !url.includes('novelfull') && !url.includes('wuxiax.com') && !url.includes('novelhall')) elms.reverse(); for (let i = 0; i < elms.length; i++) { let el = elms[i], a = document.createElement('a'); a.className = 'LN_chapteran'; a.innerText = el.title || el.innerText; if (a.querySelectorAll('*')) for (let e of a.querySelectorAll('*')) e.remove(); a.href = el.href.LN_fix(url); a.onclick = e => { e.preventDefault(); if (location.href != a.href) { alt('Loading ' + a.innerText); dynamicload(a.href.LN_fix(location.href)); } } addto.appendChild(a); } if (addto.style.display == 'grid') sh('cit'); window.LN_indexslow = false; }, getdata = () => { if (url.includes('novels.pl')) { for (let e of b.querySelectorAll('script')) { if (e.innerHTML.includes('function load(page)')) { let str = e.innerHTML; str = str.substr(str.indexOf('data: {')); let id = str.substr(10, 4); id = id.trim(); if (id.endsWith(',')) id = id.substr(0, id.length-1); str = str.substr(str.indexOf(',')+2); let novel = str.substr(6, str.indexOf(',')-6); novel = novel.replace(/'|"'/g, ''); str = str.substr(str.indexOf(',')+2); let max = str.substr(4,4); max = max.trim(); if (max.endsWith(',')) max = max.substr(0, max.length-1); return `id=${id}&novel=${novel}&max=${max}&page=${maximum || 1}`;; } } } } if (BOTCHECK(b)) { if (confirm('Caught by bot verification.\nOpen url (' + url + ') in new tab?')) { window.open(url, '_blank'); setTimeout(() => { novelindex(nurl, maximum, elm) }, 10000); return; } else { add(); alt('Cancelled!'); return; } } if (url.includes('lightnovelworld')) { if (getmax() > 10 && !confirmed) { if (!confirm('Loading index might slow the browser or cause errors due to large amount of chapters, are you sure?')) { sh('cif'); confirmed = false; return; } window.LN_indexslow = true; confirmed = true; } let max = maximum || getmax(), currentpage = parseInt(getpage()), a = b.querySelectorAll(PL.indexobj.chapters); for (let e of a) chapters.push(e); if (currentpage == max) add(); else { nurl = url.replace(/page-[0-9]?[0-9]/, 'page-' + (currentpage + 1)); novelindex(nurl, max, elm); } } else if (url.includes('novelfull')) { let cid = document.querySelector('#chapter_error').getAttribute('data-chapter-id'), nid; for (let i = 0; i < document.scripts.length; i++) { let sc = document.scripts[i].innerHTML.toString(); if (sc.indexOf('var novel = {') > -1) nid = parseInt(sc.substr(sc.indexOf('var novel = {'), 40).substr(sc.substr(sc.indexOf('var novel = {'), 40).indexOf('id:')+4)); } GM_xmlhttpRequest({ method: 'GET', url: `https://novelfull.com/ajax-chapter-option?novelId=${nid}¤tChapterId=${cid}`, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), sel = doc.body.querySelector('select'); for (let i = 0; i < sel.options.length; i++) { let t = sel.options[i].innerText, h = 'https://novelfull.com' + sel.options[i].value, a = document.createElement('a'); a.href = h; a.innerText = t; chapters.push(a); } add(); } }); } else if (url.includes('wuxiax.com')) { let novellink = url.split('/')[4].replace('.html', ''); GM_xmlhttpRequest({ method: 'POST', url: 'https://www.wuxiax.com/e/extend/fy.php?page=' + wxpage + '&wjm=' + novellink, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, a = b.querySelectorAll('.chapter-list a'); for (let e of a) { const text = e.querySelector('strong').innerText; e.innerHTML = text; chapters.push(e); } wxpage++; if (b.querySelector('.chapter-list a')) novelindex(url, (maximum + 1) || 2, elm); else add(); } }); } else if (url.includes('www.readwn.com')) { let novellink = url.split('/')[4].replace('.html', ''); GM_xmlhttpRequest({ method: 'POST', url: 'https://www.readwn.com/e/extend/fy.php?page=' + wxpage + '&wjm=' + novellink, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, a = b.querySelectorAll('.chapter-list a'); for (let e of a) { const text = e.querySelector('strong').innerText; e.innerHTML = text; chapters.push(e); } wxpage++; if (b.querySelector('.chapter-list a')) novelindex(url, (maximum + 1) || 2, elm); else add(); } }); } else if (url.includes('novels.pl')) { GM_xmlhttpRequest({ method: 'POST', url: 'https://www.novels.pl/ajax/ajaxGetChapters.php', data: getdata(), headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, a = b.querySelectorAll('a'); for (let e of a) chapters.push(e); if (b.querySelector('a')) novelindex(url, (maximum + 1) || 2, elm); else add(); } }); } else if (url.includes('boxnovel.com')) { GM_xmlhttpRequest({ method: 'POST', url: url + 'ajax/chapters/', onload: r => { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'), b = doc.body, a = b.querySelectorAll('a:not([class])'); for (let e of a) chapters.push(e); add(); } }); } else add(b.querySelectorAll(PL.indexobj.chapters)); } catch (e) { const doc = new DOMParser().parseFromString(r.responseText, "text/html"), b = doc.body; if (!b) { alt('Error: NETWORK_ERROR\nDetails: Response cannot be null! Please try again later.\nReason: Might be request timeout, bad internet connection, spammed requests in a small time frame.', 10000); console.error(e); setTimeout(() => { novelindex(nurl, maximum, elm) }, 5000); } else if (BOTCHECK(b)) { if (confirm('Caught by bot verification.\nOpen url (' + url + ') in new tab?')) { window.open(url, '_blank'); setTimeout(() => { novelindex(nurl, maximum, elm) }, 10000); } else { alt('Cancelled!'); return; } } else { alt('Error:\nDetails: Unexpected error has occured. Please try again later.\nReason: Might be request timeout, bad internet connection, another unexpected reason.', 10000); console.error(e); setTimeout(() => { novelindex(nurl, maximum, elm) }, 5000); } } } }); } function getindex(url, elm) { let link = url || location.href, PL = SITES[link.LN_host()]; if (l.querySelector('a')) return; if (document.querySelector(PL.novel)) link = document.querySelector(PL.novel).href; else if (!elm) { link = location.href.split('/'); if (link[link.length - 1] == '') { link.pop(); link.pop(); } else link.pop(); link = link.join('/'); } if (PL.favobj.link) link += PL.favobj.link; if (PL.indexobj.page) link += PL.indexobj.page; novelindex(link, undefined, elm); } function migrate(url1, url2) { alt('Please wait for migration process.'); window.LN_migrating = true; let index1 = document.createElement('div'), index2 = document.createElement('div'), history = HISTORY.LN_search(url1), distory = DHISTORY.LN_search(url1); getindex(url1, index1); getindex(url2, index2); let interval1 = setInterval(() => { if (index1.querySelector('a') && index2.querySelector('a')) { if (history.found) { let getpos = () => { for (let i = 0; i < index1.querySelectorAll('a').length; i++) if (index1.querySelectorAll('a')[i].href == history.obj.href) return i; }, i = getpos(); if (!index2.querySelectorAll('a')[i]) alt('Couldn\'t find chapter ' + index1.querySelectorAll('a')[i].innerText + ' in ' + url2.LN_host() + '.\nPlease register the novel read history manually :(.'); else { let obj = { novel: url2, href: index2.querySelectorAll('a')[i].href, text: index2.querySelectorAll('a')[i].innerText }; if (!HISTORY.LN_search(url2).found) HISTORY.push(obj); else { HISTORY.LN_search(url2).obj.href = index2.querySelectorAll('a')[i].href; HISTORY.LN_search(url2).obj.text = index2.querySelectorAll('a')[i].innerText; } GM_setValue('HISTORY', HISTORY); } } if (distory.found) { let getpos = () => { for (let i = 0; i < index1.querySelectorAll('a').length; i++) if (index1.querySelectorAll('a')[i].href == distory.obj.href) return i; }, i = getpos(); if (!index2.querySelectorAll('a')[i]) alt('Couldn\'t find chapter ' + index1.querySelectorAll('a')[i].innerText + ' in ' + url2.LN_host() + '.\nPlease register the novel download history manually :(.'); else { let obj = { novel: url2, href: index2.querySelectorAll('a')[i].href, text: index2.querySelectorAll('a')[i].innerText }; if (!DHISTORY.LN_search(url2).found) DHISTORY.push(obj); else { DHISTORY.LN_search(url2).obj.href = index2.querySelectorAll('a')[i].href; DHISTORY.LN_search(url2).obj.text = index2.querySelectorAll('a')[i].innerText; } GM_setValue('DHISTORY', DHISTORY); } } clearInterval(interval1); rvals(); window.LN_migrating = false; setTimeout(() => alt('Migration successful.'), 7000); } }, 1000); } function search(inp, s) { if (typeof inp != 'string') inp = undefined; let input = inp || prompt('Search term'), binp = '' for (let s in SITES) { if (s.includes('novelonlinefull') || s.includes('bestlightnovel')) binp = input.replaceAll(' ', '_'); else binp = input; if (SITES[s].search.link.includes('${term}')) window.open(SITES[s].search.link.replace('${term}', binp), '_blank'); else GM_setValue('searchterm', binp), window.open(SITES[s].search.link, '_blank'); } } function dynamicmode() { if (autodmode) { let time = (new Date).getHours(); if (time > dmtime && !darked) ucss(); else if (time > lmtime && time < dmtime && darked) ucss(); } } function autobackup() { if (autobackupp != 0) { let date = GM_getValue('lastbackup'), age = (new Date((new Date) - (new Date(date)))).getDate(); if (!date || age >= autobackupp + 1) br(0); } } function timedcheck() { let time = (new Date).toTimeString().substr(0, 5); for (let i = 0; i < TIMES.length; i++) { let tbc = TIMES[i].time; if (time >= tbc) { if (CHECKED[0] && (new Date(CHECKED[0])).getDate() - (new Date).getDate() == 0) { if (!CHECKED.LN_search(TIMES[i].href).found) { let index = FAVS.LN_deepSearch(TIMES[i].href).parentIndex; CHECKED.push(TIMES[i].href); setTimeout(() => { alt('Auto checking for ' + FAVS[index].novel); notify(index, 0, true, true); }, (i - 1) * 15000); } } else { CHECKED = [JSON.stringify(new Date()).replaceAll('"', '')]; CHECKED.push(TIMES[i].href); let index = FAVS.LN_deepSearch(TIMES[i].href).parentIndex; setTimeout(() => { alt('Auto checking for ' + FAVS[index].novel); notify(index, 0, true, true); }, (i - 1) * 15000); } GM_setValue('CHECKED', CHECKED); } } } function feedback() { let html = document.createElement('div'), css = document.createElement('style'); html.className = 'LN_container'; html.innerHTML = '<div class="LN_main"> <h3 class="LN_head"> Subject: </h3> <input class="LN_sub"> <br> <h3 class="LN_head"> Message Body: </h3> <span> Please don\'t actually use this to write your message and use an editor then paste here. </span> <br> <textarea class="LN_msg" spellcheck="true" style=" "></textarea> <br> <br> <button class="LN_send"> Send </button> </div>'; css.innerHTML = '.LN_container { z-index: 2147483644; top: 0; left: 0; position: fixed; background-color: #000c; color: #090; width: 100%; height: 100%; display: flex; transition: all 0.5s; user-select: none; } .LN_main { margin: auto; transition: inherit; background-color: #000; height: 70%; padding: 20px; border-radius: 15px; width: 50%; box-shadow: 0 0 20px 20px #090; position: fixed; translate: -50% -50%; top: 50%; left: 50%; } .LN_head { margin: 15px 0 0; } .LN_container input { width: auto; min-width: 100px; margin: 2px; background-color: #111; color: #777; border: none; padding: 2px; outline: 0; margin-left: 15px; font-weight: bolder; outline: 0; transition: inherit; } .LN_container input:focus { box-shadow: 0 0 5px 2px #090; padding: 3px; margin: 5px 1px 5px 10px; outline: 0; border: 1px solid #090; } .LN_container span { margin-left: 15px; } .LN_msg { width: calc(100% - 40px); height: calc(100% - 250px); min-width: 100px; margin: 2px; background-color: #111; color: #777; border: none; padding: 2px; outline: 0; margin-left: 15px; font-weight: bolder; outline: 0; transition: inherit; } .LN_send:hover { color: #090; background-color: #000; } .LN_send { transition: inherit; border: none; color: #000; background-color: #090; outline: 0; font-family: sans-serif; cursor: pointer; padding: 5px 20px; font-weight: bolder; margin-left: 10px; margin-top: 10px; }'; document.body.appendChild(html); document.head.appendChild(css); html.onclick = e => { if (e.target.LN_hasClass('LN_container')) { html.remove(); css.remove(); } } html.querySelector('.LN_send').onclick = () => { let sub = html.querySelector('.LN_sub'), msg = html.querySelector('.LN_msg'), validate = () => { let output = true; if (!msg.value) { msg.setCustomValidity('Message body is required'); msg.reportValidity(); msg.onfocus = () => msg.setCustomValidity(''); alt('Message body is required!'); output = false; } return output; }; if (validate()) { if (!sub.value) sub.value = 'LN Loader v' + GM_info.script.version + ' feedback'; let link = 'mailto:xdhx86@gmail.com&subject=' + encodeURIComponent(sub.value) + '&body=' + encodeURIComponent(msg.value); window.open(link, '_blank'); html.remove(); css.remove(); alt('Thanks for the feedback!'); } } } const stopit = () => { if (window.LN_canceldownload) { alt('No download found!'); window.LN_canceldownload = false; if (document.querySelector('.LN_btn')) document.querySelectorAll('.LN_btn')[3].disabled = true; } if (window.LN_cancelauto) { alt('No auto download found!'); window.LN_cancelauto = false; if (document.querySelector('.LN_btn')) document.querySelectorAll('.LN_btn')[4].disabled = true; } } GM_registerMenuCommand('Show Favorites', favs); GM_registerMenuCommand('Check for updates', () => { alt('Please wait while the script searches for new chapters.', 5000); notify(); }); GM_registerMenuCommand('Search all sources for a novel', search); GM_registerMenuCommand('Cancel current download', () => { window.LN_canceldownload = true; window.LN_cancelauto = false; alt('Please wait.'); if (document.querySelector('.LN_btn')) document.querySelectorAll('.LN_btn')[3].disabled = true; setTimeout(stopit, 10000); }); GM_registerMenuCommand('Cancel auto download', () => { window.LN_canceldownload = true; window.LN_cancelauto = true; alt('Please wait.'); if (document.querySelector('.LN_btn')) document.querySelectorAll('.LN_btn')[4].disabled = true; setTimeout(stopit, 10000); }); GM_registerMenuCommand('Feedback', feedback); let dispatch = (inp, value) => { inp.focus(); inp.click(); inp.value = value; inp.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, char: 'Q', key: 'q', keyCode: 81, code: 'KeyQ' })); }, searchinterval = setInterval(() => { try { let searchterm = GM_getValue('searchterm'), inp = document.querySelector(CS.search.input); if (!inp || !searchterm) { clearInterval(searchinterval); return; } dispatch(inp, searchterm); GM_setValue('searchterm', ''); clearInterval(searchinterval); } catch { clearInterval(searchinterval); } }, 1000), timedcheckint = setInterval(() => { rvals(); if (TIMES.length == CHECKED.length) clearInterval(timedcheckint); if (autoch) timedcheck(); else clearInterval(timedcheckint); }, 60000); if (!CS || !document.querySelector(CS.chapter)) { check(); autobackup(); } else { ui(); set(); window.onkeyup = handler; check(); window.onunload = window.onbeforeunload = () => WIN.close(); dynamicmode(); autobackup(); } for (let i = 1; i < FAVS.length; i++) if (FAVS[i].url.href == '') alert(`Error encountered while checking the novel ${FAVS[i].novel}\nPlease remove it and re-add it again.`); window.addEventListener('beforeunload', e => { if (window.LN_checking || window.LN_downloading || window.LN_migrating) { e.preventDefault(); return 'The script is currently checking, downloading, or migrating content. Are you sure you want to leave the page?'; if (window.LN_checking) alt('The script is currently checking updates, please wait.'); else if (window.LN_downloading) alt('The script is currently downloading content, please wait.'); else if (window.LN_migrating) alt('The script is currently migrating a novel to another source, please wait.'); } }); })();