Finish March 2025 dispatch
This commit is contained in:
334
static/archive/brainbaking-com-ro5lug.txt
Normal file
334
static/archive/brainbaking-com-ro5lug.txt
Normal file
@@ -0,0 +1,334 @@
|
||||
[1]skip to main content
|
||||
[2] [logo]
|
||||
|
||||
• [3]Archives
|
||||
• [4]Works
|
||||
• [5]About
|
||||
• [6]More...
|
||||
|
||||
Using Hugo to Launch a Gemini Capsule
|
||||
|
||||
3 April 2021
|
||||
|
||||
As you can read in the “[7]exploring the AlterNet” article, I’ve had my eye on
|
||||
Gemini for a few weeks now. Ever since discovering the new protocol thanks to a
|
||||
couple of weird Mastodon toots, I’ve been thinking about how to set up a
|
||||
“capsule” (they’re not called sites) for myself. I like the appeal of a
|
||||
text-focused, no-whizzbang protocol where the focus is on contents, not
|
||||
aesthetics, especially for blogs such as this one.
|
||||
|
||||
A few questions needed to be answered before switching to action modus and
|
||||
letting the static site generator Hugo do our dirty Gemini work for us.
|
||||
|
||||
How to host a Gemini capsule?
|
||||
|
||||
There are many pieces of [8]Gemini software available to us, but they’re all
|
||||
quite new, as the protocol itself is from 2019. I was keen on trying out a
|
||||
simple Go server, but both go-gemini-server, shavit, and go-gemini required me
|
||||
to build it myself and contained very little documentation. Furthermore, some
|
||||
packages weren’t updated in more than a year… In the end, I decided to go with
|
||||
[9]Agate, a simple Gemini server written in Rust that can serve static files.
|
||||
It has binaries for every platform, was updated six days ago, and its README.md
|
||||
it extensive.
|
||||
|
||||
Agate even generates the needed TLS certificates if none are provided. This
|
||||
allowed me to quickly set up a localhost server using the command agate
|
||||
--content docs/gemini --addr 0.0.0.0:1965 --hostname localhost --lang en-US.
|
||||
Fun fact about the port number:
|
||||
|
||||
When Gemini is served over TCP/IP, servers should listen on port 1965 (the
|
||||
first manned Gemini mission, Gemini 3, flew in March ‘65).
|
||||
|
||||
Running locally before pushing to a server was important to me as I wanted to
|
||||
fiddle with the .gmi files first to see how they look like in my Gemini browser
|
||||
/client, [10]Lagrange. Gotta double-check the ASCII art!
|
||||
|
||||
What to publish on Gemini?
|
||||
|
||||
This is very personal. There are a few options. People like [11]Drew DevVault
|
||||
and [12]Sylvain Durand mirror their HTTP(S) blog on Gemini, meaning all blog
|
||||
entries are consultable both over the web and over Gemini. Then there are more
|
||||
personal articles, published solely on Gemini to accompany the usually more
|
||||
technical HTTP blogs, such as [13]gemini://space.eli.li/. He claims to use it
|
||||
to whine like we did on MySpace yesteryear. I’ve also seen hybrids popping up:
|
||||
articles that are ported, but some exclusive content is also available through
|
||||
Gemini. I like that. My method at least makes this possible.
|
||||
|
||||
I wanted to blog in Dutch, my mother language, for a while now, and I’ve tried
|
||||
it a few years back on Brain Baking. It didn’t work out. The entries were
|
||||
misplaced somehow and I wasn’t satisfied, even though I did not expect to
|
||||
actually have readers. I hoped to use a new domain, wouter.gr, for a Dutch
|
||||
Gemini capsule to do some personal whining. That sounded like a good plan.
|
||||
|
||||
The plan fell through. Instead, I decided to mirror Brain Baking. Why?
|
||||
|
||||
• I already whine in Dutch in my personal diaries using a fountain pen. I do
|
||||
not want to give that up.
|
||||
• I already have a (nice?) blog, and I’d like to expand the Gemini
|
||||
space-i-verse by adding my existing articles to it. I already write in
|
||||
Markdown, so a conversion would be not too difficult.
|
||||
• I don’t think I can keep up with posting on yet another blog, since I also
|
||||
occasionally write about retro games on [14]jefklakscodex.com.
|
||||
|
||||
How to publish on Gemini?
|
||||
|
||||
Right. Porting articles turns out to be ridiculously easy with the help of my
|
||||
good old friend, Hugo. [15]Sylvain’s method for declaring Gemini as a custom
|
||||
Hugo output format turned out to work flawlessly. All credits go to him.
|
||||
However, I did make a few significant changes to the link replacement system.
|
||||
First, something important to consider: I do not get rid of special emphasis
|
||||
symbols such as underscores or stars, that are Markdown-specific. I still think
|
||||
they add something when reading plain text and they’re the next best thing to
|
||||
have without any markup at all. So I removed those regex-es.
|
||||
|
||||
Gemini pages cannot have inline links, so I had to strip out Markdown-style []
|
||||
() links and place them on a separate paragraph using => link title. A simple
|
||||
find-and-replace, like in Sylvain’s method, is quite ugly if you use inline
|
||||
links extensively like I do. It breaks up the text and the result is a
|
||||
difficult to read Gemlog (that’s a Gemini blog!). In my approach, I collect all
|
||||
links, replace them with a reference number like in academic papers ([1]), and
|
||||
add a section called “References” on the bottom of the article to list them
|
||||
all. This is what it looks like:
|
||||
|
||||
[16] [gemini] My Gemini AlterNet article in Lagrange.
|
||||
|
||||
I’m quite pleased with the result, although the code itself is far from pretty,
|
||||
as Gemini is very newline-sensitive, and I had to jam a bunch of Hugo-specific
|
||||
regex functions together. Source code available at GitHub: index.gmi source,
|
||||
single.gmi source (see below). Next to the link change, I also replaced all -
|
||||
and 1. (number) lines, that are enumerators in Markdown, with * ones, which is
|
||||
the only supported enumerator in Gemfiles.
|
||||
|
||||
I tried to design the index and single layout files as similar as possible to
|
||||
their html variants, while focusing in simplicity. Related articles are also
|
||||
visible at the end of an article, and the index file simply contains a short
|
||||
bio followed by an overview of all posts, groupbed by year and month, just like
|
||||
in my [17]html /post overview. After defining [outputFormats.GEMINI] in my Hugo
|
||||
config.toml, all that was left is to use rsync to copy over the gemini
|
||||
subfolder to an appropriate location that gets picked up by Agate. Job done!
|
||||
|
||||
Well, not entirely. My Markdown files are littered with surprisingly
|
||||
Hugo-specific junk:
|
||||
|
||||
• Shortcodes, such as YouTube, embedded video or audio.
|
||||
• Four hashes - h4 - which isn’t supported by the Gemini protocol.
|
||||
• <span/> tags in my quotes that help with HTML markup.
|
||||
• Links to aliases that are redirects, which don’t work for the Gemini output
|
||||
format.
|
||||
|
||||
Also, after trying out a second Gemini client, the terminal-friendly [18]Amfora
|
||||
, I noticed the reference numbers do not align with Amfora’s shortcut keys that
|
||||
allow you to quickly navigate to a link. Reference 1 would match to key 2. Why?
|
||||
Because an image is also converted to a link (=> url), wich is placed
|
||||
in-between text, while the actual references are at the bottom. Hence, pressing
|
||||
number one would let us download the image - except Amfora can’t handle that
|
||||
(yet). I solved this by starting at a specific index, based on the number of
|
||||
times the arrow notation is present in the .gmi file, before processing inline
|
||||
links. These are all things to take into account when writing future posts.
|
||||
|
||||
Now, the the most important question, “why publish on Gemini” could be answered
|
||||
with “because it’s easy!”. I’m not yet sure if that answer is very
|
||||
satisfactory, but at least Brain Baking got launched into Space today 🚀! All
|
||||
that is left is to submit it to the GUS Gemini Universal Search engine…
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Edit 21 June 2021: After a few months of fiddling with Gemini, I came to the
|
||||
conclusion that it’s simply too early. There’s almost nothing there, and it
|
||||
only increases the complexity of my website codebase. Therefore, I pulled yet
|
||||
another plug. Sorry!
|
||||
|
||||
For future reference, the following files have been added to enable Gemini
|
||||
functionality:
|
||||
|
||||
layouts/_default/index.atom.xml:
|
||||
|
||||
{{- $allowedRssSections := (slice "post") -}}
|
||||
{{- $baseurl := .Site.BaseURL -}}
|
||||
{{- $pctx := . -}}
|
||||
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
|
||||
{{- $pages := slice -}}
|
||||
{{- if or $.IsHome $.IsSection -}}
|
||||
{{- $pages = $pctx.RegularPages -}}
|
||||
{{- else -}}
|
||||
{{- $pages = $pctx.Pages -}}
|
||||
{{- end -}}
|
||||
{{- $limit := .Site.Config.Services.RSS.Limit -}}
|
||||
{{- if ge $limit 1 -}}
|
||||
{{- $pages = $pages | first $limit -}}
|
||||
{{- end -}}
|
||||
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
|
||||
<title>{{ .Site.Title }}</title>
|
||||
{{- $perm := replace .Permalink "/gemini" "" 1 -}}
|
||||
{{- $alt := .Site.BaseURL | replaceRE `https?://(.+?)` "gemini://$1" -}}
|
||||
{{ printf "<link rel=\"self\" type=\"application/atom+xml\" href=\"%s\"/>" $perm | safeHTML }}
|
||||
{{ printf "<link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>" $alt | safeHTML }}
|
||||
<updated>{{ .Date.Format "2006-01-02T15:04:05-0700" | safeHTML }}</updated>
|
||||
<author>
|
||||
<name>{{ .Site.Author.name }}</name>
|
||||
<uri>{{ .Site.BaseURL | replaceRE `https?://(.+?)` "gemini://$1" }}</uri>
|
||||
</author>
|
||||
<id>{{ $perm }}</id>
|
||||
{{ range $pages }}
|
||||
{{ if in $allowedRssSections .Section }}
|
||||
<entry>
|
||||
<title>{{ .Title }}</title>
|
||||
{{- $entryperm := .Permalink | replaceRE `https?://(.+?)` "gemini://$1" -}}
|
||||
{{ printf "<link rel=\"alternate\" href=\"%s\"/>" $entryperm | safeHTML }}
|
||||
<id>{{ $entryperm }}</id>
|
||||
<published>{{ .Date.Format "2006-01-02T15:04:05-0700" | safeHTML }}</published>
|
||||
<updated>{{ .Lastmod.Format "2006-01-02T15:04:05-0700" | safeHTML }}</updated>
|
||||
<summary>{{ if isset .Params "subtitle" }}{{ .Params.subtitle }}{{ else }}{{ .Summary | html }}{{ end }}</summary>
|
||||
</entry>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</feed>
|
||||
|
||||
layouts/index.gmi:
|
||||
|
||||
# Brain Baking in Space
|
||||
|
||||
> 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.
|
||||
|
||||
## About The Head Brain Baker
|
||||
|
||||
Hey! Yadda yadda
|
||||
|
||||
=> https://ko-fi.com/woutergroeneveld Ko-fi Donations
|
||||
=> mailto:{{ .Site.Author.email }} E-mail
|
||||
|
||||
## Freshly Baked Thoughts: The Gemlog
|
||||
|
||||
=> /atom.xml Gemini Atom Feed
|
||||
{{ range (where (where (where .Site.Pages "Section" "in" (slice "post")) ".Params.type" "ne" "archive") ".Params.concept" "ne" "true").GroupByDate "2006" "desc" }}{{ $year := .Key -}}
|
||||
{{ range .Pages.GroupByDate "January" }}
|
||||
### {{ .Key }} {{ $year }}
|
||||
{{ range .Pages.ByDate.Reverse }}
|
||||
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Date.Format ("02") }} - {{ .Title }}
|
||||
{{ .Params.Subtitle }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
# That's All Folks.
|
||||
|
||||
=> https://brainbaking.com Brain Baking on the WWW
|
||||
|
||||
And lastly, layouts/_default/single.gmi: (Note the space between {{ < that
|
||||
should be removed)
|
||||
|
||||
# {{ .Title }}{{ $scratch := newScratch }}
|
||||
{{ $content := .RawContent -}}
|
||||
{{ $content := $content | replaceRE `#### ` "### " -}}
|
||||
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
|
||||
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
|
||||
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
|
||||
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
|
||||
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
|
||||
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
|
||||
{{ $content := $content | replaceRE `{{ < audio "(.+?)" >}}` "=> https://brainbaking.com/$1 Embedded Audio link - $1" -}}
|
||||
{{ $content := $content | replaceRE `{{ < video "(.+?)" >}}` "=> https://brainbaking.com/$1 Embedded Video link - $1" -}}
|
||||
{{ $content := $content | replaceRE `{{ < youtube (.+?) >}}` "=> https://www.youtube.com/watch?v=$1 YouTube Video link to $1" -}}
|
||||
{{ $content := $content | replaceRE `{{ < vimeo (.+?) >}}` "=> https://vimeo.com/$1 Vimeo Video link to $1" -}}
|
||||
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
|
||||
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
|
||||
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
|
||||
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) }}
|
||||
{{ $refs := findRE `\[.+?\]\(.+?\)` $content }}
|
||||
{{ $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]" -}}
|
||||
{{ $content | safeHTML }}
|
||||
|
||||
---
|
||||
Written by Wouter Groeneveld on {{ .Lastmod.Format (.Site.Params.dateFormat | default "2 January 2006") }}.
|
||||
|
||||
## References
|
||||
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
|
||||
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
|
||||
{{ $scratch.Set "ref" (add $ref 1) }}{{ end}}
|
||||
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
|
||||
{{ if $related }}
|
||||
## Related articles
|
||||
{{ range $related }}
|
||||
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}
|
||||
---
|
||||
|
||||
=> / Back to the Index
|
||||
=> https://brainbaking.com{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW
|
||||
|
||||
For more information, feel free to contact me or to [19]plod around in the Git
|
||||
repo history tab.
|
||||
|
||||
[20]webdesign [21]gemini [22]hugo [23]accessibility
|
||||
|
||||
You Might Also Like...
|
||||
|
||||
• [24]Why I Retired My Webmention Server 08 May 2023
|
||||
• [25]Cool Things People Do With Their Blogs 27 Apr 2022
|
||||
• [26]Reducing Workflow Load Facilitates Writing 03 Jul 2021
|
||||
• [27]Exploring the AlterNet 24 Mar 2021
|
||||
• [28]Finding Related Images in Hugo 08 Oct 2024
|
||||
• [29]Visualizing Blog Post Links With Obsidian 10 Jun 2024
|
||||
• [30]Displaying Series of Posts in Hugo 04 Jan 2024
|
||||
|
||||
Bio and Support
|
||||
|
||||
[avatar2024]
|
||||
|
||||
I'm [31]Wouter Groeneveld, a Brain Baker, and I love the smell of freshly baked
|
||||
thoughts (and bread) in the morning. I sometimes convince others to bake their
|
||||
brain (and bread) too.
|
||||
|
||||
If you found this article amusing and/or helpful, you can support me via [32]
|
||||
PayPal or [33]Ko-Fi. I also like to hear your feedback via [34]Mastodon or
|
||||
email. Thanks!
|
||||
|
||||
JavaScript is disabled. I use it to obfuscate my e-mail, keeping spambots at
|
||||
bay.
|
||||
Reach me using: [firstname] at [this domain].
|
||||
|
||||
↑ [35]Top | [36]Archives | [37]RSS Feed | [38]bv | [39]© CC BY 4.0 License.
|
||||
[40] [brainbakin]
|
||||
|
||||
|
||||
References:
|
||||
|
||||
[1] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/#top
|
||||
[2] https://brainbaking.com/
|
||||
[3] https://brainbaking.com/archives/
|
||||
[4] https://brainbaking.com/works/
|
||||
[5] https://brainbaking.com/about
|
||||
[6] https://brainbaking.com/more
|
||||
[7] https://brainbaking.com/post/2021/03/exploring-the-alternet/
|
||||
[8] https://gemini.circumlunar.space/software/
|
||||
[9] https://github.com/mbrubeck/agate
|
||||
[10] https://gmi.skyjake.fi/lagrange/
|
||||
[11] gemini://drewdevault.com/
|
||||
[12] gemini://sylvaindurand.org
|
||||
[13] gemini://space.eli.li/
|
||||
[14] https://jefklakscodex.com/
|
||||
[15] https://sylvaindurand.org/gemini-and-hugo/
|
||||
[16] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/gemini.jpg
|
||||
[17] https://brainbaking.com/post
|
||||
[18] https://github.com/makeworld-the-better-one/amfora
|
||||
[19] https://git.brainbaking.com/wgroeneveld/brainbaking/
|
||||
[20] https://brainbaking.com/categories/webdesign
|
||||
[21] https://brainbaking.com/tags/gemini
|
||||
[22] https://brainbaking.com/tags/hugo
|
||||
[23] https://brainbaking.com/tags/accessibility
|
||||
[24] https://brainbaking.com/post/2023/05/why-i-retired-my-webmention-server/
|
||||
[25] https://brainbaking.com/post/2022/04/cool-things-people-do-with-their-blogs/
|
||||
[26] https://brainbaking.com/post/2021/07/reducing-workflow-load-facilitates-writing/
|
||||
[27] https://brainbaking.com/post/2021/03/exploring-the-alternet/
|
||||
[28] https://brainbaking.com/post/2024/10/finding-related-images-in-hugo/
|
||||
[29] https://brainbaking.com/post/2024/06/visualizing-blog-post-links-with-obsidian/
|
||||
[30] https://brainbaking.com/post/2024/01/displaying-series-of-posts-in-hugo/
|
||||
[31] https://brainbaking.com/about
|
||||
[32] https://www.paypal.com/donate/?hosted_button_id=R2WTKY7G9V2KQ
|
||||
[33] https://ko-fi.com/woutergroeneveld
|
||||
[34] https://dosgame.club/@jefklak
|
||||
[35] https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/#top
|
||||
[36] https://brainbaking.com/archives
|
||||
[37] https://brainbaking.com/index.xml
|
||||
[38] https://brainbaking.com/bv
|
||||
[39] https://brainbaking.com/copyright-and-tracking-policy
|
||||
[40] https://brainbaking.com/links
|
||||
Reference in New Issue
Block a user