---
title: "Hugo : Gemini, Gopher… 'Quoi d'autres ?!'"
date: 2021-01-24T17:12:08+01:00
description: "Comment modifier simplement Hugo, en 5 minutes, pour qu'il génére les fichiers afin de publier sur les protocoles Gemini, Gopher…"
draft: false
tags: ["Hugo","Gemini","Gopher"]
---
## Description
Gemini et Gopher sont deux autres Internet, tout à fait légaux, dont le
but est de la publication "légère" d'informations, principalement du texte.
En fait, historiquement Gopher est né en 1991, en parallèle du Grand Net
sur protocole HTTP ; tandis que Gemini est un protocole de communication
récent, né courant juin 2019.
Tout comme le Grand Net sur HTTP(S), Gopher et Gemini ont leur propre
protocole de communication, portant leur propre nom :
- Gemini : `gemini://`
- Gopher : `gopher://`
À savoir que le protocole gemini est basé sur TLS directement…
De plus, bien que ces protocoles soient cloisonnés entre eux, en effet
les protocoles Gemini, Gopher et HTTP(S) sont des réseaux différents,
par des services différents, sur des ports différents, il existe des
passerelles du côté de Gemini et Gopher, vers HTTP(S).
Ne cherchez pas toutes les fioritures que permet le protocole HTTP(S),
exit les scripts CSS, JS, voire les images, avec Gemini et Gopher, on se
concentre principalement sur la ressource importante : le texte.
*cf : cherchez **Low Web*** ;-)
---
Comment modifier Hugo pour lui faire générer des fichiers à publier sur
les protocoles Gemini, et Gopher ?
Dans les faits, vous prendrez plus de temps à lire cet article,
qu'à faire vos modifications basiques, qui sont possibles d'être faites
en moins de 5 minutes !!!
*Il y a(ura) certainements de petites modifications à apporter… mais l'esprit
de l'article est là, et fonctionnel.* ;-)
{{}}
**ATTENTION** : les modifications ci-dessous actuellement sont fonctionnelles
dans le contexte d'une configuration basique de Hugo.
Dans le cas d'un site multi-langue, ou que vous avez paramétré la variable
`permalinks.posts`, le résultat attendu n'aura pas lieu.
Dans les faits, le repertoire géré par la variable `path` est lié au répertoire
de sortie. Ainsi dans le contexte multilangue, vous retrouverez dans chaque
répertoire de langue un répertoire nommé selon le protocole cible !
Ainsi, vous aurez dans le répertoire `public/`, d'abord les répertoires de
langue, puis le répertoire `gemini` ou `gopher`.
Alors que dans une configuration basique, le répertoire `gemini` ou `gopher`
sera directement déposé à la racine du répertoire `public/`.
{{}}
## Gemini
Concernant les modifications pour Gemini, voici le propos :
### Configuration pour Gemini
Modifions très simplement le fichier de configuration de Hugo `config.toml` :
#### Configuration Gemini : ajout du mimetype
```toml
# Gemini
[mediaTypes."text/gemini"]
suffixes = ["gmi"]
```
#### Configuration Gemini : ajout du format de sortie
```toml
# Gemini
[outputFormats.Gemini]
isPlainText = true
isHTML = false
mediaType = "text/gemini"
name = "gemini"
path = "gemini/"
permalinkable = true
protocol = "gemini://"
```
Remarquons que la publication des fichiers gmi auront lieu dans un répertoire
distinct, nommé **gemini**, dans le répertoire `public/`.
Ce seront de purs fichiers texte, ayant l'extension `.gmi`.
---
Puis dans la configuration de la sortie, par exemple :
```toml
[outputs]
home = ["HTML", "gemini", …]
page = ["HTML", "gemini", …]
```
*Bien sûr, ne pas utiliser les '…' dans votre configuration ; ici, ils
expriment les autres options de génération possible, sans les nommer !*
---
Gemini est capable de lire des fichiers au format RSS, ce qui nous permet
de générer un flux RSS ; ajoutons un nouveau format de sortie spécifique :
```toml
[outputFormats.GeminiRSS]
isHTML = false
mediaType = "application/rss+xml"
name = "GeminiRSS"
protocol = "gemini://"
path = "gemini/"
```
et modifions la génération de sortie, tel que par exemple :
```toml
[outputs]
home = ["HTML", "gemini", "GeminiRSS", …]
```
### Layouts pour Gemini
#### index.gmi
Ajoutons un fichier `index.gmi` dans le repertoire `layouts/`, qui pour
l'exemple aura le code hugo basique suivant :
```hugo
{{ range .Paginator.Pages }}
{{- if .OutputFormats.Get "gemini" }}
⇒ {{ replace .Permalink "/gemini" "" 1 }} {{ .Date.Format "January 2, 2006" }}: {{ .Title | safeHTML }}{{ end }}{{ end }}
```
*Libre à vous de modifier, améliorer la pertinence du code Hugo pour obtenir
le contenu que vous désirez publier…*
---
#### index.geminirss.xml
Si vous désirez gérez un flux RSS pour Gemini, selon la configuration ci-dessus,
ajoutons un fichier `index.geminirss.xml`, ayant le contenu de génération
tel que :
```hugo
{{- $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 "" | safeHTML }}
{{ .Site.Title | safeHTML }}
{{ replace .Permalink "https" "gemini" 1 }}
{{ .Site.Params.siteDescription | safeHTML }}Hugo {{ hugo.Version }} gohugo.io{{ with .Site.LanguageCode }}
{{.}}{{end}}{{ with .Site.Author.email }}
{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Author.email }}
{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Copyright }}
{{.}}{{end}}{{ if not .Date.IsZero }}
{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf "" .Permalink .MediaType | safeHTML }}
{{ end }}
{{ range $pages }}
{{- if .OutputFormats.Get "gemini" -}}
{{ .Title | safeHTML }}
{{ with .OutputFormats.Get "gemini" }}
{{replace .Permalink "/gemini" "" 1}}
{{ end }}
{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
{{ with .Site.Author.email }}{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}
{{ with .OutputFormats.Get "gemini" }}
{{replace .Permalink "/gemini" "" 1}}
{{ end }}
{{- end -}}
{{ end }}
```
#### single.gmi
Dans le répertoire enfant `_default` du sous répertoire `layouts/`, ajoutons
un simple fichier `single.gmi` qui s'occupera principalement de la génération
des pages :
```hugo
# {{ $.Title | safeHTML }}
{{ .RawContent }}
```
C'est basique ; ca fait le boulot, simplement. Là encore libre à vous de
modifier, ajouter votre code Hugo, pour générer plus proprement afin de
débarrasser du code Markdown, par exemple :
```hugo
{{ $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 ` ` "\n" -}}
{{ $content := $content | replaceRE `(.+?)` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$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 }}
```
**Explications :**
*Ce code - qui fait très bien son travail - est un copié-collé du code créé par un certain
[Wouter Groeneveld](https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/) ;
les explications sont fournies en anglais. N'ayant pas l'utilité de gérer
des fichiers audio, vidéo, localement ou sur d'autres plateformes, j'ai
simplement supprimé les lignes correspondantes.*
---
Voilà *(pour la partie Gemini)* !
*Il ne reste plus qu'à publier…*
## Gopher
Attaquons les modifications de configurations et de calques pour générer
les fichiers textes pour Gopher. Là encore, nous générons les fichiers
dans un répertoire dédié, nommé **gopher** dans le répertoire `public/`
afin de faciliter la synchronisation vers le serveur gopher…
### Configuration pour Gopher
Modifions donc le fichier de configuration de Hugo, pour ajouter les formats
de génération. En effet :
- le premier va nous être utile pour la génération des pages, qui porteront
le nom **index**, dans leur propre répertoire
- le second pour générer les fichiers d'indexation **gophermap**
Tous auront l'extension de fichier `.txt` et seront publiés dans un sous-répertoire
nommé **gopher** du répertoire `public/`.
```toml
[outputFormats.Gopher]
baseName = "index"
isPlainText = true
isHTML = false
mediaType = "text/plain"
noUgly = false
path = "gopher/"
protocol = "gopher://"
[outputFormats.GopherMap]
baseName = "gophermap"
isPlainText = true
isHTML = false
mediaType = "text/plain"
noUgly = false
path = "gopher/"
protocol = "gopher://"
```
Puis modifions la génération des sorties, tel que :
```toml
[outputs]
home = ["HTML", "gemini", "GeminiRSS", "gophermap", …]
page = ["HTML", "gemini", "gopher"]
```
### Layouts pour Gopher
Attaquons la partie des fichiers à créer dans le sous-répertoire `layouts/`.
#### index.gophermap.txt
Restons simple :
```hugo
{{ .Site.Title | safeHTML }}
⇒ Menu :
{{ range .Site.Menus.main }}
{{- if (or (eq .Identifier "search") (eq .Identifier "lang-switcher") (eq .Identifier "theme-switcher") ) }}
{{- else }}
1{{ .Name }} {{ .URL | safeURL }} 70
{{- end -}}
{{ end }}
⇒ Articles les plus récents :
{{ $nb := 7 }}
{{ range first $nb .Paginator.Pages }}
0{{ .Title }} {{ with .OutputFormats.Get "gopher" }} {{ replaceRE "/gopher" "" .RelPermalink }} 70 {{ end }}
{{- end }}
```
Ce fichier **gophermap** nous permet de publier simplement l'équivalent
du menu principal de Hugo, ainsi que promouvoir les `x` derniers
articles. - *ici, les 7 derniers* -
*Pour ceux qui n'auraient pas compris : les fichiers gophermap sont des
fichiers d'indexation de contenu…*
#### list.gophermap.txt
Ajoutons dans le répertoire enfant `_default/` du sous-répertoire `layout/`,
un fichier de génération de liste, qui peut avoir le contenu basique suivant :
```hugo
!{{ .Title | safeHTML }}
{{ .RawContent }}
{{ range .Paginator.Pages }}
0{{ .Title }} {{ with .OutputFormats.Get "gopher" -}}{{ .RelPermalink }} {{ $.Site.Params.hostname}} 70 {{ end }}
{{ end }}
```
#### single.gopher.txt
Pour la génération des pages, ajoutons dans le même sous-répertoire `_default/`,
un fichier nommé `single.gopher.txt` qui peut avoir le contenu basique suivant :
```hugo
!{{ .Title | safeHTML }}
{{ .Date.Format (.Site.Params.dateform | default "01 January 2006") }} · {{ .ReadingTime }} minute(s) de lecture.
{{ if .Params.tags }}
Tags : {{ range .Params.tags }}{{ . }} {{ end }}
{{ end }}
---
{{ .RawContent }}
---
Publié le : {{.Date.Format "2 January 2006"}}.
0⇒ Revenir à la page d'accueil : / 70
h⇒ Lire l'article “{{ $.Title | safeHTML }}” sur le protocole HTTP(S) : {{ .Permalink | safeURL }} 443
Le contenu de ce site est diffusé sous Licence {{ $.Site.Copyright | safeHTML }}.
```
---
*Encore une fois, à vous de modifier à votre convenance et autres imaginations
nécessaires pour votre promotion…*
Voilà *(pour la partie Gopher)* !
*Il ne reste plus qu'à publier…*
## Documentations
- le projet Gemini : https://gemini.circumlunar.space/
#### Wikipedia
- {{< wp Gemini en >}}
- {{< wp Gopher >}}
## Remerciements
- **Drew Devault** : un des premiers à modifier Hugo pour générer du contenu pour Gemini - *voici son [dépôt Git](https://git.sr.ht/~sircmpwn/drewdevault.com/tree/master) pour exemple !*
- **Sylvain Durant** : un parisien qui fait simple et dont je me suis inspiré pour la communauté "OpenBSD Pour Tous" : https://sylvaindurand.org/gemini-and-hugo/
- le dépôt Git de la communauté "OpenBSD Pour Tous", où vous retrouverez les modifications de génération pour gopher et gemini : https://tildegit.org/obsd4a/www
---