Preview & metadata¶
Two opt-in features that let a share be read and searched, not just downloaded. Both are off by default, cost nothing when off, and โ like everything else in servery โ are pure standard library with no JavaScript.
Previewing a file¶
With --preview, appending ?preview=1 to any file URL renders a page around
the file instead of sending its bytes:
| File type | What you get |
|---|---|
Markdown (.md) |
rendered to HTML โ headings, lists, tables, links, highlighted code fences |
| Source code | syntax-highlighted with line numbers (Python via the stdlib's own tokenize) |
Jupyter (.ipynb) |
markdown cells rendered, code cells highlighted, text outputs shown |
| JSON | re-indented and highlighted |
| CSV / TSV | a real table (first 500 rows) |
| Images | shown inline |
| Audio / video | native <audio> / <video> controls |
| PDF, archives, binaries | an honest card with Download / Open raw |
Each listing row grows a ๐ link for anything previewable, next to the existing โ download link.
Rendered or source¶
Anything textual can also be read as highlighted source:
http://localhost:8000/README.md?preview=1 # rendered
http://localhost:8000/README.md?preview=source # syntax-highlighted source
The page carries a Rendered/Source toggle, so it is one click either way.
Languages¶
Python is tokenized by the standard library's own tokenize, so the result is
exactly CPython's view of the source. Roughly 35 more languages go through a
bounded scanner: C, C++, C#, Java, Go, Rust, Swift, Kotlin, Objective-C,
JavaScript/TypeScript, PHP, Ruby, Perl, Lua, R, Julia, Haskell, Lisp, shell, SQL,
HTML/XML/SVG, CSS, LaTeX, BibTeX, YAML, TOML/INI, JSON, Markdown,
reStructuredText, diff, Makefile, and Dockerfile.
Limits, on purpose¶
- Files above
--preview-max-bytes(default 2 MiB) are not read; you get a download card instead. The preview holds the whole file in memory. - The Markdown renderer is a subset, not CommonMark โ see Principles. It covers what a README needs; it is not GFM.
- Raw HTML in Markdown is escaped, never passed through, and link/image URLs
must pass a scheme allowlist, so a
javascript:ordata:URL cannot survive. A hostile.mdsomeone uploaded to your drop box cannot script the preview page. - The preview page's Content-Security-Policy is the listing's, plus
media-src 'self'for the players.img-srcstays'self', so remote images (README badges, for example) do not load โ a preview never fetches from a third party on your behalf.
Metadata¶
With --metadata, servery reads inside each file โ bounded, and never executing
anything โ and normalizes what it finds onto one small record:
| Format | Extracted |
|---|---|
| Markdown | YAML/TOML front matter; else the first heading and paragraph |
| Python | module docstring, __author__, __version__, __date__, class/function counts (via ast) |
| LaTeX | \title{}, \author{}, \date{}, \documentclass{} |
| HTML | <title>, <meta name=author/description/keywords>, <html lang> |
| TOML / JSON | PEP 621 [project], Cargo [package], package.json fields |
| Notebooks | first markdown heading, kernel, language, cell count |
| CSV / TSV | column names and row count |
| reStructuredText | title and :Field: docinfo |
| Images | dimensions (PNG, JPEG, GIF, WebP, BMP, SVG) + PNG text chunks |
| MP3 | ID3v2 title, artist, album, year, genre |
| Info dictionary title/author/subject/keywords, PDF version |
Show¶
The listing gains a Title column (author or description underneath), and the column header sorts by it:
| Query | Effect |
|---|---|
?C=T |
sort by extracted title |
?C=A |
sort by extracted author |
Files with nothing extracted sort last, not first.
Filter¶
| Query | Effect |
|---|---|
?meta=author:lovelace |
files whose extracted author contains lovelace |
?meta=tag:draft |
files tagged draft (also: clickable tag chips) |
?meta=title:report |
by title โ likewise description, date, version, lang |
?meta=lovelace |
no field given: search every extracted field |
Directories are always kept, so navigation still works while a filter is on.
Extract¶
?metadata=1 returns JSON instead of a page โ for one file, or for a whole
directory:
$ curl -s 'http://localhost:8000/post.md?metadata=1' | jq .metadata
{
"kind": "markdown",
"title": "The Title",
"author": "Ada Lovelace",
"tags": ["alpha", "beta"]
}
$ curl -s 'http://localhost:8000/?metadata=1' | jq -r '.entries[] | "\(.name)\t\(.metadata.title // "-")"'
sub -
post.md The Title
Each entry carries name, path, type, size, modified, content_type, and
the extracted metadata.
Cost¶
Extraction reads at most --metadata-max-bytes (default 64 KiB) per file and
caches the result on (path, mtime, size), so re-sorting or re-filtering a large
directory costs no I/O. A corrupt, truncated, or hostile file yields an empty
record โ it can never break a listing.
Flags¶
| Flag | Default | Description |
|---|---|---|
--preview |
off | enable ?preview= render pages |
--preview-max-bytes BYTES |
2 MiB | largest file the preview will read |
--metadata |
off | extract metadata; adds the column, filters, sorts, and ?metadata=1 |
--metadata-max-bytes BYTES |
64 KiB | per-file read budget for extraction |
Caveats¶
Like sorting, filtering, and archive download, these are HTTP/1.1 features. The buffered HTTP/2 and HTTP/3 backends serve plain files and listings, and ignore these query parameters.
See also¶
- Serving files โ the listing, downloads, archives
- Principles โ why the Markdown renderer is a subset