diff --git a/Makefile b/Makefile index a7f7a16..95a71eb 100644 --- a/Makefile +++ b/Makefile @@ -4,3 +4,6 @@ test: build: @echo "Building site" @hugo build + +deploy: build + @scp -r public/* server.local.bitard.fr:~/blog/ \ No newline at end of file diff --git a/content/post/2025-03-30-welcome-gemini.md b/content/post/2025-03-30-welcome-gemini.md new file mode 100644 index 0000000..e7fc312 --- /dev/null +++ b/content/post/2025-03-30-welcome-gemini.md @@ -0,0 +1,49 @@ +--- +categories: +- software +date: "2025-03-30T00:00:00Z" +tags: ["software"] +title: Publishing this blog on Gemini +summary: Using Hugo +--- + +TLDR: I have [my blog][blog_gemini] published on gemini. +You can look at my [Pull request][pull_request] if you want to copy/paste the code for Hugo. + +I've looked at [Gemini][gemini] for quite a while, and I wanted to use it for this blog. +Some time ago I used Jekyll and could not found any resource on how to create gemini files from jekyll. + +I switched to Hugo some time ago and I tried to output to gemtext, without success. + +This time I really gave it a try and I think I found a nice setup. + +I relied on 2 blog posts I found, the first one by [Sylvain Durand][sylvaindurand] and the second one by [Brain baking][brainbaking] + +These resources were quite outdated, they both gave up on gemini after quite some time, which I can understand but at the same time makes me sad. + +## Main issue + +My biggest problem is the conversion of links into a Gemtext compatible format. +For those who use the inline syntax (brackets+parentheses), that's pretty straightforward, but I use the markdown indirections, where all my links are at the bottom of the document. + + +First I had to create a map containing all the key/url pairs. +Then replace every link in my document with a reference number. +And finally, display all the references at the end of the document. + +## Build and serve + +You can have a look at this [pull request][pull_request] to glue this together, then you can build and deploy. + +Building is as easy as typing `hugo build`. +To deploy, I used [Agate][agate] server, with the docker image it's as easy as `docker run --name gemini -d --restart unless-stopped -p 1965:1965 -v /path_to_public_folder/:/gmi:ro -v /path_to_certs:/certs ghcr.io/mbrubeck/agate:3.3.14 --hostname blog.bitard.fr` + +From now one, I should by able to publish both on the web and on Gemini \o/ + + +[agate]: https://github.com/mbrubeck/agate +[blog_gemini]: gemini://blog.bitard.fr +[pull_request]: https://github.com/agileek/agileek.github.io/pull/3 +[gemini]: https://geminiprotocol.net/ +[sylvaindurand]: https://sylvaindurand.org/gemini-and-hugo/ +[brainbaking]: https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/ diff --git a/hugo.toml b/hugo.toml index afef130..5fe0748 100644 --- a/hugo.toml +++ b/hugo.toml @@ -5,15 +5,17 @@ languageCode = "en-us" title = "Software" enableRobotsTXT = true sectionPagesMenu = 'main' +summaryLength = 0 [pagination] pagerSize = 200 [outputs] -home = ["HTML", "RSS", "JSON"] +home = ["HTML", "RSS", "JSON", "GEMINI", "GEMINI_RSS"] +page = ["HTML", "GEMINI"] [params] -env = "production" # to enable google analytics, opengraph, twitter-cards and schema. +env = "production" description = "Yet another blog on software stuff" author = "Michaël Bitard" @@ -32,7 +34,7 @@ ShowPageNums = true ShowToc = true comments = false images = ["images/home.png"] -hideAuthor=true +hideAuthor = true # homeInfoParams.Title="PaperMod's Demo" # homeInfoParams.Content="👋 Welcome to demo page of Hugo's theme PaperMod!" [params.editPost] @@ -43,9 +45,28 @@ appendFilePath = true # to append fi text = "Yet another blog on software stuff" [markup.goldmark.renderer] - unsafe = true +unsafe = true # FIXME add asciinema # FIXME Languages # [[module.imports]] # path= "https://github.com/hybras/hugo-asciinema" +[mediaTypes] +[mediaTypes.'text/gemini'] +delimiter = '.' +suffixes = ['gmi'] + +[outputFormats] +[outputFormats.GEMINI] +baseName = 'index' +isHTML = false +isPlainText = false +mediaType = 'text/gemini' +protocol = "gemini://" +permalinkable = true + +[outputFormats.GEMINI_RSS] +baseName = 'feed' +isPlainText = false +mediaType = 'application/rss+xml' +protocol = "gemini://" diff --git a/layouts/_default/single.gmi b/layouts/_default/single.gmi new file mode 100644 index 0000000..a9a6042 --- /dev/null +++ b/layouts/_default/single.gmi @@ -0,0 +1,77 @@ +# {{ .Title | plainify }} + +{{- $scratch := newScratch }} +{{- $content := .RawContent -}} +{{- $content := $content | replaceRE `#### ` "### " -}} +{{- $content := $content | replaceRE `\\\n` "\n" -}} +{{- $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}} +{{- $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}} +{{- $content := $content | replaceRE `
` "\n" -}} +{{- $content := $content | replaceRE `(.+?)` "[$2]($1)" -}} +{{- $content := $content | replaceRE `{{ youtube (.+?) >}}` "=> https://www.youtube.com/watch?v=$1 YouTube 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 }} +{{- /* Get 'simple links' */}} +{{- 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]" -}} +{{- $linksValue := findRESubmatch `\[([^^:\]]*)\]:[ ]*(.+)\n` $content }} +{{- $scratch.Set "content" $content }} +{{- range $linksValue }} + {{- $contentInLoop := $scratch.Get "content" }} + {{- $scratch.Set (index . 1) (index . 2) }} + {{- $contentInLoop := replace $contentInLoop (index . 0) "" -}} + {{- $scratch.Set "content" $contentInLoop }} +{{- end }} +{{- $imagesMD := findRESubmatch `!\[([^^]+?)\]\[(.+?)\]` $content }} +{{- range $imagesMD }} + {{- $contentInLoop := $scratch.Get "content" }} + {{- $url := (printf "![%s](%s)" (index . 1) ($scratch.Get (index . 2) )) }} + {{- $contentInLoop := replace $contentInLoop (index . 0) $url -}} + {{- $scratch.Set "content" $contentInLoop }} +{{- end }} +{{- $content := $scratch.Get "content" -}} +{{- $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}} +{{- $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}} +{{- $linksMD := findRESubmatch `\[([^^]+?)\]\[(.+?)\]` $content }} +{{- $scratch.Set "content" $content }} +{{- range $linksMD }} + {{- $ref := $scratch.Get "ref" }} + {{- $contentInLoop := $scratch.Get "content" }} + {{- $url := (printf "%s[%d]" (index . 1) $ref) }} + {{- $contentInLoop := replace $contentInLoop (index . 0) $url -}} + {{- $scratch.Set "content" $contentInLoop }} + {{- $scratch.Set "ref" (add $ref 1) }} +{{- end }} +{{- $content := $scratch.Get "content" -}} +{{ $content | safeHTML }} + +--- +## 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}} +{{- range $linksMD }} +{{- $ref := $scratch.Get "ref" }} +{{- $url := (printf "%s #%d" (index . 1) $ref) }} +=> {{ $scratch.Get (index . 2) }} [{{ $ref }}] {{ index . 1}} ({{ $scratch.Get (index . 2) }}) +{{- $scratch.Set "ref" (add $ref 1) }} +{{- end}} +--- + +=> / Back to the Index +=> https://agileek.github.io{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW diff --git a/layouts/index.gemini_rss.xml b/layouts/index.gemini_rss.xml new file mode 100644 index 0000000..ae65bba --- /dev/null +++ b/layouts/index.gemini_rss.xml @@ -0,0 +1,22 @@ + + + {{ .Site.Title }} + {{ i18n "description" }} + {{ (replace .Permalink "https://" "gemini://") | safeURL }} + + {{- if .IsHome }} + {{- $pages := union .RegularPages .Sections }} + {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }} + {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }} + {{- $paginator := .Paginate $pages }} + {{- range $paginator.Pages }} + + {{ .Title | plainify }} + {{ (replace .Permalink "https://" "gemini://") | safeURL }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} + {{ (replace .Permalink "https://" "gemini://") | safeURL }} + + {{ end }} + {{ end }} + + \ No newline at end of file diff --git a/layouts/index.gmi b/layouts/index.gmi new file mode 100644 index 0000000..a40d4aa --- /dev/null +++ b/layouts/index.gmi @@ -0,0 +1,17 @@ +## Navigation + +{{ range .RegularPages }} +=> {{ .RelPermalink }} {{ .Title | plainify }} +{{- end }} + +## List of posts + +{{- if .IsHome }} + {{- $pages := union .RegularPages .Sections }} + {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }} + {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }} + {{- $paginator := .Paginate $pages }} + {{- range $index, $page := $paginator.Pages }} +=> {{ .RelPermalink }} {{ .Title | plainify }}{{ if gt (len .Summary) 0 }} - {{ .Summary | plainify | htmlUnescape }}{{ end }} ({{ .Date.Format ((default "2006/01/02" site.Params.DateFormat)) }}) + {{- end }} +{{- end }}