<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>hugo on foosel.net</title><link>https://foosel.net/tags/hugo/</link><description>Recent content in hugo on foosel.net</description><generator>Hugo</generator><language>en-us</language><copyright>Gina Häußge (foosel)</copyright><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://foosel.net/tags/hugo/feed.xml" rel="self" type="application/rss+xml"/><item><title>How to manage this Hugo based page from my Android phone in 2026</title><link>https://foosel.net/til/how-to-manage-this-page-from-my-phone-in-2026/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://foosel.net/til/how-to-manage-this-page-from-my-phone-in-2026/</guid><description>&lt;p&gt;This TIL post is basically an update to my three year old post &lt;a href="https://foosel.net/blog/2023-01-21-hugo-meet-android/"&gt;&amp;ldquo;Hugo, meet Android&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I recently got a new phone and thus had to re-do the setup of my mobile blogging pipeline. So, basically, allow me to checkout, modify, test, commit and push the sources of this &lt;a href="https://gohugo.io/"&gt;Hugo based&lt;/a&gt; static page under Android. While doing so I noticed some necessary changes and improvements, and also wanted to make use of my &lt;a href="https://github.com/foosel/foosel.github.io/blob/master/Taskfile.yml"&gt;Taskfile&lt;/a&gt; which does most of the heavy lifting now, so here are my updated steps.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This TIL post is basically an update to my three year old post <a href="/blog/2023-01-21-hugo-meet-android/">&ldquo;Hugo, meet Android&rdquo;</a>.</p>
<p>I recently got a new phone and thus had to re-do the setup of my mobile blogging pipeline. So, basically, allow me to checkout, modify, test, commit and push the sources of this <a href="https://gohugo.io/">Hugo based</a> static page under Android. While doing so I noticed some necessary changes and improvements, and also wanted to make use of my <a href="https://github.com/foosel/foosel.github.io/blob/master/Taskfile.yml">Taskfile</a> which does most of the heavy lifting now, so here are my updated steps.</p>
<h2 id="apps--permissions">Apps &amp; permissions</h2>
<ol>
<li>Install Tasker</li>
<li>From <strong>F-Droid</strong> install
<ul>
<li>Termux</li>
<li>Termux:Tasker</li>
<li>Markor</li>
</ul>
</li>
<li>Grant permissions
<ul>
<li>Tasker: Run commands via Termux</li>
<li>Termux: Draw over apps</li>
</ul>
</li>
</ol>
<h2 id="termux-setup">Termux setup</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># setup access to storage</span>
</span></span><span style="display:flex;"><span>termux-setup-storage
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># install packages</span>
</span></span><span style="display:flex;"><span>pkg upgrade
</span></span><span style="display:flex;"><span>pkg install git gh hugo iconv vim
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># log into github</span>
</span></span><span style="display:flex;"><span>gh auth login
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># navigate to Markor&#39;s document folder &amp; checkout sources</span>
</span></span><span style="display:flex;"><span>cd storage/shared/Documents/markor
</span></span><span style="display:flex;"><span>git clone --recurse-submodules https://github.com/foosel/foosel.github.io
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># create symlink in home</span>
</span></span><span style="display:flex;"><span>ln -s foosel.github.io ~/foosel.net
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># mark checkout as safe</span>
</span></span><span style="display:flex;"><span>git config --global --add safe.directory /storage/emulated/0/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># set git user metadata</span>
</span></span><span style="display:flex;"><span>git config --global user.email <span style="color:#e6db74">&#34;you@example.com&#34;</span>
</span></span><span style="display:flex;"><span>git config --global user.name <span style="color:#e6db74">&#34;Your Name&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># we want to use our Taskfile...</span>
</span></span><span style="display:flex;"><span>pkg install golang
</span></span><span style="display:flex;"><span>go install github.com/go-task/task/v3/cmd/task@latest
</span></span></code></pre></div><p>As Tasker will stay the <em>only</em> app on my system allowed to send commands to Termux, and I write all my tasks myself, I also added <code>allow-external-apps=true</code>  to <code>.termux/termux.properties</code> as described <a href="https://github.com/termux/termux-tasker#allow-external-apps-property-optional">here</a>. That allows me to directly execute stuff from Tasker by absolute path vs having to add a bunch of wrapper scripts to <code>~/.termux/shortcuts</code></p>
<p>To quickly test if everything works so far:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~/foosel.net
</span></span><span style="display:flex;"><span>task serve
</span></span></code></pre></div><p>This should build the page and serve it on <code>http://127.0.0.1:1313</code> (with auto reload).</p>
<h2 id="tasker-setup">Tasker setup</h2>
<p>I created a bunch of tasks, gave all of them an icon and added them to my launcher.</p>
<h3 id="serve-fooselnet">Serve foosel.net</h3>
<pre tabindex="0"><code>    Task: Serve foosel.net
    
    A1: Termux [
         Configuration: ~/go/bin/task serve
         
         Working Directory ✓
         Terminal Session ✓
         Wait For Result ✕
         Timeout (Seconds): 10
         Structure Output (JSON, etc): On ]
    
</code></pre><h3 id="pull-fooselnet">Pull foosel.net</h3>
<pre tabindex="0"><code>    Task: Pull foosel.net
    
    A1: Termux [
         Configuration: /data/data/com.termux/files/usr/bin/git pull
         
         Working Directory ✓
         Stdin ✕
         Custom Log Level null
         Terminal Session ✕
         Wait 
         Timeout (Seconds): 10
         Structure Output (JSON, etc): On ]
    
    A2: Flash [
         Text: Pulled foosel.net sources
         Continue Task Immediately: On
         Dismiss On Click: On ]
    
</code></pre><h3 id="push-fooselnet">Push foosel.net</h3>
<pre tabindex="0"><code>    Task: Push foosel.net
    
    A1: Termux [
         Configuration: /data/data/com.termux/files/usr/bin/git push
         
         Working Directory ✓
         Stdin ✕
         Custom Log Level null
         Terminal Session ✕
         Wait 
         Timeout (Seconds): 10
         Structure Output (JSON, etc): On ]
    
    A2: Flash [
         Text: Pushed foosel.net sources
         Continue Task Immediately: On
         Dismiss On Click: On ]
    
</code></pre><h3 id="new-blog-post">New Blog Post</h3>
<pre tabindex="0"><code>    Task: New Blog Post
    
    A1: Input Dialog [
         Title: New post
         Text: Enter title
         Close After (Seconds): 120
         Input Type: 540673 ]
    
    A2: Termux [
         Configuration: ~/.local/bin/task new-blog -- &#34;%input&#34;
         
         Working Directory ✓
         Stdin ✕
         Custom Log Level null
         Terminal Session ✕
         Wait For Re
         Timeout (Seconds): 10
         Structure Output (JSON, etc): On ]
    
    A3: JavaScriptlet [
         Code: var uri = &#34;content://net.dinglisch.android.taskerm.fileprovider/storage/emulated/0/Documents/markor/foosel.github.io/&#34; + stdout.trim();
         Auto Exit: On
         Timeout (Seconds): 45 ]
    
    A4: Send Intent [
         Cat: None
         Mime Type: text/markdown
         Data: %uri
         Package: net.gsantner.markor
         Class: net.gsantner.markor.activity.DocumentActivity
         Target: Activity ]
</code></pre><h3 id="new-til-post">New TIL Post</h3>
<pre tabindex="0"><code>    Task: New TIL Post
    
    A1: Input Dialog [
         Title: New TIL
         Text: Enter title
         Close After (Seconds): 120
         Input Type: 540673 ]
    
    A2: Termux [
         Configuration: ~/.local/bin/task new-til -- &#34;%input&#34;
         
         Working Directory ✓
         Stdin ✕
         Custom Log Level null
         Terminal Session ✕
         Wait For Res
         Timeout (Seconds): 10
         Structure Output (JSON, etc): On ]
    
    A3: JavaScriptlet [
         Code: var uri = &#34;content://net.dinglisch.android.taskerm.fileprovider/storage/emulated/0/Documents/markor/foosel.github.io/&#34; + stdout.trim();
         Auto Exit: On
         Timeout (Seconds): 45 ]
    
    A4: Send Intent [
         Cat: None
         Mime Type: text/markdown
         Data: %uri
         Package: net.gsantner.markor
         Class: net.gsantner.markor.activity.DocumentActivity
         Target: Activity ]
</code></pre><h3 id="result">Result</h3>
<p>I now have all these tasks available under a tag in my launcher (<a href="https://kvaesitso.mm20.de/">Kvaesitso</a>) and can easily work on posts from my phone once more. In fact, this post was entirely written on it.</p>
<p><img alt="My launcher showing all created Tasker tasks as shortcuts, as well as a Firefox shortcut to the local page, plus Markor and Termux" loading="lazy" src="/til/how-to-manage-this-page-from-my-phone-in-2026/shortcuts.png"></p>
<p>The whole pipeline is a bit slimmer than last time as well and required less bash wrappers, which I like a lot better 👍</p>
<p>I also decided to go a bit more commandline-centric in this iteration - <code>git add</code> and <code>git commit</code> I&rsquo;ll actually run manually in Termux this time around (I rarely used the corresponding shortcuts I created last time).</p>
<p>Once I&rsquo;m satisfied with the local preview and have committed, a <code>git push</code> is all that I need for publishing - the CI does the rest.</p>
]]></content:encoded></item><item><title>Meta: Some late spring cleaning</title><link>https://foosel.net/blog/2026-06-17-some-late-spring-cleaning/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://foosel.net/blog/2026-06-17-some-late-spring-cleaning/</guid><description>&lt;p&gt;It was annoying me for a while now that my chosen theme &lt;a href="https://github.com/adityatelange/hugo-PaperMod/"&gt;PaperMod&lt;/a&gt; didn&amp;rsquo;t also support some kind of all-in-one RSS feed with all main sections. And also that the feeds were called &lt;code&gt;index.xml&lt;/code&gt; instead of &lt;code&gt;feed.xml&lt;/code&gt;, confusing me every time I wanted to check something on them manually. Also, the feed link title just being &lt;code&gt;rss&lt;/code&gt; didn&amp;rsquo;t exactly help in a feed reader either.&lt;/p&gt;
&lt;p&gt;So just now I&amp;rsquo;ve done some long overdue spring cleaning on this page:&lt;/p&gt;</description><content:encoded><![CDATA[<p>It was annoying me for a while now that my chosen theme <a href="https://github.com/adityatelange/hugo-PaperMod/">PaperMod</a> didn&rsquo;t also support some kind of all-in-one RSS feed with all main sections. And also that the feeds were called <code>index.xml</code> instead of <code>feed.xml</code>, confusing me every time I wanted to check something on them manually. Also, the feed link title just being <code>rss</code> didn&rsquo;t exactly help in a feed reader either.</p>
<p>So just now I&rsquo;ve done some long overdue spring cleaning on this page:</p>
<ol>
<li>I updated PaperMod<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> &amp; adjusted my overwrites as necessary</li>
<li>I implemented my custom rss feed template with some more logic to render it with all main sections on home</li>
<li>I disabled the automatic inclusion of the section feeds and created my own with proper <code>title</code> attributes (&quot;(All|Blog|TIL) posts on foosel.net&quot;), put into the head of all pages</li>
<li>I overrode the default name of the generated feeds to be <code>feed.xml</code> &amp; added the necessary redirects (hopefully&hellip;)</li>
<li>I also added links to the main RSS feed at two prominent places: in the social icons on the home page as well as in the main navigation next to the search button. While the feeds were always discoverable through the related <code>link</code> tags in the HTML page itself, and there were also specific links on the section main pages, I still got some questions here and there on whether there was a feed, so I hope this makes things easier to discover now.</li>
</ol>
<p>If you want a look behind the scenes on how I did that, <a href="https://github.com/foosel/foosel.github.io">this page&rsquo;s source is on a public repo</a>, so feel free to take a look 😊</p>
<p>All that&rsquo;s left to say is: I&rsquo;m sorry should I have broken something there or caused your RSS reader to push all old posts into your face 😬</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>&hellip; and discovered that it&rsquo;s now apparently also a victim of vibe coding 😕&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>How to automatically build a human.json file in Hugo</title><link>https://foosel.net/til/how-to-automatically-build-a-humanjson-file-in-hugo/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://foosel.net/til/how-to-automatically-build-a-humanjson-file-in-hugo/</guid><description>&lt;p&gt;As I mentioned the other day, I recently added a &lt;a href="https://foosel.net/til/humanjson/"&gt;human.json file&lt;/a&gt; to this site.&lt;/p&gt;
&lt;p&gt;However, it became a bit annoying adding new vouches to the json manually.&lt;/p&gt;
&lt;p&gt;So today I sat down and made it get created automatically during my page build powered by &lt;a href="https://gohugo.io"&gt;Hugo&lt;/a&gt;, based on a list of vouches stored in a &lt;code&gt;vouches.yaml&lt;/code&gt; data file&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;For this I first created said data file in &lt;code&gt;data/vouches.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://food.foosel.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;date&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-14&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://chaos.social/@foosel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;date&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-14&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://octoprint.org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;date&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-14&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I created a new output format &lt;code&gt;humanjson&lt;/code&gt; in my &lt;code&gt;config.yaml&lt;/code&gt;, making sure to also add it to the home page:&lt;/p&gt;</description><content:encoded><![CDATA[<p>As I mentioned the other day, I recently added a <a href="/til/humanjson/">human.json file</a> to this site.</p>
<p>However, it became a bit annoying adding new vouches to the json manually.</p>
<p>So today I sat down and made it get created automatically during my page build powered by <a href="https://gohugo.io">Hugo</a>, based on a list of vouches stored in a <code>vouches.yaml</code> data file<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>For this I first created said data file in <code>data/vouches.yaml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>- <span style="color:#f92672">url</span>: <span style="color:#ae81ff">https://food.foosel.net</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">date</span>: <span style="color:#e6db74">&#34;2026-03-14&#34;</span>
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">url</span>: <span style="color:#ae81ff">https://chaos.social/@foosel</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">date</span>: <span style="color:#e6db74">&#34;2026-03-14&#34;</span>
</span></span><span style="display:flex;"><span>- <span style="color:#f92672">url</span>: <span style="color:#ae81ff">https://octoprint.org</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">date</span>: <span style="color:#e6db74">&#34;2026-03-14&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># ...</span>
</span></span></code></pre></div><p>Then I created a new output format <code>humanjson</code> in my <code>config.yaml</code>, making sure to also add it to the home page:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">outputs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">home</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">HTML</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">JSON</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">humanjson</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># ...</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">outputFormats</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># ...</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">humanjson</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">mediaType</span>: <span style="color:#ae81ff">application/json</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">baseName</span>: <span style="color:#ae81ff">human</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">isPlainText</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">notAlternative</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># ...</span>
</span></span></code></pre></div><p>Finally I created a template for that in  <code>_layout/home.humanjson.json</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go-text-template" data-lang="go-text-template"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    &#34;version&#34;: &#34;0.1.1&#34;,
</span></span><span style="display:flex;"><span>    &#34;url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Site.BaseURL</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>    &#34;vouches&#34;: [
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">$index</span><span style="color:#f92672">,</span> <span style="color:#a6e22e">$vouch</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">hugo</span><span style="color:#a6e22e">.Data.vouches</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">with</span> <span style="color:#a6e22e">$vouch</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">$index</span> <span style="color:#75715e">}}</span>,<span style="color:#75715e">{{</span><span style="color:#66d9ef">end</span><span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            &#34;url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.url</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            &#34;vouched_at&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.date</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>I kept the required <code>&lt;link rel=&quot;/human.json&quot;&gt;</code> in my <code>layouts/partials/extend_head.html</code> file that gets included on <em>all</em> pages by my theme (contrary to how the linking of output formats work, which is why I went with <code>notAlternative: true</code> for that).</p>
<p>And to make it even easier to quickly add a new vouch, I also added a new task to my <a href="https://taskfile.dev">Taskfile</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>  <span style="color:#f92672">add-vouch</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">desc</span>: <span style="color:#ae81ff">Adds a new vouch to human.json.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">vars</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">PAGE</span>: <span style="color:#e6db74">&#39;{{.CLI_ARGS}}&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">FILE</span>: <span style="color:#e6db74">&#39;data/vouches.yaml&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">TODAY</span>: <span style="color:#e6db74">&#39;{{now | date &#34;2006-01-02&#34;}}&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">cmds</span>:
</span></span><span style="display:flex;"><span>      - |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        cat &gt;&gt; {{.FILE}} &lt;&lt;EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        - url: {{.PAGE}}
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          date: &#34;{{.TODAY}}&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        EOF</span>
</span></span></code></pre></div><p>Now, vouching for a page<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> is as easy as</p>
<pre tabindex="0"><code>task add-vouch -- https://example.com
</code></pre><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Targeting Hugo 0.156.0+&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Even from my phone thanks to <a href="https://termux.dev/">Termux</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>How to add JSON Feed support to Hugo</title><link>https://foosel.net/til/how-to-add-json-feed-support-to-hugo/</link><pubDate>Sun, 29 Jan 2023 00:00:00 +0000</pubDate><guid>https://foosel.net/til/how-to-add-json-feed-support-to-hugo/</guid><description>&lt;p&gt;In order to add &lt;a href="https://www.jsonfeed.org/"&gt;JSON Feed 1.1 support&lt;/a&gt; to &lt;a href="https://gohugo.io"&gt;Hugo&lt;/a&gt; you need to first add a new &lt;code&gt;jsonfeed&lt;/code&gt; output format in &lt;code&gt;config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;mediaTypes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;application/feed+json&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;suffixes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;outputFormats&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;jsonfeed&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mediaType&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;application/feed+json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;baseName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;feed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rel&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;alternate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;isPlainText&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This adds a new media type &lt;code&gt;application/feed+json&lt;/code&gt; with the extension &lt;code&gt;json&lt;/code&gt; and creates a new output format &lt;code&gt;jsonfeed&lt;/code&gt; rendering into that media type with a base name of &lt;code&gt;feed&lt;/code&gt; (so &lt;code&gt;feed.json&lt;/code&gt; as &lt;a href="https://www.jsonfeed.org/version/1.1/#discovery"&gt;recommended by the JSON Feed spec&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This then needs to be added to the outputs it should be generated for - on this page I&amp;rsquo;ve only added it to &lt;code&gt;section&lt;/code&gt;s. Again, in &lt;code&gt;config.yaml&lt;/code&gt;:&lt;/p&gt;</description><content:encoded><![CDATA[<p>In order to add <a href="https://www.jsonfeed.org/">JSON Feed 1.1 support</a> to <a href="https://gohugo.io">Hugo</a> you need to first add a new <code>jsonfeed</code> output format in <code>config.yaml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">mediaTypes</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application/feed+json</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">suffixes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">json</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">outputFormats</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">jsonfeed</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">mediaType</span>: <span style="color:#ae81ff">application/feed+json</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">baseName</span>: <span style="color:#ae81ff">feed</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">rel</span>: <span style="color:#ae81ff">alternate</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">isPlainText</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>This adds a new media type <code>application/feed+json</code> with the extension <code>json</code> and creates a new output format <code>jsonfeed</code> rendering into that media type with a base name of <code>feed</code> (so <code>feed.json</code> as <a href="https://www.jsonfeed.org/version/1.1/#discovery">recommended by the JSON Feed spec</a>).</p>
<p>This then needs to be added to the outputs it should be generated for - on this page I&rsquo;ve only added it to <code>section</code>s. Again, in <code>config.yaml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">outputs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">home</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">HTML</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">JSON</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">section</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">HTML</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">RSS</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">jsonfeed</span>
</span></span></code></pre></div><p>Finally, a template needs to be created so that Hugo can actually render something. I&rsquo;ve put this into <code>layouts/_default/list.jsonfeed.json</code> (following the expected naming scheme of <code>list.&lt;outputFormat&gt;.&lt;extension&gt;</code>):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go-text-template" data-lang="go-text-template"><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$pctx</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">.</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">.IsHome</span> <span style="color:#75715e">-}}{{</span> <span style="color:#a6e22e">$pctx</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">site</span> <span style="color:#75715e">}}{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$pages</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">slice</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">or</span> <span style="color:#a6e22e">$.IsHome</span> <span style="color:#a6e22e">$.IsSection</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$pages</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">$pctx</span><span style="color:#a6e22e">.RegularPages</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">else</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$pages</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">$pctx</span><span style="color:#a6e22e">.Pages</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$limit</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">site</span><span style="color:#a6e22e">.Config.Services.RSS.Limit</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">ge</span> <span style="color:#a6e22e">$limit</span> <span style="color:#a6e22e">1</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$pages</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">$pages</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">first</span> <span style="color:#a6e22e">$limit</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">-}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$title</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">eq</span> <span style="color:#a6e22e">.Title</span> <span style="color:#a6e22e">.Site.Title</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$title</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">.Site.Title</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">else</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">with</span> <span style="color:#a6e22e">.Title</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$title</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">print</span> <span style="color:#a6e22e">.</span> <span style="color:#e6db74">&#34; on &#34;</span><span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$title</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">print</span> <span style="color:#a6e22e">$title</span> <span style="color:#a6e22e">.Site.Title</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    &#34;version&#34;: &#34;https://jsonfeed.org/version/1.1&#34;,
</span></span><span style="display:flex;"><span>    &#34;title&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">$title</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>    &#34;home_page_url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Permalink</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">with</span>  <span style="color:#a6e22e">.OutputFormats.Get</span> <span style="color:#e6db74">&#34;jsonfeed&#34;</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    &#34;feed_url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Permalink</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span>  <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">or</span> <span style="color:#a6e22e">.Site.Params.author</span> <span style="color:#a6e22e">.Site.Params.author_url</span><span style="color:#f92672">)</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    &#34;authors&#34;: [{
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">.Site.Params.author</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        &#34;name&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Site.Params.author</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">.Site.Params.author_url</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        &#34;url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Site.Params.author_url</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    }],
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">$pages</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    &#34;items&#34;: [
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">$index</span><span style="color:#f92672">,</span> <span style="color:#a6e22e">$element</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">$pages</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">with</span> <span style="color:#a6e22e">$element</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">$index</span> <span style="color:#75715e">}}</span>,<span style="color:#75715e">{{</span><span style="color:#66d9ef">end</span><span style="color:#75715e">}}</span> {
</span></span><span style="display:flex;"><span>            &#34;title&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Title</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            &#34;id&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Permalink</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            &#34;url&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Permalink</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">.Site.Params.showFullTextinJSONFeed</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            &#34;summary&#34;: <span style="color:#75715e">{{</span> <span style="color:#66d9ef">with</span> <span style="color:#a6e22e">.Description</span> <span style="color:#75715e">}}{{</span> <span style="color:#a6e22e">.</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}{{</span> <span style="color:#66d9ef">else</span> <span style="color:#75715e">}}{{</span> <span style="color:#a6e22e">.Summary</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}{{</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">-}}</span>,
</span></span><span style="display:flex;"><span>            &#34;content_html&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Content</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">else</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            &#34;content_text&#34;: <span style="color:#75715e">{{</span> <span style="color:#66d9ef">with</span> <span style="color:#a6e22e">.Description</span> <span style="color:#75715e">}}{{</span> <span style="color:#a6e22e">.</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}{{</span> <span style="color:#66d9ef">else</span> <span style="color:#75715e">}}{{</span> <span style="color:#a6e22e">.Summary</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}{{</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">-}}</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">.Params.cover.image</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#a6e22e">$cover</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">(</span><span style="color:#a6e22e">.Resources.ByType</span> <span style="color:#e6db74">&#34;image&#34;</span><span style="color:#f92672">)</span><span style="color:#a6e22e">.GetMatch</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">printf</span> <span style="color:#e6db74">&#34;*%s*&#34;</span> <span style="color:#f92672">(</span><span style="color:#a6e22e">.Params.cover.image</span><span style="color:#f92672">))</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">$cover</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            &#34;image&#34;: <span style="color:#75715e">{{</span> <span style="color:#f92672">(</span><span style="color:#a6e22e">path</span><span style="color:#a6e22e">.Join</span> <span style="color:#a6e22e">.RelPermalink</span> <span style="color:#a6e22e">$cover</span><span style="color:#f92672">)</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">absURL</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>            &#34;date_published&#34;: <span style="color:#75715e">{{</span> <span style="color:#a6e22e">.Date.Format</span> <span style="color:#e6db74">&#34;2006-01-02T15:04:05Z07:00&#34;</span> <span style="color:#f92672">|</span> <span style="color:#a6e22e">jsonify</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">{{-</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">{{</span> <span style="color:#66d9ef">end</span> <span style="color:#75715e">}}</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>By default, this generates a feed with summaries only. If you want a full content feed, set <code>params.showFullTextinJSONFeed</code> to <code>true</code> in <code>config.yaml</code>.</p>
<p>The relevant docs for custom media types, output formats and template locations can be found <a href="https://gohugo.io/templates/output-formats/">here</a>.</p>
<p>On <a href="https://github.com/adityatelange/hugo-PaperMod">the Papermod theme</a> the above will automatically cause something like</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;alternate&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;application/feed+json&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://foosel.net/til/feed.json&#34;</span>&gt;
</span></span></code></pre></div><p>to be added to the <code>head</code> of the page, as needed for <a href="https://www.jsonfeed.org/version/1.1/#discovery">discovery</a>. In other themes you might have to do it yourself.</p>
<p>The result of all of this is something like <a href="https://foosel.net/til/feed.json">this</a>.</p>
]]></content:encoded></item><item><title>Hugo, meet Android</title><link>https://foosel.net/blog/2023-01-21-hugo-meet-android/</link><pubDate>Sat, 21 Jan 2023 00:00:00 +0000</pubDate><guid>https://foosel.net/blog/2023-01-21-hugo-meet-android/</guid><description>Setting up a mobile blogging workflow</description><content:encoded><![CDATA[<p><em><strong>Update from 2026-06-19</strong>: I went through these steps again after getting a new phone and had to change some things here and there while also improving other bits. You can find an update <a href="/til/how-to-manage-this-page-from-my-phone-in-2026/">here</a>.</em></p>
<p>One thing that kept me from blogging more so far was the difficulty in working on posts on my phone. So after switching this blog over to Hugo I decided to see if I couldn&rsquo;t improve on this situation.</p>
<p>I needed a solution that would allow me to</p>
<ol>
<li>Checkout my page&rsquo;s git repository from GitHub</li>
<li>Quickly create a new post, consisting of a new folder inside <code>content/blog</code> matching my chosen <code>&lt;year&gt;-&lt;month&gt;-&lt;day&gt;-&lt;title slug&gt;/index.md</code> folder structure, based on just a title</li>
<li>Allow me to edit the post, preferably in a text editor focused on Markdown (and ideally allow me to preview the post as well)</li>
<li>Optional: Run the Hugo build on my phone as well for final checks</li>
<li>Finally, commit the new post and push it so that my GitHub Action workflow can take care of the rest</li>
</ol>
<p>I started hunting for options, and I&rsquo;m happy to report that for now I seem to have found a - quite geeky - solution that involves the use of <a href="https://termux.dev/en">Termux</a> (Linux terminal environment for Android), <a href="https://gsantner.net/project/markor.html">Markor</a> (Markdown editor) and <a href="https://tasker.joaoapps.com/">Tasker</a> (Automation tool)<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>I installed Termux, Termux:Tasker, Termux:Widget and Markor via <a href="https://f-droid.org/">F-Droid</a> - the versions available on Google Play are outdated and no longer supported. I already had Tasker installed, but I made sure to give it the additional permission to send commands to Termux. For Termux, I also made sure to allow it to draw over other apps.</p>
<p>I then fired up Termux and took care of storage access and some packages first:</p>
<pre tabindex="0"><code>termux-setup-storage
pkg upgrade
pkg install git gh hugo iconv vim
</code></pre><p>Markor&rsquo;s default folder is located at <code>Documents/markor</code> and so this is where I decided to checkout my page&rsquo;s repository to. I also made sure to set some config settings needed for stuff to work<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>:</p>
<pre tabindex="0"><code>gh auth login
cd storage/shared/Documents/markor
git clone https://github.com/foosel/foosel.github.io
git config --global --add safe.directory /storage/emulated/0/Documents/markor/foosel.github.io
git config --global user.email &#34;you@example.com&#34;
git config --global user.name &#34;Your Name&#34;
</code></pre><p>Next I took care of some helper scripts for Termux:Widget and Tasker. I first created some folders:</p>
<pre tabindex="0"><code>mkdir -p ~/.shortcuts
chmod 700 -R ~/.shortcuts
mkdir -p ~/.termux/tasker
chmod 700 -R ~/.termux/tasker
</code></pre><p>Then I added some helper scripts to them:</p>
<p><code>~/.shortcuts/pull_blog</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ~/storage/shared/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>git pull
</span></span></code></pre></div><p><code>~/.shortcuts/push_blog</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ~/storage/shared/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>git push
</span></span></code></pre></div><p><code>~/.termux/tasker/serve_blog</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ~/storage/shared/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>hugo server -D -F --noBuildLock
</span></span></code></pre></div><p><code>~/.termux/tasker/new_blog_post</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>checkout<span style="color:#f92672">=</span>~/storage/shared/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>slugify <span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>     echo <span style="color:#e6db74">&#34;</span>$1<span style="color:#e6db74">&#34;</span> | iconv -t ascii//TRANSLIT | sed -r s/<span style="color:#f92672">[</span>~<span style="color:#ae81ff">\^</span><span style="color:#f92672">]</span>+//g | sed -r s/<span style="color:#f92672">[</span>^a-zA-Z0-9<span style="color:#f92672">]</span>+/-/g | sed -r s/^-+<span style="color:#ae81ff">\|</span>-+$//g | tr A-Z a-z
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>title<span style="color:#f92672">=</span>$1
</span></span><span style="display:flex;"><span>date<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>date +%Y-%m-%d<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>slug<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>slugify <span style="color:#e6db74">&#34;</span>$title<span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd $checkout
</span></span><span style="display:flex;"><span>mkdir -p content/blog/$date-$slug
</span></span><span style="display:flex;"><span>cat &gt; content/blog/$date-$slug/index.md <span style="color:#e6db74">&lt;&lt;EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">---
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">title: &#34;$title&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">date: $date
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">draft: true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">---
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo $date-$slug/index.md
</span></span></code></pre></div><p><code>~/.termux/tasker/commit_blog</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>message<span style="color:#f92672">=</span>$1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ~/storage/shared/Documents/markor/foosel.github.io
</span></span><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git commit -m <span style="color:#e6db74">&#34;</span>$message<span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div><p><code>pull_blog</code> and <code>push_blog</code> take care of git synchronization.</p>
<p><code>serve_blog</code> runs Hugo with draft and future posts visible. The page can be viewed in the browser on the phone at <code>http://localhost:1313</code>.</p>
<p><code>new_blog_post</code> takes a post title as its first argument and from that creates the aforementioned folder structure within the <code>content/blog</code> folder, including a prefilled <code>index.md</code>.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>And finally <code>commit_blog</code> takes a commit message as its first argument, stages all changes in the checkout and commits them with the supplied message.</p>
<p>Next, I created Termux:Widget widgets on my desktop for <code>pull_blog</code>, <code>push_blog</code> and <code>run_hugo</code>.</p>
<p>Then I opened Tasker and created two new tasks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>    Task: New Post
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A1: Input Dialog [
</span></span><span style="display:flex;"><span>         Title: New post
</span></span><span style="display:flex;"><span>         Text: Enter title
</span></span><span style="display:flex;"><span>         Close After (Seconds): 30
</span></span><span style="display:flex;"><span>         Input Type: 540673 ]
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A2: Termux [
</span></span><span style="display:flex;"><span>         Configuration: new_blog_post &#34;%input&#34;
</span></span><span style="display:flex;"><span>         
</span></span><span style="display:flex;"><span>         Working Directory ✕
</span></span><span style="display:flex;"><span>         Stdin ✕
</span></span><span style="display:flex;"><span>         Custom Log Level null
</span></span><span style="display:flex;"><span>         Terminal Session ✕
</span></span><span style="display:flex;"><span>         Wait For Result ✓
</span></span><span style="display:flex;"><span>         Timeout (Seconds): 10
</span></span><span style="display:flex;"><span>         Structure Output (JSON, etc): On ]
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A3: JavaScriptlet [
</span></span><span style="display:flex;"><span>         Code: var uri = &#34;content://net.dinglisch.android.taskerm.fileprovider/external_files/storage/emulated/0/Documents/markor/foosel.github.io/content/blog/&#34; + stdout.trim();
</span></span><span style="display:flex;"><span>         Auto Exit: On
</span></span><span style="display:flex;"><span>         Timeout (Seconds): 45 ]
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A4: Send Intent [
</span></span><span style="display:flex;"><span>         Action: android.intent.action.SEND
</span></span><span style="display:flex;"><span>         Cat: None
</span></span><span style="display:flex;"><span>         Mime Type: text/markdown
</span></span><span style="display:flex;"><span>         Data: %uri
</span></span><span style="display:flex;"><span>         Package: net.gsantner.markor
</span></span><span style="display:flex;"><span>         Class: net.gsantner.markor.activity.DocumentActivity
</span></span><span style="display:flex;"><span>         Target: Activity ]
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>    Task: Commit Blog
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A1: Input Dialog [
</span></span><span style="display:flex;"><span>         Title: Commit Blog
</span></span><span style="display:flex;"><span>         Text: Enter commit message
</span></span><span style="display:flex;"><span>         Close After (Seconds): 30 ]
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    A2: Termux [
</span></span><span style="display:flex;"><span>         Configuration: commit_blog &#34;%input&#34;
</span></span><span style="display:flex;"><span>         
</span></span><span style="display:flex;"><span>         Working Directory ✕
</span></span><span style="display:flex;"><span>         Stdin ✕
</span></span><span style="display:flex;"><span>         Custom Log Level null
</span></span><span style="display:flex;"><span>         Terminal Session ✕
</span></span><span style="display:flex;"><span>         Wait For Result ✓
</span></span><span style="display:flex;"><span>         Timeout (Seconds): 10
</span></span><span style="display:flex;"><span>         Structure Output (JSON, etc): On ]
</span></span></code></pre></div><p>&ldquo;New Post&rdquo; queries a post title from the user, calls <code>new_post</code> with that and then opens the new post in Markor.</p>
<p>&ldquo;Commit Blog&rdquo; queries a commit message from the user and calls <code>commit_blog</code> with that.</p>
<p>I created desktop shortcuts for these too and placed all of them, together with Markor, Termux and a browser shortcut, in a new folder &ldquo;Blog&rdquo;.</p>
<p><img alt="Screenshot of the shortcut folder dedicated to my blog." loading="lazy" src="/blog/2023-01-21-hugo-meet-android/shortcuts.jpg"></p>
<p>So, my workflow now consists of pulling, creating a new post, editing it, optionally firing up Hugo to check on the whole thing locally, committing and pushing, all at least without <em>needing</em> to touch the terminal, but always <em>able</em> to if so desired.</p>
<p>It&rsquo;s not perfect, and some app that takes care of all of this from a nice UI would certainly be better (<em>hint hint</em>). But - as this post created entirely from my phone proves - it works for now 😁</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Quick shoutout to <a href="https://pipe.how/write-androidblog/">this post by Emanuel Palm</a> who found himself in a similar situation (prior to boarding a plane to boot) and showed me the path on which I was then able to set up a neat workflow.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>You&rsquo;ll obviously have to adjust that and the following bits with your own repo, name and email.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Note that I&rsquo;m aware of the existence of <code>hugo new</code>, however it insisted on prefilling the title with the date included and otherwise also felt a bit too inflexible, hence I decided to implement what I wanted directly in bash.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Meta: Hello Hugo!</title><link>https://foosel.net/blog/2023-01-20-hello-hugo/</link><pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate><guid>https://foosel.net/blog/2023-01-20-hello-hugo/</guid><description>Trying another static site generator in 2023</description><content:encoded><![CDATA[<p>Two years ago I was into learning <a href="https://reactjs.org/">React</a>, since that is what I&rsquo;m planning to use for a future
OctoPrint UI. And when I decided to reboot this webpage, I also figured I would use that
as a reason for experimenting with new build tools and techstacks. So I built this site
with <a href="https://nextjs.org/">next.js</a>, <a href="https://tailwindcss.com/">Tailwind CSS</a> and a bunch of other stuff, and spent a lot
of time implementing basic content management tooling and rendering.</p>
<p>However, once that was done, I realized that while I had learned a lot about React and next.js
in the process, I had not really created something that is fun to use, which reflected in my
reluctance to actually use it. Writing the post about <a href="/blog/2023-01-19-custom-steamdeck-buttons/">my custom SteamDeck buttons</a>,
yesterday really drove that point home again, and in fact kinda broke the camel&rsquo;s back for good 😅</p>
<p>So I decided to do what I&rsquo;d been meaning to do for a long time and finally took a look at <a href="https://gohugo.io/">Hugo</a>,
which I had seen used a lot by others for their blogs over the past years, and also its
<a href="https://github.com/adityatelange/hugo-PaperMod/">PaperMod theme</a> that I had seen on <a href="https://jugmac00.github.io/">Jürgen Gmach&rsquo;s website</a> (👋).</p>
<p>Color me extremely surprised when I had my page rebuilt within a couple of hours, with all the features I wanted and more, and a way nicer
experience for me as the content creator. I didn&rsquo;t even have to touch my posts that much, mostly some small changes on the frontmatter and boom, done.</p>
<p>So I went down the rabbit hole further, fine tuned some things, customized some others, and now I&rsquo;m really happy with the result.</p>
<p>And thus, please say hello to a new version of  <code>foosel.net</code>, now powered by Hugo and PaperMod.</p>
]]></content:encoded></item></channel></rss>