From f88e42c19486e9c95c41e166d86568a33269d0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Mon, 12 May 2025 11:14:58 +0200 Subject: [PATCH] [mangadex] implement login with client credentials unless the legacy method still works for your account, login now requires 4 values: - client-id - client-secret - username - password where 'client-id' and 'client-secret' are the credentials of a personal API client. > Public clients are not yet available. --- docs/configuration.rst | 17 +++++++++ docs/gallery-dl.conf | 2 + gallery_dl/extractor/mangadex.py | 63 +++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 05a720ff..0313cb14 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -7566,6 +7566,23 @@ How To as ``"api-key"`` and ``"api-secret"`` +extractor.mangadex.client-id & .client-secret +--------------------------------------------- +Type + ``string`` +How To + * login and go to your `User Settings `__ + * open the "API Clients" section + * click "``+ Create``" + * choose a name + * click "``✔️ Create``" + * wait for approval / reload the page + * copy the value after "AUTOAPPROVED ACTIVE" in the form "personal-client-..." + and put it in your configuration file as ``"client-id"`` + * click "``Get Secret``", then "``Copy Secret``", + and paste it into your configuration file as ``"client-secret"`` + + extractor.reddit.client-id & .user-agent ---------------------------------------- Type diff --git a/docs/gallery-dl.conf b/docs/gallery-dl.conf index a5a02e66..ea04bb50 100644 --- a/docs/gallery-dl.conf +++ b/docs/gallery-dl.conf @@ -409,6 +409,8 @@ }, "mangadex": { + "client-id" : "", + "client-secret": "", "username": "", "password": "", diff --git a/gallery_dl/extractor/mangadex.py b/gallery_dl/extractor/mangadex.py index 7f87cff8..e99d19a4 100644 --- a/gallery_dl/extractor/mangadex.py +++ b/gallery_dl/extractor/mangadex.py @@ -29,11 +29,8 @@ class MangadexExtractor(Extractor): useragent = util.USERAGENT _cache = {} - def __init__(self, match): - Extractor.__init__(self, match) - self.uuid = match.group(1) - def _init(self): + self.uuid = self.groups[0] self.api = MangadexAPI(self) def items(self): @@ -199,7 +196,14 @@ class MangadexAPI(): self.headers = {} self.username, self.password = extr._get_auth_info() - if not self.username: + if self.username: + self.client_id = cid = extr.config("client-id") + self.client_secret = extr.config("client-secret") + if cid: + self._authenticate_impl = self._authenticate_impl_client + else: + self._authenticate_impl = self._authenticate_impl_legacy + else: self.authenticate = util.noop server = extr.config("api-server") @@ -249,19 +253,58 @@ class MangadexAPI(): self._authenticate_impl(self.username, self.password) @cache(maxage=900, keyarg=1) - def _authenticate_impl(self, username, password): + def _authenticate_impl_client(self, username, password): + refresh_token = _refresh_token_cache((username, "personal")) + if refresh_token: + self.extractor.log.info("Refreshing access token") + data = { + "grant_type" : "refresh_token", + "refresh_token": refresh_token, + "client_id" : self.client_id, + "client_secret": self.client_secret, + } + else: + self.extractor.log.info("Logging in as %s", username) + data = { + "grant_type" : "password", + "username" : self.username, + "password" : self.password, + "client_id" : self.client_id, + "client_secret": self.client_secret, + } + + self.extractor.log.debug("Using client-id '%s…'", self.client_id[:24]) + url = ("https://auth.mangadex.org/realms/mangadex" + "/protocol/openid-connect/token") + data = self.extractor.request( + url, method="POST", data=data, fatal=None).json() + + try: + access_token = data["access_token"] + except Exception: + raise exception.AuthenticationError(data.get("error_description")) + + if refresh_token != data.get("refresh_token"): + _refresh_token_cache.update( + (username, "personal"), data["refresh_token"]) + + return "Bearer " + access_token + + @cache(maxage=900, keyarg=1) + def _authenticate_impl_legacy(self, username, password): refresh_token = _refresh_token_cache(username) if refresh_token: self.extractor.log.info("Refreshing access token") url = self.root + "/auth/refresh" - data = {"token": refresh_token} + json = {"token": refresh_token} else: self.extractor.log.info("Logging in as %s", username) url = self.root + "/auth/login" - data = {"username": username, "password": password} + json = {"username": username, "password": password} + self.extractor.log.debug("Using legacy login method") data = self.extractor.request( - url, method="POST", json=data, fatal=None).json() + url, method="POST", json=json, fatal=None).json() if data.get("result") != "ok": raise exception.AuthenticationError() @@ -329,6 +372,6 @@ class MangadexAPI(): return -@cache(maxage=28*86400, keyarg=0) +@cache(maxage=90*86400, keyarg=0) def _refresh_token_cache(username): return None