// ==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, ComiCastle, Dynasty-Scans, Asura Scans, Flame Scans, Realm Scans, Voids-Scans, Luminous Scans, InManga, KLManga, Leitor, LHTranslation, MangaBuddy, MangaDex, MangaFox, MangaHere, MangaFreak, Mangago, mangahosted, MangaHub, MangaKakalot, MangaNelo, MangaNato, MangaPark, MReader, Mangareader, MangaSee, Manga4life, MangaTigre, MangaTown, ManhuaScan, NineManga, PandaManga, RawDevart, ReadComicsOnline, ReadManga Today, Funmanga, MangaDoom, MangaInn, ReaperScans, SenManga(Raw), ShimadaScans, KLManga, TenManga, TuMangaOnline, UnionMangas, WebToons, Manga33, ZeroScans, FoOlSlide, Kireicake, Madara WordPress Plugin, MangaHaus, Isekai Scan, Comic Kiba, Zinmanga, mangatx, Toonily, Mngazuki, JaiminisBox, DisasterScans, ManhuaPlus, TopManhua
// @version 2022.12.09
// @license MIT
// @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.4.2/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.6.15/sweetalert2.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// @include /https?:\/\/beta.asurascans.com\/read\/.+\/.+/
// @include /https?:\/\/(www.)?bato.to\/chapter.*/
// @include /https?:\/\/(www.)?comicastle.org\/read\/.+\/[0-9]+.*/
// @include /https?:\/\/(www.)?dynasty-scans.com\/chapters\/.+/
// @include /https?:\/\/(www.)?(asura|flamescans|realmscans|void-scans|luminousscans).(com|org|gg)\/.+/
// @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.)?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.)?mangago.me\/.*\/.*\/.*/
// @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.)?mangapark.(com|me|org|net)\/(manga|chapter|comic)\/.+\/.+/
// @include /https?:\/\/(www.)?mreader.co\/reader\/.*/
// @include /https?:\/\/(www.)?mangareader.to\/read\/.+\/.+\/.+/
// @include /https?:\/\/(www.)?(mangasee123|manga4life).com\/read-online\/.+/
// @include /https?:\/\/(www.)?mangatigre.net\/.+\/.+\/.+/
// @include /https?:\/\/(www.|m.)?mangatown.com\/manga\/.+\/.+/
// @include /https?:\/\/(www.)?manhuascan.io\/.+chapter.+/
// @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?:\/\/raw.senmanga.com\/.+\/.+\/?/
// @include /https?:\/\/(www.)?shimadascans.com\/.+series.+/
// @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.)?webtoons.com\/.+viewer.+/
// @include /https?:\/\/(www.)?(manga33).com\/manga\/.+/
// @include /https?:\/\/(www.)?zeroscans.com\/comics\/.+/
// @include /^(?!.*jaiminisbox).*\/read\/.+/
// @include /https?:\/\/.+\/(manga|series|manhua)\/.+\/.+/
// @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 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.)?(asura|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 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 madarawp = {
name: [
"Madara WordPress Plugin",
"MangaHaus",
"Isekai Scan",
"Comic Kiba",
"Zinmanga",
"mangatx",
"Toonily",
"Mngazuki",
"JaiminisBox",
"DisasterScans",
"ManhuaPlus",
"TopManhua"
],
url: /https?:\/\/.+\/(manga|series|manhua)\/.+\/.+/,
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/"
],
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) => img.getAttribute("src") || img.getAttribute("data-src") || img.getAttribute("data-full-url")
)
};
}
};
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: "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("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 mangago = {
name: "Mangago",
url: /https?:\/\/(www.)?mangago.me\/.*\/.*\/.*/,
homepage: "https://www.mangago.me/",
language: ["English"],
category: "manga",
waitVar: "imgsrcs",
run() {
const W = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
const key = CryptoJS.enc.Hex.parse("e11adc3949ba59abbe56e057f20f883e");
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: `${W.manga_name} ${W.chapter_name}`,
series: W.mid,
pages: W.total_pages,
prev: document.querySelector(".recom p:nth-child(5) a")?.getAttribute("href"),
next: W.next_c_url,
listImages: images
};
}
};
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 = Object.values(JSON.parse(api?.data.chapter.pages.toString()));
return {
title: document.querySelector("#mangareader h3")?.textContent?.trim(),
series: document.querySelector("#mangareader a")?.getAttribute("href"),
pages: images.length,
prev: document.querySelector(".previous a")?.getAttribute("href"),
next: document.querySelector(".next a")?.getAttribute("href"),
listImages: images.map((i) => `https://img.mghubcdn.com/file/imghub/${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 mangapark = {
name: "MangaPark",
url: /https?:\/\/(www.)?mangapark.(com|me|org|net)\/(manga|chapter|comic)\/.+\/.+/,
homepage: "https://mangapark.net/",
language: ["English"],
category: "manga",
waitVar: "CryptoJS",
run() {
const pass = JSON.parse(CryptoJS.AES.decrypt(amWord, amPass).toString(CryptoJS.enc.Utf8));
return {
title: document.querySelector("title")?.textContent?.trim(),
series: document.querySelector(".nav-title a")?.getAttribute("href"),
pages: imgPathLis.length,
prev: document.querySelector(".nav-prev a")?.getAttribute("href"),
next: document.querySelector(".nav-next a")?.getAttribute("href"),
listImages: imgPathLis.map((i, index) => `${imgCdnHost + i}?${pass[index]}`)
};
}
};
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 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",
url: /https?:\/\/(www.)?mreader.co\/reader\/.*/,
homepage: "https://www.mreader.co/",
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 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 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.+/,
homepage: "https://shimadascans.com/",
language: ["English"],
category: "manga",
run() {
const images = [...document.querySelectorAll(".reading-content 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 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,
comicastle,
dysnatyscans,
flamecans,
inmanga,
klmanga,
leitor,
lhtranslation,
mangabuddy,
mangadex,
mangafox,
mangafreak,
mangago,
mangahosted,
mangahub,
mangakakalot,
mangapark,
mreader,
mangareader,
mangasee,
mangatigre,
mangatown,
manhuascan,
ninemanga,
pandamanga,
rawdevart,
readcomicsonline,
readmangatoday,
reaperscans,
senmanga,
shimadascans,
tapas,
tenmanga,
tmofans,
unionmangas,
webtoons,
wpmanga,
zeroscans,
foolslide,
madarawp
];
function logScript(...text) {
console.log("MangaOnlineViewer: ", ...text);
return text;
}
function getListGM() {
return typeof GM_listValues !== "undefined" ? GM_listValues() : [];
}
function removeValueGM(name) {
return typeof GM_deleteValue !== "undefined" ? GM_deleteValue(name) : logScript("Removing: ", name);
}
const getInfoGM = typeof GM_info !== "undefined" ? GM_info : {
scriptHandler: "Console",
script: {
name: "Debug",
version: "Testing"
}
};
function getValueGM(name, defaultValue = null) {
if (typeof GM_getValue !== "undefined") {
return GM_getValue(name, defaultValue);
}
logScript("Fake Getting: ", name, " = ", defaultValue);
return defaultValue;
}
function getJsonGM(name, defaultValue = null) {
const result = getValueGM(name, defaultValue);
if (typeof result === "string")
return JSON.parse(result);
return result;
}
function getSettings(defaultSettings) {
return getJsonGM("settings", defaultSettings);
}
function setValueGM(name, value) {
try {
GM_setValue(name, value);
return value.toString();
} catch (e) {
logScript("Fake Setting: ", name, " = ", value);
return String(value);
}
}
function setJsonGM(name, value) {
return setValueGM(name, JSON.stringify(value));
}
function setSettings(value) {
return setJsonGM("settings", value);
}
function getBrowser() {
const ua = navigator.userAgent;
let tem;
let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return `IE ${tem[1] || ""}`;
}
if (M[1] === "Chrome") {
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if (tem !== null) {
return tem.slice(1).join(" ").replace("OPR", "Opera");
}
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"];
tem = ua.match(/version\/(\d+)/i);
if (tem !== null) {
M.splice(1, 1, tem[1]);
}
return M.join(" ");
}
function getEngine() {
return getInfoGM.scriptHandler || "Greasemonkey";
}
const isMobile = window.matchMedia("screen and (max-width: 768px)").matches;
function isEmpty(value) {
return value === null || typeof value === "undefined" || value === void 0 || typeof value === "string" && value === "" || Array.isArray(value) && value.length === 0 || 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 value == false || value === 0 || isEmpty(value) || typeof value === "object" && isEmptyObject(value);
}
const colors = {
dark: {
name: "dark",
50: "#C1C2C5",
100: "#A6A7AB",
200: "#909296",
300: "#5c5f66",
400: "#373A40",
500: "#2C2E33",
600: "#25262b",
700: "#1A1B1E",
800: "#141517",
900: "#101113"
},
gray: {
name: "gray",
50: "#f8f9fa",
100: "#f1f3f5",
200: "#e9ecef",
300: "#dee2e6",
400: "#ced4da",
500: "#adb5bd",
600: "#868e96",
700: "#495057",
800: "#343a40",
900: "#212529"
},
red: {
name: "red",
50: "#fff5f5",
100: "#ffe3e3",
200: "#ffc9c9",
300: "#ffa8a8",
400: "#ff8787",
500: "#ff6b6b",
600: "#fa5252",
700: "#f03e3e",
800: "#e03131",
900: "#c92a2a"
},
pink: {
name: "pink",
50: "#fff0f6",
100: "#ffdeeb",
200: "#fcc2d7",
300: "#faa2c1",
400: "#f783ac",
500: "#f06595",
600: "#e64980",
700: "#d6336c",
800: "#c2255c",
900: "#a61e4d"
},
grape: {
name: "grape",
50: "#f8f0fc",
100: "#f3d9fa",
200: "#eebefa",
300: "#e599f7",
400: "#da77f2",
500: "#cc5de8",
600: "#be4bdb",
700: "#ae3ec9",
800: "#9c36b5",
900: "#862e9c"
},
violet: {
name: "violet",
50: "#f3f0ff",
100: "#e5dbff",
200: "#d0bfff",
300: "#b197fc",
400: "#9775fa",
500: "#845ef7",
600: "#7950f2",
700: "#7048e8",
800: "#6741d9",
900: "#5f3dc4"
},
indigo: {
name: "purple",
50: "#edf2ff",
100: "#dbe4ff",
200: "#bac8ff",
300: "#91a7ff",
400: "#748ffc",
500: "#5c7cfa",
600: "#4c6ef5",
700: "#4263eb",
800: "#3b5bdb",
900: "#364fc7"
},
blue: {
name: "blue",
50: "#e7f5ff",
100: "#d0ebff",
200: "#a5d8ff",
300: "#74c0fc",
400: "#4dabf7",
500: "#339af0",
600: "#228be6",
700: "#1c7ed6",
800: "#1971c2",
900: "#1864ab"
},
cyan: {
name: "cyan",
50: "#e3fafc",
100: "#c5f6fa",
200: "#99e9f2",
300: "#66d9e8",
400: "#3bc9db",
500: "#22b8cf",
600: "#15aabf",
700: "#1098ad",
800: "#0c8599",
900: "#0b7285"
},
teal: {
name: "teal",
50: "#e6fcf5",
100: "#c3fae8",
200: "#96f2d7",
300: "#63e6be",
400: "#38d9a9",
500: "#20c997",
600: "#12b886",
700: "#0ca678",
800: "#099268",
900: "#087f5b"
},
green: {
name: "green",
50: "#ebfbee",
100: "#d3f9d8",
200: "#b2f2bb",
300: "#8ce99a",
400: "#69db7c",
500: "#51cf66",
600: "#40c057",
700: "#37b24d",
800: "#2f9e44",
900: "#2b8a3e"
},
lime: {
name: "lime",
50: "#f4fce3",
100: "#e9fac8",
200: "#d8f5a2",
300: "#c0eb75",
400: "#a9e34b",
500: "#94d82d",
600: "#82c91e",
700: "#74b816",
800: "#66a80f",
900: "#5c940d"
},
yellow: {
name: "yellow",
50: "#fff9db",
100: "#fff3bf",
200: "#ffec99",
300: "#ffe066",
400: "#ffd43b",
500: "#fcc419",
600: "#fab005",
700: "#f59f00",
800: "#f08c00",
900: "#e67700"
},
orange: {
name: "orange",
50: "#fff4e6",
100: "#ffe8cc",
200: "#ffd8a8",
300: "#ffc078",
400: "#ffa94d",
500: "#ff922b",
600: "#fd7e14",
700: "#f76707",
800: "#e8590c",
900: "#d9480f"
},
darkblue: {
name: "darkblue",
50: "#E8F4F9",
100: "#D9DEE9",
200: "#B7C2DA",
300: "#6482C0",
400: "#4267B2",
500: "#385898",
600: "#314E89",
700: "#29487D",
800: "#223B67",
900: "#1E355B"
}
};
const darkest = 10;
const lightest = 95;
function setLightness(hsl, lightness) {
hsl.l = lightness;
return tinycolor(hsl).toHexString();
}
function getTextColor(hex) {
const color = tinycolor(hex);
const hsl = color.toHsl();
return setLightness(hsl, color.isDark() ? lightest : darkest);
}
function svgToUrl(str) {
const cleaned = str.replace(/[\t\n\r]/gim, "").replace(/\s\s+/g, " ").replace(/'/gim, "\\i");
const encoded = encodeURIComponent(cleaned).replace(/\(/g, "%28").replace(/\)/g, "%29");
return `data:image/svg+xml;charset=UTF-8,${encoded}`;
}
Object.values(colors).map((i) => 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 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) {
justify-self: flex-start;
}
#MangaOnlineViewer #Chapter.FluidLTR .MangaPage:not(.DoublePage):nth-child(2n-1),
#MangaOnlineViewer #Chapter.FluidRTL .MangaPage:not(.DoublePage):nth-child(2n-1) {
justify-self: flex-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 #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: 8px;
position: fixed;
top: 65px;
right: 0;
transition: transform 0.3s ease-in-out;;
transform: translateX(100%);
line-height: 1.5em;
z-index: 1000;
}
#MangaOnlineViewer #KeybindingsPanel.visible {
transform: translateX(0);
display: block;
}
#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 #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.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;
}
@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 #keybindings {
display: none;
}
}
/* Small devices (landscape 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 .ControlButton:not(#settings) {
display: none;
}
#MangaOnlineViewer #GlobalFunctions {
min-width: auto;
}
#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;
}
}
}
);
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",
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: