0.1.20-alpha · Release 4 — The Stability Milestone 🚀
This is the largest hardening pass Nuvio Linux has ever had. Under the hood, an entire layer of the app was rebuilt: playback timing, player teardown, memory management, hardware decoding resilience, and a long list of races and crashes that have been lurking since the early builds. If Nuvio ever felt almost great but occasionally weird — stuttering 4K, mystery crashes, RAM creeping up over a long session — this release is for you.
What was broken (the honest version)
4K HDR playback was "smooth but jittery." Frames averaged the right rate but arrived scattered — the async frame-transfer path we added for weak integrated GPUs was quietly scattering frame delivery on powerful discrete GPUs. We bisected it frame-by-frame on real content, proved the old model itself was the problem, and replaced it with an adaptive engine: deterministic synchronous reads by default, escalating only when measurements prove your GPU needs the async path. Result: locked, judder-free cadence — verified on AMD RDNA4 and NVIDIA across packaged builds.
Closing a popped-out video could crash the whole app. When mpv took over playback outside the app window (for example Dolby Vision content via your own mpv config), closing that window killed the app with it. Root cause: a shutdown race in our native bridge that aborted the process during cleanup. Fixed properly, pinned by a regression test.
Trailer playback was fragile by construction. The old logic preferred live-HLS variants whose streams could degrade into decoder corruption storms. Trailers now prefer proper progressive/adaptive MP4 (H.264 + AAC) chains and only fall back to HLS as a last resort.
Hardware-decode failures spammed errors every single frame, forever. When zero-copy decoding couldn't map surfaces (certain codecs/GPU driver combos), the bridge retried and failed endlessly. There's now a runtime fallback: after a short burst of failures it switches to copy-mode decoding automatically and carries on. Hybrid-GPU laptops also no longer risk decoding on one GPU while the other tries to import the frames.
Memory was held together by strings. Metadata caches grew without limit, a streaming-cache setting was silently doubled by a back-buffer bug, the torrent engine ignored its cache-size setting entirely and stayed resident in RAM all session, and image caching claimed a quarter of your heap by default. All of it is bounded, wired, and measured now — plus blocking subprocess calls were removed from the UI thread, so settings toggles can't freeze the window anymore.
A pile of races and sharp edges, fixed one by one: a use-after-free between rendering and disposal, stale window sizes causing wrong-scale frames, plugin refresh jobs racing each other, Trakt progress maps publishing half-updated snapshots, cookie jars appending duplicate entries, an updater that kept downloading after you cancelled it, and more.
Troubleshooting & reporting
Using a Nuvio online account? Having login/library/sync weirdness?
Please log out and sign back in first — it rebuilds your credentials and re-syncs library state, and resolves the majority of account-related reports on its own.
If playback misbehaves, give us data. Launch from a terminal with debug logging:
# Native package (Arch/deb/rpm/AppImage):
NUVIO_MPV_DEBUG=1 nuvio-linux
# Flatpak:
flatpak run --env=NUVIO_MPV_DEBUG=1 io.github.jjdizz1l.NuvioLinuxExtra knobs for specific problems:
| Flag | Use for |
|---|---|
NUVIO_MPV_DEBUG=1
| Everything playback: renderer init, hwdec status, frame cadence (render cadence:), readback health (readback stats[...])
|
NUVIO_READBACK=sync
| Stutter/judder triage — forces the deterministic path |
NUVIO_MPV_HWDEC=auto-copy
| Suspected hardware-decode issues |
NUVIO_MPV_NO_AUTOFALLBACK=1
| Keeps decode from auto-switching, so we can see the raw failure |
NUVIO_TRAILER_DEBUG=1
| Trailer extraction problems |
NUVIO_WINDOW_DEBUG=1
| Window sizing/fullscreen issues |
nuvio-linux --nvidia-diag
| Prints an NVIDIA driver/GPU diagnostic block and exits |
Please report issues on GitHub — with data from the application, not just sentences describing the problem. A report we can act on includes: the terminal output from the commands above (especially any [mpv/...], readback stats, or render cadence: lines), your GPU + driver (nvidia-smi or lspci), which package format you run (Arch/deb/rpm/AppImage/Flatpak), your desktop environment, and exact steps to reproduce. Reports with logs get fixed; reports without them usually can't be reproduced.
Full commit history for this release:
8b5e1e28 chore(aur): bump bin to 0.1.20alpha-4, refresh git seed r2319.g17dd43a2
17dd43a2 chore(pkg): release 4 package rebuild (0.1.20alpha-4)
48ac2716 fix(player): survive mpv core self-shutdown during dispose
810e180f fix(player): adaptive readback — deterministic sync by default, ring on demand
8e126c87 feat(player): NUVIO_READBACK diagnostic knob (fence|legacy|sync)
f9d61db6 feat(player): consumer-side presentation telemetry for the frame pump
c2c5cf12 fix(player): fence-guarded PBO copy-out cures HDR playback jitter
ef7e75f8 fix(player): @Volatile on pendingSource
877ceb3b fix(player): back off when installPixels fails instead of hot-spinning
00e01334 perf(player): memoize NVIDIA GPU-name lookup for the process lifetime
3e659387 fix(player): null-safe header collection in create() JNI
985865c1 fix(updater): stop download when caller is cancelled
4f03a006 refactor(player): narrow event-loop locking; drop superseded nvdec stub
33f7ae99 feat(player): runtime copy-mode fallback + GL-device-matched DRM nodes
f19962e1 fix(trailer): prefer progressive/adaptive streams over HLS DVR variant
bfd802fc test(watched): fix scheduling-dependent assertion in store stress test
8e2e31d5 feat(storage): map-style operators on BoundedLruCache
63807605 fix(sync): wire metadata-cache clears into wipe + profile switch
66acacb0 fix(trailer): cookie jar replaces by name+path instead of appending
be3083cb perf(memory): bound Trakt mapping/related/comments caches
c2abcc08 perf(memory): bound TmdbMetadataService's nine caches
e994bbe2 feat(storage): BoundedLruCache — LRU cap + age/idle expiry for singleton caches
58adfc03 fix(trakt): publish show-progress maps as one volatile snapshot
67e24203 fix(plugins): make refresh-job dedup atomic; clean finished jobs
b51d2a07 chore: ignore local review notes
873c7327 refactor(player): single applyCommonOptions helper; drop dead goto blocks
c274da85 fix(library): stop calling ensureLoaded on the UI thread; bound reload loop
c34138db fix(player): validate PBO ring allocation; report raw buffered end
ae7b59fa fix(player): read live AWT window size in video frame pump
c71236b8 fix(player): close renderFrame/dispose use-after-free race
cc8fb891 perf(player): PBO async readback for weak iGPUs (issue #13)
7b198482 fix(rpm): build in a Fedora container, gate on rpm -K
7208b204 chore(aur): bump to 0.1.20alpha-2 / r2287.g713a18f9