Files
gallery-dl/gallery_dl/extractor/weebdex.py
2025-12-19 20:06:40 +01:00

133 lines
4.3 KiB
Python

# -*- 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://weebdex.org/"""
from .common import ChapterExtractor, MangaExtractor
from .. import text
from ..cache import memcache
BASE_PATTERN = r"(?:https?://)?weebdex\.org"
class WeebdexBase():
"""Base class for weebdex extractors"""
category = "weebdex"
root = "https://weebdex.org"
root_api = "https://api.weebdex.org"
request_interval = 0.2 # 5 requests per second
def _init(self):
self.headers_api = {
"Referer": self.root + "/",
"Origin" : self.root,
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
}
class WeebdexChapterExtractor(WeebdexBase, ChapterExtractor):
"""Extractor for weebdex manga chapters"""
archive_fmt = "{chapter_id}_{version}_{page}"
pattern = BASE_PATTERN + r"/chapter/(\w+)"
example = "https://weebdex.org/chapter/ID/PAGE"
def metadata(self, _):
cid = self.groups[0]
url = f"{self.root_api}/chapter/{cid}"
self.data = data = self.request_json(url, headers=self.headers_api)
rel = data.pop("relationships")
chapter, sep, minor = data["chapter"].partition(".")
return {
**_manga_info(self, rel["manga"]["id"]),
"title" : data.get("title", ""),
"version" : data["version"],
"volume" : text.parse_int(data["volume"]),
"chapter" : text.parse_int(chapter),
"chapter_minor": sep + minor,
"chapter_id" : cid,
"date" : self.parse_datetime_iso(data["created_at"]),
"date_updated" : self.parse_datetime_iso(data["updated_at"]),
"lang" : data["language"],
"uploader": rel["uploader"]["name"] if "uploader" in rel else "",
"group" : [g["name"] for g in rel.get("groups") or ()],
}
def images(self, _):
data = self.data
base = f"{data['node']}/data/{data['id']}/"
return [
(base + page["name"], {
"width" : page["dimensions"][0],
"height": page["dimensions"][1],
})
for page in data["data"]
]
class WeebdexMangaExtractor(WeebdexBase, MangaExtractor):
"""Extractor for weebdex manga"""
chapterclass = WeebdexChapterExtractor
pattern = BASE_PATTERN + r"/title/(\w+)"
example = "https://weebdex.org/title/ID/SLUG"
def chapters(self, page):
mid = self.groups[0]
url = f"{self.root_api}/manga/{mid}/chapters"
params = {
"limit": 100,
"order": "asc" if self.config("chapter-reverse") else "desc",
}
base = self.root + "/chapter/"
manga = _manga_info(self, mid)
results = []
while True:
data = self.request_json(
url, params=params, headers=self.headers_api)
for ch in data["data"]:
chapter, sep, minor = ch["chapter"].partition(".")
ch["volume"] = text.parse_int(ch["volume"])
ch["chapter"] = text.parse_int(chapter)
ch["chapter_minor"] = sep + minor
ch.update(manga)
results.append((base + ch["id"], ch))
if data["total"] <= data["page"] * params["limit"]:
break
params["page"] = data["page"] + 1
return results
@memcache(keyarg=1)
def _manga_info(self, mid):
url = f"{self.root_api}/manga/{mid}"
manga = self.request_json(url, headers=self.headers_api)
rel = manga["relationships"]
return {
"manga" : manga["title"],
"manga_id": manga["id"],
"manga_date": self.parse_datetime_iso(manga["created_at"]),
"year" : manga["year"],
"status" : manga["status"],
"origin" : manga["language"],
"description": manga["description"],
"demographic": manga["demographic"],
"tags" : [f"{t['group']}:{t['name']}" for t in rel["tags"]],
"author" : [a["name"] for a in rel["authors"]],
"artist" : [a["name"] for a in rel["artists"]],
}