feat: map user-facing file extensions to pandoc format names in export URIs

Users hitting /api/v1/export/threads/{id}.md got 'Unsupported format: md'
because pandoc's internal name is 'markdown'. Add EXTENSION_ALIASES +
resolve_format() so common extensions map to the right pandoc format:
  .md    -> markdown
  .html  -> html5
  .tex   -> latex
  .txt   -> plain
  .epub  -> epub3
  .wiki  -> mediawiki
  .adoc  -> asciidoc
  ...
Pandoc's own format names pass through unchanged (commonmark_x, docbook5,
fb2, etc.) via fallback.
This commit is contained in:
russell@unturf.com 2026-04-24 12:53:53 -04:00
parent 586f2366df
commit 2fd71e9029
2 changed files with 52 additions and 3 deletions

View file

@ -24,6 +24,7 @@ from remarkbox.lib.pandoc import (
node_tree_to_markdown,
namespace_to_markdown,
get_available_output_formats,
resolve_format,
CONTENT_TYPES,
FILE_EXTENSIONS,
BINARY_FORMATS,
@ -35,10 +36,14 @@ log = logging.getLogger(__name__)
def _parse_format_from_subpath(subpath):
"""Extract format from the subpath (e.g. 'abc-123.epub' -> ('abc-123', 'epub'))."""
"""Extract format from the subpath (e.g. 'abc-123.md' -> ('abc-123', 'markdown')).
Extensions are resolved through EXTENSION_ALIASES so users can hit common
file extensions (.md, .html, .tex) instead of pandoc's internal names.
"""
if "." in subpath:
parts = subpath.rsplit(".", 1)
return parts[0], parts[1]
stem, ext = subpath.rsplit(".", 1)
return stem, resolve_format(ext)
return subpath, "markdown"

View file

@ -111,6 +111,50 @@ FILE_EXTENSIONS = {
}
# URL extension → pandoc format name. Lets users hit intuitive extensions
# (`thread.md`, `thread.html`, `thread.tex`) instead of pandoc's internal
# names (`markdown`, `html5`, `latex`).
EXTENSION_ALIASES = {
"md": "markdown",
"markdown": "markdown",
"htm": "html5",
"html": "html5",
"tex": "latex",
"txt": "plain",
"1": "man",
"wiki": "mediawiki",
"adoc": "asciidoc",
"asciidoc": "asciidoc",
"rst": "rst",
"org": "org",
"rtf": "rtf",
"docx": "docx",
"odt": "odt",
"epub": "epub3",
"pdf": "pdf",
"pptx": "pptx",
"fb2": "fb2",
"jira": "jira",
"typ": "typst",
"texi": "texinfo",
"opml": "opml",
"icml": "icml",
"json": "json",
"xml": "docbook5",
"ipynb": "ipynb",
}
def resolve_format(ext):
"""Map a URL extension (lowercase) to its pandoc format name.
Falls back to the raw extension so pandoc's own format names
(`commonmark_x`, `docbook5`, etc.) pass through unchanged.
"""
ext = ext.lower()
return EXTENSION_ALIASES.get(ext, ext)
def get_available_output_formats():
"""Return the set of output formats pandoc supports on this system."""
try: