Sits where the default browser used to and dispatches each URL to the
cheapest tool that can handle it: mpv for video, zathura for PDFs, a light
WebKit browser for reading, Firefox only when nothing else will do.
Rules live in ~/.config/furst/rules.toml and are matched in order. When a
rule's command is missing from $PATH the router falls through to the next
match, then to the default, so a config may name tools that do not exist
yet without breaking today.
- host patterns match apex plus subdomains, with = for exact and * for any
- paths glob case-insensitively, contains matches the raw URL
- {url} {url_enc} {host} {path} {scheme} placeholders, URL appended if unused
- terminal = true wraps a handler in $TERMINAL -e for TUI tools
- --explain shows the parse and every candidate in priority order
- --install registers a .desktop entry as the system default browser
Host parsing strips userinfo with rfind('@') so that
https://bank.example@evil.example/ routes on evil.example. Handlers are
exec'd rather than forked, leaving no process behind.
|
||
|---|---|---|
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
furst
A URL router. It sits where your default browser used to, and sends each URL to
the cheapest tool that can actually handle it — mpv for video, a pager for
PDFs, a light WebKit browser for reading, and Firefox only when nothing else
will do.
Built for a Core2 Duo with 4GB of RAM, where the browser is the problem.
Why
A news page is 2–5MB across 80+ requests with 1–3MB of JavaScript to parse and
JIT. The same article extracted is ~20KB. Choosing a lighter engine buys
2–3×; not loading the payload at all buys 10–100×. furst is the dispatcher
that decides which of those you get, per URL.
Install
cargo build --release
install -Dm755 target/release/furst ~/.local/bin/furst
furst --init # writes ~/.config/furst/rules.toml, probes for a light browser
furst --install # registers furst as the system default browser
--install writes ~/.local/share/applications/furst.desktop and points
xdg-settings at it, so every link click in every application routes here.
Use
furst <url> # match a rule and exec its command
furst --explain <url> # show what would run, and why; run nothing
furst --list # show the loaded rules
--explain is the one you want when a URL goes somewhere surprising:
$ furst --explain https://youtu.be/abc123
scheme https
host youtu.be
path /abc123
-> [video] mpv --ytdl-format=bestvideo[vcodec^=avc1][height<=?720]+... https://youtu.be/abc123
[default] surf https://youtu.be/abc123
Rules
~/.config/furst/rules.toml. First matching rule wins. If its command is
missing from $PATH, furst falls through to the next matching rule, and
finally to default — which is what lets you name tools you have not written
yet and have the config stay working today.
default = ["surf", "{url}"]
[[rule]]
name = "video"
hosts = ["youtube.com", "youtu.be"]
run = ["mpv", "--ytdl-format=bestvideo[vcodec^=avc1][height<=?720]+bestaudio/best", "{url}"]
[[rule]]
name = "hn"
hosts = ["news.ycombinator.com"]
terminal = true # wrap in $TERMINAL -e
run = ["furst-hn", "{url}"]
A rule matches when every criterion it states is satisfied; a criterion is satisfied by any one of its patterns. A rule that states nothing matches everything.
| Key | Matches against |
|---|---|
schemes |
https, mailto, magnet, … |
hosts |
example.com = apex and every subdomain; *.example.com = same; =example.com = that host exactly; * = any |
paths |
path component only, glob with *, case-insensitive |
contains |
substring of the whole raw URL |
| Placeholder | |
|---|---|
{url} {url_enc} |
the URL, raw or percent-encoded |
{host} {path} {scheme} |
parsed components |
If no argument mentions {url} or {url_enc}, the URL is appended last.
Notes for old hardware
- Force H.264 for video. A Core2 handles 720p
avc1in software but stalls on VP9/AV1, which is what YouTube serves by default. That format string is doing more work than the resolution cap. - Host matching strips userinfo with
rfind('@'), sohttps://bank.example@evil.example/routes onevil.example. furstexecs the handler rather than forking, so it leaves no process behind.
License
MIT