diff --git a/docs/configuration.rst b/docs/configuration.rst index 65e129b7..d021a9f0 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -468,6 +468,7 @@ Description * ``inkbunny`` * ``iwara`` * ``kemono`` + * ``madokami`` (R) * ``mangadex`` * ``mangoxo`` * ``newgrounds`` diff --git a/docs/gallery-dl.conf b/docs/gallery-dl.conf index 8a1d71cd..c2040bd1 100644 --- a/docs/gallery-dl.conf +++ b/docs/gallery-dl.conf @@ -447,6 +447,11 @@ { "gif": false }, + "madokami": + { + "username": "", + "password": "" + }, "mangadex": { "client-id" : "", diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 80e7653e..83580c03 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -583,6 +583,12 @@ Consider all listed sites to potentially be NSFW. Albums, Search Results + + Madokami + https://manga.madokami.al/ + Manga + Required + Manga Fox https://fanfox.net/ diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py index 9142fd78..f51a6063 100644 --- a/gallery_dl/extractor/__init__.py +++ b/gallery_dl/extractor/__init__.py @@ -106,6 +106,7 @@ modules = [ "lofter", "luscious", "lynxchan", + "madokami", "mangadex", "mangafox", "mangahere", diff --git a/gallery_dl/extractor/madokami.py b/gallery_dl/extractor/madokami.py new file mode 100644 index 00000000..3431cf9b --- /dev/null +++ b/gallery_dl/extractor/madokami.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +# Copyright 2025 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://manga.madokami.al/""" + +from .common import Extractor, Message +from .. import text, util, exception + +BASE_PATTERN = r"(?:https?://)?manga\.madokami\.al" + + +class MadokamiExtractor(Extractor): + """Base class for madokami extractors""" + category = "madokami" + root = "https://manga.madokami.al" + + +class MadokamiMangaExtractor(MadokamiExtractor): + """Extractor for madokami manga""" + subcategory = "manga" + directory_fmt = ("{category}", "{manga}") + archive_fmt = "{chapter_id}" + pattern = rf"{BASE_PATTERN}/Manga/(\w/\w{{2}}/\w{{4}}/.+)" + example = "https://manga.madokami.al/Manga/A/AB/ABCD/ABCDE_TITLE" + + def items(self): + username, password = self._get_auth_info() + if not username: + raise exception.LoginRequired("Missing 'username' & 'password'") + self.session.auth = util.HTTPBasicAuth(username, password) + + url = f"{self.root}/Manga/{self.groups[0]}" + page = self.request(url).text + extr = text.extract_from(page) + + chapters = [] + while True: + if not (cid := extr('", "<")), + "size": text.parse_bytes(extr("", "")), + "date": text.parse_datetime( + extr("", "").strip(), "%Y-%m-%d %H:%M"), + }) + + if self.config("chapter-reverse"): + chapters.reverse() + + self.kwdict.update({ + "manga" : text.unescape(extr('itemprop="name">', "<")), + "year" : text.parse_int(extr( + 'itemprop="datePublished" content="', "-")), + "author": text.split_html(extr('

"))[1::2], + "genre" : text.split_html(extr("

Genres

", "")), + "tags" : text.split_html(extr("

Tags

", "")), + "complete": extr('span class="scanstatus">', "<").lower() == "yes", + }) + + parse_chinfo = text.re( + r"(?i).+?\s+(" + r"(?:v(?:ol)?\.?\s*(\d+)\s+)?" + r"(?:ch?\.?\s*(\d+)(?:-(\d+))?)" + r")" + ).match + + for ch in chapters: + + chstr = ch["chapter_string"] + if match := parse_chinfo(chstr): + ch["chapter_string"], volume, chapter, end = match.groups() + ch["volume"] = text.parse_int(volume) + ch["chapter"] = text.parse_int(chapter) + ch["chapter_end"] = text.parse_int(end) + else: + ch["volume"] = ch["chapter"] = ch["chapter_end"] = 0 + + url = f"{self.root}{ch['path']}" + text.nameext_from_url(url, ch) + + yield Message.Directory, ch + yield Message.Url, url, ch diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py index 1dc2f007..f8f0fe54 100755 --- a/scripts/supportedsites.py +++ b/scripts/supportedsites.py @@ -482,6 +482,7 @@ AUTH_MAP = { "instagram" : _COOKIES, "iwara" : "Supported", "kemono" : "Supported", + "madokami" : "Required", "mangadex" : "Supported", "mangoxo" : "Supported", "mastodon.social": _OAUTH, diff --git a/test/results/madokami.py b/test/results/madokami.py new file mode 100644 index 00000000..78554bba --- /dev/null +++ b/test/results/madokami.py @@ -0,0 +1,69 @@ +# -*- 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 madokami +from gallery_dl import exception + + +__tests__ = ( +{ + "#url" : "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red", + "#class" : madokami.MadokamiMangaExtractor, + "#auth" : True, + "#results" : ( + "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20v01%20c01-02%20%281%20of%202%29.zip", + "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20v01%20c03-05%20%282%20of%202%29.zip", + "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20v02%20c06-10.zip", + "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20v03%20c11-13%20%281%20of%202%29.zip", + "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20v03%20c14-15%20%282%20of%202%29.zip", + ), + + "chapter" : {1, 3, 6, 11, 14}, + "chapter_end" : {2, 5, 10, 13, 15}, + "chapter_id" : range(57413, 57417), + "chapter_string": r"re:v\d\d c\d\d-\d\d", + "complete" : True, + "date" : "type:datetime", + "extension" : "zip", + "filename" : r"re:K - Memory of Red .+", + "manga" : "K - Memory of Red", + "path" : r"re:/Manga/K/K_/K___/K%20-%20Memory%20of%20Red/K%20-%20Memory%20of%20Red%20.+\.zip", + "size" : range(57_986_253, 82_732_646), + "volume" : range(1, 3), + "year" : 2012, + "author" : [ + "GoHands", + "GoRA", + "KUROE Yui", + ], + "genre" : [ + "Action", + "Shoujo", + "Supernatural", + ], + "tags" : [ + "Bar/s", + "Bartender/s", + "Based on an Anime", + "Bishounen", + "Gang/s", + "Multiple Protagonists", + "Mysterious Protagonist", + "Skateboarding", + "Street Fighting", + "Stubborn Protagonist", + ], +}, + +{ + "#url" : "https://manga.madokami.al/Manga/K/K_/K___/K%20-%20Memory%20of%20Red", + "#comment" : "no username & password", + "#class" : madokami.MadokamiMangaExtractor, + "#auth" : False, + "#exception": exception.LoginRequired, +}, + +)