diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index 67b93d25..54020c81 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -565,24 +565,12 @@ Consider all listed sites to potentially be NSFW.
Authors, Chapters, Followed Feed, Lists, Manga |
Supported |
-
- | MangaKakalot |
- https://mangakakalot.tv/ |
- Chapters, Manga |
- |
-
| MangaLife |
https://manga4life.com/ |
Chapters, Manga |
|
-
- | Manganato |
- https://manganato.com/ |
- Chapters, Manga |
- |
-
| MangaPark |
https://mangapark.net/ |
@@ -1408,6 +1396,34 @@ Consider all listed sites to potentially be NSFW.
|
+
+ | MangaNelo and Mirror Sites |
+
+
+ | MangaNelo |
+ https://www.nelomanga.net/ |
+ Chapters, Manga |
+ |
+
+
+ | MangaNato |
+ https://www.natomanga.com/ |
+ Chapters, Manga |
+ |
+
+
+ | MangaNato |
+ https://www.manganato.gg/ |
+ Chapters, Manga |
+ |
+
+
+ | MangaKakalot |
+ https://www.mangakakalot.gg/ |
+ Chapters, Manga |
+ |
+
+
| Misskey Instances |
diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py
index 9a7ca535..2da471e0 100644
--- a/gallery_dl/extractor/__init__.py
+++ b/gallery_dl/extractor/__init__.py
@@ -105,7 +105,6 @@ modules = [
"mangadex",
"mangafox",
"mangahere",
- "mangakakalot",
"manganelo",
"mangapark",
"mangaread",
diff --git a/gallery_dl/extractor/mangakakalot.py b/gallery_dl/extractor/mangakakalot.py
deleted file mode 100644
index 9fc8681d..00000000
--- a/gallery_dl/extractor/mangakakalot.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright 2020 Jake Mannens
-# Copyright 2021-2023 Mike Fährmann
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-
-"""Extractors for https://mangakakalot.tv/"""
-
-from .common import ChapterExtractor, MangaExtractor
-from .. import text
-import re
-
-BASE_PATTERN = r"(?:https?://)?(?:ww[\dw]?\.)?mangakakalot\.tv"
-
-
-class MangakakalotBase():
- """Base class for mangakakalot extractors"""
- category = "mangakakalot"
- root = "https://ww8.mangakakalot.tv"
-
-
-class MangakakalotChapterExtractor(MangakakalotBase, ChapterExtractor):
- """Extractor for manga chapters from mangakakalot.tv"""
- pattern = BASE_PATTERN + r"(/chapter/[^/?#]+/chapter[_-][^/?#]+)"
- example = "https://ww6.mangakakalot.tv/chapter/manga-ID/chapter-01"
-
- def __init__(self, match):
- self.path = match.group(1)
- ChapterExtractor.__init__(self, match, self.root + self.path)
-
- def metadata(self, page):
- _ , pos = text.extract(page, '', '<')
- manga , pos = text.extract(page, '', '<', pos)
- info , pos = text.extract(page, '', '<', pos)
- author, pos = text.extract(page, '. Author:', ' already has ', pos)
-
- match = re.match(
- r"(?:[Vv]ol\. *(\d+) )?"
- r"[Cc]hapter *([^:]*)"
- r"(?:: *(.+))?", info or "")
- volume, chapter, title = match.groups() if match else ("", "", info)
- chapter, sep, minor = chapter.partition(".")
-
- return {
- "manga" : text.unescape(manga),
- "title" : text.unescape(title) if title else "",
- "author" : text.unescape(author).strip() if author else "",
- "volume" : text.parse_int(volume),
- "chapter" : text.parse_int(chapter),
- "chapter_minor": sep + minor,
- "lang" : "en",
- "language" : "English",
- }
-
- def images(self, page):
- return [
- (url, None)
- for url in text.extract_iter(page, '
", "<")
- author, pos = text.extract(page, "Author(s) :", "", pos)
- data["author"] = text.remove_html(author)
-
- results = []
- for chapter in text.extract_iter(page, '', '
'):
- url, pos = text.extract(chapter, '', '', pos)
- data["title"] = title.partition(": ")[2]
- data["date"] , pos = text.extract(
- chapter, '")
- manga = extr('title="', '"')
- info = extr('title="', '"')
- author = extr("- Author(s) : ", "")
- return self._parse_chapter(
- info, text.unescape(manga), text.unescape(author))
+ data = {
+ "date" : text.parse_datetime(extr(
+ '"datePublished": "', '"')[:19], "%Y-%m-%dT%H:%M:%S"),
+ "date_updated": text.parse_datetime(extr(
+ '"dateModified": "', '"')[:19], "%Y-%m-%dT%H:%M:%S"),
+ "manga_id" : text.parse_int(extr("comic_id =", ";")),
+ "chapter_id" : text.parse_int(extr("chapter_id =", ";")),
+ "manga" : extr("comic_name =", ";").strip('" '),
+ "lang" : "en",
+ "language" : "English",
+ }
+
+ chapter_name = extr("chapter_name =", ";").strip('" ')
+ chapter, sep, minor = chapter_name.rpartition(" ")[2].partition(".")
+ data["chapter"] = text.parse_int(chapter)
+ data["chapter_minor"] = sep + minor
+ data["author"] = extr(". Author:", " already has ").strip()
+
+ return data
def images(self, page):
- page = text.extr(
- page, 'class="container-chapter-reader', 'class="container')
+ extr = text.extract_from(page)
+ cdns = util.json_loads(extr("var cdns =", ";"))[0]
+ imgs = util.json_loads(extr("var chapterImages =", ";"))
+
+ if cdns[-1] != "/":
+ cdns += "/"
+
return [
- (url, None)
- for url in text.extract_iter(page, '
", "<"))
+ author = text.remove_html(text.extr(page, "Author(s) :", ""))
+
results = []
- append = results.append
+ for chapter in text.extract_iter(page, '', '
'):
+ url, pos = text.extract(chapter, '', '', pos)
+ date, pos = text.extract(chapter, '", "<"))
- author = text.remove_html(extr("Author(s) :", ""))
-
- extr('class="row-content-chapter', '')
- while True:
- url = extr('class="chapter-name text-nowrap" href="', '"')
- if not url:
- return results
- info = extr(">", "<")
- date = extr('class="chapter-time text-nowrap" title="', '"')
- append((url, self._parse_chapter(info, manga, author, date)))
+ if url[0] == "/":
+ url = self.root + url
+ results.append((url, {
+ "manga" : manga,
+ "author" : author,
+ "chapter" : text.parse_int(chapter),
+ "chapter_minor": (sep and ".") + minor,
+ "title" : title.partition(": ")[2],
+ "date" : text.parse_datetime(date, "%b-%d-%Y %H:%M"),
+ "lang" : "en",
+ "language": "English",
+ }))
+ return results
diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py
index fb85fa2b..7fbf3ee5 100755
--- a/scripts/supportedsites.py
+++ b/scripts/supportedsites.py
@@ -101,7 +101,7 @@ CATEGORY_MAP = {
"mangahere" : "Manga Here",
"mangakakalot" : "MangaKakalot",
"mangalife" : "MangaLife",
- "manganelo" : "Manganato",
+ "manganato" : "MangaNato",
"mangapark" : "MangaPark",
"mangaread" : "MangaRead",
"mangasee" : "MangaSee",
@@ -111,7 +111,9 @@ CATEGORY_MAP = {
"micmicidol" : "MIC MIC IDOL",
"myhentaigallery": "My Hentai Gallery",
"myportfolio" : "Adobe Portfolio",
+ "natomanga" : "MangaNato",
"naverwebtoon" : "NaverWebtoon",
+ "nelomanga" : "MangaNelo",
"nhentai" : "nhentai",
"nijie" : "nijie",
"nozomi" : "Nozomi.la",
@@ -401,6 +403,7 @@ BASE_MAP = {
"jschan" : "jschan Imageboards",
"lolisafe" : "lolisafe and chibisafe",
"lynxchan" : "LynxChan Imageboards",
+ "manganelo" : "MangaNelo and Mirror Sites",
"moebooru" : "Moebooru and MyImouto",
"szurubooru" : "szurubooru Instances",
"urlshortener": "URL Shorteners",
diff --git a/test/results/mangakakalot.py b/test/results/mangakakalot.py
index b0b8bada..a2efceff 100644
--- a/test/results/mangakakalot.py
+++ b/test/results/mangakakalot.py
@@ -4,37 +4,60 @@
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
-from gallery_dl.extractor import mangakakalot
+from gallery_dl.extractor import manganelo
__tests__ = (
{
- "#url" : "https://ww3.mangakakalot.tv/chapter/manga-jk986845/chapter-34.2",
- "#category": ("", "mangakakalot", "chapter"),
- "#class" : mangakakalot.MangakakalotChapterExtractor,
- "#pattern" : r"https://cm\.blazefast\.co/[0-9a-f]{2}/[0-9a-f]{2}/[0-9a-f]{32}\.jpg",
- "#count" : 9,
- "#sha1_metadata": "0f1586ff52f0f9cbbb25306ae64ab718f8a6a633",
+ "#url" : "https://www.mangakakalot.gg/manga/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/chapter-4-5",
+ "#category": ("manganelo", "mangakakalot", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+ "#pattern" : r"https://imgs-2.2xstorage.com/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/4\.5/\d+\.webp",
+ "#count" : 24,
+
+ "author" : "NARAYAMA Bakufu",
+ "chapter" : 4,
+ "chapter_id" : 6,
+ "chapter_minor": ".5",
+ "count" : 24,
+ "date" : "dt:2025-04-29 16:08:07",
+ "date_updated" : "dt:2025-04-29 16:08:07",
+ "extension" : "webp",
+ "filename" : str,
+ "lang" : "en",
+ "language" : "English",
+ "manga" : "Danzai sareta Akuyaku Reijou wa, Gyakkou shite Kanpeki na Akujo wo Mezasu",
+ "manga_id" : 32842,
+ "page" : range(1, 24),
},
{
- "#url" : "https://mangakakalot.tv/chapter/hatarakanai_futari_the_jobless_siblings/chapter_20.1",
- "#category": ("", "mangakakalot", "chapter"),
- "#class" : mangakakalot.MangakakalotChapterExtractor,
+ "#url" : "https://mangakakalot.gg/manga/aria/chapter-60-2",
+ "#category": ("manganelo", "mangakakalot", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
},
{
- "#url" : "https://ww3.mangakakalot.tv/manga/manga-jk986845",
- "#category": ("", "mangakakalot", "manga"),
- "#class" : mangakakalot.MangakakalotMangaExtractor,
- "#pattern" : mangakakalot.MangakakalotChapterExtractor.pattern,
- "#count" : ">= 30",
+ "#url" : "https://www.mangakakalot.gg/manga/aria",
+ "#category": ("manganelo", "mangakakalot", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+ "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
+ "#count" : 70,
+
+ "author" : "Amano Kozue",
+ "chapter" : range(1, 60),
+ "chapter_minor": {"", ".1", ".2", ".5"},
+ "date" : "type:datetime",
+ "lang" : "en",
+ "language": "English",
+ "manga" : "Aria",
+ "title" : "",
},
{
- "#url" : "https://mangakakalot.tv/manga/lk921810",
- "#category": ("", "mangakakalot", "manga"),
- "#class" : mangakakalot.MangakakalotMangaExtractor,
+ "#url" : "https://mangakakalot.gg/manga/aria",
+ "#category": ("manganelo", "mangakakalot", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
},
)
diff --git a/test/results/manganato.py b/test/results/manganato.py
new file mode 100644
index 00000000..52a7d174
--- /dev/null
+++ b/test/results/manganato.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+from gallery_dl.extractor import manganelo
+
+
+__tests__ = (
+{
+ "#url" : "https://www.manganato.gg/manga/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/chapter-4-5",
+ "#category": ("manganelo", "manganato", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+ "#pattern" : r"https://imgs-2.2xstorage.com/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/4\.5/\d+\.webp",
+ "#count" : 24,
+
+ "author" : "NARAYAMA Bakufu",
+ "chapter" : 4,
+ "chapter_id" : 6,
+ "chapter_minor": ".5",
+ "count" : 24,
+ "date" : "",
+ "date_updated" : "",
+ "extension" : "webp",
+ "filename" : str,
+ "lang" : "en",
+ "language" : "English",
+ "manga" : "Danzai sareta Akuyaku Reijou wa, Gyakkou shite Kanpeki na Akujo wo Mezasu",
+ "manga_id" : 32842,
+ "page" : range(1, 24),
+},
+
+{
+ "#url" : "https://manganato.gg/manga/aria/chapter-60-2",
+ "#category": ("manganelo", "manganato", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+},
+
+{
+ "#url" : "https://www.manganato.gg/manga/aria",
+ "#category": ("manganelo", "manganato", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+ "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
+ "#count" : 70,
+
+ "author" : "Amano Kozue",
+ "chapter" : range(1, 60),
+ "chapter_minor": {"", ".1", ".2", ".5"},
+ "date" : "type:datetime",
+ "lang" : "en",
+ "language": "English",
+ "manga" : "Aria",
+ "title" : "",
+},
+
+{
+ "#url" : "https://manganato.gg/manga/aria",
+ "#category": ("manganelo", "manganato", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+},
+
+)
diff --git a/test/results/manganelo.py b/test/results/manganelo.py
deleted file mode 100644
index 7236e47c..00000000
--- a/test/results/manganelo.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-
-from gallery_dl.extractor import manganelo
-
-
-__tests__ = (
-{
- "#url" : "https://chapmanganato.com/manga-gn983696/chapter-23",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
- "#pattern" : r"https://v\d+\.mkklcdnv6tempv5\.com/img/tab_17/03/23/39/gn983696/vol_3_chapter_23_24_yen/\d+-[no]\.jpg",
- "#count" : 25,
-
- "author" : "Ei Yuzuki,Maki Hayashi",
- "chapter" : 23,
- "chapter_minor": "",
- "count" : 25,
- "date" : None,
- "extension": "jpg",
- "filename" : str,
- "lang" : "en",
- "language" : "English",
- "manga" : "By Spring",
- "page" : range(1, 25),
- "title" : "24 Yen",
- "volume" : 3,
-},
-
-{
- "#url" : "https://chapmanganelo.com/manga-ti107776/chapter-4",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
- "#pattern" : r"https://v\d+\.mkklcdnv6tempv5\.com/img/tab_17/01/92/08/ti970565/chapter_4_caster/\d+-o\.jpg",
- "#count" : 45,
- "#sha1_metadata": "06e01fa9b3fc9b5b954c0d4a98f0153b40922ded",
-},
-
-{
- "#url" : "https://chapmanganato.com/manga-no991297/chapter-8",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
- "#count" : 20,
-
- "chapter" : 8,
- "chapter_minor": "-1",
-},
-
-{
- "#url" : "https://readmanganato.com/manga-gn983696/chapter-23",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
-},
-
-{
- "#url" : "https://manganelo.com/chapter/gamers/chapter_15",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
-},
-
-{
- "#url" : "https://manganelo.com/chapter/gq921227/chapter_23",
- "#category": ("", "manganelo", "chapter"),
- "#class" : manganelo.ManganeloChapterExtractor,
-},
-
-{
- "#url" : "https://chapmanganato.com/manga-gn983696",
- "#category": ("", "manganelo", "manga"),
- "#class" : manganelo.ManganeloMangaExtractor,
- "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
- "#count" : ">= 25",
-},
-
-{
- "#url" : "https://m.manganelo.com/manga-ti107776",
- "#category": ("", "manganelo", "manga"),
- "#class" : manganelo.ManganeloMangaExtractor,
- "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
- "#count" : ">= 12",
-},
-
-{
- "#url" : "https://readmanganato.com/manga-gn983696",
- "#category": ("", "manganelo", "manga"),
- "#class" : manganelo.ManganeloMangaExtractor,
-},
-
-{
- "#url" : "https://manganelo.com/manga/read_otome_no_teikoku",
- "#category": ("", "manganelo", "manga"),
- "#class" : manganelo.ManganeloMangaExtractor,
-},
-
-{
- "#url" : "https://manganelo.com/manga/ol921234/",
- "#category": ("", "manganelo", "manga"),
- "#class" : manganelo.ManganeloMangaExtractor,
-},
-
-)
diff --git a/test/results/natomanga.py b/test/results/natomanga.py
new file mode 100644
index 00000000..461adf71
--- /dev/null
+++ b/test/results/natomanga.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+from gallery_dl.extractor import manganelo
+
+
+__tests__ = (
+{
+ "#url" : "https://www.natomanga.com/manga/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/chapter-4-5",
+ "#category": ("manganelo", "natomanga", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+ "#pattern" : r"https://imgs-2.2xstorage.com/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/4\.5/\d+\.webp",
+ "#count" : 24,
+
+ "author" : "NARAYAMA Bakufu",
+ "chapter" : 4,
+ "chapter_id" : 6,
+ "chapter_minor": ".5",
+ "count" : 24,
+ "date" : "dt:2025-04-29 16:08:07",
+ "date_updated" : "dt:2025-04-29 16:08:07",
+ "extension" : "webp",
+ "filename" : str,
+ "lang" : "en",
+ "language" : "English",
+ "manga" : "Danzai sareta Akuyaku Reijou wa, Gyakkou shite Kanpeki na Akujo wo Mezasu",
+ "manga_id" : 32842,
+ "page" : range(1, 24),
+},
+
+{
+ "#url" : "https://natomanga.com/manga/aria/chapter-60-2",
+ "#category": ("manganelo", "natomanga", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+},
+
+{
+ "#url" : "https://www.natomanga.com/manga/aria",
+ "#category": ("manganelo", "natomanga", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+ "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
+ "#count" : 70,
+
+ "author" : "Amano Kozue",
+ "chapter" : range(1, 60),
+ "chapter_minor": {"", ".1", ".2", ".5"},
+ "date" : "type:datetime",
+ "lang" : "en",
+ "language": "English",
+ "manga" : "Aria",
+ "title" : "",
+},
+
+{
+ "#url" : "https://natomanga.com/manga/aria",
+ "#category": ("manganelo", "natomanga", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+},
+
+)
diff --git a/test/results/nelomanga.py b/test/results/nelomanga.py
new file mode 100644
index 00000000..da794fda
--- /dev/null
+++ b/test/results/nelomanga.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+from gallery_dl.extractor import manganelo
+
+
+__tests__ = (
+{
+ "#url" : "https://www.nelomanga.net/manga/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/chapter-4-5",
+ "#category": ("manganelo", "nelomanga", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+ "#pattern" : r"https://imgs-2.2xstorage.com/danzai-sareta-akuyaku-reijou-wa-gyakkou-shite-kanpeki-na-akujo-wo-mezasu/4\.5/\d+\.webp",
+ "#count" : 24,
+
+ "author" : "NARAYAMA Bakufu",
+ "chapter" : 4,
+ "chapter_id" : 6,
+ "chapter_minor": ".5",
+ "count" : 24,
+ "date" : "",
+ "date_updated" : "",
+ "extension" : "webp",
+ "filename" : str,
+ "lang" : "en",
+ "language" : "English",
+ "manga" : "Danzai sareta Akuyaku Reijou wa, Gyakkou shite Kanpeki na Akujo wo Mezasu",
+ "manga_id" : 32842,
+ "page" : range(1, 24),
+},
+
+{
+ "#url" : "https://nelomanga.net/manga/aria/chapter-60-2",
+ "#category": ("manganelo", "nelomanga", "chapter"),
+ "#class" : manganelo.ManganeloChapterExtractor,
+},
+
+{
+ "#url" : "https://www.nelomanga.net/manga/aria",
+ "#category": ("manganelo", "nelomanga", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+ "#pattern" : manganelo.ManganeloChapterExtractor.pattern,
+ "#count" : 70,
+
+ "author" : "Amano Kozue",
+ "chapter" : range(1, 60),
+ "chapter_minor": {"", ".1", ".2", ".5"},
+ "date" : "type:datetime",
+ "lang" : "en",
+ "language": "English",
+ "manga" : "Aria",
+ "title" : "",
+},
+
+{
+ "#url" : "https://nelomanga.net/manga/aria",
+ "#category": ("manganelo", "nelomanga", "manga"),
+ "#class" : manganelo.ManganeloMangaExtractor,
+},
+
+)