diff options
-rw-r--r-- | res/about/help.gmi | 87 | ||||
-rw-r--r-- | res/about/version.gmi | 18 |
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 | |||
328 | MIME 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 | |||
330 | Hooks 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 | |||
332 | Example 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 | |||
341 | When a hook is called, it is given the MIME type and parameters via command line arguments. The response body is provided via stdin. | ||
342 | |||
343 | The MIME type and parameters are split at semicolons, so "text/gemini; lang=ja" would be called as: | ||
344 | ``` | ||
345 | hookprogram text/gemini lang=ja | ||
346 | ``` | ||
347 | |||
348 | Output from the program (via stdout) must be a valid "20" Gemini response that includes the new MIME type: | ||
349 | ``` | ||
350 | 20 text/gemini; lang=en\r\n | ||
351 | {...body...} | ||
352 | ``` | ||
353 | |||
354 | Any 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 | |||
358 | Like 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 | |||
360 | Each 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 | |||
365 | For example: | ||
366 | ``` | ||
367 | Convert Atom to Gemini feed | ||
368 | application/xml | ||
369 | /usr/bin/python3;/home/jaakko/atomconv.py | ||
370 | ``` | ||
371 | |||
372 | The 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 | |||
376 | The 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 | ``` | ||
378 | import sys | ||
379 | import xml.etree.ElementTree as ET | ||
380 | |||
381 | def atomtag(n): | ||
382 | return '{http://www.w3.org/2005/Atom}' + n | ||
383 | |||
384 | root = ET.fromstring(sys.stdin.read()) | ||
385 | if root.tag != atomtag('feed'): | ||
386 | sys.exit(0) | ||
387 | feed_title = '' | ||
388 | feed_author = '' | ||
389 | feed_entries = [] | ||
390 | for 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) | ||
395 | print("20 text/gemini\r") | ||
396 | print(f'# {feed_title}') | ||
397 | for 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. |