Loku is a local video browser and player. Point it at one or more media directories and get a browseable, searchable interface in your web browser.
It pairs well with yt-dlp (download a channel’s videos alongside their metadata
and thumbnails) and with MakeMKV disc rips, which it turns into first-class
library items: friendly titles from Kodi .nfo sidecars or cleaned-up rip
filenames, extracted thumbnails, and a guaranteed browser-playable copy produced
by a built-in ffmpeg worker.
Key characteristics:
- Multiple named libraries, each typed as yt-dlp
downloadsor MakeMKVdiscs. - Full-text search across every library at once, over yt-dlp
info.jsonand Kodi.nfometadata plus filenames. - Multi-title disc rips grouped into one item with a pick-the-main-title flow.
- In-browser playback with codec-aware source selection; masters that browsers cannot play get an automatically derived H.264/AAC compat copy (the original file is never modified).
- A rebuildable SQLite index kept current by filesystem watching; sidecar files remain the source of truth.
Requires Rust (stable) and cargo.
git clone https://github.com/LoganBarnett/loku
cd loku
cargo build --releaseThe binary is at target/release/loku-server.
nix run github:LoganBarnett/lokuStart the server, pointing it at a video library:
loku-server --library /path/to/videosThen open http://localhost:3000 in a browser.
--library is single-root convenience; multi-library setups define [[library]]
entries in a config file instead (see config.example.toml) and pass
--config:
[[library]]
name = "downloads"
path = "/media/videos"
kind = "downloads"
[[library]]
name = "discs"
path = "/media/rips"
kind = "discs"| Flag | Default | Description |
|---|---|---|
--config | discovered | Path to the TOML config file |
--library | (none) | Single downloads-kind root shortcut |
--listen | 127.0.0.1:3000 | host:port, socket path, or |
sd-listen | ||
--state-dir | STATE_DIRECTORY / | Where the media index database lives |
| XDG state home | ||
--log-level | info | Logging verbosity |
ffmpeg and ffprobe on PATH enable codec probing and compat derivation;
without them Loku still browses and serves, with those features disabled and
/healthz reporting a degraded media-tools component.
- The index is derived, the filesystem is truth: metadata comes from sidecars
(
info.json, Kodi.nfo, thumbnails,.compat.mp4) indexed into SQLite in the state directory. Deleting the state directory only costs a rescan (plus any manual main-title picks). - Derived files live beside masters: the worker writes
foo.compat.mp4andfoo.jpgnext tofoo.mkv, so library paths must be writable by the server and other consumers of the same trees (e.g. Kodi) should exclude*.compat.mp4from their scans. - Local only by default: the default bind is
127.0.0.1. Use--listen 0.0.0.0:3000to expose on the LAN; for real deployments use the NixOS module’s socket activation behind a TLS proxy with OIDC.
The Elm frontend is compiled hermetically in Nix. Two files in frontend/
describe the dependency set and must be kept in sync with elm.json:
elm-srcs.nix— onesha256+versionentry per package, generated byelm2nix convert.registry.dat— a snapshot of the Elm package registry, generated byelm2nix snapshot.
After adding, removing, or bumping any package in elm.json:
cd frontend
elm2nix convert 2>/dev/null > elm-srcs.nix
elm2nix snapshot
git add elm-srcs.nix registry.dat
git commit -m "Update elm-srcs.nix and registry.dat for new dependencies"Both elm2nix and elm are available in the Nix dev shell (nix develop).
The Nix build uses pkgs.elmPackages.fetchElmDeps to assemble an offline
ELM_HOME from the packages listed in elm-srcs.nix, then compiles with elm
make --optimize. No generated JavaScript lives in the repository.
cargo update
cargo test --workspace
git add Cargo.lock && git commit -m "Update Cargo.lock"nix develop --command cargo test --workspace
nix develop --command cargo fmt --check