brainbaking-com-ro5lug.txt (16592B)
1 [1]skip to main content 2 [2] [logo] 3 4 • [3]Archives 5 • [4]Works 6 • [5]About 7 • [6]More... 8 9 Using Hugo to Launch a Gemini Capsule 10 11 3 April 2021 12 13 As you can read in the “[7]exploring the AlterNet” article, I’ve had my eye on 14 Gemini for a few weeks now. Ever since discovering the new protocol thanks to a 15 couple of weird Mastodon toots, I’ve been thinking about how to set up a 16 “capsule” (they’re not called sites) for myself. I like the appeal of a 17 text-focused, no-whizzbang protocol where the focus is on contents, not 18 aesthetics, especially for blogs such as this one. 19 20 A few questions needed to be answered before switching to action modus and 21 letting the static site generator Hugo do our dirty Gemini work for us. 22 23 How to host a Gemini capsule? 24 25 There are many pieces of [8]Gemini software available to us, but they’re all 26 quite new, as the protocol itself is from 2019. I was keen on trying out a 27 simple Go server, but both go-gemini-server, shavit, and go-gemini required me 28 to build it myself and contained very little documentation. Furthermore, some 29 packages weren’t updated in more than a year… In the end, I decided to go with 30 [9]Agate, a simple Gemini server written in Rust that can serve static files. 31 It has binaries for every platform, was updated six days ago, and its README.md 32 it extensive. 33 34 Agate even generates the needed TLS certificates if none are provided. This 35 allowed me to quickly set up a localhost server using the command agate 36 --content docs/gemini --addr 0.0.0.0:1965 --hostname localhost --lang en-US. 37 Fun fact about the port number: 38 39 When Gemini is served over TCP/IP, servers should listen on port 1965 (the 40 first manned Gemini mission, Gemini 3, flew in March ‘65). 41 42 Running locally before pushing to a server was important to me as I wanted to 43 fiddle with the .gmi files first to see how they look like in my Gemini browser 44 /client, [10]Lagrange. Gotta double-check the ASCII art! 45 46 What to publish on Gemini? 47 48 This is very personal. There are a few options. People like [11]Drew DevVault 49 and [12]Sylvain Durand mirror their HTTP(S) blog on Gemini, meaning all blog 50 entries are consultable both over the web and over Gemini. Then there are more 51 personal articles, published solely on Gemini to accompany the usually more 52 technical HTTP blogs, such as [13]gemini://space.eli.li/. He claims to use it 53 to whine like we did on MySpace yesteryear. I’ve also seen hybrids popping up: 54 articles that are ported, but some exclusive content is also available through 55 Gemini. I like that. My method at least makes this possible. 56 57 I wanted to blog in Dutch, my mother language, for a while now, and I’ve tried 58 it a few years back on Brain Baking. It didn’t work out. The entries were 59 misplaced somehow and I wasn’t satisfied, even though I did not expect to 60 actually have readers. I hoped to use a new domain, wouter.gr, for a Dutch 61 Gemini capsule to do some personal whining. That sounded like a good plan. 62 63 The plan fell through. Instead, I decided to mirror Brain Baking. Why? 64 65 • I already whine in Dutch in my personal diaries using a fountain pen. I do 66 not want to give that up. 67 • I already have a (nice?) blog, and I’d like to expand the Gemini 68 space-i-verse by adding my existing articles to it. I already write in 69 Markdown, so a conversion would be not too difficult. 70 • I don’t think I can keep up with posting on yet another blog, since I also 71 occasionally write about retro games on [14]jefklakscodex.com. 72 73 How to publish on Gemini? 74 75 Right. Porting articles turns out to be ridiculously easy with the help of my 76 good old friend, Hugo. [15]Sylvain’s method for declaring Gemini as a custom 77 Hugo output format turned out to work flawlessly. All credits go to him. 78 However, I did make a few significant changes to the link replacement system. 79 First, something important to consider: I do not get rid of special emphasis 80 symbols such as underscores or stars, that are Markdown-specific. I still think 81 they add something when reading plain text and they’re the next best thing to 82 have without any markup at all. So I removed those regex-es. 83 84 Gemini pages cannot have inline links, so I had to strip out Markdown-style [] 85 () links and place them on a separate paragraph using => link title. A simple 86 find-and-replace, like in Sylvain’s method, is quite ugly if you use inline 87 links extensively like I do. It breaks up the text and the result is a 88 difficult to read Gemlog (that’s a Gemini blog!). In my approach, I collect all 89 links, replace them with a reference number like in academic papers ([1]), and 90 add a section called “References” on the bottom of the article to list them 91 all. This is what it looks like: 92 93 [16] [gemini] My Gemini AlterNet article in Lagrange. 94 95 I’m quite pleased with the result, although the code itself is far from pretty, 96 as Gemini is very newline-sensitive, and I had to jam a bunch of Hugo-specific 97 regex functions together. Source code available at GitHub: index.gmi source, 98 single.gmi source (see below). Next to the link change, I also replaced all - 99 and 1. (number) lines, that are enumerators in Markdown, with * ones, which is 100 the only supported enumerator in Gemfiles. 101 102 I tried to design the index and single layout files as similar as possible to 103 their html variants, while focusing in simplicity. Related articles are also 104 visible at the end of an article, and the index file simply contains a short 105 bio followed by an overview of all posts, groupbed by year and month, just like 106 in my [17]html /post overview. After defining [outputFormats.GEMINI] in my Hugo 107 config.toml, all that was left is to use rsync to copy over the gemini 108 subfolder to an appropriate location that gets picked up by Agate. Job done! 109 110 Well, not entirely. My Markdown files are littered with surprisingly 111 Hugo-specific junk: 112 113 • Shortcodes, such as YouTube, embedded video or audio. 114 • Four hashes - h4 - which isn’t supported by the Gemini protocol. 115 • <span/> tags in my quotes that help with HTML markup. 116 • Links to aliases that are redirects, which don’t work for the Gemini output 117 format. 118 119 Also, after trying out a second Gemini client, the terminal-friendly [18]Amfora 120 , I noticed the reference numbers do not align with Amfora’s shortcut keys that 121 allow you to quickly navigate to a link. Reference 1 would match to key 2. Why? 122 Because an image is also converted to a link (=> url), wich is placed 123 in-between text, while the actual references are at the bottom. Hence, pressing 124 number one would let us download the image - except Amfora can’t handle that 125 (yet). I solved this by starting at a specific index, based on the number of 126 times the arrow notation is present in the .gmi file, before processing inline 127 links. These are all things to take into account when writing future posts. 128 129 Now, the the most important question, “why publish on Gemini” could be answered 130 with “because it’s easy!”. I’m not yet sure if that answer is very 131 satisfactory, but at least Brain Baking got launched into Space today 🚀! All 132 that is left is to submit it to the GUS Gemini Universal Search engine… 133 134 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 135 136 Edit 21 June 2021: After a few months of fiddling with Gemini, I came to the 137 conclusion that it’s simply too early. There’s almost nothing there, and it 138 only increases the complexity of my website codebase. Therefore, I pulled yet 139 another plug. Sorry! 140 141 For future reference, the following files have been added to enable Gemini 142 functionality: 143 144 layouts/_default/index.atom.xml: 145 146 {{- $allowedRssSections := (slice "post") -}} 147 {{- $baseurl := .Site.BaseURL -}} 148 {{- $pctx := . -}} 149 {{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} 150 {{- $pages := slice -}} 151 {{- if or $.IsHome $.IsSection -}} 152 {{- $pages = $pctx.RegularPages -}} 153 {{- else -}} 154 {{- $pages = $pctx.Pages -}} 155 {{- end -}} 156 {{- $limit := .Site.Config.Services.RSS.Limit -}} 157 {{- if ge $limit 1 -}} 158 {{- $pages = $pages | first $limit -}} 159 {{- end -}} 160 {{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }} 161 <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> 162 <title>{{ .Site.Title }}</title> 163 {{- $perm := replace .Permalink "/gemini" "" 1 -}} 164 {{- $alt := .Site.BaseURL | replaceRE `https?://(.+?)` "gemini://$1" -}} 165 {{ printf "<link rel=\"self\" type=\"application/atom+xml\" href=\"%s\"/>" $perm | safeHTML }} 166 {{ printf "<link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>" $alt | safeHTML }} 167 <updated>{{ .Date.Format "2006-01-02T15:04:05-0700" | safeHTML }}</updated> 168 <author> 169 <name>{{ .Site.Author.name }}</name> 170 <uri>{{ .Site.BaseURL | replaceRE `https?://(.+?)` "gemini://$1" }}</uri> 171 </author> 172 <id>{{ $perm }}</id> 173 {{ range $pages }} 174 {{ if in $allowedRssSections .Section }} 175 <entry> 176 <title>{{ .Title }}</title> 177 {{- $entryperm := .Permalink | replaceRE `https?://(.+?)` "gemini://$1" -}} 178 {{ printf "<link rel=\"alternate\" href=\"%s\"/>" $entryperm | safeHTML }} 179 <id>{{ $entryperm }}</id> 180 <published>{{ .Date.Format "2006-01-02T15:04:05-0700" | safeHTML }}</published> 181 <updated>{{ .Lastmod.Format "2006-01-02T15:04:05-0700" | safeHTML }}</updated> 182 <summary>{{ if isset .Params "subtitle" }}{{ .Params.subtitle }}{{ else }}{{ .Summary | html }}{{ end }}</summary> 183 </entry> 184 {{ end }} 185 {{ end }} 186 </feed> 187 188 layouts/index.gmi: 189 190 # Brain Baking in Space 191 192 > Brain Baking: transforming personal thoughts about thoughts into well-digestible material. The reflective aroma of burnt nervous tissue. Includes a crispy crust of relations between technology, philosophy and the world. 193 194 ## About The Head Brain Baker 195 196 Hey! Yadda yadda 197 198 => https://ko-fi.com/woutergroeneveld Ko-fi Donations 199 => mailto:{{ .Site.Author.email }} E-mail 200 201 ## Freshly Baked Thoughts: The Gemlog 202 203 => /atom.xml Gemini Atom Feed 204 {{ range (where (where (where .Site.Pages "Section" "in" (slice "post")) ".Params.type" "ne" "archive") ".Params.concept" "ne" "true").GroupByDate "2006" "desc" }}{{ $year := .Key -}} 205 {{ range .Pages.GroupByDate "January" }} 206 ### {{ .Key }} {{ $year }} 207 {{ range .Pages.ByDate.Reverse }} 208 => {{ replace .RelPermalink "/gemini" "" 1}} {{ .Date.Format ("02") }} - {{ .Title }} 209 {{ .Params.Subtitle }}{{ end }} 210 {{ end }} 211 {{ end }} 212 213 # That's All Folks. 214 215 => https://brainbaking.com Brain Baking on the WWW 216 217 And lastly, layouts/_default/single.gmi: (Note the space between {{ < that 218 should be removed) 219 220 # {{ .Title }}{{ $scratch := newScratch }} 221 {{ $content := .RawContent -}} 222 {{ $content := $content | replaceRE `#### ` "### " -}} 223 {{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}} 224 {{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}} 225 {{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}} 226 {{ $content := $content | replaceRE `<br/??>` "\n" -}} 227 {{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}} 228 {{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}} 229 {{ $content := $content | replaceRE `{{ < audio "(.+?)" >}}` "=> https://brainbaking.com/$1 Embedded Audio link - $1" -}} 230 {{ $content := $content | replaceRE `{{ < video "(.+?)" >}}` "=> https://brainbaking.com/$1 Embedded Video link - $1" -}} 231 {{ $content := $content | replaceRE `{{ < youtube (.+?) >}}` "=> https://www.youtube.com/watch?v=$1 YouTube Video link to $1" -}} 232 {{ $content := $content | replaceRE `{{ < vimeo (.+?) >}}` "=> https://vimeo.com/$1 Vimeo Video link to $1" -}} 233 {{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}} 234 {{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}} 235 {{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}} 236 {{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) }} 237 {{ $refs := findRE `\[.+?\]\(.+?\)` $content }} 238 {{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}} 239 {{ $content | safeHTML }} 240 241 --- 242 Written by Wouter Groeneveld on {{ .Lastmod.Format (.Site.Params.dateFormat | default "2 January 2006") }}. 243 244 ## References 245 {{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }} 246 => {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}} 247 {{ $scratch.Set "ref" (add $ref 1) }}{{ end}} 248 {{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }} 249 {{ if $related }} 250 ## Related articles 251 {{ range $related }} 252 => {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }} 253 --- 254 255 => / Back to the Index 256 => https://brainbaking.com{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW 257 258 For more information, feel free to contact me or to [19]plod around in the Git 259 repo history tab. 260 261 [20]webdesign [21]gemini [22]hugo [23]accessibility 262 263 You Might Also Like... 264 265 • [24]Why I Retired My Webmention Server 08 May 2023 266 • [25]Cool Things People Do With Their Blogs 27 Apr 2022 267 • [26]Reducing Workflow Load Facilitates Writing 03 Jul 2021 268 • [27]Exploring the AlterNet 24 Mar 2021 269 • [28]Finding Related Images in Hugo 08 Oct 2024 270 • [29]Visualizing Blog Post Links With Obsidian 10 Jun 2024 271 • [30]Displaying Series of Posts in Hugo 04 Jan 2024 272 273 Bio and Support 274 275 [avatar2024] 276 277 I'm [31]Wouter Groeneveld, a Brain Baker, and I love the smell of freshly baked 278 thoughts (and bread) in the morning. I sometimes convince others to bake their 279 brain (and bread) too. 280 281 If you found this article amusing and/or helpful, you can support me via [32] 282 PayPal or [33]Ko-Fi. I also like to hear your feedback via [34]Mastodon or 283 email. Thanks! 284 285 JavaScript is disabled. I use it to obfuscate my e-mail, keeping spambots at 286 bay. 287 Reach me using: [firstname] at [this domain]. 288 289 ↑ [35]Top | [36]Archives | [37]RSS Feed | [38]bv | [39]© CC BY 4.0 License. 290 [40] [brainbakin] 291 292 293 References: 294 295 [1] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/#top 296 [2] https://brainbaking.com/ 297 [3] https://brainbaking.com/archives/ 298 [4] https://brainbaking.com/works/ 299 [5] https://brainbaking.com/about 300 [6] https://brainbaking.com/more 301 [7] https://brainbaking.com/post/2021/03/exploring-the-alternet/ 302 [8] https://gemini.circumlunar.space/software/ 303 [9] https://github.com/mbrubeck/agate 304 [10] https://gmi.skyjake.fi/lagrange/ 305 [11] gemini://drewdevault.com/ 306 [12] gemini://sylvaindurand.org 307 [13] gemini://space.eli.li/ 308 [14] https://jefklakscodex.com/ 309 [15] https://sylvaindurand.org/gemini-and-hugo/ 310 [16] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/gemini.jpg 311 [17] https://brainbaking.com/post 312 [18] https://github.com/makeworld-the-better-one/amfora 313 [19] https://git.brainbaking.com/wgroeneveld/brainbaking/ 314 [20] https://brainbaking.com/categories/webdesign 315 [21] https://brainbaking.com/tags/gemini 316 [22] https://brainbaking.com/tags/hugo 317 [23] https://brainbaking.com/tags/accessibility 318 [24] https://brainbaking.com/post/2023/05/why-i-retired-my-webmention-server/ 319 [25] https://brainbaking.com/post/2022/04/cool-things-people-do-with-their-blogs/ 320 [26] https://brainbaking.com/post/2021/07/reducing-workflow-load-facilitates-writing/ 321 [27] https://brainbaking.com/post/2021/03/exploring-the-alternet/ 322 [28] https://brainbaking.com/post/2024/10/finding-related-images-in-hugo/ 323 [29] https://brainbaking.com/post/2024/06/visualizing-blog-post-links-with-obsidian/ 324 [30] https://brainbaking.com/post/2024/01/displaying-series-of-posts-in-hugo/ 325 [31] https://brainbaking.com/about 326 [32] https://www.paypal.com/donate/?hosted_button_id=R2WTKY7G9V2KQ 327 [33] https://ko-fi.com/woutergroeneveld 328 [34] https://dosgame.club/@jefklak 329 [35] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/#top 330 [36] https://brainbaking.com/archives 331 [37] https://brainbaking.com/index.xml 332 [38] https://brainbaking.com/bv 333 [39] https://brainbaking.com/copyright-and-tracking-policy 334 [40] https://brainbaking.com/links