// ==UserScript== // @name Manga OnlineViewer // @author Tago // @namespace https://github.com/TagoDR // @description Shows all pages at once in online view for these sites: Asura Scans, Batoto, BilibiliComics, ComiCastle, Dynasty-Scans, Asura Scans, Flame Scans, Realm Scans, Voids-Scans, Luminous Scans, INKR, InManga, KLManga, Leitor, LHTranslation, LynxScans, MangaBuddy, MangaDex, MangaFox, MangaHere, MangaFreak, mangahosted, MangaHub, MangaKakalot, MangaNelo, MangaNato, Mangareader, MangaSee, Manga4life, MangaTigre, MangaToons, MangaTown, ManhuaScan, MReader, MangaGeko, NaniScans, NineManga, PandaManga, RawDevart, ReadComicsOnline, ReadManga Today, Funmanga, MangaDoom, MangaInn, ReaperScans, Reset-Scans, SenManga(Raw), ShimadaScans, KLManga, TenManga, TuMangaOnline, UnionMangas, WebNovel, WebToons, Manga33, ZeroScans, FoOlSlide, Kireicake, Madara WordPress Plugin, MangaHaus, Isekai Scan, Comic Kiba, Zinmanga, mangatx, Toonily, Mngazuki, JaiminisBox, DisasterScans, ManhuaPlus, TopManhua, LeviatanScans, NovelMic // @version 2023.03.03 // @license MIT // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_listValues // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @noframes on // @connect * // @require https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.6.0/tinycolor.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.js // @require https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/5.0.0/imagesloaded.pkgd.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.9.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/11.4.8/sweetalert2.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js // @require https://cdn.jsdelivr.net/npm/hotkeys-js@3.10.1/dist/hotkeys.min.js // @include /https?:\/\/beta.asurascans.com\/read\/.+\/.+/ // @include /https?:\/\/(www.)?bato.to\/chapter.*/ // @include /https?:\/\/(www.)?(bilibilicomics).com\/.+\/.+/ // @include /https?:\/\/(www.)?comicastle.org\/read\/.+\/[0-9]+.*/ // @include /https?:\/\/(www.)?dynasty-scans.com\/chapters\/.+/ // @include /https?:\/\/(www.)?(asurascans|flamescans|realmscans|void-scans|luminousscans).(com|org|gg)\/.+/ // @include /https?:\/\/(comics.)?inkr.com\/title\/.+\/chapter\/.+/ // @include /https?:\/\/(www.)?inmanga.com\/ver\/manga\/.+\/.+/ // @include /https?:\/\/(www.)?klmanga.com\/.+chapter.+/ // @include /https?:\/\/(www.)?leitor.net\/manga\/.+\/.+\/.+/ // @include /https?:\/\/(www.)?lhtranslation.net\/read.+/ // @include /https?:\/\/(www.)?lynxscans.com\/comics?\/.+/ // @include /https?:\/\/(www.)?mangabuddy.com\/.+\/chapter.+/ // @include /https?:\/\/(www.)?mangadex.org\/chapter\/.+(\/.+)?/ // @include /https?:\/\/(www.)?(fanfox.net|mangahere.cc)\/manga\/.+\/.+\// // @include /https?:\/\/.{3,4}?(mangafreak).net\/Read.+/ // @include /https?:\/\/(www.)?mangahosted.com\/manga\/.+\/.+/ // @include /https?:\/\/(www.)?(mangahub).io\/chapter\/.+\/.+/ // @include /https?:\/\/(www.)?((manganelo|mangakakalot).com\/chapter\/.+\/.+|(manganato|readmanganato|chapmanganato).com\/manga-\w\w\d+\/chapter-\d+)/ // @include /https?:\/\/(www.)?mangareader.to\/read\/.+\/.+\/.+/ // @include /https?:\/\/(www.)?(mangasee123|manga4life).com\/read-online\/.+/ // @include /https?:\/\/(www.)?mangatigre.net\/.+\/.+\/.+/ // @include /https?:\/\/(www.)?mangatoon.mobi\/.+\/watch\/.+/ // @include /https?:\/\/(www.|m.)?mangatown.com\/manga\/.+\/.+/ // @include /https?:\/\/(www.)?manhuascan.io\/.+chapter.+/ // @include /https?:\/\/(www.)?(mreader|mangageko).com?\/reader\/.*/ // @include /https?:\/\/(www.)?(naniscans).com\/chapters\/.+\/read/ // @include /https?:\/\/(www.)?ninemanga.com\/chapter\/.+\/.+\.html/ // @include /https?:\/\/(www.)?pandamanga.xyz\/.+\/.+\/.+/ // @include /https?:\/\/(www.)?rawdevart.com\/comic\/.+\/.+\// // @include /https?:\/\/(www.)?readcomicsonline.ru\/comic\/.*\/\d*/ // @include /https?:\/\/(www.)?(funmanga|mngdoom|readmng|mangainn).(com|net)\/.+\/\d+/ // @include /https?:\/\/(www.)?reaperscans.com\/comics\/.+\/chapters\/.+/ // @include /https?:\/\/(www.)?reset-scans.com\/manga\/.+\/chapter.+/ // @include /https?:\/\/raw.senmanga.com\/.+\/.+\/?/ // @include /https?:\/\/(www.)?shimadascans.com\/.+(series|chapter).+/ // @include /https?:\/\/(www.)?tapas.io\/episode\/.+/ // @include /https?:\/\/(www.)?(tenmanga|gardenmanage).com\/(chapter|statuses)\/.+/ // @include /https?:\/\/(www.)?(tmofans|lectortmo|followmanga).com\/.+\/.+\/(paginated|cascade)/ // @include /https?:\/\/(www.)?unionleitor.top\/leitor\/.+\/.+/ // @include /https?:\/\/(www.)?webnovel.com\/comic\/.+/ // @include /https?:\/\/(www.)?webtoons.com\/.+viewer.+/ // @include /https?:\/\/(www.)?(manga33).com\/manga\/.+/ // @include /https?:\/\/(www.)?zeroscans.com\/comics\/.+/ // @include /^(?!.*jaiminisbox).*\/read\/.+/ // @include /https?:\/\/.+\/(manga|series|manhua|comic)\/.+\/.+/ // @exclude /https?:\/\/(www.)?tsumino.com\/.+/ // @exclude /https?:\/\/(www.)?pururin.io\/.+/ // @downloadURL none // ==/UserScript== (function () { 'use strict'; const asurascans = { name: "Asura Scans", url: /https?:\/\/beta.asurascans.com\/read\/.+\/.+/, homepage: "https://beta.asurascans.com/", language: ["English"], category: "manga", run() { const { chapterID, data } = JSON.parse( document.querySelector("#__NEXT_DATA__")?.textContent ?? "" ).props.pageProps; return { title: document.querySelector("span.h2")?.textContent?.trim(), series: document.querySelector(".container a.h6")?.getAttribute("href"), pages: data.length, prev: document.querySelector(".prev:not(.disabled)")?.getAttribute("href"), next: document.querySelector(".next:not(.disabled)")?.getAttribute("href"), listImages: data.map( (img) => `https://img.asurascans.com/pages/${chapterID}/${img.uuid}.jpg` ) }; } }; const batoto = { name: "Batoto", url: /https?:\/\/(www.)?bato.to\/chapter.*/, homepage: "http://bato.to/", language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll(".page-img")]; return { title: document.querySelector(".nav-title a")?.textContent?.trim(), series: document.querySelector(".nav-title a")?.getAttribute("href"), pages: images.length, prev: document.querySelector(".nav-prev a")?.getAttribute("href"), next: document.querySelector(".nav-next a")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const bilibilicomics = { name: "BilibiliComics", url: /https?:\/\/(www.)?(bilibilicomics).com\/.+\/.+/, homepage: "https://www.bilibilicomics.com/", language: ["English"], category: "manga", waitEle: ".read-nav", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const api = await fetch( "https://www.bilibilicomics.com/twirp/comic.v1.Comic/GetImageIndex?device=pc&platform=web&lang=en&sys_lang=en", { method: "post", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify({ ep_id: W.location.href.split("/").pop(), credential: "" }) } ).then((res) => res.json()).then(({ data }) => data.images.map((image) => `${image.path}@2000w.webp`)).then(JSON.stringify).then( (urls) => fetch( "https://www.bilibilicomics.com/twirp/comic.v1.Comic/ImageToken?device=pc&platform=web&lang=en&sys_lang=en", { method: "post", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify({ urls }) } ) ).then((res) => res.json()).then( (tokens) => tokens.data.map((i) => `${i.url}?token=${i.token}`) ); return { title: document.querySelector(".read-nav")?.textContent?.trim(), series: document.querySelector(".manga-title")?.getAttribute("href"), pages: api.length, prev: document.querySelector(".navigate a button[title=Previous]")?.parentElement?.getAttribute("href"), next: document.querySelector(".navigate a button[title=Next]")?.parentElement?.getAttribute("href"), listImages: api }; } }; const comicastle = { name: "ComiCastle", url: /https?:\/\/(www.)?comicastle.org\/read\/.+\/[0-9]+.*/, homepage: "http://www.comicastle.org/", language: ["English"], category: "comic", waitEle: ".form-control option:nth-child(1)", run() { const images = [...document.querySelectorAll(".form-control")[1].querySelectorAll("option")]; const chapter = document.querySelectorAll(".form-control")[0].querySelector("option:checked"); return { title: chapter?.textContent?.trim(), series: document.querySelector(".navbar-header a")?.getAttribute("href"), pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("value"), next: chapter?.nextElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("alt")) }; } }; const dysnatyscans = { name: "Dynasty-Scans", url: /https?:\/\/(www.)?dynasty-scans.com\/chapters\/.+/, homepage: "https://dynasty-scans.com/", language: ["English"], category: "manga", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; return { title: document.querySelector("#chapter-title")?.textContent?.trim(), series: document.querySelector("#chapter-title a")?.getAttribute("href"), pages: W.pages.length, prev: document.querySelector("#prev_link")?.getAttribute("href"), next: document.querySelector("#next_link")?.getAttribute("href"), listImages: W.pages.map((x) => x.image) }; } }; const flamecans = { name: ["Asura Scans", "Flame Scans", "Realm Scans", "Voids-Scans", "Luminous Scans"], url: /https?:\/\/(www.)?(asurascans|flamescans|realmscans|void-scans|luminousscans).(com|org|gg)\/.+/, homepage: [ "https://www.asura.gg/", "https://flamescans.org/", "https://realmscans.com/", "https://void-scans.com/", "https://luminousscans.com/" ], language: ["English"], category: "manga", waitEle: "#chapter option:nth-child(2)", run() { const chapter = document.querySelector("#chapter option:checked"); const images = [...document.querySelectorAll("#readerarea img")]; return { title: document.querySelector(".entry-title")?.textContent?.trim(), series: document.querySelector(".allc a")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images.map( (img) => img.getAttribute("data-src") || img.getAttribute("data-lazy-src") || img.getAttribute("src") ) }; } }; const foolslide = { name: ["FoOlSlide", "Kireicake"], url: /^(?!.*jaiminisbox).*\/read\/.+/, homepage: ["#", "https://reader.kireicake.com"], language: ["English"], obs: "Any Site that uses FoOLSlide", category: "manga", waitEle: "img.open", run() { const chapter = [...document.querySelectorAll(".topbar_left .dropdown_parent:last-of-type li")]; const origin = chapter.findIndex((item) => { const url = item.querySelector("a")?.getAttribute("href"); if (url) return window.location.href.startsWith(url); return false; }); const pages = [...document.querySelectorAll(".topbar_right .dropdown li")]; const images = [...document.querySelectorAll(".inner img:not(.open)")]; const num = images.length > 1 ? images.length : pages.length; return { title: chapter.at(origin)?.querySelector("a")?.textContent?.trim() ?? document.querySelector("title")?.textContent?.trim(), series: document.querySelector("div.tbtitle div.text a")?.getAttribute("href"), pages: num, prev: chapter.at(origin + 1)?.querySelector("a")?.getAttribute("href"), next: chapter.at(origin - 1)?.querySelector("a")?.getAttribute("href"), listPages: images.length > 1 ? null : Array(num).fill(0).map((_, i) => `${window.location.href.replace(/\/\d+$/, "")}/${i + 1}`), listImages: images.length > 1 ? images.map((img) => img.getAttribute("src")) : null, img: "img.open" }; } }; const inkr = { name: "INKR", url: /https?:\/\/(comics.)?inkr.com\/title\/.+\/chapter\/.+/, homepage: "https://inkr.com/", language: ["English"], category: "manga", waitFunc: () => document.querySelector("#editor-v2-scroll-view-id img")?.style.width !== "", run() { const images = [...document.querySelectorAll("#editor-v2-scroll-view-id img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector("#chapter-detail-viewer-page div div div a")?.getAttribute("href"), pages: images.length, prev: document.querySelector('a[aria-label="Previous Chapter"]')?.getAttribute("href"), next: document.querySelector('a[aria-label="Next Chapter"]')?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")?.replace("/t.", "/p.")) }; } }; const inmanga = { name: "InManga", url: /https?:\/\/(www.)?inmanga.com\/ver\/manga\/.+\/.+/, homepage: "https://inmanga.com//", language: ["Spanish"], category: "manga", waitVar: "pageController", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = [...document.querySelectorAll("#PageList option")]; const chapter = document.querySelector("#ChapList option:checked"); const src = W.pageController._containers.pageUrl; return { title: document.querySelector("title")?.textContent?.trim(), series: `../${W.pageController._containers.mangaIdentification}`, pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("value"), next: chapter?.nextElementSibling?.getAttribute("value"), listImages: images.map( (img, index) => src.replace("identification", img.getAttribute("value")).replace("pageNumber", index) ) }; } }; const klmanga = { name: "KLManga", url: /https?:\/\/(www.)?klmanga.com\/.+chapter.+/, homepage: "https://klmanga.com/", language: ["Raw"], category: "manga", run() { const images = [...document.querySelectorAll(".chapter-content img")]; const chapter = document.querySelectorAll(".form-control")[0].querySelector("option:checked"); return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".navbar-brand")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const leitor = { name: "Leitor", url: /https?:\/\/(www.)?leitor.net\/manga\/.+\/.+\/.+/, homepage: "https://leitor.net/", language: ["Portuguese"], category: "manga", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const url = `https://leitor.net/leitor/pages/${W.READER_ID_RELEASE}.json?key=${W.READER_TOKEN}`; const api = await fetch(url).then((res) => res.json()); const chapter = document.querySelector(".chapter-list .selected"); return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".series-cover a")?.getAttribute("href"), pages: api.images.length, prev: chapter?.nextElementSibling?.querySelector("a")?.getAttribute("href"), next: chapter?.previousElementSibling?.querySelector("a")?.getAttribute("href"), listImages: api.images.map( (img) => img.avif || img.legacy ) }; } }; const lhtranslation = { name: "LHTranslation", url: /https?:\/\/(www.)?lhtranslation.net\/read.+/, homepage: "https://lhtranslation.net/", language: ["English"], category: "manga", run() { const chapter = document.querySelector(".form-control option:checked"); const images = [...document.querySelectorAll("img.chapter-img")]; return { title: document.querySelector(".chapter-img.tieude font")?.textContent?.trim(), series: document.querySelector(".navbar-brand.manga-name")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const lynxscans = { name: "LynxScans", url: /https?:\/\/(www.)?lynxscans.com\/comics?\/.+/, homepage: "https://lynxscans.com/", language: ["English"], category: "manga", waitAttr: ["#app", "data-page"], run() { const data = JSON.parse(document.querySelector("#app").getAttribute("data-page")); return { title: document.querySelector("title")?.textContent?.trim(), series: data.props.home, pages: data.props.pages.length, prev: data.props.previousChapter, next: data.props.nextChapter, listImages: data.props.pages.map((img) => img.url) }; } }; const madarawp = { name: [ "Madara WordPress Plugin", "MangaHaus", "Isekai Scan", "Comic Kiba", "Zinmanga", "mangatx", "Toonily", "Mngazuki", "JaiminisBox", "DisasterScans", "ManhuaPlus", "TopManhua", "LeviatanScans", "NovelMic" ], url: /https?:\/\/.+\/(manga|series|manhua|comic)\/.+\/.+/, homepage: [ "#", "https://manhuaus.com", "https://isekaiscan.com/", "https://comickiba.com/", "https://zinmanga.com/", "https://mangatx.com/", "https://toonily.net/", "https://mangazuki.me/", "https://jaiminisbox.net", "https://disasterscans.com/", "https://manhuaplus.com/", "https://www.topmanhua.com/", "https://en.leviatanscans.com/home/", "https://novelmic.com/" ], language: ["English"], obs: "Any Site that uses Madara Wordpress Plugin", category: "manga", run() { const images = [ ...document.querySelectorAll( ".wp-manga-chapter-img, .blocks-gallery-item img, .reading-content img" ) ]; return { title: document.querySelector("#chapter-heading")?.textContent?.trim(), series: (document.querySelector(".breadcrumb li:nth-child(3) a") || document.querySelector(".breadcrumb li:nth-child(2) a"))?.getAttribute("href"), pages: images.length, prev: document.querySelector(".prev_page")?.getAttribute("href"), next: document.querySelector(".next_page")?.getAttribute("href"), listImages: images.map( (img) => _.without( [ img?.getAttribute("src"), img?.getAttribute("data-src"), img?.getAttribute("data-full-url") ], null, void 0, "" ).pop() ) }; } }; const mangabuddy = { name: "MangaBuddy", url: /https?:\/\/(www.)?mangabuddy.com\/.+\/chapter.+/, homepage: "https://mangabuddy.com/", language: ["English"], category: "manga", waitVar: "final_images", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const img = [...document.querySelectorAll(".chapter-image.load-first img")].map( (img2) => img2.getAttribute("data-src") || img2.getAttribute("src") ); const images = [...img, ...W.final_images]; return { title: document.querySelector(".chapter-info")?.textContent?.trim(), series: document.querySelector("#breadcrumbs-container div:nth-child(2) a")?.getAttribute("href"), pages: images.length, prev: document.querySelector("a.prev")?.getAttribute("href"), next: document.querySelector("a.next")?.getAttribute("href"), listImages: images }; } }; const mangadex = { name: "MangaDex", url: /https?:\/\/(www.)?mangadex.org\/chapter\/.+(\/.+)?/, homepage: "https://mangadex.org/", language: ["English"], category: "manga", waitEle: ".md--reader-menu a[href^='/chapter/']", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const chapterId = W.location.pathname.match(/\/chapter\/([^/]+)(\/\d+)?/)[1]; const home = `https://api.mangadex.org/at-home/server/${chapterId}`; const server = await fetch(home).then((res) => res.json()); const images = server.chapter.data; const chapters = [...document.querySelectorAll(".md--reader-menu a[href^='/chapter/']")].map( (a) => a.getAttribute("href") ); return { title: document.querySelector("title")?.text.replace(" - MangaDex", ""), series: document.querySelector("a.text-primary[href^='/title/']")?.getAttribute("href"), pages: images.length, prev: chapters[0] !== W.location.pathname ? chapters[0] : "#", next: chapters[1] !== W.location.pathname ? chapters[1] : "#", listImages: images.map((img) => `${server.baseUrl}/data/${server.chapter.hash}/${img}`) }; } }; const mangafox = { name: ["MangaFox", "MangaHere"], url: /https?:\/\/(www.)?(fanfox.net|mangahere.cc)\/manga\/.+\/.+\//, homepage: ["https://fanfox.net/", "https://www.mangahere.cc/"], language: ["English"], category: "manga", waitVar: "chapterid", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const key = document.querySelector("#dm5_key")?.getAttribute("value"); const options = { method: "GET", headers: { "Content-Type": "text/plain" } }; const src = Array(W.imagecount).fill(0).map(async (_, i) => { const url = `chapterfun.ashx?cid=${W.chapterid || W.chapter_id}&page=${i}&key=${key}`; const api = await fetch(url, options).then((res) => res.text()); (0, eval)(api); return d; }); const images = await Promise.all(src); return { title: document.querySelector(".reader-header-title div")?.textContent?.trim(), series: document.querySelector(".reader-header-title a")?.getAttribute("href"), pages: W.imagecount, prev: W.prechapterurl, next: W.nextchapterurl, listImages: images.map((img, i) => img[i === 0 ? 0 : 1]) }; } }; const mangafreak = { name: "MangaFreak", url: /https?:\/\/.{3,4}?(mangafreak).net\/Read.+/, homepage: "https://mangafreak.net/", language: ["English"], category: "manga", run() { const chapter = document.querySelector( ".chapter_list select option:checked" ); const images = [...document.querySelectorAll(".mySlides img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".title a")?.getAttribute("href"), pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("value"), next: chapter?.nextElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const mangahosted = { name: "mangahosted", url: /https?:\/\/(www.)?mangahosted.com\/manga\/.+\/.+/, homepage: "https://mangahosted.com/", language: ["Portuguese"], category: "manga", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = [...document.querySelectorAll("picture img")]; return { title: $(".breadcrumb li:eq(3)").text().trim(), series: $(".breadcrumb li:eq(2) a").attr("href"), pages: images.length, prev: W.$read_prev, next: W.$read_next, listImages: images.map((img) => img.getAttribute("src")) }; } }; const mangahub = { name: "MangaHub", url: /https?:\/\/(www.)?(mangahub).io\/chapter\/.+\/.+/, homepage: "https://mangahub.io/", language: ["English"], category: "manga", waitEle: "#select-chapter", async run() { function getCookie(name) { const re = new RegExp(`${name}=([^;]+)`); const value = re.exec(document.cookie); return value != null ? decodeURIComponent(value[1]) : null; } const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const slug = W.CURRENT_MANGA_SLUG || window.location.pathname.split("/")[2]; const number = window.location.pathname.split("/")[3].replace("chapter-", ""); const data = { query: `{chapter(x:m01,slug:"${slug}",number:${number}){pages}}` }; const options = { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json", "x-mhub-access": getCookie("mhub_access") } }; const api = await fetch("https://api.mghubcdn.com/graphql", options).then( (res) => res.json() ); const images = JSON.parse(api?.data.chapter.pages.toString()); return { title: document.querySelector("#mangareader h3")?.textContent?.trim(), series: document.querySelector("#mangareader a")?.getAttribute("href"), pages: images.i.length, prev: document.querySelector(".previous a")?.getAttribute("href"), next: document.querySelector(".next a")?.getAttribute("href"), listImages: images.i.map( (i) => `https://img.mghubcdn.com/file/imghub/${images.p + i}` ) }; } }; const mangakakalot = { name: ["MangaKakalot", "MangaNelo", "MangaNato"], url: /https?:\/\/(www.)?((manganelo|mangakakalot).com\/chapter\/.+\/.+|(manganato|readmanganato|chapmanganato).com\/manga-\w\w\d+\/chapter-\d+)/, homepage: [ "https://mangakakalot.com/page", "https://www.manganelo.com/", "https://www.manganato.com/" ], language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll("#vungdoc img, .container-chapter-reader img")]; return { title: document.querySelector( ".info-top-chapter h2, .imageOptions-chapter-info-top h1, .panel-chapter-info-top h1" )?.textContent?.trim(), series: document.querySelectorAll("span a[title]").item(1).getAttribute("href"), pages: images.length, prev: document.querySelector(".navi-change-chapter-btn-prev, .next")?.getAttribute("href"), next: document.querySelector(".navi-change-chapter-btn-next, .back")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const mangareader = { name: "Mangareader", url: /https?:\/\/(www.)?mangareader.to\/read\/.+\/.+\/.+/, homepage: "https://mangareader.to", language: ["English"], category: "manga", obs: "Some galleries will not be usable", waitEle: ".ds-image, .iv-card", run() { const chapter = document.querySelector(".chapter-item.active"); const images = [ ...document.querySelectorAll( ".ds-image:not(.shuffled)[data-url], .iv-card:not(.shuffled)[data-url]" ) ]; return { title: document.querySelector(".hr-manga h2")?.textContent?.trim(), series: document.querySelector(".hr-manga")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.querySelector("a")?.getAttribute("href"), next: chapter?.previousElementSibling?.querySelector("a")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("data-url")) }; } }; const mangasee = { name: ["MangaSee", "Manga4life"], url: /https?:\/\/(www.)?(mangasee123|manga4life).com\/read-online\/.+/, homepage: ["https://mangasee123.com/", "https://manga4life.com/"], language: ["English"], category: "manga", waitAttr: [".img-fluid", "src"], run() { const src = document.querySelector(".img-fluid")?.getAttribute("src") || ""; const script = [...document.querySelectorAll("body script:not([src])")].at(-1)?.textContent; const textCurChapter = script?.match(/CurChapter = ({.+});/) || []; const CurChapter = JSON.parse(textCurChapter[1]); const textCHAPTERS = script?.match(/CHAPTERS = (\[\{.+}]);/) || []; const CHAPTERS = JSON.parse(textCHAPTERS[1]); const CurChapterIndex = CHAPTERS.findIndex( (chap) => chap.Chapter === CurChapter.Chapter ); function ChapterURLEncode(reference) { let ChapterString = CHAPTERS[CurChapterIndex + reference]; if (ChapterString === void 0) { return "#"; } ChapterString = ChapterString.Chapter; let Index = ""; const IndexString = ChapterString.substring(0, 1); if (IndexString !== "1") { Index = `-index-${IndexString}`; } const Chapter = parseInt(ChapterString.slice(1, -1), 10); let Odd = ""; const OddString = ChapterString[ChapterString.length - 1]; if (OddString !== "0") { Odd = `.${OddString}`; } return window.location.href.replace(/-chapter-.+/, `-chapter-${Chapter}${Odd}${Index}.html`); } return { title: document.querySelector("title")?.textContent?.replace(/ Page .+/, "").trim(), series: document.querySelector(".MainContainer a")?.getAttribute("href"), pages: parseInt(CurChapter.Page, 10), prev: ChapterURLEncode(-1), next: ChapterURLEncode(1), listImages: Array(parseInt(CurChapter.Page, 10)).fill(0).map((_, i) => src.replace(/-\d\d\d.png/, `-${String(`000${i + 1}`).slice(-3)}.png`)) }; } }; const mangatigre = { name: "MangaTigre", url: /https?:\/\/(www.)?mangatigre.net\/.+\/.+\/.+/, homepage: "https://www.mangatigre.net/", language: ["Spanish"], category: "manga", run() { const images = [...document.querySelectorAll(".chapter-content img")]; const chapter = document.querySelector(".form-control option:checked"); return { title: document.querySelector(".page-title")?.textContent?.trim(), series: document.querySelector(".breadcrumb li:nth-child(3) a")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("data-src") || img.getAttribute("src")) }; } }; const mangatoon = { name: "MangaToons", url: /https?:\/\/(www.)?mangatoon.mobi\/.+\/watch\/.+/, homepage: "https://mangatoon.mobi/", language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll(".pictures img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".top-left a")?.getAttribute("href"), pages: images.length, prev: document.querySelector(".page-icons-prev")?.getAttribute("href"), next: document.querySelector(".page-icons-next")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("data-src")) }; } }; const mangatown = { name: "MangaTown", url: /https?:\/\/(www.|m.)?mangatown.com\/manga\/.+\/.+/, homepage: "https://www.mangatown.com/", language: ["English"], category: "manga", waitVar: "chapter_id", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const key = document.querySelector("#dm5_key")?.getAttribute("value"); const options = { method: "GET", headers: { "Content-Type": "text/plain" } }; const src = Array(W.total_pages).fill(0).map(async (_, i) => { const url = `chapterfun.ashx?cid=${W.chapter_id}&page=${i}&key=${key}`; const api = await fetch(url, options).then((res) => res.text()); (0, eval)(api); return d; }); const images = await Promise.all(src); const chapter = document.querySelector("#top_chapter_list option:checked"); return { title: document.querySelector(".title h1")?.textContent, series: W.series_url, pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("value"), next: chapter?.nextElementSibling?.getAttribute("value"), listImages: images.map((img, i) => img[i === 0 ? 0 : 1]) }; } }; const manhuascan = { name: "ManhuaScan", url: /https?:\/\/(www.)?manhuascan.io\/.+chapter.+/, homepage: "https://manhuascan.io/", language: ["English"], category: "manga", waitVar: "imgsrcs", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const key = CryptoJS.enc.Hex.parse("e11adc3949ba59abbe56e057f20f131e"); const iv = CryptoJS.enc.Hex.parse("1234567890abcdef1234567890abcdef"); const opinion = { iv, padding: CryptoJS.pad.ZeroPadding }; const images = CryptoJS.AES.decrypt(W.imgsrcs, key, opinion).toString(CryptoJS.enc.Utf8).split(","); return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".breadcrumb li:nth-child(3) a")?.getAttribute("href"), pages: images.length, prev: document.querySelector(".chapter-select a:first-of-type")?.getAttribute("href"), next: document.querySelector(".chapter-select a:last-of-type")?.getAttribute("href"), listImages: images }; } }; const mreader = { name: ["MReader", "MangaGeko"], url: /https?:\/\/(www.)?(mreader|mangageko).com?\/reader\/.*/, homepage: ["https://www.mreader.co/", "https://www.mangageko.com/"], language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll("#chapter-reader img")]; return { title: document.querySelector(".titles")?.textContent?.trim(), series: document.querySelector(".titles a")?.getAttribute("href"), pages: images.length, prev: document.querySelector(".chnav.prev")?.getAttribute("href"), next: document.querySelector(".chnav.next")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const naniscans = { name: "NaniScans", url: /https?:\/\/(www.)?(naniscans).com\/chapters\/.+\/read/, homepage: "https://naniscans.com/", language: ["English"], category: "manga", waitVar: "chapterListRoute", async run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const api = await fetch(W.location.href.replace("read", "json")).then((res) => res.json()); return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector('a[href^="/titles/"]')?.getAttribute("href"), pages: api.pages.length, prev: W.previousChapterRoute, next: W.nextChapterRoute, listImages: api.pages.map((i) => i.address) }; } }; const ninemanga = { name: "NineManga", url: /https?:\/\/(www.)?ninemanga.com\/chapter\/.+\/.+\.html/, homepage: "https://ninemanga.com/", language: ["English"], category: "manga", run() { const chapter = document.querySelector("#chapter option:checked"); const pages = [...document.querySelector("#page").querySelectorAll("option")]; return { title: document.querySelector(".tip a")?.textContent?.trim(), series: document.querySelector(".subgiude > li:nth-child(2) > a")?.getAttribute("href"), pages: pages.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listPages: pages.map((item) => $(item).val()), img: ".manga_pic" }; } }; const pandamanga = { name: "PandaManga", url: /https?:\/\/(www.)?pandamanga.xyz\/.+\/.+\/.+/, homepage: "https://www.pandamanga.com/", language: ["English"], category: "manga", run() { const chapter = document.querySelector(".select-chapter option:checked"); const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); const images = data.props.pageProps.mangaview.source.split(",").filter((url) => url.length > 0); return { title: data.props.pageProps.mangaview.nameSeoChapter, series: document.querySelector(".allc a")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images }; } }; const rawdevart = { name: "RawDevart", url: /https?:\/\/(www.)?rawdevart.com\/comic\/.+\/.+\//, homepage: "https://rawdevart.com", language: ["Raw"], category: "manga", waitVar: "rconfig", waitEle: "#chapter-list select", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const chapter = document.querySelector("#chapter-list option:checked"); const images = [...document.querySelectorAll("#img-container img")]; return { title: W.rconfig.chapterTitle, series: W.rconfig.prefix, pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images.map((item) => $(item).attr("data-src") || $(item).attr("src")) }; } }; const readcomicsonline = { name: "ReadComicsOnline", url: /https?:\/\/(www.)?readcomicsonline.ru\/comic\/.*\/\d*/, homepage: "https://readcomicsonline.ru/", language: ["English"], category: "comic", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = [...document.querySelectorAll("#all img")]; return { title: W.title.replace(/ - Page \d+/, ""), series: document.querySelector("div.pager-cnt a")?.getAttribute("href"), pages: W.pages.length, prev: W.prev_chapter, next: W.next_chapter, listImages: images.map((img) => img.getAttribute("data-src")) }; } }; const readmangatoday = { name: ["ReadManga Today", "Funmanga", "MangaDoom", "MangaInn"], url: /https?:\/\/(www.)?(funmanga|mngdoom|readmng|mangainn).(com|net)\/.+\/\d+/, homepage: [ "https://www.readmng.com/", "https://funmanga.com/", "https://mngdoom.com/", "https://www.mangainn.net/" ], language: ["English"], category: "manga", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; return { title: W.chapter_page_title, series: W.manga_url, pages: W.images.length, prev: W.prev_chapter_url, next: W.next_chapter_url, listImages: W.images.map((item) => item.url) }; } }; const reaperscans = { name: "ReaperScans", url: /https?:\/\/(www.)?reaperscans.com\/comics\/.+\/chapters\/.+/, homepage: "https://reaperscans.com/", language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll("main img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".fa-list")?.parentElement?.getAttribute("href"), pages: images.length, prev: document.querySelector(".fa-arrow-left-long")?.parentElement?.getAttribute("href"), next: document.querySelector(".fa-arrow-right-long")?.parentElement?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("data-src") || img.getAttribute("src")) }; } }; const resetscans = { name: "Reset-Scans", url: /https?:\/\/(www.)?reset-scans.com\/manga\/.+\/chapter.+/, homepage: "https://reset-scans.com/", language: ["English"], category: "manga", waitVar: "chapter_data", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = Array.isArray(W.chapter_data) ? JSON.parse(W.chapter_data) : JSON.parse( JSON.parse( CryptoJS.AES.decrypt(W.chapter_data, W.wpmangaprotectornonce, { format: { stringify(data) { const cypher = { ct: data.ciphertext.toString(CryptoJS.enc.Base64), iv: data.iv?.toString(), s: data.salt?.toString() }; return JSON.stringify(cypher); }, parse(text) { const result = JSON.parse(text); return CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(result.ct), iv: CryptoJS.enc.Hex.parse(result.iv), salt: CryptoJS.enc.Hex.parse(result.s) }); } } }).toString(CryptoJS.enc.Utf8) ) ); return { title: document.querySelector("#chapter-heading")?.textContent?.trim(), series: document.querySelector(".back")?.getAttribute("href"), pages: images.length, prev: document.querySelector(".prev_page")?.getAttribute("href"), next: document.querySelector(".next_page")?.getAttribute("href"), listImages: images }; } }; const senmanga = { name: "SenManga(Raw)", url: /https?:\/\/raw.senmanga.com\/.+\/.+\/?/, homepage: "https://raw.senmanga.com/", language: ["Raw"], category: "manga", run() { const url = `/${window.location.pathname.split("/")[1]}/${window.location.pathname.split("/")[2]}`; const num = parseInt( document.querySelector(".page-list select option:last-child")?.getAttribute("value") || "0", 10 ); const chapter = [...document.querySelectorAll(".dropdown-chapter li")]; const origin = chapter.findIndex( (item) => item.querySelector("a")?.getAttribute("href") === window.location.href ); return { title: $(".title").text().trim(), series: document.querySelector(".breadcrumb li:nth-child(2) a")?.getAttribute("href"), pages: num, prev: chapter.at(origin + 1)?.querySelector("a")?.getAttribute("href"), next: chapter.at(origin - 1)?.querySelector("a")?.getAttribute("href"), listPages: Array(num).fill(0).map((_, i) => `${url}/${i + 1}/`), img: ".picture" }; } }; const shimadascans = { name: "ShimadaScans", url: /https?:\/\/(www.)?shimadascans.com\/.+(series|chapter).+/, homepage: "https://shimadascans.com/", language: ["English"], category: "manga", waitEle: "#readerarea img", run() { const images = [...document.querySelectorAll("#readerarea img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".breadcrumb li:nth-child(2) a")?.getAttribute("href"), pages: images.length, prev: document.querySelector("a.prev_page")?.getAttribute("href"), next: document.querySelector("a.next_page")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const tapas = { name: "KLManga", url: /https?:\/\/(www.)?tapas.io\/episode\/.+/, homepage: "https://tapas.io/", language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll(".viewer__body img.content__img")]; const chapter = document.querySelector(".js-episodes .body__item--selected"); return { title: document.querySelector(".viewer__header .title")?.textContent?.trim(), series: document.querySelector(".vw-nav__left a")?.getAttribute("href"), pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("data-href"), next: chapter?.nextElementSibling?.getAttribute("data-href"), listImages: images.map((img) => img.getAttribute("data-src") || img.getAttribute("src")) }; } }; const tenmanga = { name: "TenManga", url: /https?:\/\/(www.)?(tenmanga|gardenmanage).com\/(chapter|statuses)\/.+/, homepage: "https://www.tenmanga.com/", language: ["English"], category: "manga", waitVar: "_pageCtrl", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const chapter = document.querySelector( ".mangaread-pagenav select option:checked" ); const images = W._pageCtrl.options.all_imgs_url; return { title: document.querySelector(".title h1")?.textContent?.trim(), series: document.querySelector(".title a:nth-child(2)")?.getAttribute("href"), pages: images.length, prev: chapter?.nextElementSibling?.getAttribute("value"), next: chapter?.previousElementSibling?.getAttribute("value"), listImages: images }; } }; const tmofans = { name: "TuMangaOnline", url: /https?:\/\/(www.)?(tmofans|lectortmo|followmanga).com\/.+\/.+\/(paginated|cascade)/, homepage: "https://lectortmo.com/", language: ["Spanish"], category: "manga", run() { const images = [...document.querySelectorAll(".img-container img")]; const pages = [ ...document.querySelectorAll( "div.container:nth-child(4) select#viewer-pages-select option" ) ]; const num = images.length > 1 ? images.length : pages.length; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector('a[title="Volver"]')?.getAttribute("href"), pages: num, prev: document.querySelector(".chapter-prev a")?.getAttribute("href"), next: document.querySelector(".chapter-next a")?.getAttribute("href"), listPages: images.length > 1 ? null : Array(num).fill(0).map((_, i) => `${window.location.href.replace(/\/\d+$/, "")}/${i + 1}`), listImages: images.length > 1 ? images.map((item) => $(item).attr("data-src")) : null, img: "#viewer-container img, .viewer-page" }; } }; const unionmangas = { name: "UnionMangas", url: /https?:\/\/(www.)?unionleitor.top\/leitor\/.+\/.+/, homepage: "https://unionleitor.top/", language: ["Portuguese"], category: "manga", run() { const chapter = document.querySelector("#capitulo_trocar option:checked"); const images = [...document.querySelectorAll(".img-manga")]; return { title: document.querySelector(".titulo-leitura")?.textContent?.trim(), series: document.querySelector(".breadcrumbs a:nth-child(3)")?.getAttribute("href"), pages: images.length, prev: chapter?.previousElementSibling?.getAttribute("value"), next: chapter?.nextElementSibling?.getAttribute("value"), listImages: images.map((img) => img.getAttribute("src")) }; } }; const webnovel = { name: "WebNovel", url: /https?:\/\/(www.)?webnovel.com\/comic\/.+/, homepage: "https://www.webnovel.com/", language: ["English"], category: "manga", waitVar: "g_data", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = W.g_data.chapter.chapterInfo.chapterPage.map((img) => img.url); return { title: document.querySelector("title")?.textContent?.trim(), series: "./", pages: images.length, prev: `${W.g_data.chapter.chapterInfo.preChapterName}_${W.g_data.chapter.chapterInfo.preChapterId}`, next: `${W.g_data.chapter.chapterInfo.nextChapterName}_${W.g_data.chapter.chapterInfo.nextChapterId}`, listImages: images }; } }; const webtoons = { name: "WebToons", url: /https?:\/\/(www.)?webtoons.com\/.+viewer.+/, homepage: "https://www.webtoons.com/", language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll("#_imageList img")]; return { title: document.querySelector(".subj_info")?.textContent?.trim(), series: document.querySelector(".subj_info a")?.getAttribute("href"), pages: images.length, prev: document.querySelector("._prevEpisode")?.getAttribute("href"), next: document.querySelector("._nextEpisode")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("data-src") || img.getAttribute("src")) }; } }; const wpmanga = { name: ["Manga33"], url: /https?:\/\/(www.)?(manga33).com\/manga\/.+/, homepage: ["https://manga33.com/"], language: ["English"], category: "manga", run() { const images = [...document.querySelectorAll(".chapter-content img")]; return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".navbar-brand")?.getAttribute("href"), pages: images.length, prev: document.querySelector("a.prev")?.getAttribute("href"), next: document.querySelector("a.next")?.getAttribute("href"), listImages: images.map((img) => img.getAttribute("src")), before() { if (window.location.pathname.match(/all.html$/)) return; if (window.location.pathname.match(/\d+-\d+.html$/)) { window.location.pathname = window.location.pathname.replace(/-\d+.html$/, "-all.html"); } } }; } }; const zeroscans = { name: "ZeroScans", url: /https?:\/\/(www.)?zeroscans.com\/comics\/.+/, homepage: "https://zeroscans.com/", language: ["English"], category: "manga", waitVar: "__ZEROSCANS__", run() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const images = W.__ZEROSCANS__.data.at(0).current_chapter.high_quality; const chapters = document.querySelectorAll(".v-btn--router"); return { title: document.querySelector("title")?.textContent?.trim(), series: document.querySelector(".v-breadcrumbs li:nth-child(2) + a")?.getAttribute("href"), pages: images.length, prev: chapters[0]?.getAttribute("href"), next: chapters[1]?.getAttribute("href"), listImages: images }; } }; const sites = [ asurascans, batoto, bilibilicomics, comicastle, dysnatyscans, flamecans, inkr, inmanga, klmanga, leitor, lhtranslation, lynxscans, mangabuddy, mangadex, mangafox, mangafreak, // mangago, fixme mangahosted, mangahub, mangakakalot, // mangapark, fixme mangareader, mangasee, mangatigre, mangatoon, mangatown, manhuascan, mreader, naniscans, ninemanga, pandamanga, rawdevart, readcomicsonline, readmangatoday, reaperscans, resetscans, senmanga, shimadascans, tapas, tenmanga, tmofans, unionmangas, webnovel, webtoons, wpmanga, zeroscans, foolslide, // Must be at the end because is a generic check madarawp // Must be at the end because is a generic check ]; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var libExports = {}; var lib = { get exports(){ return libExports; }, set exports(v){ libExports = v; }, }; (function (module, exports) { !function(e,t){module.exports=t();}(commonjsGlobal,function(){return function(e){function t(s){if(n[s])return n[s].exports;var i=n[s]={i:s,l:!1,exports:{}};return e[s].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,s){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:s});},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=8)}([function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.controlInformation={MIN:1,MAX:2,UNKNOWN:0};},function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(){}return e.optionsValidate=function(e){if(e.min>e.max)throw new Error("Min must be less then max");e.minPointe.max&&(e.maxPoint=e.max);},e.positionValidation=function(e){return e<0&&(e=0),e>100&&(e=100),e},e}();t.default=s;},function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0});var s=n(0),i=n(9),o=n(1),r=n(10);n(7);var a=function(){function e(e,t){this.step=0,this.options=t,this.options.element=e,this.renderer=new r.default(e,t.cssClasses,t.min,t.max,t.serifs),this.mouseDown=this.onMouseDown.bind(this),this.mouseMove=this.onMouseMove.bind(this),this.mouseUp=this.onMouseUp.bind(this);}return e.prototype.init=function(){o.default.optionsValidate(this.options),this.renderer.render(),this.step=this.renderer.getStep(this.options.step);var e=this.calculateControlPostionByValue(this.options.minPoint),t=this.calculateControlPostionByValue(this.options.maxPoint);this.renderer.setMinControlPosition(e),this.renderer.setMaxControlPosition(t),this.renderer.setActiveRangePosition(e,t),this.options.element&&this.options.element.addEventListener(i.MOUSE_EVENTS.mousedown,this.mouseDown);},e.prototype.calculateControlPostionByValue=function(e){return 100*(e-this.options.min)/(this.options.max-this.options.min)},e.prototype.calculateValuesByPosition=function(e){var t=Math.round(e*(this.options.max-this.options.min)/100)+this.options.min;return this.step&&t%this.step!=1&&t>this.options.min&&t=0&&y.splice(t,1);}function a(e){var t=document.createElement("style");return e.attrs.type="text/css",l(t,e.attrs),o(e,t),t}function l(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n]);});}function u(e,t){var n,s,i,u;if(t.transform&&e.css){if(!(u=t.transform(e.css)))return function(){};e.css=u;}if(t.singleton){var p=g++;n=v||(v=a(t)),s=c.bind(null,n,p,!1),i=c.bind(null,n,p,!0);}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",l(t,e.attrs),o(e,t),t}(t),s=function(e,t,n){var s=n.css,i=n.sourceMap,o=void 0===t.convertToAbsoluteUrls&&i;(t.convertToAbsoluteUrls||o)&&(s=C(s)),i&&(s+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */");var r=new Blob([s],{type:"text/css"}),a=e.href;e.href=URL.createObjectURL(r),a&&URL.revokeObjectURL(a);}.bind(null,n,t),i=function(){r(n),n.href&&URL.revokeObjectURL(n.href);}):(n=a(t),s=function(e,t){var n=t.css,s=t.media;if(s&&e.setAttribute("media",s),e.styleSheet)e.styleSheet.cssText=n;else {for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n));}}.bind(null,n),i=function(){r(n);});return s(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;s(e=t);}else i();}}function c(e,t,n,s){var i=n?"":s.css;if(e.styleSheet)e.styleSheet.cssText=x(t,i);else {var o=document.createTextNode(i),r=e.childNodes;r[t]&&e.removeChild(r[t]),r.length?e.insertBefore(o,r[t]):e.appendChild(o);}}var p,d,h={},f=(p=function(){return window&&document&&document.all&&!window.atob},function(){return void 0===d&&(d=p.apply(this,arguments)),d}),m=function(e){var t={};return function(e){if(void 0===t[e]){var n=function(e){return document.querySelector(e)}.call(this,e);if(n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head;}catch(e){n=null;}t[e]=n;}return t[e]}}(),v=null,g=0,y=[],C=n(6);e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=f()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=i(e,t);return s(n,t),function(e){for(var o=[],r=0;r]*>[\S\s]*?<\/script[^>]*>/gi,"")},e.prototype.getControlByTarget=function(e){var t=e.classList;if(t.contains(o)){if(t.contains(r))return s.controlInformation.MIN;if(t.contains(a))return s.controlInformation.MAX}return s.controlInformation.UNKNOWN},e.prototype.setMinControlPosition=function(e){e=i.default.positionValidation(e);var t=parseInt(this.elements.maxControl.style.left,10)||100;this.element&&e<=t&&(this.elements.minControl.style.left=e+"%");},e.prototype.setMaxControlPosition=function(e){e=i.default.positionValidation(e);var t=parseInt(this.elements.minControl.style.left,10)||0;this.element&&e>=t&&(this.elements.maxControl.style.left=e+"%");},e.prototype.setActiveRangePosition=function(e,t){if(this.element){var n=this.elements.activeRange;e="number"==typeof e?i.default.positionValidation(e):parseInt(String(n.style.left),10),t="number"==typeof t?100-i.default.positionValidation(t):parseInt(String(n.style.right),10),n.style.left=e+"%",n.style.right=t+"%";}},e.prototype.getSliderLeftAndRightPositions=function(){return {left:this.elements.wrapper.getBoundingClientRect().left,right:this.elements.wrapper.getBoundingClientRect().left+this.elements.wrapper.clientWidth}},e.prototype.getStep=function(e){var t=this.elements.wrapper.clientWidth,n=(this.max-this.min)/t;if(e&&e>=n)return e;n<=1&&(n=1);for(var s=1;sl[s-1]&&n<=l[s]){n=l[s];break}return e&&console.warn("WARNING! Step value "+e+" can't be applied. Step has modified to nearest correct value "+n+"."),n},e.prototype.getControlsPositions=function(){return {min:parseInt(this.elements.minControl.style.left,10),max:parseInt(this.elements.maxControl.style.left,10)}},e.prototype.render=function(){var t=document.createDocumentFragment();if(this.elements.wrapper=document.createElement("div"),this.elements.wrapper.classList.add("input-range-slider"),this.cssClasses&&this.cssClasses.wrapper&&this.elements.wrapper.classList.add(this.cssClasses.wrapper),this.elements.lineWrapper=document.createElement("div"),this.elements.lineWrapper.classList.add("input-range-slider__line-wrapper"),this.cssClasses&&this.cssClasses.lineWrapper&&this.elements.lineWrapper.classList.add(this.cssClasses.lineWrapper),this.elements.line=document.createElement("div"),this.elements.line.classList.add("input-range-slider__line"),this.cssClasses&&this.cssClasses.line&&this.elements.line.classList.add(this.cssClasses.line),this.elements.minControl=document.createElement("div"),this.elements.minControl.classList.add(o,r),this.elements.maxControl=document.createElement("div"),this.elements.maxControl.classList.add(o,a),this.cssClasses&&this.cssClasses.control&&(this.elements.minControl.classList.add(this.cssClasses.control),this.elements.maxControl.classList.add(this.cssClasses.control)),this.elements.activeRange=document.createElement("div"),this.elements.activeRange.classList.add("input-range-slider__active-range"),this.cssClasses&&this.cssClasses.activeRange&&this.elements.activeRange.classList.add(this.cssClasses.activeRange),this.elements.lineWrapper.appendChild(this.elements.minControl),this.elements.lineWrapper.appendChild(this.elements.maxControl),this.elements.lineWrapper.appendChild(this.elements.activeRange),this.elements.lineWrapper.appendChild(this.elements.line),this.elements.wrapper.appendChild(this.elements.lineWrapper),this.serifs){var n=document.createElement("div");n.classList.add("input-range-slider__serifs"),this.cssClasses&&this.cssClasses.serifs&&n.classList.add(this.cssClasses.serifs);for(var s=0;s i["900"]); const IconArrowBigRight = ` `; const IconArrowBigLeft = ` `; const IconFileDownload = ` `; const IconLoader2 = ` `; const IconCategory = ` `; const IconX = ` `; const IconMenu2 = ` `; const IconArrowAutofitWidth = ` `; const IconArrowAutofitHeight = ` `; const IconZoomInArea = ` `; const IconZoomOutArea = ` `; const IconZoomPan = ` `; const IconArrowAutofitDown = ` `; const IconArrowAutofitLeft = ` `; const IconArrowAutofitRight = ` `; const IconSpacingVertical = ` `; const IconSettings = ` `; const IconKeyboard = ` `; const IconListNumbers = ` `; const IconBookmarks = ` `; const IconExternalLink = ` `; const IconTrash = ` `; const IconSun = ` `; const IconMoon = ` `; const IconCheck = ` `; const IconPalette = ` `; const IconBookmark = ` `; const IconBookmarkOff = ` `; const IconEye = ` `; const IconEyeOff = ` `; const IconZoomCancel = ` `; const IconZoomIn = ` `; const IconZoomOut = ` `; const IconRefresh = ` `; const IconPhoto = ` `; const IconPhotoOff = ` `; const IconPencil = ` `; const IconDeviceFloppy = ` `; const cssStyles = ` :root, .dark, .dark .default, [data-theme='dark'] { --theme-body-background: ${colors.dark["600"]}; --theme-body-text-color: ${colors.dark["50"]}; --theme-text-color: ${colors.dark["50"]}; --theme-primary-color: ${colors.dark["700"]}; --theme-primary-text-color: ${colors.dark["50"]}; --theme-background-color: ${colors.dark["600"]}; --theme-hightlight-color: ${colors.dark["500"]}; --theme-border-color: ${colors.dark["400"]}; } .light, .light .default, [data-theme='light'] { --theme-body-background: ${colors.gray["50"]}; --theme-body-text-color: ${colors.gray["900"]}; --theme-text-color: ${colors.gray["900"]}; --theme-primary-color: ${colors.gray["300"]}; --theme-primary-text-color: ${colors.gray["900"]}; --theme-background-color: ${colors.gray["50"]}; --theme-hightlight-color: ${colors.gray["500"]}; --theme-border-color: ${colors.gray["100"]}; } /* Simple Normalizer */ html { font-size: 100%; } body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; color: #333; background-color: #fff; padding: 0; } a, a:link, a:visited, a:active, a:focus { color: var(--theme-body-text-color); text-decoration: none; } img { height: auto; vertical-align: middle; border: 0 none; } .icon-tabler { height: 1rem; width: 1rem; align-self: center; vertical-align: sub; } #nprogress .bar { background: #29d; position: fixed; z-index: 1031; top: 0; left: 0; width: 100%; height: 4px; } #MangaOnlineViewer { padding-bottom: 40px; min-height: 760px; min-width: 360px; width: 100%; height: 100%; text-decoration: none; color: var(--theme-body-text-color); background-color: var(--theme-body-background); } #MangaOnlineViewer #Chapter { display: grid; grid-template-columns: repeat(1, 1fr); min-width: 225px; } #MangaOnlineViewer #Chapter.FluidLTR { direction: ltr; } #MangaOnlineViewer #Chapter.FluidRTL { direction: rtl; } #MangaOnlineViewer #Chapter.FluidLTR, #MangaOnlineViewer #Chapter.FluidRTL { display: grid; grid-template-columns: repeat(2, 1fr); } #MangaOnlineViewer #Chapter.FluidLTR .PageImg, #MangaOnlineViewer #Chapter.FluidRTL .PageImg { min-width: unset; } #MangaOnlineViewer #Chapter.FluidLTR .MangaPage.DoublePage, #MangaOnlineViewer #Chapter.FluidRTL .MangaPage.DoublePage { grid-column: span 2; } #MangaOnlineViewer #Chapter.FluidLTR .MangaPage:not(.DoublePage):nth-child(2n), #MangaOnlineViewer #Chapter.FluidRTL .MangaPage:not(.DoublePage):nth-child(2n) { display: flex; justify-content: start; } #MangaOnlineViewer #Chapter.FluidLTR .MangaPage:not(.DoublePage):nth-child(2n-1), #MangaOnlineViewer #Chapter.FluidRTL .MangaPage:not(.DoublePage):nth-child(2n-1) { display: flex; justify-content: end; } #MangaOnlineViewer #Chapter.Vertical .PageContent { margin-bottom: 15px; } #MangaOnlineViewer #Chapter.FluidLTR .MangaPage, #MangaOnlineViewer #Chapter.FluidRTL .MangaPage { width: auto; } #MangaOnlineViewer #Chapter.FluidLTR .ZoomWidth .icon-tabler, #MangaOnlineViewer #Chapter.FluidRTL .ZoomWidth .icon-tabler { color: red; } #MangaOnlineViewer #SettingsPanel { color: var(--theme-text-color); padding: 10px; position: fixed; top: 0; left: 0; bottom: 0; z-index: 1000; transition: transform 0.3s ease-in, background-color 0.3s linear; transform: translateX(-100%); display: flex; flex-flow: column; gap: 5px; overflow-y: auto; max-width: 100vw; width: 305px; } #MangaOnlineViewer #SettingsPanel.visible { transform: translateX(0); } #MangaOnlineViewer #SettingsPanel .ControlLabel { display: flex; flex-flow: row wrap; justify-content: space-between; align-items: center; } #MangaOnlineViewer #SettingsPanel .ControlLabelItem { display: flex; align-items: center; justify-content: space-between; } #MangaOnlineViewer #SettingsPanel .ControlLabelItem:not(.show) { display: none; } #MangaOnlineViewer #SettingsPanel input[type="range"] { width: 100%; } #MangaOnlineViewer #SettingsPanel .RangeValue { display: inline-block; color: var(--theme-primary-text-color); line-height: 20px; text-align: center; border-radius: 3px; background: var(--theme-primary-color); padding: 2px 5px; margin-left: 8px; } #MangaOnlineViewer #SettingsPanel datalist { display: flex; flex-direction: column; justify-content: space-between; align-items: center; writing-mode: vertical-lr; width: 100%; } #MangaOnlineViewer #SettingsPanel datalist option { padding: 0; } #MangaOnlineViewer #ThemeSection { border: 1px solid var(--theme-body-text-color); border-radius: 10px; padding: 10px; } #MangaOnlineViewer .closeButton { width: fit-content; height: fit-content; position: absolute; right: 10px; top: 10px; } #MangaOnlineViewer .overlay { position: fixed; display: none; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); z-index: 950; cursor: pointer; } #MangaOnlineViewer .overlay.visible { display: block; } #MangaOnlineViewer .ThemeRadio { border: 1px solid var(--theme-text-color); color: var(--theme-primary-text-color); background-color: var(--theme-primary-color); height: 20px; width: 20px; border-radius: 50%; padding: 1px; margin: 2px 5px; position: relative; } #MangaOnlineViewer .ThemeRadio svg { position: absolute; top: 15%; right: 15%; } #MangaOnlineViewer .ThemeRadio.custom { /*background-image: url("${svgToUrl(IconPalette)}");*/ /*background-position: center;*/ /*background-repeat: no-repeat;*/ /*background-size: 80%;*/ } #MangaOnlineViewer .ThemeRadio.selected .icon-tabler-check { display: inline; } #MangaOnlineViewer .ThemeRadio:not(.selected) .icon-tabler-check { display: none; } #MangaOnlineViewer #KeybindingsPanel { padding: 10px; position: fixed; top: 0; right: 0; bottom: 0; transition: transform 0.3s ease-in-out;; transform: translateX(100%); line-height: 1.5em; z-index: 1000; overflow-y: auto; width: 360px; max-width: 100vw; } #MangaOnlineViewer #KeybindingsPanel.visible { transform: translateX(0); display: block; } #MangaOnlineViewer #KeybindingsPanel #KeybindingsList { display: grid; grid-template-columns: 1fr 2fr; gap: 5px; } #MangaOnlineViewer #KeybindingsPanel input { display: inline-block; width: 100%; } #MangaOnlineViewer #KeybindingsPanel #HotKeysRules { grid-column: span 2; } #MangaOnlineViewer #BookmarksPanel { position: fixed; top: 10%; width: 50%; left: 25%; right: 25%; text-align: center; max-height: 70%; transition: transform 0.3s ease-in-out;; transform: scaleY(0%); z-index: 1000; } #MangaOnlineViewer #BookmarksPanel.visible { transform: scaleY(100%); display: block; } #MangaOnlineViewer #BookmarksList { padding: 0 15px; overflow: auto; max-height: 60vh; } #MangaOnlineViewer #BookmarksList .BookmarkItem { display: flex; flex-flow: row; justify-content: space-between; align-items: center; padding: 2px; } #MangaOnlineViewer #BookmarksList .bookmarkData { flex-basis: 15%; } #MangaOnlineViewer #BookmarksList .bookmarkURl { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; flex-basis: 55%; } #MangaOnlineViewer select { height: 20px; padding: 0; margin-bottom: 5px; } #MangaOnlineViewer .ControlButton { cursor: pointer; border-radius: 5px; border-width: 1px; padding: 2px; min-height: 32px; color: var(--theme-primary-text-color); background-color: var(--theme-primary-color); border-color: var(--theme-border-color); } #MangaOnlineViewer .ControlButton:hover { opacity: 0.8; } #MangaOnlineViewer .panel { padding: 5px; position: inherit; border-radius: 5px; background-color: var(--theme-background-color); } #MangaOnlineViewer .MangaPage { width: 100%; display: inline-block; text-align: center; /*transform: translate3d(0, 0, 0);*/ /*backface-visibility: hidden;*/ /*perspective: 1000px;*/ line-height: 0; min-height: 22px; min-width: 100%; } #MangaOnlineViewer .PageContent { text-align: center; display: inline-block; overflow-x: auto; max-width: 100%; transition: all 0.3s ease-in-out; height: 100%; overflow-y: hidden; } #MangaOnlineViewer .MangaPage.hide .PageContent { /*display: none;*/ height: 0; } #MangaOnlineViewer .MangaPage.hide .PageFunctions { /*position:relative;*/ } #MangaOnlineViewer .PageContent .PageImg[src=""], #MangaOnlineViewer .PageContent .PageImg:not([src]) { width: 40vw; height: 80vh; display: inline-block; background-image: url("${svgToUrl(IconPhoto)}"); background-position: center; background-repeat: no-repeat; background-size: 20%; background-color: var(--theme-hightlight-color); } #MangaOnlineViewer .PageContent .PageImg.imgBroken { width: 40vw; height: 80vh; display: inline-block; background-image: url("${svgToUrl(IconPhotoOff)}"); background-position: center; background-repeat: no-repeat; background-size: 20%; background-color: var(--theme-hightlight-color); } #MangaOnlineViewer .Thumbnail .ThumbnailImg[src=""], #MangaOnlineViewer .Thumbnail .ThumbnailImg:not([src]) { width: 100px; height: 150px; display: inline-block; background-image: url("${svgToUrl(IconPhoto)}"); background-position: center; background-repeat: no-repeat; background-size: 20%; } #MangaOnlineViewer .fitWidthIfOversize .PageContent .PageImg { max-width: 100%; } #MangaOnlineViewer #gotoPage { min-width: 35px; } #MangaOnlineViewer #ThemeSelector { width: 110px; } #MangaOnlineViewer #Header { display: flex; justify-content: space-between; align-items: center; flex-flow: row nowrap; transition: transform 0.3s ease-in; position: sticky; top: 0; left: 0; right: 0; background-color: inherit; z-index: 900; } #MangaOnlineViewer #Header.scroll.headroom-hide { transform: translateY(-100%); } #MangaOnlineViewer #Header.scroll.headroom-show { transform: translateY(-1%); } #MangaOnlineViewer #Header.hover, #MangaOnlineViewer #Header.fixed, #MangaOnlineViewer #Header.click { position: static; transform: none; } #MangaOnlineViewer #Header.headroom-end, #MangaOnlineViewer #Header.visible, #MangaOnlineViewer #Header.fixed { transform: translateY(-1%); position: sticky; } #MangaOnlineViewer #Header.hover:hover, #MangaOnlineViewer #Header.fixed { position: sticky; } #MangaOnlineViewer #Header.scroll #menu, #MangaOnlineViewer #Header.fixed #menu, #MangaOnlineViewer #Header.hover:hover #menu, #MangaOnlineViewer #Header:not(.click).visible #menu { display: none; } #MangaOnlineViewer #menu { position: fixed; min-height: 70px; width: 100%; top: 0; z-index: 1; color: var(--theme-body-text-color); } #MangaOnlineViewer #Header.click #menu { cursor: pointer; } #MangaOnlineViewer #Header.click:not(.headroom-hide) #menu, #MangaOnlineViewer #Header.click.headroom-end #menu, #MangaOnlineViewer #Header.click.visible #menu { position: static; width: 50px; min-height: unset; } #MangaOnlineViewer #MangaTitle { padding: 2px; margin: 0; font-size: 1.2rem; font-weight: normal; } #MangaOnlineViewer #GlobalFunctions { display: flex; gap: 3px; padding-left: 10px; flex-wrap: wrap; width: 300px; z-index: 100; } #MangaOnlineViewer #GlobalFunctions .icon-tabler { width: 25px; height: 25px; } #MangaOnlineViewer #GlobalFunctions #ZoomSlider { display: flex; align-items: center; } #MangaOnlineViewer #GlobalFunctions #Zoom { margin-left: 5px; } #MangaOnlineViewer #GlobalFunctions #ZoomVal { width: 40px; display: inline-block; color: var(--theme-primary-text-color); line-height: 20px; text-align: center; border-radius: 3px; background: var(--theme-primary-color); padding: 2px 5px; } #MangaOnlineViewer #ChapterNavigation { display: flex; flex-flow: column nowrap; justify-content: center; align-items: end; padding-right: 10px; width: 300px; } #MangaOnlineViewer .ChapterControl { display: flex; flex-wrap: nowrap; } #MangaOnlineViewer .ChapterControl .NavigationControlButton { display: inline-flex; margin-left: 3px; justify-content: center; align-items: center; padding: 5px 10px; gap: 0.5em; } #MangaOnlineViewer .ChapterControl .NavigationControlButton .icon-tabler { flex-shrink: 0; align-self: center; width: 1rem; height: 1rem; } #MangaOnlineViewer .ChapterControl .NavigationControlButton[href='#'], #MangaOnlineViewer .ChapterControl .NavigationControlButton[href=''], #MangaOnlineViewer .ChapterControl .NavigationControlButton[href='undefined'] { visibility: hidden; } #MangaOnlineViewer .ChapterControl #download.loading { cursor: not-allowed; pointer-events: none; opacity: 0.6; } #MangaOnlineViewer .ChapterControl #download.disabled { visibility: hidden; } #MangaOnlineViewer .ViewerTitle { text-align: center; min-height: 60px; /*max-width: 500px;*/ display: flex; justify-content: center; align-items: center; flex-direction: column; padding: 5px; flex-basis: 60%; } #MangaOnlineViewer .ViewerTitle #series[href='#'], #MangaOnlineViewer .ViewerTitle #series[href=''], #MangaOnlineViewer .ViewerTitle #series[href='undefined'] { visibility: hidden; } #MangaOnlineViewer #Counters { } #MangaOnlineViewer .PageFunctions { font-family: monospace; display: flex; justify-content: flex-end; align-items: center; margin: 0; padding: 0; gap: 3px; position: absolute; right: 0; } #MangaOnlineViewer .PageFunctions > .PageIndex { background-color: var(--theme-primary-color); color: var(--theme-primary-text-color); min-width: 20px; text-align: center; display: inline-block; padding: 3px 5px; line-height: 1rem; border-radius: 5px; border-top-right-radius: 5px; border-top-right-radius: 0; } #MangaOnlineViewer .PageFunctions .ControlButton { padding: 3px; display: flex; justify-content: center; align-items: center; margin: 0; border-width: 0; min-height: auto; opacity: 0.5; } #MangaOnlineViewer .PageFunctions:hover .ControlButton { opacity: 1; } #MangaOnlineViewer .PageFunctions .ControlButton:hover { opacity: 0.9; } #MangaOnlineViewer .ControlButton.hidden, #MangaOnlineViewer.light #ColorScheme > :not(.inverse), #MangaOnlineViewer:not(.light) #ColorScheme > .inverse, #MangaOnlineViewer .ChapterControl #download.loading > :not(.inverse), #MangaOnlineViewer .ChapterControl #download:not(.loading) > .inverse, #MangaOnlineViewer .MangaPage.hide .ControlButton.Hide > .inverse, #MangaOnlineViewer .MangaPage:not(.hide) .ControlButton.Hide > :not(.inverse), #MangaOnlineViewer.bookmarked .ControlButton.Bookmark > :not(.inverse), #MangaOnlineViewer:not(.bookmarked) .ControlButton.Bookmark > .inverse { display: none; } #MangaOnlineViewer.hideControls .PageFunctions { visibility: hidden; } #MangaOnlineViewer #NavigationCounters { margin: 5px; width: 100%; line-height: 1rem; } #MangaOnlineViewer #Navigation { color: var(--theme-text-color); background-color: var(--theme-hightlight-color); bottom: -180px; height: 185px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 20px; position: fixed; white-space: nowrap; width: 100%; text-align: center; transition: transform 0.3s ease-in, background-color 0.3s linear; border-bottom-left-radius: 0; border-bottom-right-radius: 0; line-height: 0rem; } #MangaOnlineViewer #Navigation #Thumbnails { overflow-x: auto; overflow-y: hidden; margin-right: 10px; } #MangaOnlineViewer #Navigation:hover { transform: translateY(-180px); } #MangaOnlineViewer #Navigation.disabled { display: none; } #MangaOnlineViewer #Navigation.visible { transform: translateY(-180px); } #MangaOnlineViewer #Navigation .Thumbnail { display: inline-block; height: 150px; margin: 0 5px; border: 1px solid var(--theme-primary-color); } #MangaOnlineViewer #Navigation .Thumbnail .ThumbnailIndex { color: var(--theme-text-color); background-color: var(--theme-hightlight-color); display: block; opacity: 0.8; position: relative; bottom: 25%; width: 100%; line-height: 1rem; } #MangaOnlineViewer #Navigation .Thumbnail .ThumbnailImg { cursor: pointer; display: inline-block; max-height: 150px; min-height: 150px; min-width: 80px; max-width: 160px; } #MangaOnlineViewer #menu .icon-tabler { position: absolute; top: 5px; left: 10px; height: 32px; width: 32px; } /* Medium devices (landscape phones, tablets) */ @media (max-width: 992px) { #MangaOnlineViewer #Header { flex-direction: column; } #MangaOnlineViewer .PageContent .PageImg { max-width: 100%; } #MangaOnlineViewer .ViewerTitle { order: 1; min-height: auto; padding: 0px; margin: 0px; } #MangaOnlineViewer #GlobalFunctions { flex-wrap: nowrap; padding: 0; width: auto; order: 3; padding: 5px; } #MangaOnlineViewer #ChapterNavigation { order: 2; } #MangaOnlineViewer #GlobalFunctions #ZoomSlider, #MangaOnlineViewer #GlobalFunctions .ControlButton:not(.tablets, .phones) { display: none; } } /* Small devices (portrait phones) */ @media (max-width: 600px) { #MangaOnlineViewer #Header { flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: center; } #MangaOnlineViewer .ViewerTitle { order: 1; flex-basis: 100%; margin-top: 0px; } #MangaOnlineViewer #GlobalFunctions { order: 2; padding: 0; } #MangaOnlineViewer #ChapterNavigation { order: 3; width: auto; } #MangaOnlineViewer #Navigation { display: none; } #MangaOnlineViewer .PageFunctions { padding: 0; } #MangaOnlineViewer .PageFunctions .ControlButton:not(.Bookmark) { display: none; } #MangaOnlineViewer .PageFunctions .ControlButton.Bookmark { opacity: 1; } #MangaOnlineViewer .PageContent { margin: 0; width: 100%; } #MangaOnlineViewer .PageContent .PageImg { max-width: 100%; } #MangaOnlineViewer #GlobalFunctions #ZoomSlider, #MangaOnlineViewer #GlobalFunctions .ControlButton:not(.phones) { display: none; } #MangaOnlineViewer #GlobalFunctions { min-width: auto; } #MangaOnlineViewer #SettingsPanel .DefaultZoomMode, #MangaOnlineViewer #SettingsPanel .DefaultZoom, #MangaOnlineViewer #SettingsPanel .viewMode, #MangaOnlineViewer #SettingsPanel .fitIfOversize, #MangaOnlineViewer #SettingsPanel .showThumbnails, #MangaOnlineViewer #SettingsPanel .lazyLoadImages, #MangaOnlineViewer #SettingsPanel .downloadZip, #MangaOnlineViewer #SettingsPanel .minZoom, #MangaOnlineViewer #SettingsPanel .zoomStep, #MangaOnlineViewer #SettingsPanel .headerType { display: none; } #MangaOnlineViewer #KeybindingsPanel { display: none; } #MangaOnlineViewer .ViewerTitle { height: auto; padding: 0; } #MangaOnlineViewer .ChapterControl { } #MangaOnlineViewer .ChapterControl .download { display: none; } #MangaOnlineViewer #Counters { display: none; } } @-webkit-keyframes spin { to { transform: rotate(360deg) } } @keyframes spin { to { transform: rotate(360deg) } } .animate-spin { -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite } @-webkit-keyframes spin-reverse { 0% { transform: rotate(360deg) } to { transform: rotate(0) } } @keyframes spin-reverse { 0% { transform: rotate(360deg) } to { transform: rotate(0) } } .animate-spin-reverse { -webkit-animation: spin-reverse 1s linear infinite; animation: spin-reverse 1s linear infinite } `; const startButton = ` #StartMOV { font-size: 20px; font-weight: bold; color: #fff; cursor: pointer; margin: 20px; padding: 10px 20px; text-align: center; border: none; background-size: 300% 100%; border-radius: 50px; transition: all 0.4s ease-in-out; background-image: linear-gradient(to right, #667eea, #764ba2, #6b8dd6, #8e37d7); box-shadow: 0 4px 15px 0 rgba(116, 79, 168, 0.75); position: fixed; top: 10px; right: 10px; z-index: 10000; } #StartMOV:hover { background-position: 100% 0; transition: all 0.4s ease-in-out; } #StartMOV:focus { outline: none; } `; const diffObj = (changed, original) => { const changes = (object, base) => _.transform( object, (result, value, key) => { if (!_.isEqual(value, base[key])) { if (_.isArray(value)) { result[key] = _.difference(value, base[key]); } else if (_.isObject(value) && _.isObject(base[key])) { result[key] = changes(value, base[key]); } else { result[key] = value; } } } /* omit accumulator */ ); return changes(changed, original); }; const en_US = { ID: "en_US", NAME: "English (US)", STARTING: "Starting
MangaOnlineViewer", RESUME: "Resuming reading from Page ", WAITING: "Please wait, 3 seconds...", CHOOSE_BEGINNING: "Choose the Page to start from:", BUTTON_START: "Start MangaOnlineViewer", SETTINGS: "Settings", LANGUAGE: "Language", COLOR_SCHEME: "Color Scheme", THEME: "Theme", THEME_HUE: "Theme Primary Color Hue", THEME_SHADE: "Theme Primary Color Shade", DEFAULT_LOAD_MODE: "Default Load Mode", LOAD_MODE_NORMAL: "Normal(Wait 3 sec)", LOAD_MODE_ALWAYS: "Always(Immediately)", LOAD_MODE_NEVER: "Never(Manually)", LOAD_SPEED: "Load Speed Pages/Second", DEFAULT_ZOOM: "Default Zoom (between 5 and 200)", DEFAULT_ZOOM_MODE: "Default Zoom Mode", MINIMUM_ZOOM: "Minimum Zoom relative to the width of screen (between 30 and 100)", ZOOM_STEP: "Zoom Change Step (between 5 and 50)", DEFAULT_VIEW_MODE: "Default View Mode", VIEW_MODE_VERTICAL: "Vertical", VIEW_MODE_LEFT: "Left to Right", VIEW_MODE_RIGHT: "Right to Left", VIEW_MODE_WEBCOMIC: "WebComic", FIT_WIDTH_OVERSIZED: "Fit Width if Oversized", SHOW_THUMBNAILS: "Show Thumbnails", HIDE_CONTROLS: "Always Hide Page Controls", HEADER_TYPE: "Change Header Type", HEADER_HOVER: "Hover", HEADER_SCROLL: "Scroll", HEADER_CLICK: "Click", HEADER_FIXED: "Fixed", BUTTON_DOWNLOAD: "Download", DOWNLOAD_ZIP: "Download Zip file", DOWNLOAD_IMAGES: "Download Images as Zip Automatically", BUTTON_NEXT: "Next", NEXT_CHAPTER: "Next Chapter", BUTTON_PREVIOUS: "Previous", PREVIOUS_CHAPTER: "Previous Chapter", BOOKMARKS: "Bookmarks", BOOKMARK: "Bookmark", BOOKMARK_REMOVED: "Bookmark Removed", BOOKMARK_SAVED: "Bookmark Saved", BOOKMARK_MESSAGE: "Next time you open this chapter it will resume from:

Page ##num##

(Only ONCE per Bookmark)", KEYBINDINGS: "Keybindings", EDIT_KEYBINDS: "Edit KeyBindings", SAVE_KEYBINDS: "Save KeyBindings", BUTTON_EDIT: "Edit", BUTTON_SAVE: "Save", KEYBIND_RULES: `

Supported Keys

Allowed modifiers: shift, option, alt, ctrl, control, command.
Special keys: backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 - f19, num_0 - num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide.
Examples: a, ctrl+a , shift+a , num_2 , 2 `, ATTENTION: "Attention", WARNING: "Warning", BUTTON_RESET_SETTINGS: "Reset Settings", SETTINGS_RESET: "Settings have been reset, reload the page to take effect", LANGUAGE_CHANGED: "Language has been changed, reload the page to take effect", AUTO_DOWNLOAD: "Next time a chapter finish loading you will be prompted to save automatically", LAZY_LOAD: "Lazy load is incompatible with zip download, you will not be able to download with this setting ON.
Suggestion: Disable Thumbnails to save Bandwidth/Memory.", LAZY_LOAD_IMAGES_ENABLE: "Enable Lazy Load Images", LAZY_LOAD_IMAGES: "Lazy Start From Page (between 5 and 100)", RETURN_CHAPTER_LIST: "Return to Chapter List", PAGES_LOADED: "Pages Loaded", GO_TO_PAGE: "Go to Page", ENLARGE: "Enlarge", RESTORE: "Restore", REDUCE: "Restore", FIT_WIDTH: "Fit Width", FIT_HEIGHT: "Fit Height", PERCENT: "Percent", TOGGLE_CONTROLS: "Toggle page controls", ZOOM_IN: "Zoom In", ZOOM_OUT: "Zoom Out", ZOOM_RESET: "Zoom Reset", ZOOM_WIDTH: "Zoom to Width", ZOOM_HEIGHT: "Zoom to Height", HIDE: "Hide", RELOAD: "Reload", SLOWLY: "Slowly", NORMAL: "Normal", FAST: "Fast", EXTREME: "Extreme", SCROLL_UP: "Scroll Up", SCROLL_DOWN: "Scroll Down", CLOSE: "Close", LIST_EMPTY: "List Empty" }; const pt_BR = { ID: "pt_BR", NAME: "Portugues (Brasil)", STARTING: "Iniciando
MangaOnlineViewer", RESUME: "Continuando leitura na Pagina ", WAITING: "Por Favor espere, 3 segundos...", CHOOSE_BEGINNING: "Escolha a pagina de onde começar:", BUTTON_START: "Iniciar MangaOnlineViewer", SETTINGS: "Configurações", LANGUAGE: "Idioma", COLOR_SCHEME: "Esquema de Color", THEME: "Tema", THEME_HUE: "Coloração primaria", THEME_SHADE: "Saturação de Cor", DEFAULT_LOAD_MODE: "Forma de Carregamento Padrão", LOAD_MODE_NORMAL: "Normal(Esperando 3 sec)", LOAD_MODE_ALWAYS: "Sempre(Imediatamente)", LOAD_MODE_NEVER: "Nunca(Manualmente)", LOAD_SPEED: "Velocidade de Carregamento Paginas/Segundo", DEFAULT_ZOOM: "Zoom padrão (entre 5 e 200)", DEFAULT_ZOOM_MODE: "Modo de Zoom padrão", MINIMUM_ZOOM: "Zoom minimo, relativo ao tamanho da tela (entre 30 e 100)", ZOOM_STEP: "Precisão da Mudança do Zoom (entre 5 e 50)", DEFAULT_VIEW_MODE: "Modo de Visualização Padrão", VIEW_MODE_VERTICAL: "Vertical", VIEW_MODE_LEFT: "Esquerda para Direita", VIEW_MODE_RIGHT: "Direita para Esquerda", VIEW_MODE_WEBCOMIC: "WebComic", FIT_WIDTH_OVERSIZED: "Encher a tela se grande demais", SHOW_THUMBNAILS: "Mostra Miniaturas", HIDE_CONTROLS: "Sempre esconder controles das paginas", HEADER_TYPE: "Mudar Tipo de Cabeçalho", HEADER_HOVER: "Passar por perto", HEADER_SCROLL: "Rolagem do Mouse", HEADER_CLICK: "Click", HEADER_FIXED: "Fixo", BUTTON_DOWNLOAD: "Download", DOWNLOAD_ZIP: "Baixar arquivo Zip", DOWNLOAD_IMAGES: "Download das Imagens como Zip Automaticamente", BUTTON_NEXT: "Proximo", NEXT_CHAPTER: "Proximo Capitulo", BUTTON_PREVIOUS: "Anterior", PREVIOUS_CHAPTER: "Capitulo Anterior", BOOKMARKS: "Marca paginas", BOOKMARK: "Marcar pagina", BOOKMARK_REMOVED: "Marca pagina Removido", BOOKMARK_SAVED: "Marca pagina Salvo", BOOKMARK_MESSAGE: "Proxima vez que abrir este capitulo continuará a partir da

Pagina ##num##

(Apenas UMA VEZ por marca pagina)", KEYBINDINGS: "Atalhos", EDIT_KEYBINDS: "Editar Atalhos", SAVE_KEYBINDS: "Salvar Atalhos", BUTTON_EDIT: "Editar", BUTTON_SAVE: "Salvar", KEYBIND_RULES: `

Teclas Suportadas

Modificadores permitidos: shift, option, alt, ctrl, control, command.
Teclas Especiais: backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 - f19, num_0 - num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide.
Exemplos: a, ctrl+a , shift+a , num_2 , 2 `, ATTENTION: "Atenção", WARNING: "Alerta", BUTTON_RESET_SETTINGS: "Limpar Configurações", SETTINGS_RESET: "Configurações foram limpas, recarregue o site para efetivar a alteração", LANGUAGE_CHANGED: "Idioma foi alterado, recarregue o site para efetivar a alteração", AUTO_DOWNLOAD: "Proxima vez que abrir um capitulo download iniciara automaticamente", LAZY_LOAD: "Carregamento preguiçoso não é compativel com download de zip, não conseguira com essa configuração ativa.
Sugestão: Desative Miniaturas para economizar memoria e cota de internet.", LAZY_LOAD_IMAGES_ENABLE: "Ativar Carregamento de imagens preguiçoso", LAZY_LOAD_IMAGES: "Carregamento de paginas preguiçoso começa a partir de (entre 5 e 100)", RETURN_CHAPTER_LIST: "Voltar a lista de Capitulos", PAGES_LOADED: "Paginas Carregadas", GO_TO_PAGE: "Pular para", ENLARGE: "Aumentar", RESTORE: "Restaurar", REDUCE: "Diminuir", FIT_WIDTH: "Preencher Largura", FIT_HEIGHT: "Preencher Altura ", PERCENT: "Percentual", TOGGLE_CONTROLS: "Mostar controles de pagina", ZOOM_IN: "Mais Zoom", ZOOM_OUT: "Menos Zoom", ZOOM_RESET: "Resetar Zoom", ZOOM_WIDTH: "Zoom para Largura", ZOOM_HEIGHT: "Zoom para Altura", HIDE: "Esconder", RELOAD: "Recarregar", SLOWLY: "Devagar", NORMAL: "Normal", FAST: "Rapido", EXTREME: "Extremo", SCROLL_UP: "Subir Pagina", SCROLL_DOWN: "Descer Pagina", CLOSE: "Fechar", LIST_EMPTY: "Lista Vazia" }; const zh_CN = { ID: "zh_cn", NAME: "中文 (简体)", STARTING: "正在启动
MangaOnlineViewer", RESUME: "从页面继续阅读 ", WAITING: "请等待3秒钟...", CHOOSE_BEGINNING: "选择要开始的页数:", BUTTON_START: "启动MangaOnlineViewer", SETTINGS: "设置", LANGUAGE: "语言", COLOR_SCHEME: "配色方案", THEME: "主题", THEME_HUE: "主题色调", THEME_SHADE: "主题阴影", DEFAULT_LOAD_MODE: "默认加载模式", LOAD_MODE_NORMAL: "等待模式(等待3秒自动加载 )", LOAD_MODE_ALWAYS: "自动模式(无需等待)", LOAD_MODE_NEVER: "手动模式(点击启动)", LOAD_SPEED: "加载速度页数/秒", DEFAULT_ZOOM: "默认缩放 (最小 5 最大 200)", DEFAULT_ZOOM_MODE: "默认缩放模式", MINIMUM_ZOOM: "相对于屏幕宽度的最小缩放 (最小 30 最大 100)", ZOOM_STEP: "缩放级别 (最小 5 最大 50)", DEFAULT_VIEW_MODE: "默认视图模式", VIEW_MODE_VERTICAL: "垂直有缝", VIEW_MODE_LEFT: "从左到右", VIEW_MODE_RIGHT: "从右到左", VIEW_MODE_WEBCOMIC: "垂直无缝", FIT_WIDTH_OVERSIZED: "如果尺寸过大、则适合宽度", SHOW_THUMBNAILS: "显示缩略图", HIDE_CONTROLS: "始终隐藏页面控件", HEADER_TYPE: "更改标题显示方式", HEADER_HOVER: "悬停", HEADER_SCROLL: "滚动", HEADER_CLICK: "点击", HEADER_FIXED: "固定", BUTTON_DOWNLOAD: "下载", DOWNLOAD_ZIP: "下载压缩文件", DOWNLOAD_IMAGES: "自动将图片下载成ZIP", BUTTON_NEXT: "下一页", NEXT_CHAPTER: "下一章", BUTTON_PREVIOUS: "上一页", PREVIOUS_CHAPTER: "上一章", BOOKMARKS: "书签", BOOKMARK: "Bookmark", BOOKMARK_REMOVED: "删除书签", BOOKMARK_SAVED: "保存书签", BOOKMARK_MESSAGE: "下次打开本章时,将从:

页码 ##num##

(仅一次 每个书签)", KEYBINDINGS: "快捷键", EDIT_KEYBINDS: "编辑键绑定", SAVE_KEYBINDS: "保存键绑定", BUTTON_EDIT: "编辑", BUTTON_SAVE: "救", KEYBIND_RULES: `

支持的密钥

允许的修饰符: shift, option, alt, ctrl, control, command.
特殊键: backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 - f19, num_0 - num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide.
例子: a, ctrl+a , shift+a , num_2 , 2 `, ATTENTION: "注意", WARNING: "警告", BUTTON_RESET_SETTINGS: "重置设置", SETTINGS_RESET: "设置已重置、重新加载页面才能生效", LANGUAGE_CHANGED: "语言已更改、重新加载页面才能生效", AUTO_DOWNLOAD: "下次章节加载完成时、系统将提示您自动保存", LAZY_LOAD: "延迟加载与zip下载不兼容、您将无法使用此设置下载.
建议: 禁用缩略图 以节省流量和内存.", LAZY_LOAD_IMAGES_ENABLE: "启用延迟加载图像", LAZY_LOAD_IMAGES: "惰性加载从页面 (最小 5 最大 100)", RETURN_CHAPTER_LIST: "返回章节列表", PAGES_LOADED: "已加载的页数", GO_TO_PAGE: "转到页数", ENLARGE: "放大", RESTORE: "还原", REDUCE: "缩小", FIT_WIDTH: "适合宽度", FIT_HEIGHT: "适合高度", PERCENT: "百分之", TOGGLE_CONTROLS: "显示隐藏页面控件", ZOOM_IN: "放大", ZOOM_OUT: "缩小", ZOOM_RESET: "还原", ZOOM_WIDTH: "适合宽度", ZOOM_HEIGHT: "适合高度", HIDE: "显示隐藏页面控件", RELOAD: "重新加载", SLOWLY: "慢速", NORMAL: "正常", FAST: "快速", EXTREME: "极端", SCROLL_UP: "向上滚动", SCROLL_DOWN: "向下滚动", CLOSE: "关闭", LIST_EMPTY: "没有收藏书签" }; const locales = [en_US, pt_BR, zh_CN]; const defaultSettings = { locale: "en_US", theme: "darkblue", customTheme: "#263e3a", themeShade: 600, colorScheme: "dark", fitWidthIfOversize: true, showThumbnails: true, downloadZip: false, throttlePageLoad: 1e3, zoomMode: "percent", defaultZoom: 100, zoomStep: 25, minZoom: 30, loadMode: "wait", viewMode: "WebComic", bookmarks: [], lazyLoadImages: false, lazyStart: 50, hidePageControls: false, header: "hover", maxReload: 5, keybinds: { SCROLL_UP: ["up", "W", "num_8"], SCROLL_DOWN: ["down", "S", "num_2"], NEXT_CHAPTER: ["right", "/", "D", "num_6"], PREVIOUS_CHAPTER: ["left", ";", "A", "num_4"], ENLARGE: ["-", "num_add", "E"], REDUCE: ["=", "num_subtract", "Q"], RESTORE: ["9", "num_divide", "R"], FIT_WIDTH: ["0", "num_multiply", "F"], FIT_HEIGHT: ["H"], SETTINGS: ["num_divide", "num_5", "X"], VIEW_MODE_WEBCOMIC: ["C"], VIEW_MODE_VERTICAL: ["V"], VIEW_MODE_LEFT: ["N"], VIEW_MODE_RIGHT: ["B"] } }; let settings$1 = _.defaultsDeep(getSettings(defaultSettings), defaultSettings); if (isMobile) { settings$1.lazyLoadImages = true; settings$1.fitWidthIfOversize = true; settings$1.showThumbnails = false; settings$1.viewMode = "WebComic"; settings$1.header = "click"; } function useSettings() { return settings$1; } function getLocaleString(name) { const locale = locales.find((l) => l.ID === settings$1.locale); if (locale && locale[name]) { return locale[name]; } if (locales[1] && locales[1][name]) { return locales[1][name]; } return "##MISSING_STRING##"; } function updateSettings(newValue) { logScript(JSON.stringify(newValue)); settings$1 = { ...settings$1, ...newValue }; setSettings(diffObj(settings$1, defaultSettings)); } function resetSettings() { getListGM().forEach((setting) => removeValueGM(setting)); updateSettings(defaultSettings); } const bookmarkTimeLimit = 1e3 * 60 * 60 * 24 * 30 * 12; const refreshedBookmark = settings$1.bookmarks.filter( (el) => Date.now() - el.date < bookmarkTimeLimit ); if (settings$1.bookmarks.length !== refreshedBookmark.length) { updateSettings({ bookmarks: refreshedBookmark }); } function isBookmarked(url = window.location.href) { return useSettings().bookmarks.some((el) => el.url === url); } function createStyleElement(id, content) { const style = document.createElement("style"); style.id = id; style.appendChild(document.createTextNode(content)); return style; } function appendStyleSheet(id, content) { if (!document.querySelector(`#${id}`)) { const head = document.head || document.querySelector("head"); head.appendChild(createStyleElement(id, content)); } } function removeStyleSheet(id) { document.querySelectorAll(`style[id="${id}"]`).forEach((elem) => elem.remove()); } function replaceStyleSheet(id, content) { removeStyleSheet(id); appendStyleSheet(id, content); } function wrapStyle(id, css) { return ``; } function generateThemeCSS(name, primary, text) { return ` .${name}, [data-theme='${name}'] { --theme-primary-color: ${primary}; --theme-primary-text-color: ${text}; } `; } function getNormalThemeCSS(theme) { return generateThemeCSS( theme.name, theme[useSettings().themeShade], useSettings().themeShade < 500 ? theme["900"] : theme["50"] ); } function getCustomThemeCSS(hex) { return generateThemeCSS("custom", hex, getTextColor(hex)); } function addTheme(theme) { return wrapStyle(theme.name, getNormalThemeCSS(theme)); } function addCustomTheme(hex) { replaceStyleSheet("custom", getCustomThemeCSS(hex)); } const themes = () => Object.values(colors); const themesSelector = [...Object.keys(colors).map((color) => colors[color].name)].map( (theme) => ` ${IconCheck} ` ); function refreshThemes() { themes().forEach((theme) => replaceStyleSheet(theme.name, getNormalThemeCSS(theme))); replaceStyleSheet("custom", getCustomThemeCSS(useSettings().customTheme)); } const themesCSS = themes().map(addTheme).join("") + wrapStyle("custom", getCustomThemeCSS(useSettings().customTheme)); const fix = ` #pagesSlider { min-height: 40px; } #swal2-title { color: navy; } button.swal2-styled { position: inherit; transform: inherit; } `; const sweetalert = ` ${fix} .swal2-popup.swal2-toast { box-sizing: border-box; grid-column: 1/4 !important; grid-row: 1/4 !important; grid-template-columns: 1fr 99fr 1fr; padding: 1em; overflow-y: hidden; background: #fff; box-shadow: 0 0 1px rgba(0, 0, 0, 0.075), 0 1px 2px rgba(0, 0, 0, 0.075), 1px 2px 4px rgba(0, 0, 0, 0.075), 1px 3px 8px rgba(0, 0, 0, 0.075), 2px 4px 16px rgba(0, 0, 0, 0.075); pointer-events: all; } .swal2-popup.swal2-toast > * { grid-column: 2; } .swal2-popup.swal2-toast .swal2-title { margin: 0.5em 1em; padding: 0; font-size: 1em; text-align: initial; } .swal2-popup.swal2-toast .swal2-loading { justify-content: center; } .swal2-popup.swal2-toast .swal2-input { height: 2em; margin: 0.5em; font-size: 1em; } .swal2-popup.swal2-toast .swal2-validation-message { font-size: 1em; } .swal2-popup.swal2-toast .swal2-footer { margin: 0.5em 0 0; padding: 0.5em 0 0; font-size: 0.8em; } .swal2-popup.swal2-toast .swal2-close { grid-column: 3/3; grid-row: 1/99; align-self: center; width: 0.8em; height: 0.8em; margin: 0; font-size: 2em; } .swal2-popup.swal2-toast .swal2-html-container { margin: 0.5em 1em; padding: 0; font-size: 1em; text-align: initial; } .swal2-popup.swal2-toast .swal2-html-container:empty { padding: 0; } .swal2-popup.swal2-toast .swal2-loader { grid-column: 1; grid-row: 1/99; align-self: center; width: 2em; height: 2em; margin: 0.25em; } .swal2-popup.swal2-toast .swal2-icon { grid-column: 1; grid-row: 1/99; align-self: center; width: 2em; min-width: 2em; height: 2em; margin: 0 0.5em 0 0; } .swal2-popup.swal2-toast .swal2-icon .swal2-icon-content { display: flex; align-items: center; font-size: 1.8em; font-weight: bold; } .swal2-popup.swal2-toast .swal2-icon.swal2-success .swal2-success-ring { width: 2em; height: 2em; } .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line] { top: 0.875em; width: 1.375em; } .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left] { left: 0.3125em; } .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right] { right: 0.3125em; } .swal2-popup.swal2-toast .swal2-actions { justify-content: flex-start; height: auto; margin: 0; margin-top: 0.5em; padding: 0 0.5em; } .swal2-popup.swal2-toast .swal2-styled { margin: 0.25em 0.5em; padding: 0.4em 0.6em; font-size: 1em; } .swal2-popup.swal2-toast .swal2-success { border-color: #a5dc86; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line] { position: absolute; width: 1.6em; height: 3em; transform: rotate(45deg); border-radius: 50%; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left] { top: -0.8em; left: -0.5em; transform: rotate(-45deg); transform-origin: 2em 2em; border-radius: 4em 0 0 4em; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right] { top: -0.25em; left: 0.9375em; transform-origin: 0 1.5em; border-radius: 0 4em 4em 0; } .swal2-popup.swal2-toast .swal2-success .swal2-success-ring { width: 2em; height: 2em; } .swal2-popup.swal2-toast .swal2-success .swal2-success-fix { top: 0; left: 0.4375em; width: 0.4375em; height: 2.6875em; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line] { height: 0.3125em; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip] { top: 1.125em; left: 0.1875em; width: 0.75em; } .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=long] { top: 0.9375em; right: 0.1875em; width: 1.375em; } .swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip { -webkit-animation: swal2-toast-animate-success-line-tip 0.75s; animation: swal2-toast-animate-success-line-tip 0.75s; } .swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long { -webkit-animation: swal2-toast-animate-success-line-long 0.75s; animation: swal2-toast-animate-success-line-long 0.75s; } .swal2-popup.swal2-toast.swal2-show { -webkit-animation: swal2-toast-show 0.5s; animation: swal2-toast-show 0.5s; } .swal2-popup.swal2-toast.swal2-hide { -webkit-animation: swal2-toast-hide 0.1s forwards; animation: swal2-toast-hide 0.1s forwards; } .swal2-container { display: grid; position: fixed; z-index: 1060; top: 0; right: 0; bottom: 0; left: 0; box-sizing: border-box; grid-template-areas: "top-start top top-end" "center-start center center-end" "bottom-start bottom-center bottom-end"; grid-template-rows: minmax(-webkit-min-content, auto) minmax(-webkit-min-content, auto) minmax(-webkit-min-content, auto); grid-template-rows: minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto); height: 100%; padding: 0.625em; overflow-x: hidden; transition: background-color 0.1s; -webkit-overflow-scrolling: touch; } .swal2-container.swal2-backdrop-show, .swal2-container.swal2-noanimation { background: rgba(0, 0, 0, 0.4); } .swal2-container.swal2-backdrop-hide { background: transparent !important; } .swal2-container.swal2-top-start, .swal2-container.swal2-center-start, .swal2-container.swal2-bottom-start { grid-template-columns: minmax(0, 1fr) auto auto; } .swal2-container.swal2-top, .swal2-container.swal2-center, .swal2-container.swal2-bottom { grid-template-columns: auto minmax(0, 1fr) auto; } .swal2-container.swal2-top-end, .swal2-container.swal2-center-end, .swal2-container.swal2-bottom-end { grid-template-columns: auto auto minmax(0, 1fr); } .swal2-container.swal2-top-start > .swal2-popup { align-self: start; } .swal2-container.swal2-top > .swal2-popup { grid-column: 2; align-self: start; justify-self: center; } .swal2-container.swal2-top-end > .swal2-popup, .swal2-container.swal2-top-right > .swal2-popup { grid-column: 3; align-self: start; justify-self: end; } .swal2-container.swal2-center-start > .swal2-popup, .swal2-container.swal2-center-left > .swal2-popup { grid-row: 2; align-self: center; } .swal2-container.swal2-center > .swal2-popup { grid-column: 2; grid-row: 2; align-self: center; justify-self: center; } .swal2-container.swal2-center-end > .swal2-popup, .swal2-container.swal2-center-right > .swal2-popup { grid-column: 3; grid-row: 2; align-self: center; justify-self: end; } .swal2-container.swal2-bottom-start > .swal2-popup, .swal2-container.swal2-bottom-left > .swal2-popup { grid-column: 1; grid-row: 3; align-self: end; } .swal2-container.swal2-bottom > .swal2-popup { grid-column: 2; grid-row: 3; justify-self: center; align-self: end; } .swal2-container.swal2-bottom-end > .swal2-popup, .swal2-container.swal2-bottom-right > .swal2-popup { grid-column: 3; grid-row: 3; align-self: end; justify-self: end; } .swal2-container.swal2-grow-row > .swal2-popup, .swal2-container.swal2-grow-fullscreen > .swal2-popup { grid-column: 1/4; width: 100%; } .swal2-container.swal2-grow-column > .swal2-popup, .swal2-container.swal2-grow-fullscreen > .swal2-popup { grid-row: 1/4; align-self: stretch; } .swal2-container.swal2-no-transition { transition: none !important; } .swal2-popup { display: none; position: relative; box-sizing: border-box; grid-template-columns: minmax(0, 100%); width: 32em; max-width: 100%; padding: 0 0 1.25em; border: none; border-radius: 5px; background: #fff; color: #545454; font-family: inherit; font-size: 1rem; } .swal2-popup:focus { outline: none; } .swal2-popup.swal2-loading { overflow-y: hidden; } .swal2-title { position: relative; max-width: 100%; margin: 0; padding: 0.8em 1em 0; color: inherit; font-size: 1.875em; font-weight: 600; text-align: center; text-transform: none; word-wrap: break-word; } .swal2-actions { display: flex; z-index: 1; box-sizing: border-box; flex-wrap: wrap; align-items: center; justify-content: center; width: auto; margin: 1.25em auto 0; padding: 0; } .swal2-actions:not(.swal2-loading) .swal2-styled[disabled] { opacity: 0.4; } .swal2-actions:not(.swal2-loading) .swal2-styled:hover { background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)); } .swal2-actions:not(.swal2-loading) .swal2-styled:active { background-image: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)); } .swal2-loader { display: none; align-items: center; justify-content: center; width: 2.2em; height: 2.2em; margin: 0 1.875em; -webkit-animation: swal2-rotate-loading 1.5s linear 0s infinite normal; animation: swal2-rotate-loading 1.5s linear 0s infinite normal; border-width: 0.25em; border-style: solid; border-radius: 100%; border-color: #2778c4 transparent #2778c4 transparent; } .swal2-styled { margin: 0.3125em; padding: 0.625em 1.1em; transition: box-shadow 0.1s; box-shadow: 0 0 0 3px transparent; font-weight: 500; } .swal2-styled:not([disabled]) { cursor: pointer; } .swal2-styled.swal2-confirm { border: 0; border-radius: 0.25em; background: initial; background-color: #7066e0; color: #fff; font-size: 1em; } .swal2-styled.swal2-confirm:focus { box-shadow: 0 0 0 3px rgba(112, 102, 224, 0.5); } .swal2-styled.swal2-deny { border: 0; border-radius: 0.25em; background: initial; background-color: #dc3741; color: #fff; font-size: 1em; } .swal2-styled.swal2-deny:focus { box-shadow: 0 0 0 3px rgba(220, 55, 65, 0.5); } .swal2-styled.swal2-cancel { border: 0; border-radius: 0.25em; background: initial; background-color: #6e7881; color: #fff; font-size: 1em; } .swal2-styled.swal2-cancel:focus { box-shadow: 0 0 0 3px rgba(110, 120, 129, 0.5); } .swal2-styled.swal2-default-outline:focus { box-shadow: 0 0 0 3px rgba(100, 150, 200, 0.5); } .swal2-styled:focus { outline: none; } .swal2-styled::-moz-focus-inner { border: 0; } .swal2-footer { justify-content: center; margin: 1em 0 0; padding: 1em 1em 0; border-top: 1px solid #eee; color: inherit; font-size: 1em; } .swal2-timer-progress-bar-container { position: absolute; right: 0; bottom: 0; left: 0; grid-column: auto !important; overflow: hidden; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } .swal2-timer-progress-bar { width: 100%; height: 0.25em; background: rgba(0, 0, 0, 0.2); } .swal2-image { max-width: 100%; margin: 2em auto 1em; } .swal2-close { z-index: 2; align-items: center; justify-content: center; width: 1.2em; height: 1.2em; margin-top: 0; margin-right: 0; margin-bottom: -1.2em; padding: 0; overflow: hidden; transition: color 0.1s, box-shadow 0.1s; border: none; border-radius: 5px; background: transparent; color: #ccc; font-family: serif; font-family: monospace; font-size: 2.5em; cursor: pointer; justify-self: end; } .swal2-close:hover { transform: none; background: transparent; color: #f27474; } .swal2-close:focus { outline: none; box-shadow: inset 0 0 0 3px rgba(100, 150, 200, 0.5); } .swal2-close::-moz-focus-inner { border: 0; } .swal2-html-container { z-index: 1; justify-content: center; margin: 1em 1.6em 0.3em; padding: 0; overflow: auto; color: inherit; font-size: 1.125em; font-weight: normal; line-height: normal; text-align: center; word-wrap: break-word; word-break: break-word; } .swal2-input, .swal2-file, .swal2-textarea, .swal2-select, .swal2-radio, .swal2-checkbox { margin: 1em 2em 3px; } .swal2-input, .swal2-file, .swal2-textarea { box-sizing: border-box; width: auto; transition: border-color 0.1s, box-shadow 0.1s; border: 1px solid #d9d9d9; border-radius: 0.1875em; background: inherit; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent; color: inherit; font-size: 1.125em; } .swal2-input.swal2-inputerror, .swal2-file.swal2-inputerror, .swal2-textarea.swal2-inputerror { border-color: #f27474 !important; box-shadow: 0 0 2px #f27474 !important; } .swal2-input:focus, .swal2-file:focus, .swal2-textarea:focus { border: 1px solid #b4dbed; outline: none; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(100, 150, 200, 0.5); } .swal2-input::-moz-placeholder, .swal2-file::-moz-placeholder, .swal2-textarea::-moz-placeholder { color: #ccc; } .swal2-input:-ms-input-placeholder, .swal2-file:-ms-input-placeholder, .swal2-textarea:-ms-input-placeholder { color: #ccc; } .swal2-input::placeholder, .swal2-file::placeholder, .swal2-textarea::placeholder { color: #ccc; } .swal2-range { margin: 1em 2em 3px; background: #fff; } .swal2-range input { width: 80%; } .swal2-range output { width: 20%; color: inherit; font-weight: 600; text-align: center; } .swal2-range input, .swal2-range output { height: 2.625em; padding: 0; font-size: 1.125em; line-height: 2.625em; } .swal2-input { height: 2.625em; padding: 0 0.75em; } .swal2-file { width: 75%; margin-right: auto; margin-left: auto; background: inherit; font-size: 1.125em; } .swal2-textarea { height: 6.75em; padding: 0.75em; } .swal2-select { min-width: 50%; max-width: 100%; padding: 0.375em 0.625em; background: inherit; color: inherit; font-size: 1.125em; } .swal2-radio, .swal2-checkbox { align-items: center; justify-content: center; background: #fff; color: inherit; } .swal2-radio label, .swal2-checkbox label { margin: 0 0.6em; font-size: 1.125em; } .swal2-radio input, .swal2-checkbox input { flex-shrink: 0; margin: 0 0.4em; } .swal2-input-label { display: flex; justify-content: center; margin: 1em auto 0; } .swal2-validation-message { align-items: center; justify-content: center; margin: 1em 0 0; padding: 0.625em; overflow: hidden; background: #f0f0f0; color: #666666; font-size: 1em; font-weight: 300; } .swal2-validation-message::before { content: "!"; display: inline-block; width: 1.5em; min-width: 1.5em; height: 1.5em; margin: 0 0.625em; border-radius: 50%; background-color: #f27474; color: #fff; font-weight: 600; line-height: 1.5em; text-align: center; } .swal2-icon { position: relative; box-sizing: content-box; justify-content: center; width: 5em; height: 5em; margin: 2.5em auto 0.6em; border: 0.25em solid transparent; border-radius: 50%; border-color: #000; font-family: inherit; line-height: 5em; cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .swal2-icon .swal2-icon-content { display: flex; align-items: center; font-size: 3.75em; } .swal2-icon.swal2-error { border-color: #f27474; color: #f27474; } .swal2-icon.swal2-error .swal2-x-mark { position: relative; flex-grow: 1; } .swal2-icon.swal2-error [class^=swal2-x-mark-line] { display: block; position: absolute; top: 2.3125em; width: 2.9375em; height: 0.3125em; border-radius: 0.125em; background-color: #f27474; } .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left] { left: 1.0625em; transform: rotate(45deg); } .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right] { right: 1em; transform: rotate(-45deg); } .swal2-icon.swal2-error.swal2-icon-show { -webkit-animation: swal2-animate-error-icon 0.5s; animation: swal2-animate-error-icon 0.5s; } .swal2-icon.swal2-error.swal2-icon-show .swal2-x-mark { -webkit-animation: swal2-animate-error-x-mark 0.5s; animation: swal2-animate-error-x-mark 0.5s; } .swal2-icon.swal2-warning { border-color: #facea8; color: #f8bb86; } .swal2-icon.swal2-warning.swal2-icon-show { -webkit-animation: swal2-animate-error-icon 0.5s; animation: swal2-animate-error-icon 0.5s; } .swal2-icon.swal2-warning.swal2-icon-show .swal2-icon-content { -webkit-animation: swal2-animate-i-mark 0.5s; animation: swal2-animate-i-mark 0.5s; } .swal2-icon.swal2-info { border-color: #9de0f6; color: #3fc3ee; } .swal2-icon.swal2-info.swal2-icon-show { -webkit-animation: swal2-animate-error-icon 0.5s; animation: swal2-animate-error-icon 0.5s; } .swal2-icon.swal2-info.swal2-icon-show .swal2-icon-content { -webkit-animation: swal2-animate-i-mark 0.8s; animation: swal2-animate-i-mark 0.8s; } .swal2-icon.swal2-question { border-color: #c9dae1; color: #87adbd; } .swal2-icon.swal2-question.swal2-icon-show { -webkit-animation: swal2-animate-error-icon 0.5s; animation: swal2-animate-error-icon 0.5s; } .swal2-icon.swal2-question.swal2-icon-show .swal2-icon-content { -webkit-animation: swal2-animate-question-mark 0.8s; animation: swal2-animate-question-mark 0.8s; } .swal2-icon.swal2-success { border-color: #a5dc86; color: #a5dc86; } .swal2-icon.swal2-success [class^=swal2-success-circular-line] { position: absolute; width: 3.75em; height: 7.5em; transform: rotate(45deg); border-radius: 50%; } .swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=left] { top: -0.4375em; left: -2.0635em; transform: rotate(-45deg); transform-origin: 3.75em 3.75em; border-radius: 7.5em 0 0 7.5em; } .swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=right] { top: -0.6875em; left: 1.875em; transform: rotate(-45deg); transform-origin: 0 3.75em; border-radius: 0 7.5em 7.5em 0; } .swal2-icon.swal2-success .swal2-success-ring { position: absolute; z-index: 2; top: -0.25em; left: -0.25em; box-sizing: content-box; width: 100%; height: 100%; border: 0.25em solid rgba(165, 220, 134, 0.3); border-radius: 50%; } .swal2-icon.swal2-success .swal2-success-fix { position: absolute; z-index: 1; top: 0.5em; left: 1.625em; width: 0.4375em; height: 5.625em; transform: rotate(-45deg); } .swal2-icon.swal2-success [class^=swal2-success-line] { display: block; position: absolute; z-index: 2; height: 0.3125em; border-radius: 0.125em; background-color: #a5dc86; } .swal2-icon.swal2-success [class^=swal2-success-line][class$=tip] { top: 2.875em; left: 0.8125em; width: 1.5625em; transform: rotate(45deg); } .swal2-icon.swal2-success [class^=swal2-success-line][class$=long] { top: 2.375em; right: 0.5em; width: 2.9375em; transform: rotate(-45deg); } .swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-tip { -webkit-animation: swal2-animate-success-line-tip 0.75s; animation: swal2-animate-success-line-tip 0.75s; } .swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-long { -webkit-animation: swal2-animate-success-line-long 0.75s; animation: swal2-animate-success-line-long 0.75s; } .swal2-icon.swal2-success.swal2-icon-show .swal2-success-circular-line-right { -webkit-animation: swal2-rotate-success-circular-line 4.25s ease-in; animation: swal2-rotate-success-circular-line 4.25s ease-in; } .swal2-progress-steps { flex-wrap: wrap; align-items: center; max-width: 100%; margin: 1.25em auto; padding: 0; background: inherit; font-weight: 600; } .swal2-progress-steps li { display: inline-block; position: relative; } .swal2-progress-steps .swal2-progress-step { z-index: 20; flex-shrink: 0; width: 2em; height: 2em; border-radius: 2em; background: #2778c4; color: #fff; line-height: 2em; text-align: center; } .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step { background: #2778c4; } .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step ~ .swal2-progress-step { background: #add8e6; color: #fff; } .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step ~ .swal2-progress-step-line { background: #add8e6; } .swal2-progress-steps .swal2-progress-step-line { z-index: 10; flex-shrink: 0; width: 2.5em; height: 0.4em; margin: 0 -1px; background: #2778c4; } [class^=swal2] { -webkit-tap-highlight-color: transparent; } .swal2-show { -webkit-animation: swal2-show 0.3s; animation: swal2-show 0.3s; } .swal2-hide { -webkit-animation: swal2-hide 0.15s forwards; animation: swal2-hide 0.15s forwards; } .swal2-noanimation { transition: none; } .swal2-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; } .swal2-rtl .swal2-close { margin-right: initial; margin-left: 0; } .swal2-rtl .swal2-timer-progress-bar { right: 0; left: auto; } @-webkit-keyframes swal2-toast-show { 0% { transform: translateY(-0.625em) rotateZ(2deg); } 33% { transform: translateY(0) rotateZ(-2deg); } 66% { transform: translateY(0.3125em) rotateZ(2deg); } 100% { transform: translateY(0) rotateZ(0deg); } } @keyframes swal2-toast-show { 0% { transform: translateY(-0.625em) rotateZ(2deg); } 33% { transform: translateY(0) rotateZ(-2deg); } 66% { transform: translateY(0.3125em) rotateZ(2deg); } 100% { transform: translateY(0) rotateZ(0deg); } } @-webkit-keyframes swal2-toast-hide { 100% { transform: rotateZ(1deg); opacity: 0; } } @keyframes swal2-toast-hide { 100% { transform: rotateZ(1deg); opacity: 0; } } @-webkit-keyframes swal2-toast-animate-success-line-tip { 0% { top: 0.5625em; left: 0.0625em; width: 0; } 54% { top: 0.125em; left: 0.125em; width: 0; } 70% { top: 0.625em; left: -0.25em; width: 1.625em; } 84% { top: 1.0625em; left: 0.75em; width: 0.5em; } 100% { top: 1.125em; left: 0.1875em; width: 0.75em; } } @keyframes swal2-toast-animate-success-line-tip { 0% { top: 0.5625em; left: 0.0625em; width: 0; } 54% { top: 0.125em; left: 0.125em; width: 0; } 70% { top: 0.625em; left: -0.25em; width: 1.625em; } 84% { top: 1.0625em; left: 0.75em; width: 0.5em; } 100% { top: 1.125em; left: 0.1875em; width: 0.75em; } } @-webkit-keyframes swal2-toast-animate-success-line-long { 0% { top: 1.625em; right: 1.375em; width: 0; } 65% { top: 1.25em; right: 0.9375em; width: 0; } 84% { top: 0.9375em; right: 0; width: 1.125em; } 100% { top: 0.9375em; right: 0.1875em; width: 1.375em; } } @keyframes swal2-toast-animate-success-line-long { 0% { top: 1.625em; right: 1.375em; width: 0; } 65% { top: 1.25em; right: 0.9375em; width: 0; } 84% { top: 0.9375em; right: 0; width: 1.125em; } 100% { top: 0.9375em; right: 0.1875em; width: 1.375em; } } @-webkit-keyframes swal2-show { 0% { transform: scale(0.7); } 45% { transform: scale(1.05); } 80% { transform: scale(0.95); } 100% { transform: scale(1); } } @keyframes swal2-show { 0% { transform: scale(0.7); } 45% { transform: scale(1.05); } 80% { transform: scale(0.95); } 100% { transform: scale(1); } } @-webkit-keyframes swal2-hide { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(0.5); opacity: 0; } } @keyframes swal2-hide { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(0.5); opacity: 0; } } @-webkit-keyframes swal2-animate-success-line-tip { 0% { top: 1.1875em; left: 0.0625em; width: 0; } 54% { top: 1.0625em; left: 0.125em; width: 0; } 70% { top: 2.1875em; left: -0.375em; width: 3.125em; } 84% { top: 3em; left: 1.3125em; width: 1.0625em; } 100% { top: 2.8125em; left: 0.8125em; width: 1.5625em; } } @keyframes swal2-animate-success-line-tip { 0% { top: 1.1875em; left: 0.0625em; width: 0; } 54% { top: 1.0625em; left: 0.125em; width: 0; } 70% { top: 2.1875em; left: -0.375em; width: 3.125em; } 84% { top: 3em; left: 1.3125em; width: 1.0625em; } 100% { top: 2.8125em; left: 0.8125em; width: 1.5625em; } } @-webkit-keyframes swal2-animate-success-line-long { 0% { top: 3.375em; right: 2.875em; width: 0; } 65% { top: 3.375em; right: 2.875em; width: 0; } 84% { top: 2.1875em; right: 0; width: 3.4375em; } 100% { top: 2.375em; right: 0.5em; width: 2.9375em; } } @keyframes swal2-animate-success-line-long { 0% { top: 3.375em; right: 2.875em; width: 0; } 65% { top: 3.375em; right: 2.875em; width: 0; } 84% { top: 2.1875em; right: 0; width: 3.4375em; } 100% { top: 2.375em; right: 0.5em; width: 2.9375em; } } @-webkit-keyframes swal2-rotate-success-circular-line { 0% { transform: rotate(-45deg); } 5% { transform: rotate(-45deg); } 12% { transform: rotate(-405deg); } 100% { transform: rotate(-405deg); } } @keyframes swal2-rotate-success-circular-line { 0% { transform: rotate(-45deg); } 5% { transform: rotate(-45deg); } 12% { transform: rotate(-405deg); } 100% { transform: rotate(-405deg); } } @-webkit-keyframes swal2-animate-error-x-mark { 0% { margin-top: 1.625em; transform: scale(0.4); opacity: 0; } 50% { margin-top: 1.625em; transform: scale(0.4); opacity: 0; } 80% { margin-top: -0.375em; transform: scale(1.15); } 100% { margin-top: 0; transform: scale(1); opacity: 1; } } @keyframes swal2-animate-error-x-mark { 0% { margin-top: 1.625em; transform: scale(0.4); opacity: 0; } 50% { margin-top: 1.625em; transform: scale(0.4); opacity: 0; } 80% { margin-top: -0.375em; transform: scale(1.15); } 100% { margin-top: 0; transform: scale(1); opacity: 1; } } @-webkit-keyframes swal2-animate-error-icon { 0% { transform: rotateX(100deg); opacity: 0; } 100% { transform: rotateX(0deg); opacity: 1; } } @keyframes swal2-animate-error-icon { 0% { transform: rotateX(100deg); opacity: 0; } 100% { transform: rotateX(0deg); opacity: 1; } } @-webkit-keyframes swal2-rotate-loading { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes swal2-rotate-loading { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @-webkit-keyframes swal2-animate-question-mark { 0% { transform: rotateY(-360deg); } 100% { transform: rotateY(0); } } @keyframes swal2-animate-question-mark { 0% { transform: rotateY(-360deg); } 100% { transform: rotateY(0); } } @-webkit-keyframes swal2-animate-i-mark { 0% { transform: rotateZ(45deg); opacity: 0; } 25% { transform: rotateZ(-25deg); opacity: 0.4; } 50% { transform: rotateZ(15deg); opacity: 0.8; } 75% { transform: rotateZ(-5deg); opacity: 1; } 100% { transform: rotateX(0); opacity: 1; } } @keyframes swal2-animate-i-mark { 0% { transform: rotateZ(45deg); opacity: 0; } 25% { transform: rotateZ(-25deg); opacity: 0.4; } 50% { transform: rotateZ(15deg); opacity: 0.8; } 75% { transform: rotateZ(-5deg); opacity: 1; } 100% { transform: rotateX(0); opacity: 1; } } body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) { overflow: hidden; } body.swal2-height-auto { height: auto !important; } body.swal2-no-backdrop .swal2-container { background-color: transparent !important; pointer-events: none; } body.swal2-no-backdrop .swal2-container .swal2-popup { pointer-events: all; } body.swal2-no-backdrop .swal2-container .swal2-modal { box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); } @media print { body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) { overflow-y: scroll !important; } body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) > [aria-hidden=true] { display: none; } body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container { position: static !important; } } body.swal2-toast-shown .swal2-container { box-sizing: border-box; width: 360px; max-width: 100%; background-color: transparent; pointer-events: none; } body.swal2-toast-shown .swal2-container.swal2-top { top: 0; right: auto; bottom: auto; left: 50%; transform: translateX(-50%); } body.swal2-toast-shown .swal2-container.swal2-top-end, body.swal2-toast-shown .swal2-container.swal2-top-right { top: 0; right: 0; bottom: auto; left: auto; } body.swal2-toast-shown .swal2-container.swal2-top-start, body.swal2-toast-shown .swal2-container.swal2-top-left { top: 0; right: auto; bottom: auto; left: 0; } body.swal2-toast-shown .swal2-container.swal2-center-start, body.swal2-toast-shown .swal2-container.swal2-center-left { top: 50%; right: auto; bottom: auto; left: 0; transform: translateY(-50%); } body.swal2-toast-shown .swal2-container.swal2-center { top: 50%; right: auto; bottom: auto; left: 50%; transform: translate(-50%, -50%); } body.swal2-toast-shown .swal2-container.swal2-center-end, body.swal2-toast-shown .swal2-container.swal2-center-right { top: 50%; right: 0; bottom: auto; left: auto; transform: translateY(-50%); } body.swal2-toast-shown .swal2-container.swal2-bottom-start, body.swal2-toast-shown .swal2-container.swal2-bottom-left { top: auto; right: auto; bottom: 0; left: 0; } body.swal2-toast-shown .swal2-container.swal2-bottom { top: auto; right: auto; bottom: 0; left: 50%; transform: translateX(-50%); } body.swal2-toast-shown .swal2-container.swal2-bottom-end, body.swal2-toast-shown .swal2-container.swal2-bottom-right { top: auto; right: 0; bottom: 0; left: auto; } `; const normalize = ` /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ html { line-height: 1.15; -webkit-text-size-adjust: 100% } body { margin: 0 } main { display: block } h1 { font-size: 2em; margin: .67em 0 } hr { box-sizing: content-box; height: 0; overflow: visible } pre { font-family: monospace, monospace; font-size: 1em } a { background-color: transparent } abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted } b, strong { font-weight: bolder } code, kbd, samp { font-family: monospace, monospace; font-size: 1em } small { font-size: 80% } sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline } sub { bottom: -.25em } sup { top: -.5em } img { border-style: none } button, input, optgroup, select, textarea { font-family: inherit; font-size: 100%; line-height: 1.15; margin: 0 } button, input { overflow: visible } button, select { text-transform: none } [type=button], [type=reset], [type=submit], button { -webkit-appearance: button } [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner { border-style: none; padding: 0 } [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring { outline: 1px dotted ButtonText } fieldset { padding: .35em .75em .625em } legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal } progress { vertical-align: baseline } textarea { overflow: auto } [type=checkbox], [type=radio] { box-sizing: border-box; padding: 0 } [type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button { height: auto } [type=search] { -webkit-appearance: textfield; outline-offset: -2px } [type=search]::-webkit-search-decoration { -webkit-appearance: none } ::-webkit-file-upload-button { -webkit-appearance: button; font: inherit } details { display: block } summary { display: list-item } template { display: none } [hidden] { display: none } `; const nprogress = ` #nprogress { pointer-events: none } #nprogress .bar { background: #29d; position: fixed; z-index: 1031; top: 0; left: 0; width: 100%; height: 2px } #nprogress .peg { display: block; position: absolute; right: 0; width: 100px; height: 100%; box-shadow: 0 0 10px #29d, 0 0 5px #29d; opacity: 1; -webkit-transform: rotate(3deg) translate(0, -4px); -ms-transform: rotate(3deg) translate(0, -4px); transform: rotate(3deg) translate(0, -4px) } #nprogress .spinner { display: block; position: fixed; z-index: 1031; top: 15px; right: 15px } #nprogress .spinner-icon { width: 18px; height: 18px; box-sizing: border-box; border: 2px solid transparent; border-top-color: #29d; border-left-color: #29d; border-radius: 50%; -webkit-animation: nprogress-spinner 400ms linear infinite; animation: nprogress-spinner 400ms linear infinite } .nprogress-custom-parent { overflow: hidden; position: relative } .nprogress-custom-parent #nprogress .bar, .nprogress-custom-parent #nprogress .spinner { position: absolute } @-webkit-keyframes nprogress-spinner { 0% { -webkit-transform: rotate(0deg) } 100% { -webkit-transform: rotate(360deg) } } @keyframes nprogress-spinner { 0% { transform: rotate(0deg) } 100% { transform: rotate(360deg) } } `; const keycss = ` .key, kbd { display: inline; display: inline-block; white-space: nowrap; min-width: 1em; padding: 0.3em 0.4em 0.2em 0.3em; font-style: normal; font-family: "Lucida Grande", Lucida, Arial, sans-serif; text-align: center; text-decoration: none; border-radius: 0.3em; border: none; background-color: #505050; background-color: gradient(linear, left top, left bottom, from(#3c3c3c), to(#505050)); color: #fafafa; text-shadow: -1px -1px 0 #464646; -webkit-box-shadow: inset 0 0 1px #969696, inset 0 -0.05em 0.4em #505050, 0 0.1em 0 #1e1e1e, 0 0.1em 0.1em rgba(0, 0, 0, 0.3); box-shadow: inset 0 0 1px #969696, inset 0 -0.05em 0.4em #505050, 0 0.1em 0 #1e1e1e, 0 0.1em 0.1em rgba(0, 0, 0, 0.3); font-size: 0.85em; line-height: 1; cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none } .key[title], kbd[title] { cursor: help } .dark-keys .key, .dark-keys kbd, .key.dark, kbd.dark { display: inline; display: inline-block; white-space: nowrap; min-width: 1em; padding: 0.3em 0.4em 0.2em 0.3em; font-style: normal; font-family: "Lucida Grande", Lucida, Arial, sans-serif; text-align: center; text-decoration: none; border-radius: 0.3em; border: none; background-color: #505050; background-color: gradient(linear, left top, left bottom, from(#3c3c3c), to(#505050)); color: #fafafa; text-shadow: -1px -1px 0 #464646; -webkit-box-shadow: inset 0 0 1px #969696, inset 0 -0.05em 0.4em #505050, 0 0.1em 0 #1e1e1e, 0 0.1em 0.1em rgba(0, 0, 0, 0.3); box-shadow: inset 0 0 1px #969696, inset 0 -0.05em 0.4em #505050, 0 0.1em 0 #1e1e1e, 0 0.1em 0.1em rgba(0, 0, 0, 0.3) } .key.light, .light-keys .key, .light-keys kbd, kbd.light { display: inline; display: inline-block; white-space: nowrap; min-width: 1em; padding: 0.3em 0.4em 0.2em 0.3em; font-style: normal; font-family: "Lucida Grande", Lucida, Arial, sans-serif; text-align: center; text-decoration: none; border-radius: 0.3em; border: none; background-color: #fafafa; background-color: gradient(linear, left top, left bottom, from(#d2d2d2), to(#ffffff)); color: #323232; text-shadow: 0 0 2px #ffffff; -webkit-box-shadow: inset 0 0 1px #ffffff, inset 0 0 0.4em #c8c8c8, 0 0.1em 0 #828282, 0 0.11em 0 rgba(0, 0, 0, 0.4), 0 0.1em 0.11em rgba(0, 0, 0, 0.9); box-shadow: inset 0 0 1px #ffffff, inset 0 0 0.4em #c8c8c8, 0 0.1em 0 #828282, 0 0.11em 0 rgba(0, 0, 0, 0.4), 0 0.1em 0.11em rgba(0, 0, 0, 0.9) } .key.so, .so-keys .key, .so-keys kbd, kbd.so { display: inline; display: inline-block; white-space: nowrap; min-width: 1em; padding: 0.3em 0.4em 0.2em 0.3em; font-style: normal; font-family: "Lucida Grande", Lucida, Arial, sans-serif; text-align: center; text-decoration: none; border-radius: 0.3em; border: none; margin: 0 0.1em; padding: 0.1em 0.6em; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; line-height: 1.4; color: #242729; text-shadow: 0 1px 0 #FFF; background-color: #e1e3e5; border: 1px solid #adb3b9; border-radius: 0.27272727em; -webkit-box-shadow: 0 1px 0 rgba(12, 13, 14, 0.2), 0 0 0 2px #FFF inset; box-shadow: 0 1px 0 rgba(12, 13, 14, 0.2), 0 0 0 2px #FFF inset } .github-keys .key, .github-keys kbd, .key.github, kbd.github { display: inline; display: inline-block; white-space: nowrap; min-width: 1em; padding: 0.3em 0.4em 0.2em 0.3em; font-style: normal; font-family: "Lucida Grande", Lucida, Arial, sans-serif; text-align: center; text-decoration: none; border-radius: 0.3em; border: none; padding: 0.27272727em 0.45454545em; font-size: 68.75%; line-height: 0.90909091; color: #444d56; vertical-align: middle; background-color: #fafbfc; border: solid 1px #c6cbd1; border-bottom-color: #959da5; border-radius: 0.27272727em; -webkit-box-shadow: inset 0 -1px 0 #959da5; box-shadow: inset 0 -1px 0 #959da5; font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; -webkit-box-sizing: border-box; box-sizing: border-box; text-shadow: none } `; const sweetalertStyle = [normalize, sweetalert, nprogress, keycss].join("\n"); function head(manga) { return ` ${manga.title} ${wrapStyle("externals", sweetalertStyle)} ${wrapStyle("reader", cssStyles)} ${themesCSS} ${wrapStyle( "MinZoom", `#MangaOnlineViewer .PageContent .PageImg {min-width: ${useSettings().minZoom}vw;}` )} `; } function indexList(repeat, begin = 1) { return Array(repeat).fill(0).map((_, i) => i + 1).filter((i) => i >= begin); } const listPages = (times, begin) => indexList(times, begin).map( (index) => `
${index}
` ); const localeSelector = locales.map( (locale) => `` ); const SettingsPanel = `

${getLocaleString("SETTINGS")}

${getLocaleString("LANGUAGE")}:
${getLocaleString("COLOR_SCHEME")}:
${getLocaleString("THEME")}: ${IconPalette} ${IconCheck} ${themesSelector.join("")}
${getLocaleString("THEME_HUE")}:
${getLocaleString("THEME_SHADE")}: ${useSettings().themeShade}
${getLocaleString("DEFAULT_LOAD_MODE")}:
${getLocaleString("LOAD_SPEED")}:
${getLocaleString("DEFAULT_ZOOM_MODE")}:
${getLocaleString("DEFAULT_ZOOM")}: ${useSettings().defaultZoom}%
${getLocaleString("MINIMUM_ZOOM")}: ${useSettings().minZoom}%
${getLocaleString("ZOOM_STEP")}: ${useSettings().zoomStep}%
${getLocaleString("DEFAULT_VIEW_MODE")}:
${getLocaleString("FIT_WIDTH_OVERSIZED")}:
${getLocaleString("SHOW_THUMBNAILS")}:
${getLocaleString("LAZY_LOAD_IMAGES_ENABLE")}:
${getLocaleString("LAZY_LOAD_IMAGES")}: ${useSettings().lazyStart}
${getLocaleString("DOWNLOAD_IMAGES")}:
${getLocaleString("HIDE_CONTROLS")}:
${getLocaleString("HEADER_TYPE")}:
`; const keybindList = () => Object.keys(useSettings().keybinds).map((kb) => { const keys = useSettings().keybinds[kb]?.length ? useSettings().keybinds[kb]?.map((key) => `${key}`).join(" / ") : ""; return `${getLocaleString(kb)}: ${keys}`; }); const keybindEditor = () => Object.keys(useSettings().keybinds).map( (kb) => ` ` ).concat(`
${getLocaleString("KEYBIND_RULES")}
`); const KeybindingsPanel = `

${getLocaleString("KEYBINDINGS")}

${keybindList().join("\n")}
`; const ThumbnailsPanel = (times, begin) => indexList(times, begin).map( (index) => `
${index}
` ); function isEmpty(value) { return value === null || // check for null typeof value === "undefined" || value === void 0 || // check for undefined typeof value === "string" && value === "" || // check for empty string Array.isArray(value) && value.length === 0 || // check for empty array typeof value === "object" && Object.keys(value).length === 0; } function isNothing(value) { const isEmptyObject = (a) => { if (!Array.isArray(a)) { const hasNonempty = Object.keys(a).some((element) => !isNothing(a[element])); return hasNonempty ? false : isEmptyObject(Object.keys(a)); } return !a.some( (element) => !isNothing(element) // ); }; return ( // eslint-disable-next-line eqeqeq value == false || value === 0 || isEmpty(value) || typeof value === "object" && isEmptyObject(value) ); } const listBookmarks = () => { if (isEmpty(useSettings().bookmarks)) return [getLocaleString("LIST_EMPTY")]; return useSettings().bookmarks.map( (mark, index) => `
${new Date(mark.date).toLocaleDateString()} ${mark.url} Page: ${mark.page}
` ); }; const BookmarkPanel = `

${getLocaleString("BOOKMARKS")}

${listBookmarks().join("")}
`; function reloadBookmarks() { const list = document.getElementById("BookmarksList"); if (list) { list.innerHTML = listBookmarks().join(""); } } const listOptions = (times, begin) => indexList(times, begin).map((index) => ``); const app = (manga, begin = 1) => `
${listPages(manga.pages, begin).join("")}
${SettingsPanel} ${KeybindingsPanel} ${BookmarkPanel}
`; function buttonBookmarks() { document.querySelector("#BookmarksPanel")?.classList.toggle("visible"); document.querySelector("#BookmarksOverlay")?.classList.toggle("visible"); } function eraseBookmarks(elem) { elem.addEventListener("click", (event) => { const target = event.currentTarget.value; const marks = useSettings().bookmarks.filter((el) => el.url !== target); if (target === window.location.href) { document.querySelector("#MangaOnlineViewer")?.classList.toggle("bookmarked"); } logScript(`Bookmark Removed ${target}`); Swal.fire({ title: getLocaleString("BOOKMARK_REMOVED"), timer: 1e4, icon: "error" }); updateSettings({ bookmarks: marks }); reloadBookmarks(); document.querySelectorAll(".BookmarkItem .erase")?.forEach(eraseBookmarks); }); } function buttonBookmark(elem) { elem.addEventListener("click", (event) => { document.querySelector("#MangaOnlineViewer")?.classList.toggle("bookmarked"); const num = parseInt( event.currentTarget.parentElement?.querySelector(".PageIndex")?.textContent || "0", 10 ); const mark = { url: window.location.href, page: num, date: Date.now() }; if (isBookmarked(mark.url)) { updateSettings({ bookmarks: useSettings().bookmarks.filter((el) => el.url !== mark.url) }); Swal.fire({ title: getLocaleString("BOOKMARK_REMOVED"), timer: 1e4, icon: "error" }); } else { updateSettings({ bookmarks: [...useSettings().bookmarks, mark] }); Swal.fire({ title: getLocaleString("BOOKMARK_SAVED"), html: getLocaleString("BOOKMARK_SAVED").replace("##NUM##", num.toString()), icon: "success" }); } reloadBookmarks(); document.querySelectorAll(".BookmarkItem .erase")?.forEach(eraseBookmarks); }); } function bookmarks() { document.querySelector("#bookmarks")?.addEventListener("click", buttonBookmarks); document.querySelector("#CloseBookmarks")?.addEventListener("click", buttonBookmarks); document.querySelector("#BookmarksOverlay")?.addEventListener("click", buttonBookmarks); document.querySelectorAll(".BookmarkItem .erase")?.forEach(eraseBookmarks); document.querySelectorAll(".Bookmark")?.forEach(buttonBookmark); } let zip; const base64Regex = /^data:(?image\/\w+);base64,+(?.+)/; const getExtension = (mimeType) => ((/image\/(?jpe?g|png|webp)/.exec(mimeType) || {}).groups || {}).ext || "" || "png"; const getFilename = (name, index, total, ext) => `${name}${(index + 1).toString().padStart(Math.floor(Math.log10(total)) + 1, "0")}.${ext.replace( "jpeg", "jpg" )}`; function getImage(src) { return new Promise((resolve) => { logScript(`Getting Image data: ${src}`); GM_xmlhttpRequest({ method: "GET", url: src, headers: { referer: src, origin: src }, responseType: "blob", onload(response) { resolve(response); } }); }); } function getImageData(img, index, array) { const src = img.getAttribute("src") ?? img.getAttribute("data-src"); if (src == null) return Promise.reject(new Error("Image source not specified")); const base64 = base64Regex.exec(src); if (base64 && base64.groups) { return Promise.resolve({ name: getFilename("Page-", index, array.length, getExtension(base64.groups?.mimeType)), data: base64.groups.data }); } return new Promise((resolve) => { getImage(src).then( (res) => resolve({ name: getFilename("Page-", index, array.length, getExtension(res.response.type)), data: res.response }) ); }); } function addZip(img) { logScript(`${img.name} Added to Zip from Base64 Image`); zip.file(img.name, img.data, { base64: true, createFolders: true, compression: "DEFLATE" }); } async function generateZip() { zip = new JSZip(); const images = [...document.querySelectorAll(".PageImg")]; const data = await Promise.all(images.map(getImageData)); data.forEach(addZip); logScript("Generating Zip"); zip.generateAsync( { type: "blob" } // logScript, progress ).then((content) => { logScript("Download Ready"); const zipName = `${document.querySelector("#MangaTitle")?.textContent?.trim()}.zip`; saveAs(content, zipName, true); document.getElementById("download")?.classList.remove("loading"); }).catch(logScript); } function startDownload(event) { const button = event.currentTarget; if (button.classList.contains("loading")) return; logScript("Downloading Chapter"); button.classList.add("loading"); generateZip(); } function globalHideImageControls() { document.querySelector("#MangaOnlineViewer")?.classList.toggle("hideControls"); } function redirect(event) { const element = event.target; const url = element.getAttribute("value") || element.getAttribute("href"); if (url) window.location.href = url; } function globals() { document.querySelector("#download")?.addEventListener("click", startDownload); document.querySelector("#pageControls")?.addEventListener("click", globalHideImageControls); document.querySelector("#next")?.addEventListener("click", redirect); document.querySelector("#prev")?.addEventListener("click", redirect); } function headroom(showEnd = 0) { let prevOffset = 0; const setScrollDirection = (classSuffix) => { const header = document.querySelector("#Header"); header.classList.remove("headroom-end"); header.classList.remove("headroom-hide"); header.classList.remove("headroom-show"); if (classSuffix) header.classList.add(`headroom-${classSuffix}`); }; function toggleScrollDirection() { const { scrollY } = window; if (showEnd && useSettings().zoomMode !== "height" && scrollY + window.innerHeight + showEnd > document.body.offsetHeight) { setScrollDirection("end"); } else if (scrollY > prevOffset && scrollY > 50) { setScrollDirection("hide"); } else if (scrollY < prevOffset && scrollY > 50) { setScrollDirection("show"); } else { setScrollDirection(""); } prevOffset = scrollY; } window.addEventListener("scroll", _.debounce(toggleScrollDirection, 50)); } function scrollToElement(ele) { window.scroll(0, ele?.offsetTop || 0); } const doClick = (selector) => document.querySelector(selector)?.dispatchEvent(new Event("click")); function doScrolling(sign) { if (useSettings().zoomMode === "height") { const pages = [...document.querySelectorAll(".MangaPage")]; const distance = pages.map((element) => Math.abs(element.offsetTop - window.scrollY)); const currentPage = distance.findIndex((d) => d <= 5); const target = currentPage + sign; const header = document.querySelector("#Header"); if (target < 0) { scrollToElement(header); } else if (target >= pages.length) { header.classList.add("headroom-end"); } else { logScript(`Current array page ${currentPage},`, `Scrolling to page ${target}`); scrollToElement(pages.at(target)); } } else { window.scrollBy({ top: sign * window.innerHeight / 2, behavior: "smooth" }); } } const actions = { SCROLL_UP: () => { doScrolling(-1); }, SCROLL_DOWN: () => { doScrolling(1); }, NEXT_CHAPTER: () => { doClick("#next"); }, PREVIOUS_CHAPTER: () => { doClick("#prev"); }, ENLARGE: () => { doClick("#enlarge"); }, REDUCE: () => { doClick("#reduce"); }, RESTORE: () => { doClick("#restore"); }, FIT_WIDTH: () => { doClick("#fitWidth"); }, FIT_HEIGHT: () => { doClick("#fitHeight"); }, SETTINGS: () => { doClick("#settings"); }, VIEW_MODE_WEBCOMIC: () => { doClick("#webComic"); }, VIEW_MODE_VERTICAL: () => { doClick("#verticalMode"); }, VIEW_MODE_LEFT: () => { doClick("#rtlMode"); }, VIEW_MODE_RIGHT: () => { doClick("#ltrMode"); } }; function keybindings() { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; document.onkeydown = null; document.onkeyup = null; document.onkeypress = null; W.onkeydown = null; W.onkeyup = null; W.onkeypress = null; W.onload = null; document.body.onload = null; hotkeys.unbind(); Object.keys(useSettings().keybinds).forEach((key) => { hotkeys(useSettings().keybinds[key]?.join(",") || "", actions[key]); }); } function isImagesManga(manga) { return "listImages" in manga && !isNothing(manga.listImages); } function isPagesManga(manga) { return "listPages" in manga && !isNothing(manga.listPages); } function isBruteforceManga(manga) { return "bruteForce" in manga && !isNothing(manga.bruteForce); } function fetchText(url, format) { return new Promise((resolve) => { logScript("Fetching page: ", url); fetch(url).then( (response) => ( // When the page is loaded convert it to text response.text() ) ).then((html) => { const parser = new DOMParser(); const doc = parser.parseFromString(html, format); resolve(doc); }).catch((err) => { logScript("Failed to fetch page: ", err); }); }); } function fetchHtml(url) { return fetchText(url, "text/html"); } function getElementAttribute(url, selector, attribute) { return fetchHtml(url).then((doc) => doc.querySelector(selector)?.getAttribute(attribute)); } const settings = { threshold: 2e3, throttle: 500, lazyAttribute: "data-src", targetAttribute: "src" }; let listElements = []; let setup = false; function filterInView(value) { const { element } = value; const rect = element.getBoundingClientRect(); const viewport = { top: 0 - settings.threshold, bottom: window.scrollY + window.innerHeight + settings.threshold }; return rect.bottom >= viewport.top && rect.top <= viewport.bottom; } function showElement(item) { const value = item.element.getAttribute(settings.lazyAttribute); if (value) item.element.setAttribute(settings.targetAttribute, value); item.callback(item.element); } function executeCheck() { const inView = listElements.filter(filterInView); listElements = listElements.filter((item) => !filterInView(item)); inView.forEach(showElement); } const observerEvent = _.throttle(executeCheck, settings.throttle); function lazyLoad(element, callback) { if (!setup) { window.addEventListener("scroll", observerEvent, { passive: true }); window.addEventListener("touchmove", observerEvent, { passive: true }); window.addEventListener("resize", observerEvent, { passive: true }); setup = true; } listElements.push({ element, callback }); observerEvent(); } function applyZoom(zoom = useSettings().zoomMode, pages = ".PageContent img") { const pg = [...document.querySelectorAll(pages)]; pg.forEach((img) => { img.removeAttribute("width"); img.removeAttribute("height"); img.removeAttribute("style"); if (zoom === "width") { img.style.width = `${window.innerWidth}px`; } else if (zoom === "height") { const nav = document.querySelector("#Navigation")?.classList.contains("disabled"); const chap = document.querySelector("#Chapter")?.classList.contains("WebComic"); const nextHeight = window.innerHeight + (nav ? 0 : -30) + (chap ? 0 : -35); img.style.height = `${nextHeight}px`; img.style.minWidth = "unset"; } else if (zoom === "percent") { img.style.width = `${img.naturalWidth * (useSettings().defaultZoom / 100)}px`; } else { img.style.width = `${img.naturalWidth * (zoom / 100)}px`; } }); } function invalidateImageCache(src, repeat) { const url = src.replace(/[?&]cache=\d+$/, ""); const symbol = url.indexOf("?") === -1 ? "?" : "&"; return `${url + symbol}cache=${repeat}`; } function getRepeatValue(src) { let repeat = 1; const cache = src?.match(/cache=(\d+)$/); if (cache && cache[1]) repeat = parseInt(cache[1], 10) + 1; return repeat; } function reloadImage(img) { const src = img.getAttribute("src"); if (!src) return; img.removeAttribute("src"); img.setAttribute("src", invalidateImageCache(src, getRepeatValue(src))); } function onImagesDone() { logScript("Images Loading Complete"); if (useSettings().downloadZip) { document.getElementById("download")?.dispatchEvent(new Event("click")); } document.getElementById("download")?.classList.remove("disabled"); } function updateProgress() { const total = document.querySelectorAll(".PageContent .PageImg").length; const loaded = document.querySelectorAll(".PageContent .PageImg.imgLoaded").length; const percentage = Math.floor(loaded / total * 100); const title = document.querySelector("title"); if (title) { title.innerHTML = `(${percentage}%) ${document.querySelector("#MangaTitle")?.textContent}`; } document.querySelectorAll("#Counters i, #NavigationCounters i").forEach((ele) => { ele.textContent = loaded.toString(); }); NProgress.configure({ showSpinner: false }).set(loaded / total); logScript(`Progress: ${percentage}%`); if (loaded === total) onImagesDone(); } function onImagesSuccess(instance) { instance.images.forEach((image) => { image.img.classList.add("imgLoaded"); image.img.classList.remove("imgBroken"); const thumbId = image.img.id.replace("PageImg", "ThumbnailImg"); const thumb = document.getElementById(thumbId); if (thumb) thumb.setAttribute("src", image.img.getAttribute("src")); applyZoom(useSettings().zoomMode, `#${image.img.id}`); updateProgress(); }); } function onImagesFail(instance) { instance.images.forEach((image) => { image.img.classList.add("imgBroken"); const src = image.img.getAttribute("src"); if (src && getRepeatValue(src) <= useSettings().maxReload) { setTimeout(() => { reloadImage(image.img); const imgLoad = imagesLoaded(image.img.parentElement); imgLoad.on("done", onImagesSuccess); imgLoad.on("fail", onImagesFail); }, 2e3); } }); } function normalizeUrl(url = "") { let uri = url.trim(); if (uri.startsWith("//")) { uri = `https:${uri}`; } return uri; } function addImg(manga, index, imageSrc, position) { const src = normalizeUrl(imageSrc); const img = document.querySelector(`#PageImg${index}`); if (img) { if (!useSettings().lazyLoadImages || position <= useSettings().lazyStart) { setTimeout(() => { const imgLoad = imagesLoaded(img.parentElement); imgLoad.on("done", onImagesSuccess); imgLoad.on("fail", onImagesFail); img.setAttribute("src", src); logScript("Loaded Image:", index, "Source:", src); }, (manga.timer || useSettings().throttlePageLoad) * position); } else { img.setAttribute("data-src", src); lazyLoad(img, () => { const imgLoad = imagesLoaded(img.parentElement); imgLoad.on("done", onImagesSuccess); imgLoad.on("fail", onImagesFail); logScript("Lazy Image: ", index, " Source: ", img.getAttribute("src")); }); } } } function findPage(manga, index, pageUrl, lazy) { return async () => { const src = await getElementAttribute(pageUrl, manga.img, manga.lazyAttr ?? "src"); const img = document.querySelector(`#PageImg${index}`); if (src && img) { img.style.width = "auto"; const imgLoad = imagesLoaded(img.parentElement); imgLoad.on("done", onImagesSuccess); imgLoad.on("fail", onImagesFail); img.setAttribute("src", src); logScript(`${lazy && "Lazy "}Page: `, index, " Source: ", img.getAttribute("src")); } }; } async function addPage(manga, index, pageUrl, position) { const img = document.querySelector(`#PageImg${index}`); if (img) { if (!useSettings().lazyLoadImages || position <= useSettings().lazyStart) { setTimeout(() => { findPage(manga, index, pageUrl, false)(); }, (manga.timer || useSettings().throttlePageLoad) * position); } else { img.setAttribute( "data-src", "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" ); lazyLoad(img, findPage(manga, index, pageUrl, true)); } } } function loadMangaPages(begin, manga) { indexList(manga.pages, begin).forEach( (index, position) => addPage(manga, index, manga.listPages[index - 1], position) ); } function loadMangaImages(begin, manga) { indexList(manga.pages, begin).forEach( (index, position) => addImg(manga, index, manga.listImages[index - 1], position) ); } function loadManga(manga, begin = 1) { useSettings().lazyLoadImages = manga.lazy || useSettings().lazyLoadImages; logScript("Loading Images"); logScript(`Intervals: ${manga.timer || useSettings().throttlePageLoad || "Default(1000)"}`); logScript(`Lazy: ${useSettings().lazyLoadImages}, Starting from: ${useSettings().lazyStart}`); if (isImagesManga(manga)) { logScript("Method: Images:", manga.listImages); loadMangaImages(begin, manga); } else if (isPagesManga(manga)) { logScript("Method: Pages:", manga.listPages); loadMangaPages(begin, manga); } else if (isBruteforceManga(manga)) { logScript("Method: Brute Force"); manga.bruteForce({ begin, addImg, loadImages: (list) => loadMangaImages(begin, { ...manga, listImages: list }), loadPages: (list, img, lazyAttr) => loadMangaPages(begin, { ...manga, listPages: list, img, lazyAttr }), wait: useSettings().throttlePageLoad }); } else { logScript("No Loading Method Found"); } } function individual() { function buttonReloadPage(elem) { return elem.addEventListener("click", (event) => { const img = event.currentTarget.parentElement?.parentElement?.querySelector(".PageImg"); reloadImage(img); }); } document.querySelectorAll(".Reload")?.forEach(buttonReloadPage); function buttonHidePage(elem) { elem.addEventListener("click", (event) => { const img = event.currentTarget.parentElement?.parentElement; img.classList.toggle("hide"); }); } document.querySelectorAll(".Hide")?.forEach(buttonHidePage); } function navigation() { function selectGoToPage(event) { const target = event.currentTarget.value; applyZoom(); scrollToElement(document.querySelector(`#Page${target}`)); } document.querySelector("#gotoPage")?.addEventListener("change", selectGoToPage); function clickThumbnail(elem) { return elem.addEventListener("click", (event) => { applyZoom(); scrollToElement( document.querySelector( `#Page${event.currentTarget.querySelector(".ThumbnailIndex")?.textContent}` ) ); }); } document.querySelectorAll(".Thumbnail")?.forEach(clickThumbnail); } function options() { function buttonResetSettings() { resetSettings(); Swal.fire({ title: getLocaleString("ATTENTION"), text: getLocaleString("SETTINGS_RESET"), timer: 1e4, icon: "info" }); } document.querySelector("#ResetSettings")?.addEventListener("click", buttonResetSettings); function changeLocale(event) { const locale = event.currentTarget.value; updateSettings({ locale }); Swal.fire({ title: getLocaleString("ATTENTION"), text: getLocaleString("LANGUAGE_CHANGED"), timer: 1e4, icon: "info" }); } document.querySelector("#locale")?.addEventListener("change", changeLocale); function checkFitWidthOversize(event) { document.querySelector("#Chapter")?.classList.toggle("fitWidthIfOversize"); updateSettings({ fitWidthIfOversize: event.currentTarget.checked }); } document.querySelector("#fitIfOversize")?.addEventListener("change", checkFitWidthOversize); function changeLoadMode(event) { const mode = event.currentTarget.value; updateSettings({ loadMode: mode }); } document.querySelector("#loadMode")?.addEventListener("change", changeLoadMode); function checkShowThumbnails(event) { document.querySelector("#Navigation")?.classList.toggle("disabled"); updateSettings({ showThumbnails: event.currentTarget.checked }); applyZoom(); } document.querySelector("#showThumbnails")?.addEventListener("change", checkShowThumbnails); function changeAutoDownload(event) { updateSettings({ downloadZip: event.currentTarget.checked }); if (event.currentTarget.checked) { Swal.fire({ title: getLocaleString("ATTENTION"), text: getLocaleString("AUTO_DOWNLOAD"), timer: 1e4, icon: "info" }); } } document.querySelector("#downloadZip")?.addEventListener("change", changeAutoDownload); function checkLazyLoad(event) { updateSettings({ lazyLoadImages: event.currentTarget.checked }); const start = document.querySelector(".lazyStart"); if (useSettings().lazyLoadImages) { start?.classList.add("show"); } else { start?.classList.remove("show"); } if (event.currentTarget.checked) { Swal.fire({ title: getLocaleString("WARNING"), html: getLocaleString("LAZY_LOAD"), icon: "warning" }); } } document.querySelector("#lazyLoadImages")?.addEventListener("change", checkLazyLoad); function changeLazyStart(event) { const start = event.currentTarget.value; updateSettings({ lazyStart: parseInt(start, 10) }); } document.querySelector("#lazyStart")?.addEventListener("change", changeLazyStart); function changePagesPerSecond(event) { const timer = parseInt(event.currentTarget.value, 10); updateSettings({ throttlePageLoad: timer }); } document.querySelector("#PagesPerSecond")?.addEventListener("change", changePagesPerSecond); function changeZoomStep(event) { const step = event.currentTarget.value; updateSettings({ zoomStep: parseInt(step, 10) }); } document.querySelector("#zoomStep")?.addEventListener("change", changeZoomStep); function changeMinZoom(event) { const min = event.currentTarget.value; replaceStyleSheet("MinZoom", `#MangaOnlineViewer .PageContent .PageImg {min-width: ${min}vw;}`); updateSettings({ minZoom: parseInt(min, 10) }); } document.querySelector("#minZoom")?.addEventListener("input", changeMinZoom); function checkHideImageControls(event) { document.querySelector("#MangaOnlineViewer")?.classList.toggle("hideControls"); updateSettings({ hidePageControls: event.currentTarget.checked }); } document.querySelector("#hidePageControls")?.addEventListener("change", checkHideImageControls); function changeHeaderType(event) { document.querySelector("#Header").className = ""; const headerType = event.currentTarget.value; document.querySelector("#Header")?.classList.add(headerType); updateSettings({ header: headerType }); } document.querySelector("#headerType")?.addEventListener("change", changeHeaderType); } function panels() { function buttonHeader() { const header = document.querySelector("#Header"); if (header?.classList.contains("click")) header?.classList.toggle("visible"); } document.querySelector("#menu")?.addEventListener("click", buttonHeader); function buttonSettingsOpen() { document.querySelector("#SettingsPanel")?.classList.add("visible"); document.querySelector("#Navigation")?.classList.add("visible"); document.querySelector("#Header")?.classList.add("visible"); document.querySelector("#SettingsOverlay")?.classList.add("visible"); } function buttonSettingsClose() { document.querySelector("#SettingsPanel")?.classList.remove("visible"); document.querySelector("#Navigation")?.classList.remove("visible"); document.querySelector("#Header")?.classList.remove("visible"); document.querySelector("#SettingsOverlay")?.classList.remove("visible"); } document.querySelector("#settings")?.addEventListener("click", buttonSettingsOpen); document.querySelector("#CloseSettings")?.addEventListener("click", buttonSettingsClose); document.querySelector("#SettingsOverlay")?.addEventListener("click", buttonSettingsClose); function buttonKeybindings() { document.querySelector("#KeybindingsList").innerHTML = keybindList().join("\n"); document.querySelector("#SaveKeybindings")?.classList.add("hidden"); document.querySelector("#EditKeybindings")?.classList.remove("hidden"); document.querySelector("#KeybindingsPanel")?.classList.toggle("visible"); document.querySelector("#KeybindingsOverlay")?.classList.toggle("visible"); } function saveKeybindings() { const newkeybinds = useSettings().keybinds; Object.keys(useSettings().keybinds).forEach((kb) => { const keys = document.querySelector(`#${kb}`)?.value.split(",")?.map((value) => value.trim()); newkeybinds[kb] = isNothing(keys) ? void 0 : keys; }); updateSettings({ keybinds: newkeybinds }); document.querySelector("#KeybindingsList").innerHTML = keybindList().join("\n"); document.querySelector("#SaveKeybindings")?.classList.add("hidden"); document.querySelector("#EditKeybindings")?.classList.remove("hidden"); keybindings(); } function editKeybindings() { document.querySelector("#KeybindingsList").innerHTML = keybindEditor().join("\n"); document.querySelector("#SaveKeybindings")?.classList.remove("hidden"); document.querySelector("#EditKeybindings")?.classList.add("hidden"); } document.querySelector("#keybindings")?.addEventListener("click", buttonKeybindings); document.querySelector("#CloseKeybindings")?.addEventListener("click", buttonKeybindings); document.querySelector("#KeybindingsOverlay")?.addEventListener("click", buttonKeybindings); document.querySelector("#EditKeybindings")?.addEventListener("click", editKeybindings); document.querySelector("#SaveKeybindings")?.addEventListener("click", saveKeybindings); } function size() { function buttonZoomIn(elem) { return elem.addEventListener("click", (event) => { const img = event.currentTarget.parentElement?.parentElement?.querySelector(".PageImg"); const ratio = img.width / img.naturalWidth * (100 + useSettings().zoomStep); applyZoom(ratio, `#${img.getAttribute("id")}`); }); } document.querySelectorAll(".ZoomIn")?.forEach(buttonZoomIn); function buttonZoomOut(elem) { return elem.addEventListener("click", (event) => { const img = event.currentTarget.parentElement?.parentElement?.querySelector(".PageImg"); const ratio = img.width / img.naturalWidth * (100 - useSettings().zoomStep); applyZoom(ratio, `#${img.getAttribute("id")}`); }); } document.querySelectorAll(".ZoomOut")?.forEach(buttonZoomOut); function buttonRestoreZoom(elem) { return elem.addEventListener("click", () => { document.querySelector(".PageContent .PageImg")?.removeAttribute("width"); }); } document.querySelectorAll(".ZoomRestore")?.forEach(buttonRestoreZoom); function buttonZoomWidth(elem) { return elem.addEventListener("click", (event) => { const page = event.currentTarget.parentElement?.parentElement; const img = page?.querySelector(".PageImg"); applyZoom("width", `#${img.getAttribute("id")}`); page?.classList.toggle("DoublePage"); }); } document.querySelectorAll(".ZoomWidth")?.forEach(buttonZoomWidth); function buttonZoomHeight(elem) { elem.addEventListener("click", (event) => { const img = event.currentTarget.parentElement?.parentElement?.querySelector(".PageImg"); applyZoom("height", `#${img.getAttribute("id")}`); }); } document.querySelectorAll(".ZoomHeight")?.forEach(buttonZoomHeight); } function theming() { function changeColorScheme() { const isDark = useSettings().colorScheme === "dark"; updateSettings({ colorScheme: isDark ? "light" : "dark" }); const elem = document.getElementById("MangaOnlineViewer"); elem?.classList.remove(isDark ? "dark" : "light"); elem?.classList.add(useSettings().colorScheme); } document.querySelector("#ColorScheme")?.addEventListener("click", changeColorScheme); function changeTheme(event) { const target = event.currentTarget; [...document.querySelectorAll(".ThemeRadio")].forEach( (elem) => elem.classList.remove("selected") ); target.classList.add("selected"); document.getElementById("MangaOnlineViewer")?.setAttribute("data-theme", target.title); updateSettings({ theme: target.title }); const hue = document.querySelector("#Hue"); const shade = document.querySelector("#Shade"); if (target.title.startsWith("custom")) { hue?.classList.add("show"); shade?.classList.remove("show"); } else { hue?.classList.remove("show"); shade?.classList.add("show"); } } [...document.querySelectorAll(".ThemeRadio")].forEach( (elem) => elem.addEventListener("click", changeTheme) ); function changeCustomTheme(event) { const target = event.currentTarget.value; updateSettings({ customTheme: target }); addCustomTheme(target); } document.querySelector("#CustomThemeHue")?.addEventListener("change", changeCustomTheme); function changeThemeShade(event) { const target = parseInt(event.currentTarget.value, 10); updateSettings({ themeShade: target }); refreshThemes(); } document.querySelector("#ThemeShade")?.addEventListener("change", changeThemeShade); } function updateViewMode(mode) { return () => { document.querySelector("#Chapter")?.classList.remove("Vertical"); document.querySelector("#Chapter")?.classList.remove("WebComic"); document.querySelector("#Chapter")?.classList.remove("FluidLTR"); document.querySelector("#Chapter")?.classList.remove("FluidRTL"); document.querySelector("#Chapter")?.classList.add(mode); applyZoom(); }; } function changeViewMode(event) { const mode = event.currentTarget.value; updateViewMode(mode)(); updateSettings({ viewMode: mode }); } function viewMode() { document.querySelector("#viewMode")?.addEventListener("change", changeViewMode); document.querySelector("#webComic")?.addEventListener("click", updateViewMode("WebComic")); document.querySelector("#ltrMode")?.addEventListener("click", updateViewMode("FluidLTR")); document.querySelector("#rtlMode")?.addEventListener("click", updateViewMode("FluidRTL")); document.querySelector("#verticalMode")?.addEventListener("click", updateViewMode("Vertical")); } function changeGlobalZoom(value) { return () => { if (typeof value !== "number") { useSettings().zoomMode = value; } else { useSettings().zoomMode = "percent"; } const globalZoomVal = document.querySelector("#ZoomVal"); globalZoomVal.textContent = Number.isInteger(value) ? `${value}%` : value; applyZoom(value); }; } function changeZoomByStep(sign = 1) { return () => { const globalZoom = document.querySelector("#Zoom"); const ratio = parseInt(globalZoom.value, 10) + sign * useSettings().zoomStep; globalZoom.value = ratio.toString(); globalZoom?.dispatchEvent(new Event("input", { bubbles: true })); }; } function zoom() { function changeDefaultZoomMode(event) { const target = event.currentTarget.value; updateSettings({ zoomMode: target }); changeGlobalZoom(target)(); const percent = document.querySelector(".DefaultZoom"); if (useSettings().zoomMode === "percent") { percent?.classList.add("show"); } else { percent?.classList.remove("show"); } } document.querySelector("#DefaultZoomMode")?.addEventListener("change", changeDefaultZoomMode); function changeDefaultZoom(event) { const target = parseInt(event.currentTarget.value, 10); updateSettings({ defaultZoom: target }); changeGlobalZoom(target)(); } document.querySelector("#DefaultZoom")?.addEventListener("input", changeDefaultZoom); function changeZoom(event) { const target = parseInt(event.currentTarget.value, 10); changeGlobalZoom(target)(); document.querySelector("#ZoomVal").textContent = `${target}%`; } document.querySelector("#Zoom")?.addEventListener("input", changeZoom); document.querySelector("#enlarge")?.addEventListener("click", changeZoomByStep()); document.querySelector("#reduce")?.addEventListener("click", changeZoomByStep(-1)); document.querySelector("#restore")?.addEventListener("click", changeGlobalZoom(100)); document.querySelector("#fitWidth")?.addEventListener("click", changeGlobalZoom("width")); document.querySelector("#fitHeight")?.addEventListener("click", changeGlobalZoom("height")); } function events() { bookmarks(); globals(); headroom(100); keybindings(); individual(); navigation(); options(); panels(); size(); theming(); viewMode(); zoom(); } function display(manga) { window.stop(); if (manga.before !== void 0) { manga.before(); } [document.documentElement, document.head, document.body].forEach((element) => { element.getAttributeNames().forEach((attr) => element.removeAttribute(attr)); }); document.head.innerHTML = head(manga); document.body.innerHTML = app(manga, manga.begin); logScript("Rebuilding Site"); setTimeout(() => { try { events(); setTimeout(() => { window.scrollTo(0, 0); loadManga(manga, manga.begin); }, 50); if (!isNothing(useSettings().bookmarks.filter((el) => el.url === window.location.href))) { logScript(`Bookmark Removed ${window.location.href}`); useSettings().bookmarks = useSettings().bookmarks.filter( (el) => el.url !== window.location.href ); setValueGM("Bookmarks", JSON.stringify(useSettings().bookmarks)); } } catch (e) { logScript(e); } }, 50); if (manga.after !== void 0) { manga.after(); } } function testAttribute(site) { if (site.waitAttr !== void 0) { const wait = document.querySelector(site.waitAttr[0])?.getAttribute(site.waitAttr[1]); if (isNothing(wait)) { logScript(`Waiting for Attribute ${site.waitAttr[1]} of ${site.waitAttr[0]} = ${wait}`); return true; } logScript(`Found Attribute ${site.waitAttr[1]} of ${site.waitAttr[0]} = ${wait}`); } return false; } function testElement(site) { if (site.waitEle !== void 0) { const wait = document.querySelector(site.waitEle); if (isNothing(wait?.tagName)) { logScript(`Waiting for Element ${site.waitEle} = `, wait); return true; } logScript(`Found Element ${site.waitEle} = `, wait); } return false; } function testVariable(site) { if (site.waitVar !== void 0) { const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const wait = W[site.waitVar]; if (isNothing(wait)) { logScript(`Waiting for Variable ${site.waitVar} = ${wait}`); return true; } logScript(`Found Variable ${site.waitVar} = ${wait}`); } return false; } function testFunc(site) { if (site.waitFunc !== void 0) { const wait = site.waitFunc(); if (!wait) { logScript(`Waiting to pass Function check ${site.waitFunc} = ${wait}`); return true; } logScript(`Found Function check ${site.waitFunc} = ${wait}`); } return false; } async function lateStart(site, begin = 1) { const manga = await site.run(); logScript("LateStart"); let beginPage = begin || 1; let endPage = manga.pages; const options = { title: getLocaleString("STARTING"), html: ` ${getLocaleString("CHOOSE_BEGINNING")} ${begin} - ${endPage}
`, showCancelButton: true, cancelButtonColor: "#d33", reverseButtons: true, icon: "question", didOpen() { const Slider = new RangeInputSlider(document.getElementById("pagesSlider"), { minPoint: beginPage, maxPoint: endPage, min: 1, max: manga.pages, onValueChangeStop(newValues) { const el = document.getElementById("pagesValues"); beginPage = newValues.min; endPage = newValues.max; if (el) { el.innerText = `${beginPage} - ${endPage}`; } }, onValueChange(newValues) { const el = document.getElementById("pagesValues"); beginPage = newValues.min; endPage = newValues.max; if (el) { el.innerText = `${newValues.min} - ${newValues.max}`; } }, serifs: [ { position: 0, html: "1" }, { position: 100, html: `${manga.pages}` } ] }); Slider.init(); } }; Swal.fire(options).then((result) => { if (result.value) { logScript(`Choice: ${beginPage} - ${endPage}`); manga.begin = beginPage; manga.pages = endPage; display(manga); } else { logScript(result.dismiss); } }); } function createLateStartButton(site, beginning) { const button = document.createElement("button"); button.innerText = getLocaleString("BUTTON_START"); button.id = "StartMOV"; button.onclick = () => { lateStart(site, beginning); }; document.body.appendChild(button); const style = document.createElement("style"); style.appendChild(document.createTextNode(startButton)); document.head.appendChild(style); logScript("Start Button added to page", button); } function showWaitPopup(site, manga) { Swal.fire({ title: getLocaleString("STARTING"), html: `${manga.begin > 1 ? `${getLocaleString("RESUME")}${manga.begin}.
` : ""}${getLocaleString("WAITING")}`, showCancelButton: true, cancelButtonColor: "#d33", reverseButtons: true, timer: 3e3 }).then((result) => { if (result.value || result.dismiss === Swal.DismissReason.timer) { display(manga); } else { createLateStartButton(site, manga.begin); logScript(result.dismiss); } }); } async function preparePage(site) { const manga = await site.run(); logScript(`Found Pages: ${manga.pages}`); if (manga.pages <= 0) return; manga.begin = useSettings()?.bookmarks?.find((b) => b.url === window.location.href)?.page || manga.begin || 1; const style = document.createElement("style"); style.appendChild(document.createTextNode(sweetalertStyle)); document.body.appendChild(style); const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; W.MOV = (startPage, endPage) => { if (startPage !== void 0) manga.begin = startPage; if (endPage !== void 0) manga.pages = endPage; display(manga); }; switch (site.start ?? useSettings()?.loadMode) { case "never": createLateStartButton(site, manga.begin); break; case "always": display(manga); break; case "wait": default: showWaitPopup(site, manga); break; } } function waitExec(site, waitElapsed = 0) { if (waitElapsed < (site.waitMax || 5e3) && (testAttribute(site) || testElement(site) || testVariable(site) || testFunc(site))) { setTimeout(() => { waitExec(site, waitElapsed + (site.waitStep || 1e3)); }, site.waitStep || 1e3); return; } preparePage(site); } function start(sites) { logScript( `Starting ${getInfoGM.script.name} ${getInfoGM.script.version} on ${getBrowser()} with ${getEngine()}` ); logScript(`${sites.length} Known Manga Sites, Looking for a match...`); const site = sites.find((s) => s.url.test(window.location.href)); if (site) { logScript(`Found site: ${site.name}`); waitExec(site); } else { logScript(`Sorry, didnt find any valid site`); } } start(sites); })();