From cf86f688640684260d47db636d23560fb3565486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Wed, 19 Oct 2022 10:58:42 +0200 Subject: [PATCH] [instagram] add 'avatar' extractor (#929, #1097, #2992) --- docs/configuration.rst | 7 +++- docs/supportedsites.md | 2 +- gallery_dl/extractor/instagram.py | 56 ++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 7543828f..3986d766 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -1517,7 +1517,12 @@ Description when processing a user profile. Possible values are - ``"posts"``, ``"reels"``, ``"tagged"``, ``"stories"``, ``"highlights"``. + ``"posts"``, + ``"reels"``, + ``"tagged"``, + ``"stories"``, + ``"highlights"``, + ``"avatar"``. You can use ``"all"`` instead of listing all values separately. diff --git a/docs/supportedsites.md b/docs/supportedsites.md index 1f8e7db7..2fed3e2d 100644 --- a/docs/supportedsites.md +++ b/docs/supportedsites.md @@ -400,7 +400,7 @@ Consider all sites to be NSFW unless otherwise known. Instagram https://www.instagram.com/ - Collections, Highlights, Posts, Reels, Saved Posts, Stories, Tag Searches, Tagged Posts, User Profiles + Avatars, Collections, Highlights, Posts, Reels, Saved Posts, Stories, Tag Searches, Tagged Posts, User Profiles Supported diff --git a/gallery_dl/extractor/instagram.py b/gallery_dl/extractor/instagram.py index 4839275f..ce3f22d0 100644 --- a/gallery_dl/extractor/instagram.py +++ b/gallery_dl/extractor/instagram.py @@ -361,6 +361,7 @@ class InstagramUserExtractor(InstagramExtractor): base = "{}/{}/".format(self.root, self.item) stories = "{}/stories/{}/".format(self.root, self.item) return self._dispatch_extractors(( + (InstagramAvatarExtractor , base + "avatar/"), (InstagramStoriesExtractor , stories), (InstagramHighlightsExtractor, base + "highlights/"), (InstagramPostsExtractor , base + "posts/"), @@ -417,7 +418,7 @@ class InstagramTaggedExtractor(InstagramExtractor): return {"tagged_owner_id": self.user_id} self.user_id = self.api.user_id(self.item) - user = self.api.user(self.item) + user = self.api.user_by_name(self.item) return { "tagged_owner_id" : user["id"], @@ -529,6 +530,48 @@ class InstagramTagExtractor(InstagramExtractor): return self.api.tags_media(self.item) +class InstagramAvatarExtractor(InstagramExtractor): + """Extractor for an Instagram user's avatar""" + subcategory = "avatar" + pattern = USER_PATTERN + r"/avatar" + test = ("https://www.instagram.com/instagram/avatar", { + "pattern": r"https://instagram\.[\w.-]+\.fbcdn\.net/v/t51\.2885-19" + r"/281440578_1088265838702675_6233856337905829714_n\.jpg", + }) + + def posts(self): + if self._logged_in: + user_id = self.api.user_id(self.item) + user = self.api.user_by_id(user_id) + avatar = (user.get("hd_profile_pic_url_info") or + user["hd_profile_pic_versions"][-1]) + else: + user = self.item + if user.startswith("id:"): + user = self.api.user_by_id(user[3:]) + else: + user = self.api.user_by_name(user) + user["pk"] = user["id"] + url = user.get("profile_pic_url_hd") or user["profile_pic_url"] + avatar = {"url": url, "width": 0, "height": 0} + + pk = user.get("profile_pic_id") + if pk: + pk = pk.partition("_")[0] + code = shortcode_from_id(pk) + else: + pk = code = "avatar:" + str(user["pk"]) + + return ({ + "pk" : pk, + "code" : code, + "user" : user, + "caption" : None, + "like_count": 0, + "image_versions2": {"candidates": (avatar,)}, + },) + + class InstagramPostExtractor(InstagramExtractor): """Extractor for an Instagram post""" subcategory = "post" @@ -678,15 +721,19 @@ class InstagramRestAPI(): return self._pagination_sections(endpoint, data) @memcache(keyarg=1) - def user(self, screen_name): + def user_by_name(self, screen_name): endpoint = "/v1/users/web_profile_info/" params = {"username": screen_name} return self._call(endpoint, params=params)["data"]["user"] + def user_by_id(self, user_id): + endpoint = "/v1/users/{}/info/".format(user_id) + return self._call(endpoint)["user"] + def user_id(self, screen_name): if screen_name.startswith("id:"): return screen_name[3:] - user = self.user(screen_name) + user = self.user_by_name(screen_name) if user is None: raise exception.AuthorizationError( "Login required to access this profile") @@ -797,7 +844,8 @@ class InstagramGraphqlAPI(): self._json_dumps = json.JSONEncoder(separators=(",", ":")).encode api = InstagramRestAPI(extractor) - self.user = api.user + self.user_by_name = api.user_by_name + self.user_by_id = api.user_by_id self.user_id = api.user_id @staticmethod