diff --git a/docs/configuration.rst b/docs/configuration.rst index b626a930..6772c9f4 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -1185,6 +1185,31 @@ Description Download embedded videos hosted on https://www.blogger.com/ +extractor.bluesky.include +------------------------- +Type + * ``string`` + * ``list`` of ``strings`` +Default + ``"media"`` +Example + * ``"avatar,background,posts"`` + * ``["avatar", "background", "posts"]`` +Description + A (comma-separated) list of subcategories to include + when processing a user profile. + + Possible values are + ``"avatar"``, + ``"background"``, + ``"posts"``, + ``"replies"``, + ``"media"``, + ``"likes"``, + + It is possible to use ``"all"`` instead of listing all values separately. + + extractor.bluesky.metadata -------------------------- Type diff --git a/gallery_dl/extractor/bluesky.py b/gallery_dl/extractor/bluesky.py index 221598c4..5dae14bc 100644 --- a/gallery_dl/extractor/bluesky.py +++ b/gallery_dl/extractor/bluesky.py @@ -108,6 +108,36 @@ class BlueskyExtractor(Extractor): def posts(self): return () + def _make_post(self, actor, kind): + did = self.api._did_from_actor(actor) + profile = self.api.get_profile(did) + + if kind not in profile: + return () + cid = profile[kind].rpartition("/")[2].partition("@")[0] + + return ({ + "post": { + "embed": {"images": [{ + "alt": kind, + "image": { + "$type" : "blob", + "ref" : {"$link": cid}, + "mimeType": "image/jpeg", + "size" : 0, + }, + "aspectRatio": { + "width" : 1000, + "height": 1000, + }, + }]}, + "author" : profile, + "record" : (), + "createdAt": "", + "uri" : cid, + }, + },) + class BlueskyUserExtractor(BlueskyExtractor): subcategory = "user" @@ -120,10 +150,12 @@ class BlueskyUserExtractor(BlueskyExtractor): def items(self): base = "{}/profile/{}/".format(self.root, self.user) return self._dispatch_extractors(( - (BlueskyPostsExtractor , base + "posts"), - (BlueskyRepliesExtractor, base + "replies"), - (BlueskyMediaExtractor , base + "media"), - (BlueskyLikesExtractor , base + "likes"), + (BlueskyAvatarExtractor , base + "avatar"), + (BlueskyBackgroundExtractor, base + "banner"), + (BlueskyPostsExtractor , base + "posts"), + (BlueskyRepliesExtractor , base + "replies"), + (BlueskyMediaExtractor , base + "media"), + (BlueskyLikesExtractor , base + "likes"), ), ("media",)) @@ -213,6 +245,26 @@ class BlueskyPostExtractor(BlueskyExtractor): return self.api.get_post_thread(self.user, self.post_id) +class BlueskyAvatarExtractor(BlueskyExtractor): + subcategory = "avatar" + filename_fmt = "avatar_{post_id}.{extension}" + pattern = USER_PATTERN + r"/avatar" + example = "https://bsky.app/profile/HANDLE/avatar" + + def posts(self): + return self._make_post(self.user, "avatar") + + +class BlueskyBackgroundExtractor(BlueskyExtractor): + subcategory = "background" + filename_fmt = "background_{post_id}.{extension}" + pattern = USER_PATTERN + r"/ba(?:nner|ckground)" + example = "https://bsky.app/profile/HANDLE/banner" + + def posts(self): + return self._make_post(self.user, "banner") + + class BlueskyAPI(): """Interface for the Bluesky API