[madokami] add 'manga' extractor (#7828)

This commit is contained in:
Mike Fährmann
2025-07-17 20:40:26 +02:00
parent 493fc483c6
commit 1561284815
7 changed files with 172 additions and 0 deletions

View File

@@ -468,6 +468,7 @@ Description
* ``inkbunny``
* ``iwara``
* ``kemono``
* ``madokami`` (R)
* ``mangadex``
* ``mangoxo``
* ``newgrounds``

View File

@@ -447,6 +447,11 @@
{
"gif": false
},
"madokami":
{
"username": "",
"password": ""
},
"mangadex":
{
"client-id" : "",

View File

@@ -583,6 +583,12 @@ Consider all listed sites to potentially be NSFW.
<td>Albums, Search Results</td>
<td></td>
</tr>
<tr>
<td>Madokami</td>
<td>https://manga.madokami.al/</td>
<td>Manga</td>
<td>Required</td>
</tr>
<tr>
<td>Manga Fox</td>
<td>https://fanfox.net/</td>

View File

@@ -106,6 +106,7 @@ modules = [
"lofter",
"luscious",
"lynxchan",
"madokami",
"mangadex",
"mangafox",
"mangahere",

View File

@@ -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('<tr data-record="', '"')):
break
chapters.append({
"chapter_id": text.parse_int(cid),
"path": text.unescape(extr('href="', '"')),
"chapter_string": text.unescape(extr(">", "<")),
"size": text.parse_bytes(extr("<td>", "</td>")),
"date": text.parse_datetime(
extr("<td>", "</td>").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('<p class="staff', "</p>"))[1::2],
"genre" : text.split_html(extr("<h3>Genres</h3>", "</div>")),
"tags" : text.split_html(extr("<h3>Tags</h3>", "</div>")),
"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

View File

@@ -482,6 +482,7 @@ AUTH_MAP = {
"instagram" : _COOKIES,
"iwara" : "Supported",
"kemono" : "Supported",
"madokami" : "Required",
"mangadex" : "Supported",
"mangoxo" : "Supported",
"mastodon.social": _OAUTH,

69
test/results/madokami.py Normal file
View File

@@ -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,
},
)