diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index d046aad4..057515c9 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -502,7 +502,7 @@ Consider all listed sites to potentially be NSFW.
| MangaDex |
https://mangadex.org/ |
- Chapters, Followed Feed, Manga |
+ Chapters, Followed Feed, Lists, Manga |
Supported |
diff --git a/gallery_dl/extractor/mangadex.py b/gallery_dl/extractor/mangadex.py
index 94bea570..d287d5cf 100644
--- a/gallery_dl/extractor/mangadex.py
+++ b/gallery_dl/extractor/mangadex.py
@@ -148,6 +148,31 @@ class MangadexFeedExtractor(MangadexExtractor):
return self.api.user_follows_manga_feed()
+class MangadexListExtractor(MangadexExtractor):
+ """Extractor for mangadex lists"""
+ subcategory = "list"
+ pattern = (BASE_PATTERN +
+ r"/list/([0-9a-f-]+)(?:/[^/?#]*)?(?:\?tab=(\w+))?")
+ example = ("https://mangadex.org/list"
+ "/01234567-89ab-cdef-0123-456789abcdef/NAME")
+
+ def __init__(self, match):
+ MangadexExtractor.__init__(self, match)
+ if match.group(2) != "feed":
+ self.subcategory = "list-feed"
+ self.items = self._items_titles
+
+ def chapters(self):
+ return self.api.list_feed(self.uuid)
+
+ def _items_titles(self):
+ data = {"_extractor": MangadexMangaExtractor}
+ for item in self.api.list(self.uuid)["relationships"]:
+ if item["type"] == "manga":
+ url = "{}/title/{}".format(self.root, item["id"])
+ yield Message.Queue, url, data
+
+
class MangadexAPI():
"""Interface for the MangaDex API v5
@@ -173,6 +198,12 @@ class MangadexAPI():
params = {"includes[]": ("scanlation_group",)}
return self._call("/chapter/" + uuid, params)["data"]
+ def list(self, uuid):
+ return self._call("/list/" + uuid)["data"]
+
+ def list_feed(self, uuid):
+ return self._pagination("/list/" + uuid + "/feed")
+
@memcache(keyarg=1)
def manga(self, uuid):
params = {"includes[]": ("artist", "author")}
diff --git a/test/results/mangadex.py b/test/results/mangadex.py
index 17b2157c..ae1c7ab1 100644
--- a/test/results/mangadex.py
+++ b/test/results/mangadex.py
@@ -113,4 +113,31 @@ __tests__ = (
"#class" : mangadex.MangadexFeedExtractor,
},
+{
+ "#url" : "https://mangadex.org/list/3a0982c5-65aa-4de2-8a4a-2175be7383ab/test",
+ "#category": ("", "mangadex", "list"),
+ "#class" : mangadex.MangadexListExtractor,
+ "#urls" : (
+ "https://mangadex.org/title/cba4e5d6-67a0-47a0-b37a-c06e9bf25d93",
+ "https://mangadex.org/title/cad76ec6-ca22-42f6-96f8-eca164da6545",
+ ),
+},
+
+{
+ "#url" : "https://mangadex.org/list/3a0982c5-65aa-4de2-8a4a-2175be7383ab/test?tab=titles",
+ "#category": ("", "mangadex", "list"),
+ "#class" : mangadex.MangadexListExtractor,
+},
+
+{
+ "#url" : "https://mangadex.org/list/3a0982c5-65aa-4de2-8a4a-2175be7383ab/test?tab=feed",
+ "#category": ("", "mangadex", "list-feed"),
+ "#class" : mangadex.MangadexListExtractor,
+ "#urls" : (
+ "https://mangadex.org/chapter/c765d6d5-5712-4360-be0b-0c8e0914fc94",
+ "https://mangadex.org/chapter/fa8a695d-260f-4dcc-95a3-1f30e66d6571",
+ "https://mangadex.org/chapter/788766b9-41c6-422e-97ba-552f03ba9655",
+ ),
+},
+
)