Skip to content

Commit 88a1b15

Browse files
authored
Merge pull request #387 from knatten/bluesky-mastodon-x
Bluesky mastodon x
2 parents 3fef613 + 8544430 commit 88a1b15

File tree

1 file changed

+62
-22
lines changed

1 file changed

+62
-22
lines changed
Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import json
22
import sys
3+
import requests
4+
from datetime import datetime, timezone
35
from pathlib import Path
46

57
import tweepy
@@ -22,31 +24,69 @@ def handle(self, *args, **options):
2224
print(f"Publishing question {q}")
2325
q.state = 'PUB'
2426
q.save()
25-
socials_message = "No posts to social media"
2627
if (q.socials_text):
2728
if skip_socials:
2829
print("Skipping posting to social media!")
2930
else:
30-
socials_message = self.post_to_x(q.socials_text)
31-
mail_admins(f"Published question {q}", socials_message)
31+
self.post_to_x()
32+
self.post_to_bluesky(q.socials_text)
33+
self.post_to_mastodon(q.socials_text)
3234

33-
def post_to_x(self, content):
35+
def post_to_x(self):
36+
content = "We just published a new question! Follow us on Bluesky @cppquiz.bsky.social or Mastodon @cppquiz@mastodon.online for updates. For obvious reasons, no longer post to Elon Musk's X."
3437
print(f"Posting to X: '{content}'")
35-
try:
36-
secrets_file = Path.home() / ".cppquiz-secrets.json"
37-
with secrets_file.open() as f:
38-
secrets = json.load(f)
39-
40-
client = tweepy.Client(
41-
consumer_key=secrets["consumer_key"], consumer_secret=secrets["consumer_secret"],
42-
access_token=secrets["access_token"], access_token_secret=secrets["access_token_secret"],
43-
)
44-
response = client.create_tweet(
45-
text=content
46-
)
47-
post_url = f"https://x.com/user/status/{response.data['id']}"
48-
print(f"Posted {post_url}")
49-
return post_url
50-
except Exception as e:
51-
print(f"Failed to post '{content}' to X due to exception '{e}'")
52-
sys.exit(1)
38+
secrets = self.read_secrets()
39+
40+
client = tweepy.Client(
41+
consumer_key=secrets["consumer_key"], consumer_secret=secrets["consumer_secret"],
42+
access_token=secrets["access_token"], access_token_secret=secrets["access_token_secret"],
43+
)
44+
response = client.create_tweet(
45+
text=content
46+
)
47+
post_url = f"https://x.com/user/status/{response.data['id']}"
48+
49+
def post_to_bluesky(self, content):
50+
print(f"Posting to Bluesky: '{content}'")
51+
secrets = self.read_secrets()
52+
53+
resp = requests.post(
54+
"https://bsky.social/xrpc/com.atproto.server.createSession",
55+
json={"identifier": "cppquiz.bsky.social", "password": secrets["bsky_password"]},
56+
)
57+
resp.raise_for_status()
58+
session = resp.json()
59+
60+
now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
61+
post = {
62+
"$type": "app.bsky.feed.post",
63+
"text": content,
64+
"createdAt": now,
65+
}
66+
67+
resp = requests.post(
68+
"https://bsky.social/xrpc/com.atproto.repo.createRecord",
69+
headers={"Authorization": "Bearer " + session["accessJwt"]},
70+
json={
71+
"repo": session["did"],
72+
"collection": "app.bsky.feed.post",
73+
"record": post,
74+
},
75+
)
76+
resp.raise_for_status()
77+
78+
def post_to_mastodon(self, content):
79+
print(f"Posting to Mastodon: '{content}'")
80+
secrets = self.read_secrets()
81+
82+
url = "https://mastodon.online/api/v1/statuses"
83+
auth = {"Authorization": f"Bearer {secrets['mastodon_token']}"}
84+
params = {"status": content}
85+
86+
r = requests.post(url, data=params, headers=auth)
87+
r.raise_for_status()
88+
89+
def read_secrets(self):
90+
secrets_file = Path.home() / ".cppquiz-secrets.json"
91+
with secrets_file.open() as f:
92+
return json.load(f)

0 commit comments

Comments
 (0)