The catch-all rule now sends anything that did not match a more specific
rule to furst-serve, while `default` stays a plain browser. Because rules
fall through when their command is missing, that arrangement needs no new
mechanism: if furst-serve is not installed the reader rule is skipped and
the browser still gets the URL.
Firefox drops to a short list of sites that genuinely need it. Every reader
page carries a browser link, so the list can stay short.
Adds a README for furst-serve and rewrites the top-level one around the
whole pipeline: what it is for, what each piece does, measured output
sizes, and the limits — client-rendered pages, rate-limited search
endpoints, DRM.
Extraction looks for prose, so a front page, a comment thread or a search
result page correctly yields almost nothing. These render the structure
instead, and every link they emit routes back through /read.
/search?q= results from a configurable HTML endpoint
/feed?u= RSS and Atom
/read?u= now picks a site view, falling back to a link index when a
page has too little text to be an article
Feeds are scanned rather than parsed. A feed needs five fields per entry
and an HTML parser mangles XML, so this walks the tags directly: CDATA,
named and numeric entities, and Atom's preference for rel=alternate over
rel=self. No XML dependency.
Hacker News gets a real adapter: stories with score, author and a link
into the discussion, and comment threads rendered with their indent
preserved. Comment bodies go through the article renderer so links inside
them behave like every other link.
Search is deliberately engine-agnostic. Known result shapes are tried
first, then heading links, then any link, because every free HTML endpoint
eventually rate-limits a repeat visitor. When one answers with a challenge
page rather than results the reader says so and points at the config,
instead of showing an empty page; detection reads the body, since these
arrive as 200 or 202 rather than an error status. A blocked search is
never cached.
Pages that turn out to be feeds redirect to the feed view, and a page that
declares its own feed offers it.
Following a link inside an extracted article used to drop the reader back
onto the live site. The server rewrites in-page links to /read?u=... so
browsing stays in reader mode, and caches rendered pages on disk, which
takes a revisit from ~350ms to under a millisecond.
The HTTP layer is blocking and hand-rolled: GET only, one response per
connection, a fixed pool of four worker threads so memory stays
predictable, and nothing but the loopback interface is ever bound.
Routes so far:
/ home, from ~/.config/furst/home.toml
/read?u= the article, with links routed back through the reader
/go?u= hand the original URL to the heavy browser
Pages that are not documents redirect to the original rather than being
run through an article extractor, and pages with too little text to be an
article say so and offer the escape hatches. Redirect stubs are followed
before that judgement is made.
furst-serve --open ensures a server is running, starting a detached one if
needed, then execs a browser at the reader URL. Cache entries carry a
schema number so a renderer change drops them rather than serving stale
markup.