summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/about/help.gmi87
-rw-r--r--res/about/version.gmi18
2 files changed, 104 insertions, 1 deletions
diff --git a/res/about/help.gmi b/res/about/help.gmi
index 3f21adb8..af534c2e 100644
--- a/res/about/help.gmi
+++ b/res/about/help.gmi
@@ -315,12 +315,99 @@ Other Unix : ~/.config/lagrange/
315 315
316* bindings.txt 316* bindings.txt
317* bookmarks.txt 317* bookmarks.txt
318* feeds.txt
318* idents.binary and idents/ 319* idents.binary and idents/
320* mimehooks.txt
319* prefs.cfg 321* prefs.cfg
320* state.binary 322* state.binary
321* trusted.txt 323* trusted.txt
322* visited.txt 324* visited.txt
323 325
326# MIME hooks
327
328MIME hooks enable piping Gemini responses through external programs for arbitrary processing. This allows leveraging scripting languages and binary executables to perform format conversions, content transformation, and data analysis.
329
330Hooks are configured using the file "mimehooks.txt" in Lagrange's config directory. Each hook has a regexp that is matched against the response MIME type and parameters, and each matching hook is offered the response body via stdin. The called external programs are free to rewrite the entire response, including the MIME type. If one of the hooks returns a valid response, it is used as the final response of the Gemini request.
331
332Example use cases:
333* Parsing an Atom XML feed and generating a Gemini feed index page
334* Rendering a MIDI file using Timidity as PCM WAV
335* Generate a graph PNG based on values in a CSV
336* Converting HTML or Markdown to 'text/gemini'
337* Language translations
338
339## Interface
340
341When a hook is called, it is given the MIME type and parameters via command line arguments. The response body is provided via stdin.
342
343The MIME type and parameters are split at semicolons, so "text/gemini; lang=ja" would be called as:
344```
345hookprogram text/gemini lang=ja
346```
347
348Output from the program (via stdout) must be a valid "20" Gemini response that includes the new MIME type:
349```
35020 text/gemini; lang=en\r\n
351{...body...}
352```
353
354Any output that does not follow this format is considered to mean that the hook refused to process the contents. The next hook will be offered the response instead.
355
356## mimehooks.txt syntax
357
358Like other Lagrange configuration lines, mimehooks.txt has a simple line-oriented syntax. Lagrange must be restarted for changes to the configuration file to take effect.
359
360Each hook is specified as three lines:
361* A human-readable label (for reporting to the user)
362* MIME type/parameter regular expression
363* Command to execute, plus additional arguments each separated with semicolons
364
365For example:
366```
367Convert Atom to Gemini feed
368application/xml
369/usr/bin/python3;/home/jaakko/atomconv.py
370```
371
372The hook program is executed directly without involving the shell. This means scripts must be invoked via the interpreter executable.
373
374## Example: Converting from Atom to Gemini
375
376The following simple Python script demonstrates how a MIME hook could be used to parse an Atom XML document using Python 3 and output a Gemini feed index page based on the parsed entries. This is just a simple example; a more robust script could include more content from the Atom feed and handle errors, too.
377```
378import sys
379import xml.etree.ElementTree as ET
380
381def atomtag(n):
382 return '{http://www.w3.org/2005/Atom}' + n
383
384root = ET.fromstring(sys.stdin.read())
385if root.tag != atomtag('feed'):
386 sys.exit(0)
387feed_title = ''
388feed_author = ''
389feed_entries = []
390for child in root:
391 if child.tag == atomtag('title'):
392 feed_title = child.text
393 elif child.tag == atomtag('entry'):
394 feed_entries.append(child)
395print("20 text/gemini\r")
396print(f'# {feed_title}')
397for entry in feed_entries:
398 entry_date = ''
399 entry_title = ''
400 entry_link = ''
401 for child in entry:
402 if child.tag == atomtag('updated'):
403 entry_date = child.text[:10]
404 elif child.tag == atomtag('title'):
405 entry_title = child.text
406 elif child.tag == atomtag('link'):
407 entry_link = child.attrib['href']
408 print(f'=> {entry_link} {entry_date} {entry_title}')
409```
410
324# Open source licenses 411# Open source licenses
325 412
326=> about:license 413=> about:license
diff --git a/res/about/version.gmi b/res/about/version.gmi
index 85490dc7..418d01c5 100644
--- a/res/about/version.gmi
+++ b/res/about/version.gmi
@@ -7,7 +7,23 @@
7# Release notes 7# Release notes
8 8
9## 0.12 9## 0.12
10* Subscribe to new headings on pages. 10* Added MIME hooks: pipe Gemini responses through external programs for arbitrary processing. (See "about:help" for usage.)
11* Added a right-hand sidebar; have a sidebar on the right or on both sides at once.
12* Added a clear warning banner when there is an issue with the server's TLS certificate.
13* Follow Weiph/pikkulogs — subscribe to new headings on pages.
14* Added UI for subscribing: feed name, entry type (Gemini feed or new headings).
15* Added keyboard shortcut ${SHIFT+}${CTRL+}D for subscribing to page.
16* Feeds sidebar is capped to 100 entries. "about:feeds" shows all known entries.
17* Network connections have a timeout in case server doesn't respond at all.
18* Adjusted spacing before/after links to reflect use of empty lines in the source.
19* Clicking on page area unfocuses URL input field.
20* Added keybindings for switching tabs.
21* Gopher: Query links have a 🔍 icon.
22* Fixed handling of "file:///" URIs on Windows.
23* Fixed misaligned Unicode box-drawing characters.
24* Fixed missing error page if status code is unknown (torture test 34).
25* Fixed detection of invalid headers (torture test 39).
26* Fixed rendering of soft hyphens (torture test 50).
11 27
12## 0.11 28## 0.11
13* Added feed subscriptions. A subscription is any bookmark with the "subscribed" tag. Subscribed feeds are refreshed in the background while Lagrange is running. 29* Added feed subscriptions. A subscription is any bookmark with the "subscribed" tag. Subscribed feeds are refreshed in the background while Lagrange is running.