<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Hyperlink Your Heart - smolnet</title><link href="https://blog.hyperlinkyourheart.com/" rel="alternate"></link><link href="https://blog.hyperlinkyourheart.com/feeds/tag.smolnet.atom.xml" rel="self"></link><id>https://blog.hyperlinkyourheart.com/</id><updated>2021-06-26T14:59:00+02:00</updated><subtitle>Until there's nothing left.</subtitle><entry><title>Gemini Launch!</title><link href="https://blog.hyperlinkyourheart.com/gemini-launch.html" rel="alternate"></link><published>2021-06-26T14:59:00+02:00</published><updated>2021-06-26T14:59:00+02:00</updated><author><name>Kevin Houlihan</name></author><id>tag:blog.hyperlinkyourheart.com,2021-06-26:/gemini-launch.html</id><summary type="html">&lt;p&gt;All about the launch of my Gemini capsule, and how it is generated and&amp;nbsp;hosted.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the olden-times, before the Web became basically synonymous with the Internet itself in many people&amp;#8217;s minds, there was another, competing hypertext protocol: &lt;a href="https://en.wikipedia.org/wiki/Gopher_(protocol)" title="Gopher entry on Wikipedia"&gt;Gopher&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I say &amp;#8220;was&amp;#8221;, but of course Gopher never really went away - it was kept alive by enthusiasts, and in recent years there has been a resurgence of interest in it as a sort of haven from the ubiquitous surveillance and relentless commercialisation of the&amp;nbsp;Web.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve long been interested in Gopher (I even &lt;a href="https://hyperlinkyourheart.itch.io/gophers" title="Gophers on itch.io"&gt;made a game about it&lt;/a&gt;), and have intended to start a phlog for a while without ever going ahead with it. Something about it always just seemed a little bit awkward and off-putting. I was torn between using Gophermap (i.e. menu) files for everything, or using plain text for posts and sacrificing any hypertextuality. I was torn between finding the need to wrap text to be cool and retro, or a hassle that results in an inferior experience for both creating and consuming&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gemini.circumlunar.space/docs/faq.gmi" title="Gemini FAQ"&gt;Gemini&lt;/a&gt; is a new protocol which takes inspiration from both Gopher and the Web, and from a certain perspective, improves on&amp;nbsp;both.&lt;/p&gt;
&lt;p&gt;When I heard about Gemini I didn&amp;#8217;t really get it at first. I thought it was just Gopher with &lt;span class="caps"&gt;SSL&lt;/span&gt;, which is nice, but I figured I&amp;#8217;d get set up on Gopher first and then consider a Gemini mirror. A few days ago I saw a screenshot of the Lagrange browser on Mastodon and started to look into it a bit more. When I realised just how many issues of both Gopher and the web it addresses, I was hooked! I spent several days after that setting up &lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;a capsule&lt;/a&gt; (the Gemini equivalent of a&amp;nbsp;&amp;#8220;site&amp;#8221;).&lt;/p&gt;
&lt;p&gt;&lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;&lt;img alt="My Gemlog in Lagrange" src="https://blog.hyperlinkyourheart.com/images/gemini-launch/gemlog.png" title="My Gemlog in Lagrange"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Static&amp;nbsp;Generation&lt;/h2&gt;
&lt;p&gt;After experimenting with a Gemini server for a bit and creating a few static &lt;code&gt;text/gemini&lt;/code&gt; files, I decided that I wanted to statically generate my gemlog the same way that I do my blog. I expected to have to write something from scratch to do this, but after some experimentation I was able to get the &lt;a href="https://blog.getpelican.com/" title="Pelican static site generator"&gt;Pelican static site generator&lt;/a&gt; (which I also use for my blog) to both read and output &lt;code&gt;.gmi&lt;/code&gt; files. It does take a bit of configuration however, and I had to monkeypatch a couple of methods in&amp;nbsp;Pelican.&lt;/p&gt;
&lt;p&gt;Unfortunately this means that it is only guaranteed to work with the current version of Pelican, 4.6.0, and could break at any time. Nonetheless, the plugin is &lt;a href="https://github.com/khoulihan/pelican-gemini" title="pelican-gemini plugin"&gt;available on GitHub&lt;/a&gt; if you want to try it&amp;nbsp;out.&lt;/p&gt;
&lt;h3&gt;Gemini&amp;nbsp;Reader&lt;/h3&gt;
&lt;p&gt;The first thing required was a custom &amp;#8220;Reader&amp;#8221; that can handle &lt;code&gt;.gmi&lt;/code&gt; files instead of the usual Markdown or reStructuredText files. It&amp;#8217;s simple enough - it just parses the file up to the first blank line as metadata, and the rest of the content is returned unmodified, since we are also going to output the same&amp;nbsp;format.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;GeminiReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;file_extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gmi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;end_of_meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;end_of_meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;end_of_meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="c1"&gt;# After the first blank line, the rest is content.&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Handling Internal&amp;nbsp;Links&lt;/h3&gt;
&lt;p&gt;Pelican has a mechanism for linking to content internal to the site where you start the &lt;span class="caps"&gt;URL&lt;/span&gt; as &lt;code&gt;{static}&lt;/code&gt; or &lt;code&gt;{filename}&lt;/code&gt; and it replaces those with the appropriate paths during generation. However, this didn&amp;#8217;t work with the Gemini link syntax - the replacement is based on a regular expression that assumes the placeholder will be found in an attribute of a &lt;span class="caps"&gt;HTML&lt;/span&gt;&amp;nbsp;element.&lt;/p&gt;
&lt;p&gt;I couldn&amp;#8217;t find any setting or hook in the plugin system to alter this regular expression. There is a setting to customise the part that specifies the braces, so you could change the placeholders to &lt;code&gt;¿¿static??&lt;/code&gt; or something if you like, as long as it is still found in &lt;span class="caps"&gt;HTML&lt;/span&gt;. It seemed like my only option was to replace the method where the problem regex pattern is defined, and use something that matches Gemini links&amp;nbsp;instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_get_intrasite_link_regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;intrasite_link_regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INTRASITE_LINK_REGEX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(?P&amp;lt;markup&amp;gt;=&amp;gt; )(?P&amp;lt;quote&amp;gt;)(?P&amp;lt;path&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;(?P&amp;lt;value&amp;gt;[\S]*))&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intrasite_link_regex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;#8217;ll notice this also has to include a &amp;#8220;quote&amp;#8221; group because that was present in the &lt;span class="caps"&gt;HTML&lt;/span&gt; version and was expected elsewhere - here it will always be an empty&amp;nbsp;string.&lt;/p&gt;
&lt;p&gt;Unfortunately, the problems didn&amp;#8217;t end there. I found that the placeholders were removed, but not replaced with the absolute &lt;span class="caps"&gt;URL&lt;/span&gt; of the capsule. This turned out to be because urllib is used to join the &lt;span class="caps"&gt;URL&lt;/span&gt; components, and it doesn&amp;#8217;t recognise the gemini protocol. To get around this I had to replace another method, and make a call to a wrapper around &lt;code&gt;urllib.urljoin&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_urljoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;is_gemini&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_gemini&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urljoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_gemini&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Gemini&amp;nbsp;Output&lt;/h3&gt;
&lt;p&gt;Pelican uses Jinja2 for its templating, which is happy to work with any type of text file, so creating &lt;code&gt;.gmi&lt;/code&gt; templates wasn&amp;#8217;t an issue. Handily, there is a setting to look for templates with extensions other than &lt;code&gt;.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;THEME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;themes/hypergem&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TEMPLATE_EXTENSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.gmi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.gemini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To get Pelican to output files with a &lt;code&gt;.gmi&lt;/code&gt; extension instead of &lt;code&gt;.html&lt;/code&gt;, there are a bunch of settings for the different parts of the site. A single &amp;#8220;extension&amp;#8221; setting like for the templates would be nice, but whatchagonnado? I took the opportunity to customise the article location and file names as&amp;nbsp;well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# These settings are required to output files as .gmi instead of .html&lt;/span&gt;
&lt;span class="n"&gt;ARTICLE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;articles/{date:%Y}-{date:%m}-{date:&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;}-&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;ARTICLE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ARTICLE_URL&lt;/span&gt;

&lt;span class="n"&gt;DRAFT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;DRAFT_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DRAFT_URL&lt;/span&gt;

&lt;span class="n"&gt;PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pages/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;PAGE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PAGE_URL&lt;/span&gt;

&lt;span class="n"&gt;DRAFT_PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts/pages/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;DRAFT_PAGE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DRAFT_PAGE_URL&lt;/span&gt;

&lt;span class="n"&gt;AUTHOR_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;author/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AUTHOR_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AUTHOR_URL&lt;/span&gt;

&lt;span class="n"&gt;CATEGORY_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;category/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CATEGORY_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CATEGORY_URL&lt;/span&gt;

&lt;span class="n"&gt;TAG_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tag/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TAG_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TAG_URL&lt;/span&gt;

&lt;span class="n"&gt;ARCHIVES_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;archives.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AUTHORS_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;authors.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CATEGORIES_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;categories.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TAGS_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tags.gmi&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Theme&lt;/h3&gt;
&lt;p&gt;I haven&amp;#8217;t got much to say about this. I wanted the article links to be a bit more descriptive than just the date and title, so I did something similar to what medusae.space does and included the article summary, the category, and the&amp;nbsp;tags.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s close to general purpose but not quite - I added a custom &lt;code&gt;SITELOGO&lt;/code&gt; setting that is used on the index page with an &lt;span class="caps"&gt;ASCII&lt;/span&gt; art version of my logo generated using &lt;a href="https://ascii-generator.site/" title="ASCII Generator"&gt;ascii-generator.site&lt;/a&gt;, and there is also a custom template for the custom landing page. The index is renamed using a setting, and another page is renamed to index.gmi to take its place. This is so if I want to add content that isn&amp;#8217;t generated by Pelican, I have the scope to do&amp;nbsp;so.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;INDEX_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemlog.gmi&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Hyperlink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Heart&lt;/span&gt;
&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;
&lt;span class="n"&gt;Slug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;
&lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Kevin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Houlihan&lt;/span&gt;
&lt;span class="n"&gt;Summary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Capsule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;
&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gmi&lt;/span&gt;
&lt;span class="n"&gt;save_as&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gmi&lt;/span&gt;
&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capsule_intro&lt;/span&gt;
&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Hosting&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m serving the capsule using &lt;a href="https://github.com/michael-lazar/jetforce" title="Jetforce github"&gt;Jetforce&lt;/a&gt; from a first generation Raspberry Pi which I had lying around and haven&amp;#8217;t done anything with in a while. There was nothing really involved in setting it up beyond what is described in the documentation, except that I installed it in a&amp;nbsp;virtualenv.&lt;/p&gt;
&lt;p&gt;I also took steps to make sure it is running as a dedicated user with no permissions to anything else on the&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Real professional operation" src="https://blog.hyperlinkyourheart.com/images/gemini-launch/hosting.jpg" title="Real professional operation"&gt;&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m not sure what&amp;#8217;s next, but I&amp;#8217;m excited! I might discuss with the Pelican crew if there are any ways around the issues I encountered that I might have overlooked, or if it could be adapted to be more suited to non-&lt;span class="caps"&gt;HTML&lt;/span&gt; output. If not, maybe a Gemini fork is in order. I have no idea if there are further issues with it beyond the functionality that I&amp;#8217;ve&amp;nbsp;used.&lt;/p&gt;
&lt;p&gt;I have quite a few posts to port over from my blog yet, and I need to get some image optimisation happening there like I have here. Besides that, I guess all I have to do is get to know the&amp;nbsp;community!&lt;/p&gt;
&lt;h2&gt;Visit My Capsule (and&amp;nbsp;Beyond)&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;re already familiar with Gemini please &lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;check out my capsule&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not, well, I still encourage you to visit, but I should probably give you some guidance on getting&amp;nbsp;started.&lt;/p&gt;
&lt;p&gt;If you just want to dip your toes you can browse the Gemini network using a &lt;span class="caps"&gt;HTTP&lt;/span&gt; proxy (&lt;a href="https://proxy.vulpes.one/gemini/gemini.hyperlinkyourheart.com" title="Vulpes.one proxy"&gt;here&amp;#8217;s one&lt;/a&gt;, and &lt;a href="https://portal.mozz.us/gemini/gemini.hyperlinkyourheart.com" title="Mozz.us proxy"&gt;another&lt;/a&gt;). For what I would consider the &amp;#8220;full experience&amp;#8221; you will need a dedicated browser. I&amp;#8217;ve been using &lt;a href="https://github.com/skyjake/lagrange" title="Lagrange browser GitHub"&gt;Lagrange&lt;/a&gt;, and highly recommend it, but there are a &lt;a href="https://gemini.circumlunar.space/software/" title="Gemini software list"&gt;whole bunch of others&lt;/a&gt; if that doesn&amp;#8217;t suit you. Many of them also support Gopher, which makes browsing both into a seamless experience outside of the modern&amp;nbsp;Web.&lt;/p&gt;
&lt;p&gt;When you want to move beyond my capsule, here are some others I&amp;nbsp;recommend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Medusae.space, a content directory: &lt;a href="gemini://medusae.space" title="Medusae.space content directory"&gt;gemini://medusae.space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Station, a social network with user accounts: &lt;a href="gemini://station.martinrue.com/" title="Station - where capsuleers hang out"&gt;gemini://station.martinrue.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Geddit, an anonymous link aggregator: &lt;a href="gemini://geddit.glv.one/" title="Geddit?"&gt;gemini://geddit.glv.one/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Astrobotany, a community garden game: &lt;a href="gemini://astrobotany.mozz.us/" title="Astrobotany"&gt;gemini://astrobotany.mozz.us/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A gemlog post about the &amp;#8220;smolnet&amp;#8221;, which explains the appeal far better than I ever could: &lt;a href="gemini://republic.circumlunar.space/users/maugre/200701-smolnet.gmi" title="The smolnet of smol things"&gt;gemini://republic.circumlunar.space/users/maugre/200701-smolnet.gmi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I leave you with my anxious young poppy, Jennifer, on&amp;nbsp;AstroBotany:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            O
            |
           \o
            |o
           \/
.  , &lt;span class="ge"&gt;_ . ., l, _&lt;/span&gt; ., _ .  
^      &amp;#39;        `    &amp;#39;

name  : &amp;quot;Jennifer&amp;quot;
stage : anxious young poppy
age   : 2 days
rate  : 1st generation (x1.0)
score : 326788
water : |██████████| 100%
bonus : |          | 2%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Gemini"></category><category term="python"></category><category term="pelican"></category><category term="blogging"></category><category term="smolnet"></category></entry></feed>