The federated Mastodon social network has gotten very popular lately. It's fun to post on social media, but it's also fun to automate your interactions. There is some documentation of the client-facing API, but it's a bit light on examples. This article aims to help with that.
You should be fairly confident with Python before trying to follow along with this article. If you're not comfortable in Python yet, check out Seth Kenlon's Getting started with Python article and my Program a simple game article.
Create an application
The first step is to go to Preferences in Mastodon and select the Development category. In the Development panel, click on the New Applications button.
After creating an application, copy the access token. Be careful with it. This is your authorization to post to your Mastodon account.
There are a few Python modules that can help.
- The httpx module is useful, given that it is a web API.
- The
getpass
module allows you to paste the token into the session safely. - Mastodon uses HTML as its post content, so a nice way to display HTML inline is useful.
- Communication is all about timing, and the
dateutil
andzoneinfo
modules will help deal with that.
Here's what my typical import list looks like:
import httpx
import getpass
from IPython.core import display
from dateutil import parser
import zoneinfo
Paste in the token into the getpass
input:
token=getpass.getpass()
Create the httpx.Client
:
client = httpx.Client(headers=dict(Authorization=f"Bearer {token}"))
The verify_credentials method exists to verify that the token works. It's a good test, and it gives you useful metadata about your account:
res = client.get("https://mastodon.social/api/v1/accounts/verify_credentials")
You can query your Mastodon identity:
res.raise_for_status()
result = res.json()
result["id"], result["username"]
>>> ('27639', 'moshez')
Your mileage will vary, but you get your internal ID and username in response. The ID can be useful later.
For now, abstract away the raise_for_status and parse the JSON output:
def parse(result):
result.raise_for_status()
return result.json()
Here's how this can be useful. Now you can check your account data by ID. This is a nice way to cross-check consistency:
result = parse(client.get("https://mastodon.social/api/v1/accounts/27639"))
result["username"]
>>> 'moshez'
But the interesting thing, of course, is to get your timeline. Luckily, there's an API for that:
statuses = parse(client.get("https://mastodon.social/api/v1/timelines/home"))
len(statuses)
>>> 20
It's just a count of posts, but that's enough for now. There's no need to deal with paging just yet. The question is, what can you do with a list of your posts? Well, you can query it for all kinds of interesting data. For instance, who posted the fourth status?
some_status = statuses[3]
some_status["account"]["username"]
>>> 'donwatkins'
Wonderful, a tweet from fellow Opensource.com correspondent Don Watkins! Always great content. I'll check it out:
display.HTML(some_status["content"])
<p>Just finished installed <span class="h-card"><a href="https://fosstodon.org/@fedora" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@<span>fedora</span></a></span> <a href="https://fosstodon.org/tags/Silverblue" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Silverblue</span></a> 37 on <span class="h-card"><a href="https://fosstodon.org/@system76" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@<span>system76</span></a></span> <a href="https://fosstodon.org/tags/DarterPro" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>DarterPro</span></a></p>
"Just" finished? Wait, when was this tweet posted? I live in California, so I want the time in my local zone:
california = zoneinfo.ZoneInfo("US/Pacific")
when = parser.isoparse(some_status["created_at"])
print(when.astimezone(california))
>>> 2022-12-29 13:56:56-08:00
Today (at the time of this writing), a little before 2 PM. Talk about timeliness.
Do you want to see the post for yourself? Here's the URL:
some_status["url"]
>>> 'https://fosstodon.org/@donwatkins/109599196234639478'
Enjoy tooting, now with 20% more API!
2 Comments