Mastotron is a different interface to Mastodon, replacing the mindless "feed" of most social media with a network map of conversations and recent and popular posts.
Mastotron-v1c.mov
Right now Mastotron is a desktop application rather than a website you can navigate to right away. This is primarily so that the (already minimal) data it collects stays entirely on your hardware rather than on a server somewhere. That makes it safer and free to run: no server costs, less risk of hacking, etc.
Maybe one day we could make a mobile app, though the graphical interface would probably need to be redesigned.
Thankfully installation is working normally here, though you'll need to convince MacOS to open an app from an "unidentified developer" (more info).
- Download the latest zip file release (
Mastotron-macos.zip
) - Unzip the file to reveal
Mastotron.app
- Hold control (⌃) and click the file; click "Open" in the menu; then click "open" again at the prompt
- If this doesn't work, try going to System Preferences->Security and "allow" it to run.
- If this doesn't work, try moving the app to your /Applications folder. (Feel free to do that regardless.)
- Wait for the window to appear (this is slow; could take a minute+)
As of Release v1, the builtin mini browser isn't working for linux users, but it works just as fine in your own browser with mastotron running in the background:
- Install python
- Install mastotron via pip (run just once):
pip3 install -U git+https://github.com/mastotron/mastotron
- Run
mastotron --bg
- Then, in your favorite browser, navigate to http://localhost:1789.
Like linux, so far you'll have to run mastotron in the background and then use your own browser to view it:
- Install Miniconda3
- Open up Anaconda Powershell Prompt from the Start menu
- Install by pasting in this:
pip3 install -U git+https://github.com/mastotron/mastotron
- Then run Mastotron by typing:
mastotron --bg
- Then, in your favorite browser, navigate to http://localhost:1789.
- Hover over a node to read the post.
- Right-click it or press (C) to load its replies.
- Press (D) to dismiss it or "mark it as read".
- Crucially, a dismissed post will never re-appear. This is good! It means you can "mark as read" a post and by never seeing it again you can trust that more of your timeline is new content.
- Press (N) for next batch in queue.
- Press (L) for latest in queue.
- Press (R) to query mastodon to find 3 new posts not in graph or queue.
- Press (Cmd+R) to query mastodon to find 10 new posts not in graph or queue.
- Press (P) to pause/play the animation.
from mastotron import Tron
me = 'me@myserver.com'
posts = Tron().timeline(me)
There are a few different processes happening once you boot up:
- The backend (written in python) makes sure you're logged in and the account name is set locally: if not, it redirects you to the login page.
- Once the frontend (written in javascript) boots up, it sends a request to the backend for
N
posts (set by#
button on lefthand side) - Once the backend hears from the frontend, it starts up a few processes:
- A separate 'listener' thread is created which connects to your mastodon server's Streaming API for real-time brand-new push updates
- A separate 'crawler' thread which, after a 60 second delay, will request the last 10 posts from your mastodon server every 60 seconds. (This is a separate thread so your communication with the mastodon server about the latest posts is kept separate from the normal request operations)
- Then the next, normal request operation is performed:
- Whenever the backend is asked for updates, it starts iterating backwards over 5-minute intervals, starting from now and rounding down (if it's 5:43pm, it starts at 5:35-5:40, then 5:30-35, and so n)
- For each of these 5 minute intervals, it either...
- requests your mastodon account's server for any timeline post in that 5-minute interval, and then caches the result
- or, if that 5-minute interval was requested previously and cached, it returns the cached result
- As these results come in, it pushes each one immediately to the frontend
- For each of these 5 minute intervals, it either...
- Whenever the frontend receives a new post from the backend, it thinks through these steps:
- Do I have as many nodes in the graph right now as I want to (set by
#
on lefthand side)?- No? then display this post immediately on the graph.
- Yes? then proceed to next step
- Is this a special kind of update?
- Is this a 'force push' update? (e.g. when replies are requested via right-click or (C)
- then add it directly to the graph, booting off the least recent one if necessary to stay under the
#
limit
- then add it directly to the graph, booting off the least recent one if necessary to stay under the
- Is this a 'background' update? (e.g. from the crawler process above)
- then proceed to next step
- Is this a 'force push' update? (e.g. when replies are requested via right-click or (C)
- Otherwise, add to the "queue" stored on the frontend
- (For now, this queue stores a maximum 200 posts; the most recent 200 sent from the backend are preserved)
- Do I have as many nodes in the graph right now as I want to (set by
- In addition, every X seconds (set by the
⟤
button on the left-hand side),turnover_nodes()
occurs- This just brings in the latest addition to the queue into the graph, booting back into the queue the least recent post on the graph
- Crucially, this means that you are not querying your mastodon server every X (default: 5) seconds: it's just a front-end animation
- When the turnover animation is active, you can turn it off by pressing the
■
on the left-hand side; when paused, you can re-activate it by pressing the▶
key.
- This just brings in the latest addition to the queue into the graph, booting back into the queue the least recent post on the graph
- Finally, every 60 seconds an update is requested from the server, which will follow the logic of step 4 above.
Now that I've typed this all out I can see it's a bit over-complicated. I've created an issue here if you have thoughts on how to simplify it.
Code here mainly. It's my (simple but probably clunky) javascript adaptation of visjs to display the nodes and edges and labels and images of the posts.
Code here. Running flask and communicating with the front-end via HTTP (only to serve the initial HTML and CSS and javascript) and subsequently via realtime web sockets (through flask-socketio).
Code here mainly. This interfaces with mastodon.py (which is a python implementation of the Mastodon API) to read and cache posts from your timeline. Mastotron's only innovation here is laid out in step 4 of the section above, which is to query for 5 minute intervals and cache the results; this ensures minimal requests to your mastodon server.
Mastodon is weird. Sorry. I'm new to it. The account and post URIs it gives you are relative to your local server but there is no simple way to translate between URIs and ones on the server for the account it posted from. This is a problem for understanding relations between posts across URIs:
- If post-A-from-server-X is a reply to post-B-from-server-Y, then in order to load other replies to post-B-on-server-Y (such as post-C-from-server-Z) you need to ask server Y for the "context" of post B.
- Server Y will then give you a bunch of IDs which make sense only to server Y:
- Server X (where our user is located) has no idea what they mean!
- Server Z (where the author of the reply is located) also has no idea what they mean!
Mastotron tries hard to figure all this out by storing post URLs and their relations in a mini graph database known as cogdb. Here a node is any post URL, on any server, which may have relations with other post URLs including IS_LOCAL_FOR
(is a local URL for the URL of the post), IS_BOOST_OF
, and IS_REPLY_TO
(self-explanatory).
That way it's possible to ask of any post, what posts have replied to me, even if the replies are expressed in IDs across different servers. (It does that in graph-speak by asking what incoming edges both the local URL of a post and its "remote" URL on its own server have.) Which posts have boosted me? And so on. All those facts are discovered in a few different ways each of which returns IDs from different servers (e.g., as described above, a post which is a reply will give you a reply ID from the timeline server but the context API will give you an ID from the poster's server, etc). Because of that, we thought it'd be better to store those facts in a graph database so you can ask questions like "who replied to this post" with minimal querying of mastodon – but let us know if you think of a saner way to navigate the fediverse from within python and the app.
Please do! You can report bugs and ask questions on the issues page. Pull requests are always welcome and encouraged. It's fantastic that Mastotron has received interest and we'd love for it to be a wide, collective, open source endeavor as much as posssible!