Skip to content

Commit

Permalink
Action: Add social media cards to BlueSky posts.
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosperate committed Jan 3, 2025
1 parent 4c433d2 commit 7017c12
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 23 deletions.
1 change: 1 addition & 0 deletions .github/actions/tweet-commit/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
twitter_secrets.py
bluesky_secrets.py
67 changes: 56 additions & 11 deletions .github/actions/tweet-commit/post_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

from git import Repo
import tweepy
from atproto import Client, client_utils
from atproto import Client, client_utils, models
import httpx


# Getting the Twitter secrets form local dev file or GH action secrets
Expand All @@ -27,10 +28,6 @@
TWITTER_ACCESS_TOKEN,
TWITTER_ACCESS_TOKEN_SECRET,
)
from bluesky_secrets import (
BLUESKY_USERNAME,
BLUESKY_TOKEN,
)
except ImportError:
TWITTER_CONSUMER_KEY = os.environ.get("INPUT_TWITTER_CONSUMER_KEY", None)
TWITTER_CONSUMER_SECRET = os.environ.get(
Expand All @@ -40,6 +37,12 @@
TWITTER_ACCESS_TOKEN_SECRET = os.environ.get(
"INPUT_TWITTER_ACCESS_TOKEN_SECRET", None
)
try:
from bluesky_secrets import (
BLUESKY_USERNAME,
BLUESKY_TOKEN,
)
except ImportError:
BLUESKY_USERNAME = os.environ.get("INPUT_BLUESKY_USERNAME", None)
BLUESKY_TOKEN = os.environ.get("INPUT_BLUESKY_TOKEN", None)

Expand Down Expand Up @@ -181,7 +184,7 @@ def format_msg_bluesky(section, title, url, description):
description = format_use_hashtags(description)

# Now let's make sure we don't exceed the max character limit
msg = "{}\n\n{}\n{}".format(section, title, description)
msg = "{} - {}\n\n{}".format(section, title, description)
if len(msg) > BLUESKY_MAX_CHARS:
ellipsis = "..."
characters_over = len(msg) - BLUESKY_MAX_CHARS + len(ellipsis)
Expand All @@ -190,20 +193,62 @@ def format_msg_bluesky(section, title, url, description):
)

text_builder = client_utils.TextBuilder()
text_builder.text(section + "\n\n")
text_builder.text(section + " - ")
text_builder.link(title, url)
text_builder.text("\n" + description)
text_builder.text("\n\n" + description)
return text_builder


def skeet_msg(text_builder):
def skeet_msg(text_builder, url):
"""Post to BluSky the given message content."""
if not all((BLUESKY_USERNAME, BLUESKY_TOKEN)):
print("BlueSky username or token not available.")
sys.exit(1)

# Posting Open Graph Protocol (OGP) social media cards, based on example:
# https://github.com/MarshalX/atproto/blob/v0.0.56/examples/advanced_usage/send_ogp_link_card.py
_META_PATTERN = re.compile(r'<meta property="og:.*?>')
_CONTENT_PATTERN = re.compile(r'<meta[^>]+content="([^"]+)"')

def _get_og_tag_value(og_tags, tag_name):
# tag = _find_tag(og_tags, tag_name)
for tag in og_tags:
if tag_name in tag:
match = _CONTENT_PATTERN.match(tag)
if match:
return match.group(1)
return None

def _get_og_tags(url):
response = httpx.get(url)
response.raise_for_status()
og_tags = _META_PATTERN.findall(response.text)
og_image = _get_og_tag_value(og_tags, "og:image")
og_title = _get_og_tag_value(og_tags, "og:title")
og_description = _get_og_tag_value(og_tags, "og:description")
return og_image, og_title, og_description

client = Client()
client.login(BLUESKY_USERNAME, BLUESKY_TOKEN)
client.send_post(text_builder)

# Process social media card
img_url, title, description = _get_og_tags(url)
if title and description:
thumb_blob = None
if img_url:
# Download image from og:image url and upload it as a blob
img_data = httpx.get(img_url).content
thumb_blob = client.upload_blob(img_data).blob

# AppBskyEmbedExternal is the same as "link card" in the app
embed_external = models.AppBskyEmbedExternal.Main(
external=models.AppBskyEmbedExternal.External(
title=title, description=description, uri=url, thumb=thumb_blob
)
)
client.send_post(text=text_builder, embed=embed_external)
else:
client.send_post(text_builder)


def main():
Expand Down Expand Up @@ -239,7 +284,7 @@ def main():
flush=True,
)
tweet_msg(formatted_tweet)
skeet_msg(formatted_skeet)
skeet_msg(formatted_skeet, entry["url"])
print("Sent Tweet and Skeet #{}!".format(i))


Expand Down
20 changes: 8 additions & 12 deletions .github/actions/tweet-commit/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ def test_commit_1(self):
)
self.assertEqual(
skeet.build_text(),
"MicroPython Libraries\n\n"
"MB1013\n"
"MicroPython Libraries - MB1013\n\n"
"Module for the MB1013 ultrasonic sensor controlled via UART.",
)

Expand Down Expand Up @@ -197,8 +196,7 @@ def test_commit_6(self):
)
self.assertEqual(
skeet.build_text(),
"📱 Mobile Apps\n\n"
"Official Swift Playgrounds\n"
"📱 Mobile Apps - Official Swift Playgrounds\n\n"
"([Source Code](https://github.com/microbit-foundation/"
"microbit-swift-playgrounds)) "
"Swift Playgrounds is an app for the iPad that helps teach people "
Expand Down Expand Up @@ -327,7 +325,7 @@ def test_msg_format_max_length(self):
"s" * 9, "t" * 12, "u" * 23, ("d" * 230) + "."
)
skeet = post_commit.format_msg_bluesky(
"s" * 8, "t" * 9, "u" * 100, ("d" * 279) + "."
"s" * 7, "t" * 8, "u" * 100, ("d" * 279) + "."
)

self.assertEqual(len(tweet), 280)
Expand All @@ -343,7 +341,7 @@ def test_msg_format_max_length(self):
self.assertEqual(len(skeet.build_text()), 300)
self.assertEqual(
skeet.build_text(),
("s" * 8) + "\n\n" + ("t" * 9) + "\n" + ("d" * 279) + ".",
("s" * 7) + " - " + ("t" * 8) + "\n\n" + ("d" * 279) + ".",
)

def test_msg_format_over_length(self):
Expand All @@ -357,7 +355,7 @@ def test_msg_format_over_length(self):
"s" * 9, "t" * 12, "u" * 23, "dd " * 1000
)
skeet = post_commit.format_msg_bluesky(
"s" * 8, "t" * 9, "u" * 100, "dd " * 1000
"s" * 7, "t" * 8, "u" * 100, "dd " * 1000
)

self.assertEqual(len(tweet), 279)
Expand All @@ -374,7 +372,7 @@ def test_msg_format_over_length(self):
self.assertEqual(len(skeet.build_text()), 298)
self.assertEqual(
skeet.build_text(),
("s" * 8) + "\n\n" + ("t" * 9) + "\n" + ("dd " * 91) + "dd...",
("s" * 7) + " - " + ("t" * 8) + "\n\n" + ("dd " * 91) + "dd...",
)

def test_long_tweet(self):
Expand Down Expand Up @@ -419,8 +417,7 @@ def test_long_tweet(self):
)
self.assertEqual(
skeet.build_text(),
"Miscellaneous\n\n"
"Radiobit, a BBC Micro:Bit RF firmware\n"
"Miscellaneous - Radiobit, a BBC Micro:Bit RF firmware\n\n"
"Radiobit is composed of a dedicated #MicroPython-based firmware "
"and a set of tools allowing security researchers to sniff, "
"receive and send data over Nordic's ShockBurst protocol, "
Expand Down Expand Up @@ -693,8 +690,7 @@ def test_commit_replace_makecode_2(self):
)
self.assertEqual(
skeet.build_text(),
"MakeCode Libraries\n\n"
"CCS811\n"
"MakeCode Libraries - CCS811\n\n"
"#MakeCode Package for the CCS811 Air Quality Sensor.",
)

Expand Down

0 comments on commit 7017c12

Please sign in to comment.