From f0e7992674e162f8174ee74c164b32eb1a1de72b Mon Sep 17 00:00:00 2001 From: stephanelsmith <10711596+stephanelsmith@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:34:57 -0500 Subject: [PATCH] [twitter] added 'followers' extractor modeled after the 'following' extractor - cleanup - add test --- docs/supportedsites.md | 2 +- gallery_dl/extractor/twitter.py | 20 ++++++++++++++++++++ test/results/twitter.py | 6 ++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/supportedsites.md b/docs/supportedsites.md index c45c5a94..95dd34ec 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -998,7 +998,7 @@ Consider all listed sites to potentially be NSFW. Twitter https://x.com/ - Avatars, Backgrounds, Bookmarks, Communities, Events, Followed Users, Hashtags, individual Images, User Profile Information, Likes, Lists, List Members, Media Timelines, Quotes, Search Results, Timelines, Tweets, User Profiles + Avatars, Backgrounds, Bookmarks, Communities, Events, Followers, Followed Users, Hashtags, individual Images, User Profile Information, Likes, Lists, List Members, Media Timelines, Quotes, Search Results, Timelines, Tweets, User Profiles Supported diff --git a/gallery_dl/extractor/twitter.py b/gallery_dl/extractor/twitter.py index fd77553f..e2fe0000 100644 --- a/gallery_dl/extractor/twitter.py +++ b/gallery_dl/extractor/twitter.py @@ -798,6 +798,17 @@ class TwitterFollowingExtractor(TwitterExtractor): return self._users_result(TwitterAPI(self).user_following(self.user)) +class TwitterFollowersExtractor(TwitterExtractor): + """Extractor for a user's followers""" + subcategory = "followers" + pattern = BASE_PATTERN + r"/(?!search)([^/?#]+)/followers(?!\w)" + example = "https://x.com/USER/followers" + + def items(self): + self.login() + return self._users_result(TwitterAPI(self).user_followers(self.user)) + + class TwitterSearchExtractor(TwitterExtractor): """Extractor for Twitter search results""" subcategory = "search" @@ -1411,6 +1422,15 @@ class TwitterAPI(): } return self._pagination_users(endpoint, variables) + def user_followers_verified(self, screen_name): + endpoint = "/graphql/GHg0X_FjrJoISwwLPWi1LQ/BlueVerifiedFollowers" + variables = { + "userId": self._user_id_by_screen_name(screen_name), + "count": 100, + "includePromotedContent": False, + } + return self._pagination_users(endpoint, variables) + def user_following(self, screen_name): endpoint = "/graphql/4QHbs4wmzgtU91f-t96_Eg/Following" variables = { diff --git a/test/results/twitter.py b/test/results/twitter.py index ef47a304..02a792b2 100644 --- a/test/results/twitter.py +++ b/test/results/twitter.py @@ -271,6 +271,12 @@ __tests__ = ( "#class" : twitter.TwitterFollowingExtractor, }, +{ + "#url" : "https://twitter.com/supernaturepics/followers", + "#category": ("", "twitter", "followers"), + "#class" : twitter.TwitterFollowersExtractor, +}, + { "#url" : "https://twitter.com/search?q=nature", "#category": ("", "twitter", "search"),