diff --git a/docs/supportedsites.md b/docs/supportedsites.md index e810f42215..1e29c868e2 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -535,12 +535,6 @@ Consider all listed sites to potentially be NSFW. Chapters, Manga - - MangaRead - https://mangaread.org/ - Chapters, Manga - - MangaSee https://mangasee123.com/ @@ -1723,5 +1717,27 @@ Consider all listed sites to potentially be NSFW. Albums + + + WordPressMadara based websites + + + MangaRead + https://mangaread.org/ + Chapters, Manga + + + + Toonily + https://toonily.com/ + Chapters, Manga + + + + WebtoonXYZ + https://www.webtoon.xyz/ + Chapters, Manga + + diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index d624736211..72aee020ee 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -95,7 +95,7 @@ "mangakakalot", "manganelo", "mangapark", - "mangaread", + "wpmadara", "mangasee", "mangoxo", "misskey", diff --git a/gallery_dl/extractor/mangaread.py b/gallery_dl/extractor/wpmadara.py similarity index 58% rename from gallery_dl/extractor/mangaread.py rename to gallery_dl/extractor/wpmadara.py index 4b017dca00..79b145c2b1 100644 --- a/gallery_dl/extractor/mangaread.py +++ b/gallery_dl/extractor/wpmadara.py @@ -4,16 +4,16 @@ # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. -"""Extractors for https://mangaread.org/""" +"""Extractors for WordPressMadara based websites.""" -from .common import ChapterExtractor, MangaExtractor +from .common import BaseExtractor, ChapterExtractor, MangaExtractor from .. import text, exception import re -class MangareadBase(): - """Base class for Mangaread extractors""" - category = "mangaread" +class WPMadaraBase(BaseExtractor): + """Base class for WordPressMadara based extractors""" + basecategory = "wpmadara" root = "https://www.mangaread.org" @staticmethod @@ -31,12 +31,37 @@ def parse_chapter_string(chapter_string, data): data["language"] = "English" -class MangareadChapterExtractor(MangareadBase, ChapterExtractor): - """Extractor for manga-chapters from mangaread.org""" - pattern = (r"(?:https?://)?(?:www\.)?mangaread\.org" - r"(/manga/[^/?#]+/[^/?#]+)") +BASE_PATTERN = WPMadaraBase.update({ + "mangaread": { + "root": "https://www.mangaread.org", + "pattern": r"(?:https?://)?(?:www\.)?mangaread\.org", + }, + "toonily": { + "root": "https://www.toonily.com", + "pattern": r"(?:https?://)?(?:www\.)?toonily\.com", + }, + "webtoonxyz": { + "root": "https://www.webtoon.xyz", + "pattern": r"(?:https?://)?(?:www\.)?webtoon\.xyz", + }, +}) + + +class WPMadaraChapterExtractor(WPMadaraBase, ChapterExtractor): + """Extractor for manga-chapters from WordPressMadara based websites.""" + subcategory = "chapter" + pattern = BASE_PATTERN + r"(/(manga|webtoon|read)/[^/?#]+/[^/?#]+)" example = "https://www.mangaread.org/manga/MANGA/chapter-01/" + def __init__(self, match, url=None): + WPMadaraBase.__init__(self, match) + self.chapter = match.group(match.lastindex) + self.log.debug("chapter: %s", self.chapter) + self.gallery_url = self.root + match.group(match.lastindex) + + if self.config("chapter-reverse", False): + self.reverse = not self.reverse + def metadata(self, page): tags = text.extr(page, 'class="wp-manga-tags-list">', '') data = {"tags": list(text.split_html(tags)[::2])} @@ -44,23 +69,31 @@ def metadata(self, page): if not info: raise exception.NotFoundError("chapter") self.parse_chapter_string(info, data) + self.log.debug("data: %s", data) return data def images(self, page): page = text.extr( page, '
', '
', 'class="manga-action"')) + # rating = 0.0 + if len(text.extr(page, 'total_votes">', "").strip()) > 0: + rating = text.parse_float(text.extr( + page, 'total_votes">', "").strip()) + elif len(text.extr(page, 'property="ratingValue" id="averagerate">', + "").strip()) > 0: + rating = text.parse_float( + text.extr(page, + 'property="ratingValue" id="averagerate">', + "").strip()) + else: + rating = 0.0 + return { "manga" : text.extr(page, "

", "

").strip(), "description": text.unescape(text.remove_html(text.extract( page, ">", "
", page.index("summary__content"))[0])), - "rating" : text.parse_float( - extr('total_votes">', "").strip()), + "rating" : rating, "manga_alt" : text.remove_html( extr("Alternative \n
", "")).split("; "), "author" : list(text.extract_iter( diff --git a/test/results/mangaread.py b/test/results/mangaread.py index 4330a13d36..de2ae68752 100644 --- a/test/results/mangaread.py +++ b/test/results/mangaread.py @@ -4,15 +4,15 @@ # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. -from gallery_dl.extractor import mangaread +from gallery_dl.extractor import wpmadara from gallery_dl import exception __tests__ = ( { "#url" : "https://www.mangaread.org/manga/one-piece/chapter-1053-3/", - "#category": ("", "mangaread", "chapter"), - "#class" : mangaread.MangareadChapterExtractor, + "#category": ("wpmadara", "mangaread", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, "#pattern" : r"https://www\.mangaread\.org/wp-content/uploads/WP-manga/data/manga_[^/]+/[^/]+/[^.]+\.\w+", "#count" : 11, @@ -27,15 +27,15 @@ { "#url" : "https://www.mangaread.org/manga/one-piece/chapter-1000000/", - "#category": ("", "mangaread", "chapter"), - "#class" : mangaread.MangareadChapterExtractor, + "#category": ("wpmadara", "mangaread", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, "#exception": exception.NotFoundError, }, { "#url" : "https://www.mangaread.org/manga/kanan-sama-wa-akumade-choroi/chapter-10/", - "#category": ("", "mangaread", "chapter"), - "#class" : mangaread.MangareadChapterExtractor, + "#category": ("wpmadara", "mangaread", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, "#pattern" : r"https://www\.mangaread\.org/wp-content/uploads/WP-manga/data/manga_[^/]+/[^/]+/[^.]+\.\w+", "#count" : 9, @@ -51,8 +51,8 @@ { "#url" : "https://www.mangaread.org/manga/above-all-gods/chapter146-5/", "#comment" : "^^ no whitespace", - "#category": ("", "mangaread", "chapter"), - "#class" : mangaread.MangareadChapterExtractor, + "#category": ("wpmadara", "mangaread", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, "#pattern" : r"https://www\.mangaread\.org/wp-content/uploads/WP-manga/data/manga_[^/]+/[^/]+/[^.]+\.\w+", "#count" : 6, @@ -67,8 +67,8 @@ { "#url" : "https://www.mangaread.org/manga/kanan-sama-wa-akumade-choroi", - "#category": ("", "mangaread", "manga"), - "#class" : mangaread.MangareadMangaExtractor, + "#category": ("wpmadara", "mangaread", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, "#pattern" : r"https://www\.mangaread\.org/manga/kanan-sama-wa-akumade-choroi/chapter-\d+([_-].+)?/", "#count" : ">= 13", @@ -93,8 +93,8 @@ { "#url" : "https://www.mangaread.org/manga/one-piece", - "#category": ("", "mangaread", "manga"), - "#class" : mangaread.MangareadMangaExtractor, + "#category": ("wpmadara", "mangaread", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, "#pattern" : r"https://www\.mangaread\.org/manga/one-piece/chapter-\d+(-.+)?/", "#count" : ">= 1066", @@ -114,8 +114,8 @@ { "#url" : "https://www.mangaread.org/manga/doesnotexist", - "#category": ("", "mangaread", "manga"), - "#class" : mangaread.MangareadMangaExtractor, + "#category": ("wpmadara", "mangaread", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, "#exception": exception.HttpError, }, diff --git a/test/results/toonily.py b/test/results/toonily.py new file mode 100644 index 0000000000..b2f29b98b6 --- /dev/null +++ b/test/results/toonily.py @@ -0,0 +1,64 @@ +# -*- 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 wpmadara +from gallery_dl import exception + + +__tests__ = ( +{ + "#url" : "https://toonily.com/webtoon/such-a-cute-spy/chapter-36/", + "#category": ("wpmadara", "toonily", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, + "#pattern" : r"https://toonily\.com/wp-content/uploads/WP-manga/data/manga_[^/]+/[^/]+/[^.]+\.\w+", + "#count" : 11, + + "manga" : "Jinxed", + "title" : "", + "chapter" : 36, + "tags" : ["harem"], + "lang" : "en", + "language" : "English", +}, + +{ + "#url" : "https://toonily.com/webtoon/such-a-cute-spy/chapter-1000000/", + "#category": ("wpmadara", "toonily", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, + "#exception": exception.NotFoundError, +}, + +{ + "#url" : "https://toonily.com/webtoon/such-a-cute-spy", + "#category": ("wpmadara", "toonily", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, + "#pattern" : r"https://toonily\.com/webtoon/such-a-cute-spy/chapter-\d+([_-].+)?/", + "#count" : ">= 13", + + "manga" : "Such a Cute Spy", + "author" : ["Life of Ruin"], + "artist" : ["Ganghyeon Yeo"], + "genres" : [ + "Action", + "Comedy", + "Romance", + "School Life", + ], + "rating" : float, + "status" : "End", + "lang" : "en", + "language" : "English", + "manga_alt" : list, +}, + +{ + "#url" : "https://toonily.com/webtoon/doesnotexist", + "#category": ("wpmadara", "toonily", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, + "#exception": exception.HttpError, +}, + +) diff --git a/test/results/webtoonxyz.py b/test/results/webtoonxyz.py new file mode 100644 index 0000000000..18aa89faf9 --- /dev/null +++ b/test/results/webtoonxyz.py @@ -0,0 +1,62 @@ +# -*- 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 wpmadara +from gallery_dl import exception + + +__tests__ = ( +{ + "#url" : "https://www.webtoon.xyz/read/the-world-after-the-end/chapter-105/", + "#category": ("wpmadara", "webtoonxyz", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, + "#pattern" : r"https://www\.webtoon\.xyz/wp-content/uploads/WP-manga/data/manga_[^/]+/[^/]+/[^.]+\.\w+", + "#count" : 11, + + "manga" : "The World After The End", + "title" : "", + "chapter" : 105, + "lang" : "en", + "language" : "English", +}, + +{ + "#url" : "https://www.webtoon.xyz/read/the-world-after-the-end/chapter-1000000/", + "#category": ("wpmadara", "webtoonxyz", "chapter"), + "#class" : wpmadara.WPMadaraChapterExtractor, + "#exception": exception.NotFoundError, +}, + +{ + "#url" : "https://www.webtoon.xyz/read/the-world-after-the-end/", + "#category": ("wpmadara", "webtoonxyz", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, + "#pattern" : r"https://www\.webtoon\.xyz/read/such-a-cute-spy/chapter-\d+([_-].+)?/", + "#count" : ">= 13", + + "manga" : "The World After The End", + "author" : ["S-Cynaan", "Sing Shong"], + "artist" : ["Undead Potato"], + "genres" : [ + "Action", + "Adventure", + "Fantasy", + ], + "rating" : float, + "status" : "OnGoing", + "lang" : "en", + "language" : "English", + "manga_alt" : list, +}, + +{ + "#url" : "https://www.webtoon.xyz/read/doesnotexist", + "#category": ("wpmadara", "webtoonxyz", "manga"), + "#class" : wpmadara.WPMadaraMangaExtractor, + "#exception": exception.HttpError, +}, + +)