diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index e8e836eb..ff4971f7 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -292,7 +292,7 @@ Consider all listed sites to potentially be NSFW.
| Fansly |
https://fansly.com/ |
- Creator Posts, Home Feed, Lists, Account Lists, Posts |
+ Creator Media, Creator Posts, Home Feed, Lists, Account Lists, Posts |
|
diff --git a/gallery_dl/extractor/fansly.py b/gallery_dl/extractor/fansly.py
index 873da0d0..d4d8ea26 100644
--- a/gallery_dl/extractor/fansly.py
+++ b/gallery_dl/extractor/fansly.py
@@ -191,13 +191,20 @@ class FanslyCreatorPostsExtractor(FanslyExtractor):
example = "https://fansly.com/CREATOR/posts"
def posts(self):
- creator = self.groups[0]
- if creator.startswith("id:"):
- account = self.api.account_by_id(creator[3:])
- else:
- account = self.api.account(creator)
- wall_id = account["walls"][0]["id"]
- return self.api.timeline_new(account["id"], wall_id)
+ account = self.api.account(self.groups[0])
+ return self.api.timeline_new(
+ account["id"], account["walls"][0]["id"])
+
+
+class FanslyCreatorMediaExtractor(FanslyExtractor):
+ subcategory = "creator-media"
+ pattern = rf"{BASE_PATTERN}/([^/?#]+)/media"
+ example = "https://fansly.com/CREATOR/media"
+
+ def posts(self):
+ account = self.api.account(self.groups[0])
+ return self.api.mediaoffers_location(
+ account["id"], account["walls"][0]["id"])
class FanslyAPI():
@@ -217,7 +224,12 @@ class FanslyAPI():
else:
self.extractor.log.warning("No 'token' provided")
- def account(self, username):
+ def account(self, creator):
+ if creator.startswith("id:"):
+ return self.account_by_id(creator[3:])
+ return self.account_by_username(creator)
+
+ def account_by_username(self, username):
endpoint = "/v1/account"
params = {"usernames": username}
return self._call(endpoint, params)[0]
@@ -252,6 +264,20 @@ class FanslyAPI():
}
return self._pagination(endpoint, params)
+ def mediaoffers_location(self, account_id, wall_id):
+ endpoint = "/v1/mediaoffers/location"
+ params = {
+ "locationId": wall_id,
+ "locationType": "1002",
+ "accountId": account_id,
+ "mediaType": "",
+ "before": "",
+ "after" : "0",
+ "limit" : "30",
+ "offset": "0",
+ }
+ return self._pagination_media(endpoint, params)
+
def post(self, post_id):
endpoint = "/v1/post"
params = {"ids": post_id}
@@ -319,6 +345,19 @@ class FanslyAPI():
return posts
+ def _update_media(self, items, response):
+ posts = {
+ post["id"]: post
+ for post in response["posts"]
+ }
+
+ response["posts"] = [
+ posts[item["correlationId"]]
+ for item in items
+ ]
+
+ return self._update_posts(response)
+
def _update_items(self, items):
ids = [item["id"] for item in items]
accounts = {
@@ -353,3 +392,13 @@ class FanslyAPI():
posts = self._update_posts(response)
yield from posts
params["before"] = min(p["id"] for p in posts)
+
+ def _pagination_media(self, endpoint, params):
+ while True:
+ response = self._call(endpoint, params)
+
+ data = response["data"]
+ if not data:
+ return
+ yield from self._update_media(data, response["aggregationData"])
+ params["before"] = data[-1]["id"]
diff --git a/scripts/supportedsites.py b/scripts/supportedsites.py
index 328cd258..70ecda25 100755
--- a/scripts/supportedsites.py
+++ b/scripts/supportedsites.py
@@ -591,7 +591,7 @@ def subcategory_text(bc, c, sc):
sc = f"{sc[:-1]}ies"
elif sc.endswith("h"):
sc = f"{sc}es"
- elif not sc.endswith("s"):
+ elif not sc.endswith("s") and not sc.endswith("edia"):
sc = f"{sc}s"
return sc
diff --git a/test/results/fansly.py b/test/results/fansly.py
index cfebfcf7..1c460542 100644
--- a/test/results/fansly.py
+++ b/test/results/fansly.py
@@ -67,6 +67,11 @@ __tests__ = (
"#class" : fansly.FanslyCreatorPostsExtractor,
},
+{
+ "#url" : "https://fansly.com/Oliviaus/media",
+ "#class" : fansly.FanslyCreatorMediaExtractor,
+},
+
{
"#url" : "https://fansly.com/home",
"#class" : fansly.FanslyHomeExtractor,