Mythos is pre-1.0 but already cuts tagged releases. Three ways in: pull the published Docker image (recommended), build the server from source, or build one of the native clients. The server image is the only artifact published by CI today — the desktop, Android, Apple TV, and webOS clients build from source with their own toolchains.

The fastest way in. CI builds and pushes a linux/amd64 server image to Docker Hub whenever a vX.Y.Z git tag is cut — it tags both the immutable semver (:0.3.6) and :latest. The image bundles jellyfin-ffmpeg so HW tonemap filters (tonemap_vaapi / tonemap_opencl / tonemap_cuda) and the SIMD-optimised CPU tonemapx kernel are all available, and runs the server as PID 1 under tini.

docker run -d --name mythos \
  -p 8080:8080 \
  -v mythos-data:/data \
  -v /path/to/media:/media:ro \
  -e MYTHOS_TMDB_API_KEY=... \
  darkspar/mythos-server:latest
TagWhat it points at
:latestTracks whichever vX.Y.Z tag was most recently pushed (not the semver-highest — so don’t cut tags out of order). Fine for “just give me the newest build.”
:X.Y.ZImmutable per-release image (e.g. :0.3.6). Pin to this in production-ish setups so an unattended docker pull doesn’t surprise you.

There are no rolling :edge or per-commit :sha-… images — publishing is tag-triggered only. Pin :X.Y.Z if you don’t want :latest moving under you.

Bind-mount your media read-only. Everything Mythos writes (SQLite DB, JWT secret, poster cache, transcode segments, sidecar subtitles) lives under /data.

For VAAPI / QSV pass the render node through with --device /dev/dri:/dev/dri. For NVENC use the NVIDIA container runtime (--gpus all). The server probes available encoders at startup; override the choice with MYTHOS_HW_ENCODER=nvenc|qsv|vaapi|videotoolbox|cpu|auto.

Build from source

If you’d rather build it yourself — or you want to hack on it — the main branch builds end-to-end.

Prerequisites

A working toolchain for both the Rust server and the embedded SvelteKit UI, plus ffmpeg/ffprobe on PATH for library scans and HLS transcoding.

  • Rust 1.95+ (pinned in rust-toolchain.toml)
  • Node 22+
  • pnpm 10+
  • ffmpeg / ffprobe (recent enough to expose the encoders you want — h264_nvenc, h264_qsv, h264_vaapi, h264_videotoolbox, or libx264 as a fallback; jellyfin-ffmpeg is the easiest way to get HW tonemap filters and the tonemapx SIMD CPU kernel)

Build and run

git clone https://gitlab.mattmoore.io/darkspar/mythos
cd mythos
cargo run --release --bin mythos-server

The build script in crates/mythos-server invokes pnpm install && pnpm build in web/ so the SPA is compiled and embedded in the same cargo invocation. Set MYTHOS_SKIP_WEB_BUILD=1 if you only want to rebuild the Rust side.

Then open http://localhost:8080 (or http://<lan-ip>:8080 from another device — the default listen is 0.0.0.0:8080). A 3-step setup wizard walks through creating an admin account, dropping in your TMDb key (optional — scans still index files without one), and adding the first library.

Native clients

Beyond the embedded web UI, Mythos has a fleet of native clients that talk to the same REST API and can pair with multiple servers at once — each client keeps its own list of paired servers and fans browse, search, and continue-watching across all of them. They build with their own toolchains, so they aren’t published by CI yet:

  • Desktop — apps/mythos-qt — Qt 6 + cxx-qt + libmpv. The only client that’s a Cargo workspace member; build it from the repo root (below).
  • Android — apps/mythos-android — Kotlin + Jetpack Compose, two apps from one Gradle build: a phone/foldable app and a D-pad-native Google/Android TV app, both on Media3/ExoPlayer. Build with ./gradlew :mythos:assembleRelease / :mythos-tv:assembleRelease.
  • Apple TV — apps/mythos-tvos — native SwiftUI on AVPlayer with a custom chrome suite. Open the Xcode project under apps/mythos-tvos/.
  • LG webOS — apps/mythos-webos — a thin TV launcher (.ipk) that loads the server’s SPA over the LAN; packaged with ares-package.

Desktop (Qt 6 + libmpv)

A Qt 6 + cxx-qt app at apps/mythos-qt/ ships the exact same SvelteKit codebase as the embedded server SPA, bundled into the binary via rust-embed and served to QtWebEngine through a custom mythos:// URL scheme. The SvelteKit chrome lives in QtWebEngine; the player swaps <video> + hls.js for libmpv rendered into a QQuickFramebufferObject via mpv’s OpenGL render API, and IPC runs over QWebChannel — so HEVC, AV1, and HDR files play natively without the browser’s codec gauntlet, and HDR→SDR tonemapping happens in mpv’s render chain rather than ffmpeg.

git clone https://gitlab.mattmoore.io/darkspar/mythos
cd mythos
cargo run -p mythos-qt --release

You’ll need Qt 6.5+ on PATH (QtCore, QtQuick, QtWebEngine, QtWebChannel) and system libmpv discoverable via pkg-config. cxx-qt-build picks Qt up from qmake6; the mythos-qt/README has the per-distro prerequisite list.

The chrome strategy is the video-region pattern: instead of trying to make a transparent webview overlay an mpv surface (which is unreliable on NVIDIA + Wayland-XWayland + the Chromium Vulkan fallback), the SPA reports a target rect via setVideoRegion(x, y, w, h), QML pins MpvVideo to that rect, and a native QML chrome layer (top overlay + scrubber) renders in the strips around it. Idle-auto-hide on the chrome, fullscreen toggled by flipping Window.visibility rather than going through the Chromium key handler, and clicks on the strips are blocked from falling through to the video.

It’s a scaffold — usable, with rough edges. The current shape lights up auth + servers + playback over QWebChannel, runs the SvelteKit SPA from the embedded mythos:// scheme so it can talk to plain-http Mythos servers (Chromium’s secure-context rules don’t apply to a custom scheme the host marks accordingly), and routes f-key fullscreen through Qt directly. Subtitle selection now flows through the backend; ABR-variant selection from mpv’s HLS demuxer still isn’t exposed, so the quality picker is a no-op against the desktop player (mpv typically direct-plays anyway).

Hardware acceleration

Mythos probes ffmpeg -encoders at startup and smoke-tests each candidate before committing to it. Priority order: NVENC → QSV → VAAPI → VideoToolbox → libx264. Pin a specific encoder with MYTHOS_HW_ENCODER=vaapi (etc.), or force CPU with MYTHOS_HW_ENCODER=cpu. The Docker image preconfigures MYTHOS_FFMPEG_BIN / MYTHOS_FFPROBE_BIN to point at jellyfin-ffmpeg already; on a bare-metal install set those if you’d rather not put jellyfin-ffmpeg on PATH.

Status

What works today: movies and TV — scan, browse, direct-play, HLS transcoding with hardware acceleration (NVENC stays on the GPU end-to-end), a multi-rendition ABR ladder in both AVC and HEVC, HDR→SDR tonemapping with a configurable filter pipeline (now including tonemapx, jellyfin-ffmpeg’s SIMD CPU kernel), Dolby Vision transcode-on-the-fly so DV files play on clients without a DV pipeline, subtitle burn-in and WebVTT sidecars, sidecar .srt discovery, TMDb metadata enrichment with backdrops and a year-in-title rescue (Blade Runner 2049 / Cyberpunk 2077 now resolve correctly), movie collections and a cast & crew strip, title search across movies + series, continue-watching across movies and episodes, auto-play-next, a media-chrome-based player that collapses into a persistent mini-bar so playback survives navigation, a 3-step setup wizard, a Plex-style vertical alphabet jump bar on library browse, “Recently added” home rails, per-library Refresh-art and Stop-scan + per-series Rescan / Rematch / manual TMDb identify admin actions, per-user library visibility + sharing, and multi-server pairing across a fleet of native clients — Qt 6 desktop, Android phone + Google TV, Apple tvOS, and an LG webOS launcher — alongside the browser SPA.

What’s next: the remaining Phase 3 media types — music, photos, books — and a Jellyfin-API compatibility shim (Phase 6) for existing clients like Findroid and Swiftfin. See the roadmap on the homepage .