<h2 id="episode-4---embed-mastodon-threads">Episode 4 - Embed Mastodon
Threads</h2>
<p>This is Episode 4 of the Plain Text Programs Podcast hosted at Hacker
Public Radio. As always I will include links with the show notes rather
than reading them on the podcast except there will be one exception to
that today, the link to my Plain Text Blog, home.gamerplus.org.</p>
<p>My blog and this podcast were my inspiration for writing the Embed
Mastodon Threads program. Besides posting the show notes at Hacker
Public Radio where they have a comments section I also post them at my
blog. Then I make a Mastodon post that includes a link to the show notes
on my blog and designate it as being the comment thread for that episode
of the podcast. I also post a link to the comment thread on Mastodon in
my show notes. Or at least I did in the past.</p>
<p>It came to mind that it would be nice to be able to display the
comment thread at the bottom of the blog post. So I made a Mastodon post
about this, and I quote.</p>
<blockquote>
<p>So here's my idea.</p>
<p>I want to use mastodon toots as a comment thread for my blog
posts.</p>
<p>At the bottom of the blog post I want to embed the toot and the
replies.</p>
<p>I can pull the toot id from the embed code.</p>
<p>Then I want to make a database query to get all the replies to that
toot.</p>
<p>Then I can generate the embed codes needed to show the toot and all
the replies.</p>
<p>I'm a mysql guy, not postgres. Also a Mastodon newb.</p>
<p>I want to know how to get the reply ids for a toot.</p>
<p>Any help, links, etc?</p>
<p>End quote.</p>
</blockquote>
<p>I immediately got responses from some programmers expressing interest
in the idea and giving good advice.</p>
<p>I did some research based on their suggestions. I had a good night's
sleep. And then I made another post in the morning. And I quote.</p>
<blockquote>
<p>Mastodon is so great.</p>
<p>I had this idea last night and fiddled around with it long enough to
realize I was doing it wrong.</p>
<p>So I made a post on Mastodon and almost immediately got help.</p>
<p>I found some good info on the Mastodon API.</p>
<p>I wake up this morning to more help and I found out about using curl
in php to make https requests.</p>
<p>Then a musician friend of mine who I've been following since before
Mastodon sends a working example, with code, in a javascript
environment.</p>
<p>And I've got a plan.</p>
<p>End quote.</p>
</blockquote>
<p>So credit where credit is due.</p>
<p>The programmers, gamers, and musicians helping me were:</p>
<p>Jeff the GenX Alien<br />
<span class="citation" data-cites="jeff">@jeff</span><span
class="citation"
data-cites="soapbox.hackdefendr.com">@soapbox.hackdefendr.com</span></p>
<p>EcksDy<br />
<span class="citation" data-cites="EcksDy">@EcksDy</span><span
class="citation" data-cites="techtoots.com">@techtoots.com</span></p>
<p>Malin<br />
<span class="citation" data-cites="malin">@malin</span><span
class="citation" data-cites="dice.camp">@dice.camp</span></p>
<p>and</p>
<p>Wayne Myers<br />
<span class="citation" data-cites="conniptions">@conniptions</span><span
class="citation"
data-cites="mastodon.social">@mastodon.social</span></p>
<p>Now, I've known Wayne Myers since before I was ever on Mastodon. We
share an interest in free culture music and I have played his songs on
my radio show, Something Blue, recorded by his band, Fit and the
Conniptions.</p>
<p>He sent some links in a couple of comments to other blogs that were
embedding Mastodon threads which confirmed that my idea could work.</p>
<p>Jeff the GenX Alien gave me some significant technical help. And I
quote.</p>
<blockquote>
<p>Use tootcli to learn everything you need to know about the inner
workings of Mastodon.</p>
<p><a href="https://github.com/ihabunek/toot"
class="uri">https://github.com/ihabunek/toot</a></p>
<p>Whatever the API supports so does toot.</p>
<p>End quote.</p>
</blockquote>
<p>So I looked into tootcli and the Mastodon API and I realized that I
didn't need to access the database for my program, I could just use the
API.</p>
<p>So, thanks Jeff.</p>
<p>My second clue came from EcksDy. And I quote.</p>
<blockquote>
<p>I've got some help too. Using the Mastodon API and curl in php it
should be doable.</p>
<p>End quote.</p>
</blockquote>
<p>So then I started to research using curl in PHP to retrieve json data
from the Mastodon API and that's what I went with.</p>
<p>I set up a testbed and Malin chimed in with test results. He
continued to help with testing and ideas throughout the rest of the
project.</p>
<p>That's why Mastodon is so great! Way better than consulting an AI
bot.</p>
<p>So I had my work cut out for me. Here is where this program is like
my Plain Text Programs. I work hard, up front, until I am convinced that
I have an idea that will be easy to implement. This is much easier than
doing it the hard way first and then rewriting the program later after
it becomes difficult to maintain.</p>
<p>I said I had a plan. This was my plan.</p>
<p>Write a PHP program that will generate a webpage that can be embedded
in an iframe. This program will take a link as a parameter included in
the url.</p>
<p>Get that link from the Mastodon embed code for the parent post.</p>
<p>Use the API to retrieve the data associated with the parent post
including the replies.</p>
<p>Then generate the page by inserting the appropriate data into
Mastodon's existing embed structure.</p>
<p>That's kind of a broad framework but it certainly seemed doable. And
it was.</p>
<p>So first I wanted to make the API call so I could look at the
data.</p>
<p>I found this video by Alejandro AO.</p>
<p>How to easily create cURL API requests in PHP (Wordpress, Laravel,
Symfony) <a
href="https://www.youtube.com/watch?v=iRLgEWMNA6w&amp;t=602s"
class="uri">https://www.youtube.com/watch?v=iRLgEWMNA6w&amp;t=602s</a></p>
<p>He recommended that you use curl in the terminal to test your API
call. Then you use a web app called Curl-to-PHP to generate your PHP
code to make the same API call from your program.</p>
<p>My first time consuming stumbling block was what I call the problem
with the colon.</p>
<p>There are some great documents detailing the syntax for API calls
which I will link to in the show notes.</p>
<p>And where you are supposed to insert an id they show that as :id.</p>
<p>Like an idiot I thought the colon was part of the syntax, not as they
intended, a marker to indicate insert your id here. This is why I like
to see actual code examples in syntax documents.</p>
<p>Anyway I couldn't get it to work so I searched around until I found
some code examples and that turned on the lightbulb in my head.</p>
<p>Now I was able to make API calls using curl in the terminal. I copied
the working curl command and pasted it into the Curl-to-PHP website and
it output some code. And it worked! Which I was very glad about because
previous research into how to make API calls with PHP was confusing to
say the least. Sometimes PHP gifts you with and abundance of riches
which doesn't always make life easier.</p>
<p>So I made my API call from my program. The Curl-to-PHP code returned
$result. And then I used the json_decode command to turn the result
string into an array of Mastodon data.</p>
<p><code>$obj = json_decode($result, true);</code></p>
<p>And I could use the print_r command to look at that data.</p>
<p><code>print_r($obj);</code></p>
<p>I immediately put the print_r command at the bottom of my program
where it resides today as commented out debug code. This way while I was
looking at my program output I could just scroll down or search to find
what the actual data looked like.</p>
<p>So I fumbled around for a while before I figured out that I would
need the id and the url to make my idea work.</p>
<p>Accessing json data is reading an array. So easy peasy or maybe not.
This code returns the id of the reply from inside a while loop where $i
is the index.</p>
<p><code>$id = $obj['descendants'][$i]['id'];</code></p>
<p>Like I said, it looks easy now. Needless to say it took some head
scratching to figure out the exact syntax.</p>
<p>I used to be a mason and people would always ask me how I learned
masonry. I'd look them in the eye and say, "Trowel and error". There
was, in fact, a lot of trowel and error going on.</p>
<p>So then I generated the embed code to display each post and it
worked. For all of my posts. Not for replies from other servers.</p>
<p>So I scrolled down and examined the json data and I found the url
field that had all the info about the replies, server, username, and id.
So I picked up the url field the same way I picked up the id field and
updated my code with the url server and name.</p>
<p>This still didn't work. After staring at the json data for a while
the light finally dawned. The id I was using was the gamerplus id from
my server. The id I needed to use was in the url field from their
server.</p>
<p>Now that I had become enlightened it was easy to notice that the url
field contained the exact info that I needed to use in the embed.
Remember what I said about doing it the hard way before you replaced
that code with the easy way. That can happen even when you have a
plan.</p>
<p>So by using the url data in the embed I have less string handling and
fewer lines of code.</p>
<p>I went to bed and in the morning I made this post. And I quote. &gt;
&gt; I am able to pull the urls from the json call so that should solve
the missing comments issue. &gt; &gt; And then it comes down to the
issue of data structures. &gt; &gt; KISS &gt; &gt; I have decided, for
now, to display the comments in chronological order without concern for
whether a comment is a reply to the post or a reply to another comment.
&gt; &gt; A chronological list rather than a tree. &gt; &gt; Easy to
implement (kind of/relatively) and easy to understand. Also no indents.
&gt; &gt; This project will be licensed GPL so I am certainly open to
others applying other data structures to the data display. Everything
you need to display a tree is in the json. &gt; &gt; End quote.</p>
<p>So the data structure I needed is called a multidimensional array or
an array of arrays.</p>
<p>In terms of a database table it is two columns and a bunch of
rows.</p>
<p>In terms of PHP arrays it's an array where each element is an array
with two values in it, the id and the url. Now, in my case, the id is
from the gamerplus server. The url is from whatever server the replyer
calls home.</p>
<p>I initialize the array with the parent post.</p>
<p><code>$ids = array(array($id,$url));</code></p>
<p>You can see the nested arrays in the code.</p>
<p>Then I add items to the array like this.</p>
<p><code>$ids[] =  array($id,$url);</code></p>
<p>I access an array item like this.</p>
<pre><code>foreach($ids as $id) {
  $url = $id[1];</code></pre>
<p>The 1 refers to the second element of the array because programmers
start counting at 0.</p>
<p>Then using the url and the domain that I captured from the GET
parameter that passes the parent url into the program I build the iframe
embed for that post using the Mastodon embed as a template.</p>
<p>Which worked but the posts weren't displayed in chronological order.
Because the json data isn't necessarily in chronological order.</p>
<p>So I had to sort the multidimensional array on the id. Which isn't as
straight forward as the sort() command.</p>
<p>So I found this article on stackoverflow called</p>
<p><em>How do I sort a multidimensional array by one of the fields of
the inner array in PHP?</em></p>
<p>It had a two line solution that I modified to work with my array.</p>
<p>And now all my posts were in chronological order.</p>
<p>Stack Overflow code is licensed CC BY which is one way compatible
with the GPL. Just include the attribution in a comment.</p>
<p>My first post quoted above was posted on Friday, October 25, at 8:40
PM.</p>
<p>On Monday, October 28 at 8:52 PM I wrote, "Here's the blog post proof
of concept/working code."</p>
<p>Three days from "I have an idea" to "working code". That wasn't all I
did in those three days. Saturday I had a repertoire session with my
band, Jazz Buskers. Sunday I produced my radio show, Something Blue. But
when I'm in the middle of a programming project I get hyper focused.
Sometimes I have to force myself to step away.</p>
<p>And I have worked on the code a little bit today. And I will in the
future too. I did a lot of testing today and some Mastodon servers
and/or accounts just don't support embeds. But if you want to use Embed
Mastodon Threads on your blog or website your toot will probably be the
parent and if it works on your account, you're good.</p>
<p>Also posts from different servers look different. Sometimes the
background color is different. Sometimes the links look different.
Sometimes the whole post is a link to that post on Mastodon.</p>
<p>I decided to embrace that as a feature rather than a bug with the
different look making it easier to distinguish posts made on Gamer+ from
posts made on other servers.</p>
<p>I have uploaded Embed Mastodon Threads to home.gamerplus.org. At my
blog I have a post called Embed Mastodon Threads Hosted On Gamerplus
where I say, "The program is licensed GPL and I will put up a codeberg
repository so you can download it and install it wherever you want. But
feel free to use my server." And then I go into detail about just how to
do that in the embedded comments thread.</p>
<p>The program is 46 lines of code with 11 lines of comments including
attribution comments and debug code that is commented out. So 35 lines
of code. Over three days that's 12 lines of code a day. About double
normal expectations for a programmer.</p>
<p>This has been a long podcast, certainly longer than most of my
podcasts will be. But I wrote it right after I did the project and it
gave me an opportunity to discuss the development process. There were
many issues I had that I didn't mention but I think I hit the high
points.</p>
<p>Throughout the whole project I was posting to my threads on Mastodon
so that also helped me check back on the development history of this
three day project. The stream of boosts and replies from my compatriots
helped keep me going too.</p>
<p>It was a rush!</p>
<p>So this is not exactly a plain text program because it uses a
database accessed through the Mastodon API. Still, I do not have to
maintain that database, it's just there on every Mastodon instance,
ready to use.</p>
<p>Most of my plain text programs are web apps or web pages. This one is
a web service.</p>
<p>And it is simple to use. All you have to be able to do is copy the
embed code from Mastodon, extract the link, and paste the link into the
url that calls the web service. Then you put that url into an iframe on
your blog or web page.</p>
<p>I have a help page for using Embed Mastodon Threads in the same
directory as the thread.php program where you can generate and copy your
iframe code. In fact the help page is also a Plain Text Program which I
may talk about in a future podcast. On the help page are instructions on
how to get a link from the Mastodon embed code. Then you paste the link
into a form and hit submit. The page generates your iframe embed code
that you can use in your blog or web page. The page also displays what
the embedded thread will look like.</p>
<p>If you would rather download the code and install your own instance
of Embed Mastodon Threads I have a codeberg repository. Again all the
links are in the show notes at Hacker Public Radio and at my blog at
home.gamerplus.org.</p>
<p>If you have questions you can reply to a thread on Mastodon or email
me at hairylarry@deltaboogie.com. If you don't have a mastodon account
you can get one at gamerplus.org.</p>
<h2 id="links">Links</h2>
<ul>
<li><p>My Plain Text Blog<br />
<a href="https://home.gamerplus.org/"
class="uri">https://home.gamerplus.org/</a></p></li>
<li><p>Embed Mastodon Threads Help Page<br />
<a href="https://home.gamerplus.org/Embed_Mastodon_Threads/"
class="uri">https://home.gamerplus.org/Embed_Mastodon_Threads/</a></p></li>
<li><p>Codeberg Repository<br />
<a href="https://codeberg.org/hairylarry/EmbedMastodonThreads"
class="uri">https://codeberg.org/hairylarry/EmbedMastodonThreads</a></p></li>
<li><p>From Jeff the GenX Alien<br />
Use tootcli to learn everything you need to know about the inner
workings of Mastodon.<br />
<a href="https://github.com/ihabunek/toot"
class="uri">https://github.com/ihabunek/toot</a><br />
Whatever the API supports so does toot.</p></li>
<li><p>How to easily create cURL API requests in PHP (Wordpress,
Laravel, Symfony)<br />
<a href="https://www.youtube.com/watch?v=iRLgEWMNA6w&amp;t=602s"
class="uri">https://www.youtube.com/watch?v=iRLgEWMNA6w&amp;t=602s</a></p></li>
<li><p>Curl-to-PHP<br />
<a href="https://incarnate.github.io/curl-to-php/"
class="uri">https://incarnate.github.io/curl-to-php/</a></p></li>
<li><p>Playing with public data - Mastodon documentation<br />
<a href="https://docs.joinmastodon.org/client/public/"
class="uri">https://docs.joinmastodon.org/client/public/</a></p></li>
<li><p>Status - Mastodon documentation<br />
<a href="https://docs.joinmastodon.org/entities/Status/"
class="uri">https://docs.joinmastodon.org/entities/Status/</a></p></li>
<li><p>Context - Mastodon documentation<br />
<a href="https://docs.joinmastodon.org/entities/Context/"
class="uri">https://docs.joinmastodon.org/entities/Context/</a></p></li>
<li><p>How do I sort a multidimensional array by one of the fields of
the inner array in PHP?<br />
<a
href="https://stackoverflow.com/questions/2426917/how-do-i-sort-a-multidimensional-array-by-one-of-the-fields-of-the-inner-array-i"
class="uri">https://stackoverflow.com/questions/2426917/how-do-i-sort-a-multidimensional-array-by-one-of-the-fields-of-the-inner-array-i</a></p></li>
<li><p>Embed Mastodon Threads Hosted On Gamerplus<br />
<a
href="https://home.gamerplus.org/permalink.php?fname=Embed_Mastodon_Threads_Hosted_On_Gamerplus.txt"
class="uri">https://home.gamerplus.org/permalink.php?fname=Embed_Mastodon_Threads_Hosted_On_Gamerplus.txt</a></p></li>
<li><p>Gamer+DBN Mastodon server<br />
<a href="https://gamerplus.org"
class="uri">https://gamerplus.org</a></p></li>
</ul>
