[tumblr] add 'following' & 'followers' extractors (#8018)

This commit is contained in:
Mike Fährmann
2025-08-12 21:14:24 +02:00
parent ab54f71511
commit ca22cb1487
3 changed files with 80 additions and 1 deletions

View File

@@ -1052,7 +1052,7 @@ Consider all listed sites to potentially be NSFW.
<tr>
<td>Tumblr</td>
<td>https://www.tumblr.com/</td>
<td>Days, Likes, Posts, Search Results, Tag Searches, User Profiles</td>
<td>Days, Followers, Followed Users, Likes, Posts, Search Results, Tag Searches, User Profiles</td>
<td><a href="https://github.com/mikf/gallery-dl#oauth">OAuth</a></td>
</tr>
<tr>

View File

@@ -171,6 +171,11 @@ class TumblrExtractor(Extractor):
post["count"] = len(posts)
yield msg, url, post
def items_blogs(self):
for blog in self.blogs():
blog["_extractor"] = TumblrUserExtractor
yield Message.Queue, blog["url"], blog
def posts(self):
"""Return an iterable containing all relevant posts"""
@@ -345,6 +350,30 @@ class TumblrLikesExtractor(TumblrExtractor):
return self.api.likes(self.blog)
class TumblrFollowingExtractor(TumblrExtractor):
"""Extractor for a Tumblr user's followed blogs"""
subcategory = "following"
pattern = BASE_PATTERN + r"/following"
example = "https://www.tumblr.com/BLOG/following"
items = TumblrExtractor.items_blogs
def blogs(self):
return self.api.following(self.blog)
class TumblrFollowersExtractor(TumblrExtractor):
"""Extractor for a Tumblr user's followers"""
subcategory = "followers"
pattern = BASE_PATTERN + r"/followers"
example = "https://www.tumblr.com/BLOG/followers"
items = TumblrExtractor.items_blogs
def blogs(self):
return self.api.followers(self.blog)
class TumblrSearchExtractor(TumblrExtractor):
"""Extractor for a Tumblr search"""
subcategory = "search"
@@ -420,6 +449,14 @@ class TumblrAPI(oauth.OAuth1API):
yield from posts
params["before"] = posts[-1]["liked_timestamp"]
def following(self, blog):
endpoint = f"/v2/blog/{blog}/following"
return self._pagination_blogs(endpoint)
def followers(self, blog):
endpoint = f"/v2/blog/{blog}/followers"
return self._pagination_blogs(endpoint)
def search(self, query, params, mode="top", post_type=None):
"""Retrieve search results"""
endpoint = "/v2/timeline/search"
@@ -556,3 +593,21 @@ class TumblrAPI(oauth.OAuth1API):
params["before"] = None
if params["offset"] >= data["total_posts"]:
return
def _pagination_blogs(self, endpoint, params=None):
if params is None:
params = {}
if self.api_key:
params["api_key"] = self.api_key
params["limit"] = 20
params["offset"] = text.parse_int(params.get("offset"), 0)
while True:
data = self._call(endpoint, params)
blogs = data["blogs"]
yield from blogs
params["offset"] = params["offset"] + params["limit"]
if params["offset"] >= data["total_blogs"]:
return

View File

@@ -403,4 +403,28 @@ __tests__ = (
"#class" : tumblr.TumblrSearchExtractor,
},
{
"#url" : "https://www.tumblr.com/mikf123/following",
"#class" : tumblr.TumblrFollowingExtractor,
"#results" : (
"https://smarties-art.tumblr.com/",
"https://demo.tumblr.com/",
),
"can_show_badges": True,
"description" : str,
"name" : str,
"title" : str,
"tumblrmart_accessories": {},
"updated" : int,
"url" : str,
"uuid" : str,
},
{
"#url" : "https://www.tumblr.com/mikf123/followers",
"#class" : tumblr.TumblrFollowersExtractor,
"#exception": exception.AuthorizationError,
},
)