diff --git a/docs/configuration.rst b/docs/configuration.rst
index d9feb440..986ecc39 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -368,6 +368,7 @@ Description
* ``imgbb``
* ``inkbunny``
* ``instagram``
+ * ``kemonoparty``
* ``mangadex``
* ``mangoxo``
* ``pillowfort``
diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index 19194c8e..72cf211a 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -383,7 +383,7 @@ Consider all sites to be NSFW unless otherwise known.
Kemonoparty |
https://kemono.party/ |
Favorites, Posts, User Profiles |
- |
+ Supported |
| Khinsider |
diff --git a/gallery_dl/extractor/kemonoparty.py b/gallery_dl/extractor/kemonoparty.py
index 75d17810..ee668963 100644
--- a/gallery_dl/extractor/kemonoparty.py
+++ b/gallery_dl/extractor/kemonoparty.py
@@ -9,7 +9,8 @@
"""Extractors for https://kemono.party/"""
from .common import Extractor, Message
-from .. import text
+from .. import text, exception
+from ..cache import cache
import itertools
import re
@@ -75,6 +76,25 @@ class KemonopartyExtractor(Extractor):
text.nameext_from_url(file["name"], post)
yield Message.Url, url, post
+ def login(self):
+ username, password = self._get_auth_info()
+ if username:
+ self._update_cookies(self._login_impl(username, password))
+
+ @cache(maxage=28*24*3600, keyarg=1)
+ def _login_impl(self, username, password):
+ self.log.info("Logging in as %s", username)
+
+ url = self.root + "/account/login"
+ data = {"username": username, "password": password}
+
+ response = self.request(url, method="POST", data=data)
+ if response.url.endswith("/account/login") and \
+ "Username or password is incorrect" in response.text:
+ raise exception.AuthenticationError()
+
+ return {c.name: c.value for c in response.history[0].cookies}
+
class KemonopartyUserExtractor(KemonopartyExtractor):
"""Extractor for all posts from a kemono.party user listing"""
@@ -179,12 +199,17 @@ class KemonopartyFavoriteExtractor(KemonopartyExtractor):
"""Extractor for kemono.party favorites"""
subcategory = "favorite"
pattern = r"(?:https?://)?kemono\.party/favorites"
- test = ("https://kemono.party/favorites",)
+ test = ("https://kemono.party/favorites", {
+ "pattern": KemonopartyUserExtractor.pattern,
+ "url": "f4b5b796979bcba824af84206578c79101c7f0e1",
+ "count": 3,
+ })
def items(self):
self._prepare_ddosguard_cookies()
- users = self.request(self.root + "/api/favorites").json()
+ self.login()
+ users = self.request(self.root + "/api/favorites").json()
for user in users:
user["_extractor"] = KemonopartyUserExtractor
url = "{}/{}/user/{}".format(
diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py
index 023e1a21..92602003 100755
--- a/scripts/supportedsites.py
+++ b/scripts/supportedsites.py
@@ -219,6 +219,7 @@ AUTH_MAP = {
"imgbb" : "Supported",
"inkbunny" : "Supported",
"instagram" : "Supported",
+ "kemonoparty" : "Supported",
"mangadex" : "Supported",
"mangoxo" : "Supported",
"mastodon.social": _OAUTH,