Posting text and images to Mastodon
Tutorial – Mastodon
Creating a custom application that toots text to Mastodon (the Fediverse's version of Twitter) is simple and straightforward. But we can mix it up by adding images and video, scheduling posts, and changing privacy settings.
If you haven't read the prior article in this series [1], you may want to do that now. There, you will learn how to read from a Mastodon feed and print out the toots (the name Mastodon gives its posts) onto the command line. You can do that quite easily with Python, because the API for Mastodon is open and well documented, and also because there is a comprehensive Python wrapper [2] that makes building ad hoc clients a breeze.
In this article, we're going a step further, and you will see how to create an app that posts your toots. Before you start, and just in case you haven't already, install the Mastodon.py
module with
pip install Mastodon.py
and let's get started.
Registering
As with your reading application, the first thing you have to do is register your application with Mastodon (Listing 1).
Listing 1
posttoots_register.py
01 #!/usr/bin/env python 02 03 from mastodon import Mastodon 04 05 Mastodon.create_app( 06 'posttoots', 07 api_base_url = 'https://your.mastodon.server', 08 scopes=['read', 'write'], 09 to_file = '.secrets' 10 ) 11 12 mastodon = Mastodon ( 13 client_id = '.secrets', 14 ) 15 16 print ('Mastodon version: ' + mastodon.retrieve_mastodon_version())
You only have to run this once. It registers the posttoots
application (line 6) with https://your.mastodon.server
(line 7 – insert the server hosting your account here), sets its scope to 'read'
and 'write'
so you can both post to an account and also read information off the server (line 8), and grabs some credentials and stores them in a hidden file called .secrets
(line 9).
Although it does not affect the registration, you can tack on lines 12 through 16. Lines 12, 13, and 14 check to see if the app can be activated using the downloaded credentials in .secrets
and line 16 tells you what version of Mastodon your server is using. This can be useful if your program relies on features available on the very latest Mastodon, but your server has not updated yet.
You only need to run posttoots_register.py
once as you can use the credentials stored in .secrets
over and over. .secrets
(Listing 2) contains a client_id
(line 1) and a client_secret
(line 2) that you will be able to use to identify your application each time it has to interact with the Mastodon instance. On line 3 you also have the address of the instance the app is registered with, which is convenient as you will see later on.
Listing 2
.secrets
01 53eM1n9lyHR4nd0mUnUMB3r5vAN6G133TeR5X4g 02 KM0r340FdTh3p54M3A60nTnUkKN0WC0hweMigLcng6U 03 https://your.mastodon.server
So, posting is very straightforward. Consider Listing 3.
Listing 3
posttoots.py (Basic)
01 #!/usr/bin/env python 02 03 import sys 04 from mastodon import Mastodon 05 06 mastodon = Mastodon ( 07 client_id = '.secrets', 08 ) 09 10 mastodon.access_token = mastodon.log_in ( 11 username = sys.argv[1], 12 password = sys.argv[2], 13 scopes = ['read', 'write'] 14 ) 15 16 mastodon.status_post (sys.argv[3])
After pulling in sys
(to process the command-line arguments – line 3) and Mastodon
(for everything else – line 4), you activate your app with the Mastodon server (lines 6 through 8). You could insert here the client_id
, client_secret
, and the host, but we have all that in the .secrets
file, remember? So all you have to do is point to that (line 7).
Then you need to log in with your username and password so the application posts to a specific account (lines 10 through 14). Pass your username
and password
to the application and the value of scopes
. I am not sure why you have to add the latter, but if you don't, the login fails. The value of scopes
must be the same as what you used when registering your application in Listing 1. Finally, on line 16, you post a message using Mastodon.py
's status_post()
function.
You can use posttoots.py like this:
./posttoots.py youremail@here.com "Your awesome password" "Tooting from the command line with my own app!"
And "Tooting from the command line with my own app!" will pop up in your feed (Figure 1).
That's it. The end. See you next issue…
Beyond Simple
Well, not really, because there is so much more you can do when posting. You can, for example, append an image or a video, schedule your toots so they are posted automatically at a later date (easier said than done), set the visibility of each toot, and quite a bit more. To see how all of the above is achieved, consider Listing 4.
Listing 4
posttoots.py (Advanced)
01 #!/usr/bin/env python 02 03 import datetime 04 import cv2 05 from optparse import OptionParser 06 from mastodon import Mastodon 07 08 class post: 09 def __init__ (self, vUser, vPassword): 10 f_read = open(".secrets", "r") 11 instance = f_read.readlines()[-1].strip(" \n") 12 f_read.close() 13 14 self.mastodon = Mastodon( 15 client_id = '.secrets', 16 api_base_url = instance 17 ) 18 19 self.mastodon.access_token = self.mastodon.log_in( 20 username = vUser, 21 password = vPassword, 22 scopes = ['read', 'write'], 23 to_file = '.token' 24 ) 25 26 self.post_date = None 27 28 def send (self, vToot, vMedia, vVis): 29 self.mastodon.status_post(vToot, media_ids = vMedia, scheduled_at = self.post_date, visibility = vVis) 30 31 def add_Media (self, vMedia): 32 return (self.mastodon.media_post (vMedia)) 33 34 def set_date (self, vDate): 35 try: 36 self.post_date = datetime.datetime.strptime(vDate, '%b %d %Y %H:%M %Z') 37 except: 38 self.post_date = None 39 40 def show_scheduled (self): 41 print (self.mastodon.scheduled_statuses()) 42 43 if __name__ == '__main__': 44 parser = OptionParser() 45 parser.add_option ('-a', '--action', help = '"post", "schedule" or "list"', dest = 'vAction', default = 'list') 46 parser.add_option ('-u', '--username', help = 'user\'s email', dest = 'vUser') 47 parser.add_option ('-p', '--password', help = 'user\'s password', dest = 'vPassword') 48 parser.add_option ('-t', '--toot', help = 'toot text', dest = 'vToot') 49 parser.add_option ('-m', '--media', help = 'media ("cam" or image, video, etc.)', dest = 'vMedia', default = None) 50 parser.add_option ('-w', '--when', help = 'when to publish toot. Format: "mmm dd YYYY HH:MM Z"', dest = 'vWhen', default = None) 51 parser.add_option ('-v', '--visibility',help = '"public", "unlisted", "private" or "direct"', dest = 'vVis', default = 'public') 52 53 (options, args) = parser.parse_args() 54 55 p=post(options.vUser, options.vPassword) 56 57 mmedia = options.vMedia 58 if mmedia != None: 59 if mmedia == "cam": 60 camera=cv2.VideoCapture(0) 61 return_value, image =camera.read() 62 cv2.imwrite("pic.png", image) 63 del(camera) 64 mmedia="pic.png" 65 66 mmedia = p.add_Media(mmedia) 67 68 if options.vAction == 'post': 69 p.send (options.vToot, mmedia, options.vVis) 70 71 elif options.vAction == 'schedule': 72 p.set_date (options.vWhen) 73 p.send (options.vToot, mmedia, options.vVis) 74 75 else: 76 p.show_scheduled()
You can divide the program into 5 distinct sections:
- Line 1 sets the interpreter for the program.
- Lines 3 through 6 pull in the modules you'll need. The
datetime
module lets you convert strings to dates. You will need this when you want to parse dates passed on by the user to schedule toots. Thecv2
module is the Python implementation of OpenCV [3], the library that will allow you to capture an image from your webcam. As you need to parse quite a few parameters to make life easier for the user, let's useoptparse
too. Finally, we import themastodon
module. - Lines 8 through 41 is the class that does all the dirty work of activating the app, posting, and scheduling.
- Lines 44 through 53 collect and allocate all the options the user inputs from the command line.
- Finally, lines 55 through 76 call the functions we need depending on the input from the user.
To go into detail, let's see how we can post an image within a toot.
Posting Pictures
One nice feature that comes bundled with optparse
is how it provides help for the user. Run this:
./ postoots.py -h
And you'll get a summary of the possible options and hints as to how to use them.
To start with, -h
tells you to input your username (the email associated with your Mastodon account) with the -u
option and your password with the -p
option.
The -a
option tells your app what you want to do. You can choose between post
(send a toot), schedule
(schedule a toot for later), or list
(list all the scheduled toots). As you want to send a toot with an image, use post
here.
The -t
option contains the text for the toot, and -m
contains the path and name of the media (picture) you want to send. Given all of the above, your complete command line will look like this:
./posttoots.py -u youremail@here.com -p "Your awesome password" -a post -t "Tooting an image from the command line with my own app!" -m /path/to/image.png
Looking at Listing 4, once you hit Enter, the pairs of options and values from the command-line arguments get dumped into (options, args)
(line 53), and the Mastodon object is initiated with your username and password (line 55). The initialization function (lines 9 to 26), takes the URL of the Mastodon instance, client_id
and client_secret
from the .secrets
file (lines 10 to 17), logs the application in (lines 19 to 24), and sets the post_date
attribute to None
(line 26).
You will have noticed that the program gets the URL of the Mastodon instance in a very roundabout way. Instead of just loading all the values in from .secrets
, including the URL, into client_id
, we do this convoluted thing of opening the .secrets
file (line 10), dumping the contents of the last line into instance
(line 11), and then closing the file (line 12).
The reason for this is that there seems to be a bug in Mastodon.py
that appears when you try to use scheduling: If you rely on a file to load in your instance's URL, anything to do with scheduling will fail with an error complaining about the version of Mastodon running on the server, or some such nonsense. The workaround is setting the URL explicitly on line 16.
This is not the only problem with scheduling as we will see later, but let's get back down into the main body of the program where, on line 58, you check to see if the user has given a path and filename of a media file. If they have, you add the media file to the toot object (line 66 and then lines 31 and 32).
Finally the toot, along with the media, is sent on line 69 by calling the actual Mastodon sending function on lines 28 and 29 (Figure 2).
You can add up to four images to a toot, as well as videos and other kinds of files.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Thousands of Linux Servers Infected with Stealth Malware Since 2021
Perfctl is capable of remaining undetected, which makes it dangerous and hard to mitigate.
-
Halcyon Creates Anti-Ransomware Protection for Linux
As more Linux systems are targeted by ransomware, Halcyon is stepping up its protection.
-
Valve and Arch Linux Announce Collaboration
Valve and Arch have come together for two projects that will have a serious impact on the Linux distribution.
-
Hacker Successfully Runs Linux on a CPU from the Early ‘70s
From the office of "Look what I can do," Dmitry Grinberg was able to get Linux running on a processor that was created in 1971.
-
OSI and LPI Form Strategic Alliance
With a goal of strengthening Linux and open source communities, this new alliance aims to nurture the growth of more highly skilled professionals.
-
Fedora 41 Beta Available with Some Interesting Additions
If you're a Fedora fan, you'll be excited to hear the beta version of the latest release is now available for testing and includes plenty of updates.
-
AlmaLinux Unveils New Hardware Certification Process
The AlmaLinux Hardware Certification Program run by the Certification Special Interest Group (SIG) aims to ensure seamless compatibility between AlmaLinux and a wide range of hardware configurations.
-
Wind River Introduces eLxr Pro Linux Solution
eLxr Pro offers an end-to-end Linux solution backed by expert commercial support.
-
Juno Tab 3 Launches with Ubuntu 24.04
Anyone looking for a full-blown Linux tablet need look no further. Juno has released the Tab 3.
-
New KDE Slimbook Plasma Available for Preorder
Powered by an AMD Ryzen CPU, the latest KDE Slimbook laptop is powerful enough for local AI tasks.