XDHx86 / Light Novel Loader

// ==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}&currentChapterId=${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.');
        }
    });
})();