--- 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 ---