16
16
17
17
from git import Repo
18
18
import tweepy
19
- from atproto import Client , client_utils
19
+ from atproto import Client , client_utils , models
20
+ import httpx
20
21
21
22
22
23
# Getting the Twitter secrets form local dev file or GH action secrets
27
28
TWITTER_ACCESS_TOKEN ,
28
29
TWITTER_ACCESS_TOKEN_SECRET ,
29
30
)
30
- from bluesky_secrets import (
31
- BLUESKY_USERNAME ,
32
- BLUESKY_TOKEN ,
33
- )
34
31
except ImportError :
35
32
TWITTER_CONSUMER_KEY = os .environ .get ("INPUT_TWITTER_CONSUMER_KEY" , None )
36
33
TWITTER_CONSUMER_SECRET = os .environ .get (
40
37
TWITTER_ACCESS_TOKEN_SECRET = os .environ .get (
41
38
"INPUT_TWITTER_ACCESS_TOKEN_SECRET" , None
42
39
)
40
+ try :
41
+ from bluesky_secrets import (
42
+ BLUESKY_USERNAME ,
43
+ BLUESKY_TOKEN ,
44
+ )
45
+ except ImportError :
43
46
BLUESKY_USERNAME = os .environ .get ("INPUT_BLUESKY_USERNAME" , None )
44
47
BLUESKY_TOKEN = os .environ .get ("INPUT_BLUESKY_TOKEN" , None )
45
48
@@ -181,7 +184,7 @@ def format_msg_bluesky(section, title, url, description):
181
184
description = format_use_hashtags (description )
182
185
183
186
# Now let's make sure we don't exceed the max character limit
184
- msg = "{}\n \n {} \n {}" .format (section , title , description )
187
+ msg = "{} - {} \n \n {}" .format (section , title , description )
185
188
if len (msg ) > BLUESKY_MAX_CHARS :
186
189
ellipsis = "..."
187
190
characters_over = len (msg ) - BLUESKY_MAX_CHARS + len (ellipsis )
@@ -190,20 +193,62 @@ def format_msg_bluesky(section, title, url, description):
190
193
)
191
194
192
195
text_builder = client_utils .TextBuilder ()
193
- text_builder .text (section + "\n \n " )
196
+ text_builder .text (section + " - " )
194
197
text_builder .link (title , url )
195
- text_builder .text ("\n " + description )
198
+ text_builder .text ("\n \n " + description )
196
199
return text_builder
197
200
198
201
199
- def skeet_msg (text_builder ):
202
+ def skeet_msg (text_builder , url ):
200
203
"""Post to BluSky the given message content."""
201
204
if not all ((BLUESKY_USERNAME , BLUESKY_TOKEN )):
202
205
print ("BlueSky username or token not available." )
203
206
sys .exit (1 )
207
+
208
+ # Posting Open Graph Protocol (OGP) social media cards, based on example:
209
+ # https://github.com/MarshalX/atproto/blob/v0.0.56/examples/advanced_usage/send_ogp_link_card.py
210
+ _META_PATTERN = re .compile (r'<meta property="og:.*?>' )
211
+ _CONTENT_PATTERN = re .compile (r'<meta[^>]+content="([^"]+)"' )
212
+
213
+ def _get_og_tag_value (og_tags , tag_name ):
214
+ # tag = _find_tag(og_tags, tag_name)
215
+ for tag in og_tags :
216
+ if tag_name in tag :
217
+ match = _CONTENT_PATTERN .match (tag )
218
+ if match :
219
+ return match .group (1 )
220
+ return None
221
+
222
+ def _get_og_tags (url ):
223
+ response = httpx .get (url )
224
+ response .raise_for_status ()
225
+ og_tags = _META_PATTERN .findall (response .text )
226
+ og_image = _get_og_tag_value (og_tags , "og:image" )
227
+ og_title = _get_og_tag_value (og_tags , "og:title" )
228
+ og_description = _get_og_tag_value (og_tags , "og:description" )
229
+ return og_image , og_title , og_description
230
+
204
231
client = Client ()
205
232
client .login (BLUESKY_USERNAME , BLUESKY_TOKEN )
206
- client .send_post (text_builder )
233
+
234
+ # Process social media card
235
+ img_url , title , description = _get_og_tags (url )
236
+ if title and description :
237
+ thumb_blob = None
238
+ if img_url :
239
+ # Download image from og:image url and upload it as a blob
240
+ img_data = httpx .get (img_url ).content
241
+ thumb_blob = client .upload_blob (img_data ).blob
242
+
243
+ # AppBskyEmbedExternal is the same as "link card" in the app
244
+ embed_external = models .AppBskyEmbedExternal .Main (
245
+ external = models .AppBskyEmbedExternal .External (
246
+ title = title , description = description , uri = url , thumb = thumb_blob
247
+ )
248
+ )
249
+ client .send_post (text = text_builder , embed = embed_external )
250
+ else :
251
+ client .send_post (text_builder )
207
252
208
253
209
254
def main ():
@@ -239,7 +284,7 @@ def main():
239
284
flush = True ,
240
285
)
241
286
tweet_msg (formatted_tweet )
242
- skeet_msg (formatted_skeet )
287
+ skeet_msg (formatted_skeet , entry [ "url" ] )
243
288
print ("Sent Tweet and Skeet #{}!" .format (i ))
244
289
245
290
0 commit comments