Linthra

io.github.thezupzup.linthra
by Zapstore _@zapstore.dev

Open-source, local-first music player for music you own. No forced sync.

Republished from GitHub / F-Droid by the Zapstore main account.

Linthra is an open-source Android music player for people who keep their music on their own devices or self-hosted servers. It plays local files, and it streams from self-hosted music servers such as Jellyfin and Navidrome/Subsonic — you bring your own server and sign in with your own account. Linthra is an unofficial community client. It is not affiliated with Jellyfin, Navidrome, or Subsonic. The app is still early alpha. It's usable for testing on a real device, but it isn't production-stable and has a few rough edges. The lists below separate what works today from what's still planned. On privacy: * No ads, no tracking, no analytics, and no crash-reporting or telemetry SDK. * No account to create, and nothing phones home — streaming is the default, and downloads only happen when you ask for them (Wi-Fi only unless you opt in to mobile data). * When you sign in to a server, the password is used once to get a session token, then dropped; the token is stored encrypted and never logged. * Open-source under the GNU Affero General Public License v3.0 or later, so anyone can read, build, and contribute to it. What works today: * Local library — pick a folder with the Storage Access Framework (no broad storage permission), scan it, and browse Songs, Albums, and Artists with search. * Streaming from your own Jellyfin or Navidrome / Subsonic server: test the connection, sign in, sync, and play, including over HTTPS. * A smart offline cache — download tracks for offline play, with a size limit and a "Keep offline" pin. * Queue / Up Next, playlists and favourites (synced with Jellyfin where it's supported), and automatic "smart mixes" built from on-device signals. * Background playback with a media notification and lock-screen, Bluetooth, and wired-headset controls, plus shuffle / repeat and synced lyrics. * Android Auto browsing, and casting to a Chromecast, speaker, or TV through a pure-Dart Cast implementation (no Google Play Services). Still to come: * Reading tags and album art from local files (for now they show file names). * Subsonic favourites, lyrics, and cover art, and fuller playlist sync. * "Download all" for an album or playlist. * More sources, such as WebDAV / NAS, behind the same interface. * A Linux desktop build later, from the same codebase. Linthra is distributed for testing as a sideloaded APK from GitHub Releases. It isn't on F-Droid or Google Play yet.

First release: Aug 3, 2026, 16 total releases.

Most recent release: Oct 27, 2026.

Repo

Appears in 0 app stacks.

0 sats / 0 zaps received in the past year.

Sats Received

Underlying data available via MCP: app_zaps, app_releases.

Zap Count

Underlying data available via MCP: app_zaps, app_releases.

Releases

  • Oct 27, 2026 0.2.11
    # Linthra v0.2.11 Linthra 0.2.11 is an urgent stability hotfix. It fixes a major bug in 0.2.10 on Android: music stopped when the screen turned off. If you are on 0.2.10, please update. ## Fixed: playback stopped with the screen off (0.2.10) On Android 13 and later, Linthra 0.2.10 stopped playing a few seconds after the screen turned off or the phone locked, and the media notification and lock screen controls never appeared. It happened with every source: downloaded tracks, local files, and streams from Jellyfin, Navidrome and other servers. The 0.2.10 release builds were missing the icons Linthra's media controls use. Without them, Android 13 and later could not set up the playback notification, so the background playback service never started, and Android silenced or stopped Linthra once the screen went off. Debug builds weren't affected, which is how it slipped through.
    More…
    - Music keeps playing with the screen off or the phone locked. - The media notification and lock screen controls are back. - On Android 12 and older, where playback kept going, the notification buttons have their icons again. Every Android release build is now checked for these icons before it can be published, so this can't ship again unnoticed. Nothing else changes from 0.2.10. Linux is unaffected. ## Upgrade notes No manual migration is needed. Update over 0.2.10 as usual. ## Android and F-Droid Canonical Android version for this release: - versionName: `0.2.11` - base versionCode: `211999` Expected F-Droid split-ABI version codes: - armeabi-v7a: `2119991` - arm64-v8a: `2119992` - x86_64: `2119993` F-Droid builds Linthra from source at the release tag and signs with its own key. GitHub APKs and F-Droid packages use different signing keys, so keep updating from the source you originally installed from.
  • Oct 27, 2026 0.2.10
    # Linthra v0.2.10 Linthra 0.2.10 makes remote playback faster, targets Android 17, adds a few library and Android Auto features, and carries another large round of stability fixes across playback, downloads, the offline cache, syncing and local libraries. ## Highlights ### Faster remote playback - A remote track checks the session and fetches its stream URL at the same time, so playback starts one round trip sooner. - A request lost to a brief drop (a Wi-Fi/mobile handover, a server restarting) is tried once more before the track fails.
    More…
    - The next track's stream is warmed again near the end of the current one, so tracks change without waiting on the server. ### Android 17 Linthra now targets Android 17 (API 37). Android 17 blocks connections to the local network until an app is allowed to make them, so: - Linthra asks for local network access when you test, sign in to, connect to or play from a server on your LAN. Background work never shows the prompt. - Settings > Connections shows a "Local network access" card while a configured LAN server needs it. - A server reached over a VPN (Tailscale, WireGuard and similar) can still connect without the permission. - Playback still resumes after a call with the screen off, which Android 17 would otherwise block. - A Play or skip sent from a Jellyfin remote on another device no longer starts playback while Linthra is paused in the background. Pause, stop, seek and control of playback that is already running work as before. Local music and downloads never need the permission, and nothing asks for it on Android 16 or older. The minimum Android version is unchanged. ### New in the library - Sort the Songs tab by title, artist, album or date added, in either direction. - In the A-Z list, accented titles file under their letter, and titles starting with a digit or a non-Latin letter share one # section at the top. - Swipe a song to the right to add it to the queue (Android). - Open an album's artist from the album page. - Android Auto has favorite and shuffle controls. - Shuffle buttons start from a random song instead of the collection's first one, and adding songs to an empty queue with shuffle on shuffles them. - Saving the queue as a playlist no longer duplicates songs. - Settings keeps its categories in a sidebar beside the page on wide windows. - Subsonic has an opt-in legacy sign-in for servers that refuse token sign-in, such as Nextcloud Music. It only works over https and keeps the password in the system's secure storage until you sign out. An app password or API key is the better choice where the server offers one. ### Linux desktop - Starting playback keeps you in the list you were browsing. Now Playing is one click away, and Escape leaves it. - Track rows show each song's length, album pages number their songs, and the queue opens as a side sheet on narrower windows. - An opt-in "Show audio quality" switch (Music & playback) shows the codec, sample rate, bitrate and bit depth on Now Playing. - The library catalog moves out of `~/Documents` into Linthra's own data directory. In the Flatpak this stops the library being rebuilt from scratch on every launch. - A track that plays through a system sleep is reloaded after wake. - Bug reports and diagnostics are saved through the desktop's save dialog, which also works in the Flatpak. - Flatpak: with "Keep playing" on, Linthra asks the Background portal before playing on with the window closed, and quits normally if the desktop says no. - Metered-connection settings use desktop wording instead of talking about mobile data. ## Stability Most of this release is reliability work again. Nearly every fix comes with a regression test that reproduces the failure first. ### Playback - A reload that loses its stream while seeking back, a seek on Android after a playback error, and a stream that failed during a call no longer hang. - A stall after pressing Play on a paused track, or after a seek while paused, is caught instead of staying on Buffering. - A copy that opens and then fails falls back to the cached file or another copy of the song, at the same spot. - A seek on the error panel is where Retry and Play pick the song up. - A mid-stream drop gets its quick reconnect back after real playback, so a later drop on the same track is still recovered. - A playback failure can be explained and copied for a bug report. ### Downloads and offline cache - Downloads are written to disk as they arrive instead of being held in memory, and one larger than the cache limit stops early. - A body that ends short, an empty or truncated cache file, or an error page is never served as a downloaded song. - An unreadable downloads record is set aside instead of being written over, so the next launch can't delete the files it named. - Clear all and Remove download only ever delete inside the offline folder. - Clearing storage stops a running "Download all". - Cancel, eviction and removal no longer leave a song stuck on Downloading or marked downloaded with no file. - Subsonic and Navidrome offline copies are tied to the server they came from. - The artwork cache keeps covers per server, refreshes covers older than 30 days, never keeps an error page as a cover, and is capped at 256 MB. - A custom cache limit such as `NaN` or `1e999` is refused instead of breaking the dialog. ### Sync and accounts - Signing in to a different Jellyfin or Subsonic account replaces the previous account's library and queue instead of leaving its songs behind. - Jellyfin and Plex no longer miss tracks when the library changes between pages. Subsonic goes on past an album that keeps failing, and reads one-entry lists from older servers. - Large synced playlists save: Jellyfin adds songs 100 at a time, and Subsonic uses a form POST when the server supports it. - Audiobookshelf renews an expired access token instead of failing every request, and servers older than 2.26 can sign in. - A favorite or playlist change the disk refuses is undone instead of staying in memory, and a heart that wasn't pushed yet survives a restart. - A Jellyfin answer without items no longer clears favorites or playlists. - Plex reads numeric fields sent as strings, and treats a timeout or rate limit as a server error instead of a wrong address. ### Local libraries - A music folder that is an unmounted mount point keeps its music instead of being read as emptied. - A network share that stops answering no longer freezes rescans or the Local music card. - On Linux, a FLAC, MP3, OGG or Opus file with one malformed tag field keeps the rest of its tags. - A moved local song keeps its playlists, and a move that one store couldn't save is retried on the next scan. - One malformed download, play history, playlist or saved-queue record now drops only itself instead of failing the whole load, and a failed read no longer clears the saved queue. ## Privacy - Diagnostics and "Report a bug" describe server addresses (http or https, the kind of network, default or custom port) instead of including the host. - Revealed password fields keep keyboard suggestions and autocorrect off. - Cover URLs that carry credentials are kept out of the saved queue, the media session and MPRIS. - Casting stays unavailable while #575 is open. No telemetry, tracking or analytics were added. ## Accessibility - The A-Z index letters are buttons a screen reader and keyboard can use. - Buffering, the selected icon and section headings are announced. - On desktop, Tab moves through one pane at a time. ## Upgrade notes No manual migration is needed. - Linux: the library catalog is moved from `~/Documents` to Linthra's data directory on first launch. If the move can't finish, the old file stays where it was and is used. - Subsonic, Plex and Jellyfin covers are downloaded once more under their new per-server names. The old files age out of the cache. - The first Plex sync after the update rebuilds the library once. ## Known limitations - Android 17: a server whose only address is a global IPv6 address on the same subnet isn't recognized as local, so Linthra won't ask for access and the connection fails. Granting local network access in Android settings fixes it. - Android 17: a VPN is recognized by its interface name (`tun`, `wg`, `ipsec`, `ppp`). - "Show audio quality" is Linux only for now. - Casting remains unavailable (#575). ## Android and F-Droid Canonical Android version for this release: - versionName: `0.2.10` - base versionCode: `210999` Expected F-Droid split-ABI version codes: - armeabi-v7a: `2109991` - arm64-v8a: `2109992` - x86_64: `2109993` F-Droid builds Linthra from source at the release tag and signs with its own key. GitHub APKs and F-Droid packages use different signing keys, so keep updating from the source you originally installed from.
  • Oct 4, 2026 0.2.9
    # Linthra v0.2.9 Linthra 0.2.9 is a stability and reliability release focused on making everyday playback, downloads, syncing, local libraries, Android, and Linux more predictable under failures, races, account changes, and disappearing resources. There is deliberately no headline feature in this release. The work since 0.2.8 concentrated on making existing features hold up when operations overlap or something goes wrong. ## Highlights ### Playback is harder to knock off course
    More…
    Playback now handles a much wider set of awkward timing and failure cases without getting stuck, showing the wrong state, or letting an older track leak into the one you selected. Among the fixes: - Play after Stop reloads the current track instead of reviving an older source or hanging on Loading. - Pause, seek, Next, queue changes, session restore, repeat-one, and audio-focus changes keep the latest listener action authoritative while a track is loading. - A failed or stalled remote stream has bounded recovery instead of silently remaining in a playing/loading state forever. - Missing local files are reported as local-file problems rather than network failures. - A failed track cannot silently replace the title/state of the track that is actually playing. - Finished queues, restored queues, repeat-one loops, and replaying a recently played song behave consistently. - Automatic skipping remains bounded and visible rather than silently running through the queue. ### Downloads and smart pre-cache Downloads and automatic caching now agree more reliably about ownership, cancellation, network policy, and account identity. - Cancelling a download stays cancelled even when smart pre-cache overlaps it. - A server error page cannot be saved as if it were an audio download. - Downloads held for Wi-Fi start once the network policy allows them, including on Linux. - A pre-cached copy promoted to a real download is not immediately treated as the oldest cache entry. - Work started under an account or server that has since been replaced is not committed to the new session. - Cached stream URLs are not reused after the account that authorized them signs out. ### Syncing, playlists, favorites, and accounts A large part of the hardening pass targeted operations that finish in a different order from the one they started in. - Playlist and favorite edits made while a refresh is running are preserved. - Older network answers cannot overwrite newer server/account state. - Playlist pushes, refreshes, sign-outs, and server switches are reconciled without silently undoing the latest local action. - Playback reporting stays with the account that started the play instead of moving to whoever signs in later. - Jellyfin remote control follows the active session and remains available through normal loading/rebuffering transitions without leaving stale connections behind. ### Local libraries and storage failures Local-library operations now preserve the last known-good catalog more aggressively when storage is slow, unavailable, moved, or cannot be written. - An unfinished or malformed media file cannot freeze a scan indefinitely in the cases covered by the new guards. - Removing, changing, or reselecting folders is serialized against background refreshes so an overlapping scan cannot silently undo the choice. - Picking an unreadable replacement folder leaves the existing library intact. - Disk-full/read-only failures keep the previous catalog on screen instead of replacing it with an unrelated folder error. - Local artwork can be recovered after the artwork cache is cleared. - Supported move cases preserve song history such as favorites, play counts, and added dates. - A rescan keeps an already loaded library visible while the replacement catalog is prepared. ### Android and Android Auto - Android Auto queue and library selections are tied to the item the listener actually picked, even when the underlying list changes or an earlier lookup finishes later. - Back navigation closes selection/menu surfaces consistently instead of unexpectedly leaving the app. - Media-session and remote-control actions follow the same playback intent as the in-app controls through loading and stalls. ### Linux desktop - Stream loss and failed opens are detected instead of leaving the UI playing or loading forever. - Repeat-one state, pause/resume, and end-of-track handling are more reliable with the libmpv backend. - Background window closing and graceful shutdown are more predictable. - Network-status handling no longer leaves Wi-Fi-held downloads permanently queued when the desktop portal is slow or initially silent. ## F-Droid reproducibility F-Droid's rebuild of v0.2.8 exposed a reproducibility problem in the native FLAC fallback introduced in that release. The compiled code matched, but the GNU build ID in `libflacJNI.so` depended on build-machine paths that were present before AGP stripped the library. 0.2.9 links that FLAC JNI target without a GNU build ID and checks the built APK for all three Android ABIs. The same check also keeps the native hardening requirements in place: RELRO, BIND_NOW, 16 KB LOAD alignment, a non-executable stack, JNI-only exports, and stack-protector use. This fixes the demonstrated v0.2.8 mismatch. Issue #703 should remain open until F-Droid performs its real rebuild of 0.2.9 and reports the per-ABI packages as successfully verified. ## Privacy and security This release does not restore casting. The receiver-trust work tracked in #575 remains contained. Several fixes make account/server transitions safer: in-flight downloads, pre-cache work, playback reports, reachability results, and Jellyfin remote-control connections are prevented from being applied to a replacement session when their original session is gone. ## Known limitations The hardening work intentionally did not turn uncertain edge cases into speculative fixes. Known follow-ups include some vendored audio-engine lifecycle behavior, hard/unresponsive network-mounted local folders, and a few libmpv edge cases around device loss or unusual truncation. These remain follow-up work rather than being hidden behind broad claims in this release. Casting also remains unavailable while #575 is unresolved. ## Android and F-Droid Canonical Android version for this release: - versionName: `0.2.9` - base versionCode: `209999` Expected F-Droid split-ABI version codes: - armeabi-v7a: `2099991` - arm64-v8a: `2099992` - x86_64: `2099993` F-Droid builds Linthra from source at the release tag and signs with its own key. GitHub APKs and F-Droid packages use different signing keys, so users should continue updating from the same distribution source they originally installed from. ## Upgrade notes No manual migration is expected. Libraries, downloads, queue state, server sessions, and settings remain in place across the update. ## Thanks Thanks to everyone reporting real-world failures and testing the fixes. 0.2.9 is intentionally about reliability: fewer surprising state changes, safer recovery when something disappears underneath the app, and clearer behavior when a request cannot be completed.
  • Sep 30, 2026 0.2.8
    # Linthra v0.2.8 Smarter playback, stronger offline behavior, and more reliable large libraries. Smart pre-cache now follows the queue you are actually playing, playback picks itself back up when a remote stream drops, and very large Navidrome/Subsonic libraries can finally finish syncing. This release also fixes an "Unknown Album" grouping bug and brings FLAC playback to Android devices that have no FLAC decoder of their own. ## Highlights ### Smart pre-cache follows your real queue
    More…
    Smart pre-cache (Settings > Cache & data) quietly caches the next few tracks so they start instantly and keep playing when the network drops. In 0.2.8 it caches what the player is really going to play next: - **The real queue order.** With shuffle on, that is the shuffled order the player already made. Under repeat-all it wraps back to the start of the queue; under repeat-one it caches nothing extra. - **The latest queue wins.** Skipping, Play next, Add to queue, starting a new album or playlist, or toggling shuffle stops the old pass after the download already in flight and moves on to the new queue. - **Nearest tracks first.** Under a tight cache limit, the track that plays next can replace a cached copy of one further away instead of being skipped. A download that turns out bigger than the space left is stopped as soon as that is clear, instead of being pulled in full and thrown away. - **Network comes back.** On Android, the current queue is cached again when the connection returns or moves from mobile data to Wi-Fi. On Linux, which has no network-status signal, that happens at the next queue change. - **Account changes.** If you sign out or switch server or account, a pre-cache that is still downloading is dropped instead of saved, and the rest of the old queue is not fetched with the new account. Pre-cache still follows your mobile-data setting and your cache limit, and still downloads one track at a time. ### Your downloads are never treated as cache Automatic caching and the songs you choose to download are now kept strictly apart: - Smart pre-cache only makes room by replacing older pre-cached tracks. It never removes a song you downloaded yourself (kept offline or not), the track that is playing, or a track that plays sooner than the one it is caching. - Before this release, a full cache could remove an unpinned download to make room for a pre-cached track. That no longer happens. - If there is not enough room, pre-cache simply skips that track and it streams when it is reached. Library rows still tell the two apart: a song you asked for reads as **Downloaded**, while one the app fetched ahead of time reads as **Cached for offline play**. ### Playback recovers on its own When a track can't be played, Linthra no longer sits on the error panel for good. A stream that drops mid-song still gets its existing quick retry first. After that, the same bounded policy runs on Android and Linux: 1. **One more try, for network and server problems.** After about ten seconds it asks the server again for the same track with a fresh stream URL. A track that was playing picks up where it left off, showing "Reconnecting…"; one that never started simply loads again. That covers a Wi-Fi/LTE handover or a server that blinked. Other problems with a track (a missing local file, a sign-in the server rejects, audio the device can't decode) skip this step, since trying again seconds later would give the same answer. 2. **Then the next track.** If it still fails, playback moves to the next queue entry that has not already failed, with a short, growing pause between moves. Downloaded, pre-cached and local tracks keep playing while a server is down. 3. **Then it stops.** After six failures in a row, once every other entry in the queue has already failed, or at the end of the queue, the error is shown with its buttons and nothing else happens until you act. It stays out of your way: - It never moves on after you pause, after headphones are unplugged, or once another app takes over audio. During a call it can prepare the next track, but starting it waits for the call to end. - Under repeat-one it stays on the track you chose. - It does not skip through the queue for an audio engine problem (every track would fail the same way), and it never starts sound on its own after a restored session or the end of a cast. - Anything you do (play, skip, seek, Retry, a new queue) starts fresh. - On Android the waits show as reconnecting, so the media notification and background playback stay up with the screen off. ### Large Navidrome and Subsonic libraries A Navidrome library of around 80,000 tracks (#680) could never finish its first sync: the whole library had to be read in one go, and any interruption threw everything away. Sync now reconciles instead of replacing: - The library is read in batches of about 2,000 tracks, and each batch is saved as it arrives. An interrupted first sync keeps what it already read, and an interrupted re-sync keeps your previous catalog. - Temporary failures and rate limiting (HTTP 429) are retried, and an album deleted on the server during the scan is skipped instead of failing the whole sync. - Tracks that disappeared from the server are only removed after a complete, trustworthy pass over the library. - An unfinished sync is remembered per account and runs again on its own when the app starts or comes back to the foreground. That run walks the library from the start again, and everything already saved stays in place while it does. - Signing out or switching accounts stops the old sync from writing anything further. - Diagnostics now show the Subsonic sync state, the number of stored Subsonic tracks and the last sync error, instead of "Library tracks: 0" with no error. This applies to Navidrome and other Subsonic-compatible servers. ### Library and queue - **Each artist gets their own Unknown Album** (#682). Tracks with no album title all used to land in one library-wide "Unknown Album", so opening or playing it (including from Android Auto) pulled in every other artist's loose tracks. Each artist now has their own, and tracks with no artist share one under Unknown Artist. Album ids are worked out when the library is read, so existing libraries pick this up after the update with no rescan. - **Album queue actions.** The album page now offers **Play next** and **Add to queue** beside Play and Shuffle, so you can line an album up behind what is already playing. Albums are queued once, in order, as a single action. ### Android: FLAC on more devices - Some older devices, such as the Android 7-era Echo Show 8 in #674, have no FLAC decoder of their own. On those, FLAC tracks looked like they were playing but made no sound. Linthra now includes a built-in FLAC decoder as a fallback. Devices with their own decoder keep using it first; the built-in one only steps in when the device's decoder is missing or turns a particular file down. - Audio that nothing on the device can decode is now caught as an unsupported format instead of silently "playing". Like any other track that can't play, it is skipped when there is another track to move to, and the error is shown when there isn't. - Diagnostics now include the Android SDK level, the CPU architecture (ABI), how FLAC is being decoded and the kind of playback failure. ### Linux desktop - **The window has a real title everywhere.** On Wayland sessions (GNOME and KDE Plasma alike) and on GNOME under X11, Linthra's window used to reach the desktop with no title, so task switchers, overview labels, window rules and screen readers had nothing to show. It is now set on every session. - **Keyboard shortcuts window.** Ctrl+/ (or "Show all shortcuts" in the Keyboard shortcuts settings) lists every shortcut with the key it is bound to right now, and updates live when you remap one. - **`linthra --version`** prints the app version and exits without opening a window. ### GitHub Sponsor APK - **Disconnect GitHub** is now available whenever a GitHub token is stored, including when the account is not an active sponsor or the check at launch failed. Before, those users had no way to remove the stored token short of clearing app data. ## Privacy - Every fixed network destination written into the code Linthra ships (host names, IP addresses and mail domains, across the Dart code, the Android app, the Linux runner, packaging metadata, native code and vendored packages) now has to be listed with its purpose in the repository's network-destination inventory. A new host, a known host showing up in a new file, or an entry that no longer matches anything fails CI (#504). - Servers you type in are your data, not code, and are never affected by this check. - The privacy policy now names the two outside services Linthra itself can contact, and when: plex.tv, only if you choose "Connect with Plex", and GitHub, only in the GitHub Sponsor APK after you choose "Connect GitHub". The F-Droid, Flatpak and other builds never contact GitHub on their own. - A new `PRIVACY_AUDIT.md` records what is checked automatically, what was reviewed by hand, what is still open in #504, and the limits of each. These checks describe the code in this repository. They are not a claim about what the servers you connect to do. ## Casting Casting remains **temporarily unavailable** while the receiver-trust security work in #575 is completed. This release does not restore it, and there is no fallback or bypass. Groundwork for bringing it back safely did land: a short-lived relay on your own device that serves cast media to the receiver, so the receiver never sees your server's credential, and a written design for a replacement Cast client. Both stay switched off in shipped builds. ## Under the hood - **Toolchain:** Flutter 3.47.5 (Dart 3.13.4) and Android Gradle Plugin 8.11.1. - **Flatpak:** every build source is pinned to an immutable reference, with a check that keeps the manifest, its template, the Flutter version and the lockfile in step (#443). The Flatpak launch smoke now also checks that the installed package reports the expected version. - **Release pipeline:** the GitHub Sponsor APK is now built in the same release run, from the same commit and with the same signing decision as the other Android artifacts, and gets the same Cast containment check before upload. - **Linux testing:** credential-free integration tests now cover the Jellyfin, Navidrome/Subsonic and Plex streaming chain end to end against local fake servers (#424), plus a repeatable GNOME and KDE Plasma compatibility pass (#458) and an Orca screen-reader checklist (#461). - **Audio CD groundwork (Linux):** Linthra can now detect optical drives and read an audio CD's track list and CD-Text (#631, parts 1 and 2 of 5). Nothing in the app uses this yet: there is no CD playback or ripping in this release, and it is not available inside the Flatpak. - **Maintenance:** CI now reports when the scheduled dependency updaters stop working, and the F-Droid license follow-up (#659) is documented and ready. ## Known limitations - Casting is still unavailable (#575). - On Linux, pre-cache does not react to the network coming back until the next queue change. - An interrupted Navidrome/Subsonic sync starts its walk over from the beginning when it runs again. What it already saved is kept, but it does not resume from the exact point where it stopped. - The audio CD work is not user-facing yet. - Linthra is not on Flathub or Google Play. The Flatpak is a GitHub Release download. - F-Droid's canonical metadata may still show MPL-2.0 as the license until #659 lands there. ## Licensing Linthra's current project license is **AGPL-3.0-or-later**. Releases through **v0.2.4** remain under the MPL-2.0 terms under which they were published; **v0.2.5 and later**, including v0.2.8, are released under AGPL-3.0-or-later. ## Android and F-Droid Canonical Android version: - versionName: `0.2.8` - base versionCode: `208999` F-Droid split-ABI version codes: - armeabi-v7a: `2089991` - arm64-v8a: `2089992` - x86_64: `2089993` F-Droid builds from source at the release tag on its own infrastructure and signs with its own key. GitHub APKs and F-Droid packages use different signing keys, so keep updating from the same source you originally installed from. Linthra is not publicly available on Google Play. ## Release artifacts The stable GitHub Release is expected to carry: - the signed universal Android APK, the three per-ABI APKs and the AAB; - the GitHub Sponsor APK; - the native Linux x64 archive; - the standalone Flatpak bundle, targeting GNOME Platform 51 (installing it can fetch that runtime from Flathub when it is not already present). ## Upgrade notes No manual migration is needed. Your libraries, downloads, queue, server sessions and settings stay as they are. - The Unknown Album change applies as soon as the library is read, with no rescan. - If a large Navidrome/Subsonic sync never finished before, the next sync saves what it reads as it goes, and runs again on its own if it is interrupted. - Songs you downloaded stay downloaded. Only pre-cached copies are ever replaced automatically. ## Thanks Thanks to everyone who tested, reported and reviewed this cycle, especially the reports behind #674 (silent FLAC on an older Android device), #680 (a Navidrome library too big to sync) and #682 (the shared Unknown Album). Real-world reports like these are what make Linthra hold up outside a test suite.
  • Sep 19, 2026 0.2.7
    # Linthra v0.2.7 Linthra 0.2.7 is a large Android and Linux quality release. It fixes the Android Auto track-change regression reported in 0.2.6, makes the Linux local-library experience much more resilient, expands the desktop UI, and turns the GitHub Linux release into something users can install as a standalone Flatpak bundle. This release is cut from the current `main` work rather than waiting for the remaining feature PRs. Those continue toward the next release. ## Highlights ### Android Auto
    More…
    - **Next and Previous work again in Android Auto.** The media-session path now carries car controls all the way through Linthra's shared playback controller instead of letting the command disappear before the queue changes. - The regression coverage includes playing and paused states, reconnects, queue boundaries, shuffle/repeat interactions and exactly-once dispatch, so one steering-wheel/head-unit press cannot accidentally skip twice. - Track metadata remains synchronized after a car-originated track change. ### Android and accessibility - Local Android metadata now reads **disc numbers**, including common values such as `1` and `1/2`, so the data needed for proper multi-disc ordering is preserved. - TalkBack/accessibility semantics were audited and tightened across the main app surfaces, especially icon-only and stateful controls. - Selection mode keeps its scroll position instead of jumping a large library back to the top. ### Local music on Linux The local-library path received a substantial reliability pass: - **Multiple music folders** can make up one local library. - Linthra can **watch configured folders** and refresh automatically when files change. - Incremental scans avoid reparsing files that did not change. - Moved and deleted tracks are handled without treating every scan as a brand-new library. - A removable USB/SSD music library is kept when the drive is temporarily unplugged instead of being mistaken for deleted data. - Missing folders, permission errors and temporarily unavailable mounts now produce a recoverable state instead of silently looking like an empty library. - Embedded local cover art is extracted and cached, with follow-up fixes for scaling and cache invalidation. - The **Add folder** action now lives in **Folders**, where local-library management belongs, instead of the Library browsing header. ### Desktop experience Linthra's Linux UI is much closer to a first-class desktop player: - A persistent **queue side panel** can stay beside the main content on wide windows. - Queue items can be reordered with mouse or keyboard. - Playlists can be reordered and tracks can be dragged onto playlists. - A global **quick search** overlay is available from the desktop. - Compact and Comfortable density modes are available. - The Now Playing bar/view, panes, hover states, context menus and multi-select behavior received a large desktop polish pass. - Full keyboard navigation was added, followed by **configurable keyboard shortcuts**. - Mouse-wheel and trackpad behavior was tuned for desktop use. - Configured self-hosted sources can show their current availability state in the sidebar. - Optional desktop notifications can announce real track changes without exposing provider credentials or private paths. ### Playback and audio on Linux - Linthra can select the Linux audio output device. - Audio-device hotplug is handled cleanly when devices appear or disappear. - A broken/missing libmpv runtime is reported as a Linux runtime problem instead of being mislabeled as an ordinary track failure. - A failed track now has a shared recovery path for retry, skip and provider fallback where available. - Native playback diagnostics can be copied from Settings for troubleshooting. - Playback work that was being performed unnecessarily in the background was reduced. ### Library, queue and downloads - Entire albums and playlists can be downloaded for offline use. - Search now folds accents more consistently. - Recently played history is available in the desktop queue pane and received follow-up correctness fixes. - Queue operations and desktop interactions received additional regression coverage for large libraries and long-running sessions. ### Audiobookshelf groundwork - Linthra can connect to an Audiobookshelf server from Settings. - The initial browse/library foundation is present. - This is groundwork only; it should not be read as a claim that the complete Audiobookshelf playback experience is finished. ### Linux packaging - Stable GitHub releases can now publish a **standalone `.flatpak` bundle** in addition to the native Linux archive. - Flatpak audio and selected-folder library smokes run inside the packaged sandbox. - Smoke cleanup was hardened so local contributor app data is not removed by destructive test cleanup. - Flatpak permissions have written rationale and automated checks. - The Flathub linter is part of the packaging checks. - For this release, the Flatpak build moves to **GNOME Platform 51 / freedesktop-sdk 26.08** and the matching LLVM 22 SDK extension. Linthra is **not on Flathub yet**. The standalone Flatpak is a GitHub Release artifact. ## Privacy and project guardrails - The repository now has an independently runnable dependency-level audit for known advertising, analytics, attribution, telemetry and third-party crash-reporting SDKs. - The current expected result remains: no known advertising, analytics, attribution, telemetry/session-replay/APM or automatic third-party crash-reporting SDK is present in the shipped dependency graph. - This is deliberately a narrow claim: it does not replace review of Linthra's own network behavior. ## Casting Casting remains **temporarily unavailable in production** while the receiver-trust remediation tracked in #575 is still under review. Several Cast hardening pieces landed after 0.2.6, including receiver pinning/remembering groundwork and additional containment verification, but this release does **not** restore production Cast. There is no insecure fallback or user-facing bypass. ## Licensing Linthra's **current project license is AGPL-3.0-or-later**. The license transition happened after v0.2.4: - releases through **v0.2.4** remain under the MPL-2.0 terms under which they were published; - **v0.2.5 and later**, including v0.2.7, are released under **AGPL-3.0-or-later**. The Linthra repository metadata, AppStream metadata and the F-Droid metadata kept in this repository all declare `AGPL-3.0-or-later`. Historical MPL-2.0 text remains preserved for the releases to which it applies. F-Droid's separate canonical `fdroiddata` entry and some third-party listings may still show MPL-2.0 until their metadata is updated or refreshed; that synchronization is tracked in #659. That lag does not change the license of this release. ## Android and F-Droid Canonical Android version: - versionName: `0.2.7` - base versionCode: `207999` F-Droid split-ABI version codes: - armeabi-v7a: `2079991` - arm64-v8a: `2079992` - x86_64: `2079993` F-Droid builds from source at the release tag on its own infrastructure and signs with its own key. GitHub APKs and F-Droid packages use different signing keys, so continue updating from the same source you originally installed from. Linthra is not publicly available on Google Play. ## Linux artifacts The stable GitHub Release is expected to publish: - the native Linux x64 archive; - the standalone Flatpak bundle; - the signed Android APK/AAB artifacts handled by the release workflow. The Flatpak bundle targets GNOME Platform 51. Installing the bundle can fetch that runtime from Flathub when it is not already present. ## Upgrade notes No manual data migration is required. Your configured libraries, queue, downloads, server sessions and playback settings are intended to remain in place across the update. Temporarily unavailable local folders/drives are preserved rather than treated as deleted. ## Community Thank you to everyone testing Linthra, reporting regressions, suggesting features and contributing code. The Android Auto report that led to #638/#643 is exactly the kind of real-device feedback that makes the app more reliable.
  • Sep 8, 2026 0.2.6
    # Linthra v0.2.6 Linthra 0.2.6 is a security maintenance release. Casting is temporarily turned off while a security fix is finished, and the release also carries the Linux desktop and Android library work that landed since 0.2.5. Updating is recommended for anyone who has used or might use casting. ## What's new ### Casting
    More…
    - **Casting is temporarily unavailable.** Linthra will not hand a track to a Cast receiver in this build. The cast control is still there, but it is muted and the device sheet explains that casting is off for now rather than offering devices. This is a deliberate, temporary safeguard while a reported security issue is resolved, not a removal of the feature. See below. ### Android - **A large music folder no longer freezes the app while it scans.** Picking a folder used to walk the whole tree on Android's main thread, one query per folder plus metadata and artwork extraction per file. On a real library that froze the UI and could end in an ANR. The scan now runs on a background thread and replies once when it is done, so the app stays responsive. Picking a second folder supersedes the first: the older scan stops rather than making you wait out a folder you already moved on from. No change to the permission model: the same folder grant, no MediaStore, no broad storage access. ### Linux - **Media keys and desktop media controls work.** Linthra now exports an MPRIS media session, so it shows up in GNOME's lock screen and top bar, KDE's media applet, and `playerctl`, and hardware media keys drive it. Play, pause, stop, next, previous, seek and absolute position are all wired, along with shuffle, repeat and the track's title, artist, album and duration. - Two things are deliberately not published on the session bus: the track's URL (for a streamed track that is an authenticated URL, for a local one it is your file path) and any cover reference that is not a plain loadable image. The track identifier is a counter, not your library's own id. - **Local files show their real tags.** A local Linux library used to show filenames. Linthra now reads title, artist, album, album artist and duration from the files themselves, parsing tags rather than loading whole files, and without pulling cover images out of every file during a scan. A file with missing, unsupported or broken tags still appears under its filename instead of vanishing. Embedded artwork is still to come. - **No more stray mpv cache file.** The audio backend was letting mpv keep an on-disk packet cache, which is the right default for a video player and the wrong one here, and which logged "Failed to create cache temporary file" on every stream where it could not write. That cache is now off. Memory and network buffering are unchanged, and Linthra's own offline downloads are a separate mechanism this does not touch. ### Project - **A security policy and a private reporting route.** The repository now has a `SECURITY.md` and GitHub private vulnerability reporting is enabled, so a security issue has somewhere to go that is not a public issue. Everything else behaves as it did in 0.2.5. Your queue, playback settings, saved servers, downloads and library are untouched by the update. ## Why casting is off A security researcher reported an issue in Linthra's Cast path through [private vulnerability reporting](https://github.com/TheZupZup/Linthra/security/advisories). The report is being handled in a private advisory, and the technical details stay there until a fix is ready and disclosure is coordinated with the reporter. There is no evidence that anyone was affected, and this release makes no such claim. The honest position until receiver identity can be verified properly is to not cast at all, so this release disables the path rather than papering over it. That containment is enforced in three independent places in the code, so a UI change or a single reverted line cannot quietly re-enable it. Public tracking issues: [#572](https://github.com/TheZupZup/Linthra/issues/572) (this containment), [#575](https://github.com/TheZupZup/Linthra/issues/575) (restoring casting properly) and [#576](https://github.com/TheZupZup/Linthra/issues/576) (reducing what any external playback device is given in the first place). Casting will come back in a later release, in a separate reviewed change. It is not restored by this one. ## Android and F-Droid The canonical Android version for this release is: - versionName: `0.2.6` - base versionCode: `206999` F-Droid's split-ABI scheme: - armeabi-v7a: `2069991` - arm64-v8a: `2069992` - x86_64: `2069993` F-Droid builds from source at this tag on its own infrastructure, so its build will follow once it picks the tag up. GitHub APKs and F-Droid packages are signed by different keys, so keep updating from the same install source you originally chose. They cannot update each other. Linthra is **not** publicly available on Google Play. ## Linux The native Linux x64 archive is published as usual: `Linthra-v0.2.6-linux-x64.tar.gz` Casting was never wired up on Linux, so that part of this release changes nothing there. Linthra is not on Flathub yet. ## Upgrade notes No manual migration is required. Update normally from the source you installed from. Your library, queue, downloads and saved servers stay exactly where they are. If you were using casting, it will stop being offered after this update. That is expected, and it is temporary. ## Reporting security issues If you have found something, please use [private vulnerability reporting](https://github.com/TheZupZup/Linthra/security/advisories/new) rather than a public issue. See [SECURITY.md](https://github.com/TheZupZup/Linthra/blob/main/SECURITY.md). ## Community Thank you to the reporter for a careful, responsibly disclosed report, and for coordinating privately while this was prepared. Thanks as always to everyone testing Linthra, filing issues, and contributing the desktop and library work in this release.
  • Sep 6, 2026 0.2.5
    # Linthra v0.2.5 Linthra 0.2.5 is the desktop release. It turns the Linux build from a phone layout stretched across a monitor into something that behaves like a desktop music player: a persistent navigation shell, layouts that adapt to the width they are actually given, and a window that finally identifies itself correctly to the desktop. Android gets a clearer local-music story, an Android Auto fix for large libraries, and more honest Jellyfin connection state. ## What's new - **Persistent desktop navigation.** Wide Linux windows get a navigation rail that stays put beside the content instead of a bottom bar. Each destination keeps its own stack, so switching tabs and coming back lands where you left off. Keyboard traversal reads the rail as one group rather than interleaving it with the page. - **Layouts adapt to the window, not to the platform.** Breakpoints are driven by the width a view is actually given, so a screen inside the rail measures the space it really has. Everything below 600 px is unchanged from the phone layout. - **Denser album and artist grids.** Album cards stay between 200 and 260 px and the grid adds columns instead of inflating covers: 5 across in a 1280-wide window, 7 at 1920, 9 at 2560, and more beyond. Artists flow into 3, 4 and 5 columns at the same widths instead of one row per monitor width. - **Album and artist detail get a side pane.** At expanded widths the cover or portrait, the counts, and Play/Shuffle sit in a persistent left pane beside the scrolling track list. Selection mode falls back to the single column.
    More…
    - **Now Playing and lyrics use the whole window.** The cover sits beside the metadata and transport at expanded widths, and lyrics open next to the cover instead of replacing it, sharing the same toggle and playback state. - **Single-column views stop stretching.** Songs, playlists, downloads and settings cap and centre their column, so a title and its trailing action never end up a screen apart. - **Resizing preserves state.** Crossing a breakpoint moves the navigation without rebuilding it, and inactive branch stacks survive the resize. - **Transport controls on the now-playing bar.** When the bar has room it carries favorite, previous, play/pause, next and a queue button. Previous and next follow the live queue and grey out at its ends. It is the same widget on a phone, so it sheds controls as the window narrows and below 360 px it is the bar we had before. - **Folders is a top-level destination.** It moved out of the Library tab strip and sits next to Library, Playlists, Downloads and Settings, so the folder trail survives a trip to another tab. - **The Linux window identifies itself correctly.** WM_CLASS now matches the app id exactly instead of the capitalised variant GDK derived by default, so shells that compare it exactly can group the window with its own launcher. This comes from the runner, so it applies to both Linux builds. - **The packaged Flatpak carries a real window icon.** The desktop entry declares the matching `StartupWMClass`, and the manifest installs raster icons alongside the scalable one so GTK's icon lookup resolves inside the sandbox and the window ships a `_NET_WM_ICON` for panels and task switchers. This is Flatpak-only: `linux/CMakeLists.txt` builds the executable, libraries and Flutter assets, so the native x64 archive still ships no desktop entry or icon and a user placing it on their system supplies those themselves. - **Music folders open through the desktop portal on Linux.** The runner registers its own folder picker backed by `GtkFileChooserNative`, which draws in process on a native build and routes to `xdg-desktop-portal` inside the sandbox. One code path serves both, and the Flatpak still ships without host filesystem access. - **Secure credential storage works inside the Flatpak.** Provider credentials go through the Secret portal, which every Flatpak may talk to, so this needs no extra sandbox permission at all: no session-bus socket, no D-Bus name grant. GNOME (gnome-keyring) and KDE Plasma 6 (KWallet's ksecretd) both provide that portal backend. On a desktop that provides none, Linthra reports a recoverable storage error and stays signed out rather than inventing storage of its own; a user who wants the Secret Service fallback can grant it themselves with `flatpak override --user`. - **Configured servers reach the network from the Flatpak.** The sandbox now permits the networking a configured server needs, and the finish-args parser handles quoted and commented entries correctly. - **Device-wide music access on Android is explicit.** Choosing your whole device library is now its own visible choice, separate from picking a folder, with its own permission flow and its own empty-state and error wording. Switching is transactional: a denied permission or a failed first scan leaves the previous folder and the indexed catalog exactly as they were. - **Android Auto no longer spins on the Songs list.** Songs is served in bounded browse pages, so large libraries load instead of overrunning the media browser's transaction buffer and never returning. - **Jellyfin connection state is real.** Configuration and reachability are tracked separately, so a LAN-only server you are away from reports as unavailable instead of "connected" while every stream fails. The catalog, playlists, favourites and downloads stay put. - **AppStream metainfo for software centres.** Linthra ships an AppStream component so Linux software centres can describe and list it. ## Linux and Flatpak status The GitHub Release still publishes the native Linux x64 archive: `Linthra-v0.2.5-linux-x64.tar.gz` Flatpak packaging in this repository is now building end to end on clean runners, with sandbox coverage for filesystem access and offline sources. Linthra is **not** published on Flathub yet, and this release does not claim a Flathub submission. The desktop work above is validated on the native Linux build and the packaged Flatpak. Runtime requirements and the current Linux support matrix are documented in `docs/linux-desktop.md`. ## Android and F-Droid Android remains a first-class target. The canonical Android version for this release is: - versionName: `0.2.5` - base versionCode: `205999` F-Droid's split-ABI scheme remains: - armeabi-v7a: `2059991` - arm64-v8a: `2059992` - x86_64: `2059993` GitHub APKs and F-Droid packages remain signed by different keys, so users should keep updating from the same install source they originally chose. Linthra is **not** publicly available on Google Play. CI can publish signed builds to a Google Play testing track; that is a distribution pipeline, not a public listing. ## Licensing This is the first release cut after the relicensing to **AGPL-3.0-or-later** (#535). Releases up to and including v0.2.4 remain under the MPL-2.0 terms they were published under, and that text is preserved at `docs/licenses/MPL-2.0.txt`. See `docs/license-transition.md`. v0.2.5 is therefore the F-Droid license cutover. Its `CurrentVersion` is the first cut from an AGPL source commit, so the F-Droid metadata's `License:` field moves to `AGPL-3.0-or-later` in this same change, as `docs/license-transition.md` requires. The historical `Builds` entries keep their pre-transition versions and are not relabelled. The matching update in the external `fdroiddata` repository still has to be made separately, along with the submission text, per `docs/fdroid-submission.md` §9. ## Upgrade notes No manual migration is required. Existing Android library and settings data remain in place during a normal same-source update, and Linux users can replace the previous native archive with the new one. Android users who previously pointed Linthra at a folder keep that folder. Device-wide music access is an opt-in choice, not a default. ## Community Thank you to everyone testing Linthra, reporting issues, reviewing changes, and contributing fixes. This release includes community work on desktop layout, Linux packaging, and playback robustness alongside the desktop shell and adaptive-layout work.
  • Aug 27, 2026 0.2.4
    # Linthra v0.2.4 Linthra 0.2.4 is a Linux packaging, desktop polish, accessibility, and project-safety release. It moves the Linux port closer to a packageable desktop application while tightening shutdown behavior and repository trust boundaries. ## What's new - **Flatpak packaging has moved from plan to a working foundation.** Linthra now carries the initial manifest/offline source pipeline, bundles the Linux audio runtime it needs, installs a desktop entry and scalable app icon, and documents local Flatpak development. This is packaging groundwork; Linthra is not yet published on Flathub. - **Desktop shutdown is deterministic.** Linthra waits for app-owned asynchronous teardown — including database, playback, control services, and caches — before shutdown completes, reducing exit/restart races. - **Keyboard and accessibility support is broader.** The custom seek bar can be operated from the keyboard, icon-only controls expose clearer semantics, cast/queue/source controls report their state better, and destructive dialogs default focus to Cancel. - **Large text no longer breaks the mini-player.** The compact player remains usable when text scaling is increased.
    More…
    - **Linux integration is more complete.** The application has a proper desktop launcher identity and scalable icon, while the packaged audio path is designed to be self-contained. - **Repository trust boundaries are substantially stronger.** PR security scanning and repository-integrity checks cover more sensitive surfaces and commit history, while trusted reporting can explain findings on fork PRs without executing contributor code. - **CI dependencies were refreshed.** `actions/setup-java` and `actions/github-script` moved to their current major versions after successful build validation. ## Linux / Flatpak status The GitHub Release still publishes the native Linux x64 archive: `Linthra-v0.2.4-linux-x64.tar.gz` Flatpak packaging is now present in the repository and suitable for local development/testing, but this release does **not** claim a Flathub publication yet. ## Android and F-Droid Android remains a first-class target. The canonical Android version for this release is: - versionName: `0.2.4` - base versionCode: `204999` F-Droid's split-ABI scheme remains: - armeabi-v7a: `2049991` - arm64-v8a: `2049992` - x86_64: `2049993` GitHub APKs and F-Droid packages remain signed by different keys, so users should keep updating from the same install source they originally chose. ## Upgrade notes No special user action is expected beyond a normal same-source update. Existing Android library/settings data remain in place during a normal update, and Linux users can replace the previous native archive with the new one. ## Community Thank you to everyone testing Linthra, reporting issues, reviewing changes, and contributing fixes. This release includes community work around desktop accessibility and UI robustness alongside the Linux packaging and project-hardening work.
  • Aug 20, 2026 0.2.3
    # Linthra v0.2.3 Linthra 0.2.3 is a community-driven stability and Linux desktop release, with stronger playback recovery, safer session restoration, better self-hosted server handling, and the first Audiobookshelf integration foundation. ## What's new - **Linux playback recovers instead of getting stuck.** Mid-stream server and network failures now use bounded recovery, a buffering watchdog, sibling-source fallback when available, and a clear Retry path instead of looping forever. - **Temporary network drops have a real reconnect state.** Now Playing can show **Reconnecting…** while Linthra re-resolves a fresh authenticated stream URL and resumes near the preserved position. - **Suspend/resume is much safer on Linux.** A track that was actively playing before system sleep can be re-resolved and reloaded after wake on the same player, while a track the user paused stays paused. - **Crash-safe Linux playback restoration.** After an unexpected restart, Linthra can restore the logical queue, current item, repeat/shuffle state, and position as a **paused** session. It never persists authenticated stream URLs or provider tokens, and remote tracks re-resolve normally when playback resumes.
    More…
    - **Audiobookshelf support has started.** This release adds the connection, authentication, server validation, session model, and library-listing foundation. Audiobook playback, chapters, progress sync, bookmarks, and offline audiobook support remain follow-up milestones. - **Self-hosted server URLs are more robust.** Jellyfin, Plex, and Subsonic/Navidrome now share one URL-normalization path, including correct handling for IPv6 literal hosts. - **Large source re-syncs are cheaper.** The local database now indexes `tracks.source_id`, avoiding a full catalog scan when one source is refreshed. Existing databases migrate automatically. - **Linux library defaults fit the desktop better.** The folder chooser can start from the user's XDG Music directory instead of assuming `~/Music`, including localized or relocated Music folders. - **System theme behavior is documented and guarded across desktop/mobile.** Linthra keeps one shared Flutter `ThemeMode.system` path rather than adding GNOME/KDE-specific theme code. - **Player accessibility improved.** The custom play/pause control now exposes the proper button role and enabled state to assistive technologies. ## Linux reliability The recent Linux playback work intentionally reuses Linthra's existing playback controller rather than creating provider-specific retry systems or extra players. Recovery is bounded, concurrent recovery triggers are coalesced, and failure still ends in a normal user-visible error/Retry state. Real hardware timing can vary after suspend — especially with Bluetooth, PipeWire/PulseAudio, or networking that returns after the Flutter lifecycle signal — so `docs/linux-desktop.md` includes the manual matrix used for milestone testing. ## Audiobookshelf status Audiobookshelf in v0.2.3 is the **first integration milestone**, not the complete audiobook player. The foundation validates the server before credentials are sent, uses the server's supported login/token flow, and keeps session parsing defensive against corrupt persisted data. The next milestones can build browsing/domain models, chapters/playback, progress sync, bookmarks, and offline behavior on top of this base without mixing audiobook behavior into the existing music providers. ## Android and F-Droid Android remains a first-class target. The Linux-specific recovery/restore paths are gated so Android screen-on and normal mobile lifecycle behavior do not begin auto-restarting playback. The canonical Android version for this release is: - versionName: `0.2.3` - base versionCode: `203999` F-Droid's split-ABI scheme remains: - armeabi-v7a: `2039991` - arm64-v8a: `2039992` - x86_64: `2039993` GitHub APKs and F-Droid packages remain signed by different keys, so users should keep updating from the same install source they originally chose. ## Linux download The GitHub Release workflow can attach: `Linthra-v0.2.3-linux-x64.tar.gz` This is the native Flutter Linux bundle, not the future Flatpak. Runtime requirements and the current Linux support matrix are documented in `docs/linux-desktop.md`. ## Upgrade notes No manual migration is required. The SQLite schema upgrade that adds the source index is handled automatically, and crash-safe playback state uses defensive versioned persistence. Existing Android library/settings data remain in place during a normal same-source update. ## Community A big part of v0.2.3 came from community contributions across self-hosted server support, Audiobookshelf, accessibility, database performance, Linux desktop integration, and playback reliability. Special thanks to **@jpdexter101-lang** and **@Borhan2004** for their contributions to this release. These acknowledgements are release-level thanks, not a one-to-one mapping between each nearby feature bullet and a specific commit author. Thank you to everyone testing Linthra, reporting edge cases, reviewing changes, and helping the project grow.
  • Aug 16, 2026 0.2.2
    # Linthra v0.2.2 Linthra 0.2.2 is a feature and stability release for Android, with the first official native Linux release path alongside it. ## What's new - **Now Playing feels smoother.** The playback progress control now uses Linthra's wavy seek bar, with a stable seek handoff so the marker does not snap back while the player catches up. - **Synced lyrics got a full presentation pass.** The active line follows cleanly in-place on Now Playing, surrounding lines use progressive emphasis, and the layout stays stable while the active line changes. - **Artwork survives restarts.** Remote artwork can be kept in Linthra's managed disk cache instead of being downloaded again every time the app opens. - **Automatic song precaching is optional.** It can be disabled independently; normal streaming and explicit/manual downloads keep working.
    More…
    - **Linux now has real native playback.** Linthra can build and run as a native Flutter Linux app using the Linux media backend, and official releases can publish an x64 Linux bundle from GitHub Actions. ## Stability and accessibility This release also includes fixes around seek acknowledgement, short lyrics layouts, timed-lyrics geometry, reduced-motion behavior, keyboard/screen-reader semantics in the updated player controls, and stronger Linux lifecycle/build validation. ## Android and F-Droid Android remains a first-class target and the normal F-Droid source-build path stays separate from GitHub release signing. The canonical Android version for this release is: - versionName: `0.2.2` - base versionCode: `202999` F-Droid's split-ABI build keeps Linthra's established `base * 10 + ABI rank` scheme: - armeabi-v7a: `2029991` - arm64-v8a: `2029992` - x86_64: `2029993` The release tooling now preserves that transformed F-Droid `CurrentVersionCode` instead of accidentally writing the untransformed base code. The committed `pubspec.lock`, Rust `Cargo.lock`, per-ABI Gradle override, and canonical GitHub per-ABI asset names remain part of the reproducible-build guardrails. F-Droid builds from source and can appear later than the GitHub Release while its own update/build/review pipeline runs. ## Linux download The GitHub Release workflow can attach: `Linthra-v0.2.2-linux-x64.tar.gz` This is the native Flutter Linux bundle, not the future Flatpak. It may still require the Linux runtime libraries documented in `docs/linux-desktop.md`. Flatpak/Flathub packaging and deeper desktop integration such as MPRIS remain separate roadmap work. ## Upgrade notes No migration step is required. Existing Android installs keep their library/settings data during a normal same-source update. As always, GitHub APKs and F-Droid packages are signed by different keys, so do not switch install sources on top of an existing installation.
  • Aug 10, 2026 0.2.1
    # Linthra v0.2.1 — release notes **Linthra v0.2.1 is a maintenance release focused on reproducible source builds and F-Droid compatibility.** It keeps the v0.2.0 player behavior intact while fixing the Rust dependency-locking issue that blocked F-Droid's source build pipeline. - **Version:** `0.2.1` (`versionName`), `versionCode` `201999` - **Platform:** Android - **Application ID:** `io.github.thezupzup.linthra` - **License:** MPL-2.0 ## What's new
    More…
    ### F-Droid source-build fix - Commits `native/linthra_core/Cargo.lock` so the Rust dependency manifest has a matching lockfile in the tagged source tree. - This resolves the dependency-scanner failure introduced when the standalone Rust core was added in v0.2.0. - Rust Clippy, unit tests, and the 200k-track benchmark now run with `--locked`, preventing CI from silently changing dependency resolution. ### No player behavior changes - Playback, local library behavior, Jellyfin, Navidrome / Subsonic, Plex, offline cache, casting, Android Auto, playlists, favorites, and onboarding remain functionally unchanged from v0.2.0. - This patch exists so the next immutable release tag contains the complete dependency-locking state F-Droid expects. ## Upgrade and distribution notes - Normal in-place updates preserve accounts, settings, playlists, catalog, favorites, and cache. - Do not mix GitHub and F-Droid installations because the APKs use different signing keys and cannot update one another. - F-Droid builds and signs its own APKs from the source tag; GitHub Release APKs are signed by the upstream project. - The existing `v0.2.0` tag remains untouched and immutable; v0.2.1 carries the source-build correction forward. No ads, no tracking, no analytics, no telemetry. Linthra plays music you already own or that your own server provides.
  • Aug 8, 2026 0.2.0
    # Linthra v0.2.0 release notes **Linthra is an Android music player for local files and self-hosted music servers.** v0.2.0 introduces a proper first-run experience for new installs and expands the project foundations for future performance work and broader open-source contributions. - **Version:** `0.2.0` (`versionName`), `versionCode` `200999` - **Platform:** Android - **Application ID:** `io.github.thezupzup.linthra` - **License:** MPL-2.0 ## What's new
    More…
    ### A real first-run welcome - New installs now open a guided welcome instead of dropping directly into an empty library. - The source chooser helps users start with local music, Jellyfin, Navidrome / Subsonic, or Plex. - Notification permission is deferred until the welcome has completed so first launch stays focused on setup. - The welcome can be replayed later from Settings. ### Existing installs stay out of the way - Linthra now records onboarding completion and detects Android install history during startup. - Existing users upgrading from an earlier version continue into the normal app instead of being treated like a fresh install. - The startup state is resolved before the router is built, preventing a temporary jump into the wrong screen. ### More resilient onboarding UI - The welcome layout now uses the actual SafeArea constraints and handles very short viewports without producing invalid layout constraints. - Regression coverage protects first-run routing, upgrade classification, onboarding persistence, and short-screen layout behavior. ## Project foundations for v0.2.x This release also opens more of Linthra to contributors working outside Dart while keeping these components deliberately separate from the shipped playback path until they are ready to be integrated. - A Rust `linthra_core` prototype provides a deterministic large-library search index and a 200k-track benchmark. - A native C++ audio DSP project defines an allocation-free processing chain, stable C ABI, EQ/preamp/limiter tests, and a realtime-safety benchmark. - Python and SQL tooling can generate and benchmark a deterministic 200k-track SQLite library. - CI now validates the Rust core, C++ DSP work, and large-library SQL benchmark independently. - Contributor documentation maps real areas where Dart, Kotlin, Rust, C++, Python, and SQL can be used in Linthra. These native and tooling projects are foundations for future work; v0.2.0 does not claim that Rust search or the C++ DSP chain has replaced the current Flutter playback/search implementation yet. ## Upgrade and distribution notes - Normal in-place updates preserve accounts, settings, playlists, catalog, favorites, and cache. - Existing installs should bypass the new first-run welcome automatically. - Do not mix GitHub and F-Droid installations because the APKs use different signing keys and cannot update one another. - F-Droid builds and signs its own APKs from the source tag; GitHub Release APKs are signed by the upstream project. No ads, no tracking, no analytics, no telemetry. Linthra plays music you already own or that your own server provides.
  • Aug 6, 2026 0.1.15
    # Linthra v0.1.15 — release notes **Linthra is an Android music player for local files and self-hosted music servers.** v0.1.15 is a focused player-interface stability release for Navidrome, Jellyfin, Plex, local music, offline cache, and casting. - **Version:** `0.1.15` (`versionName`), `versionCode` `115999` - **Platform:** Android - **Application ID:** `io.github.thezupzup.linthra` - **License:** MPL-2.0 ## What's new
    More…
    ### A steadier Now Playing screen - The Now Playing screen no longer jumps when playback moves between source, buffering, cache, casting, and error indicators. - The fix applies to Navidrome/Subsonic, Jellyfin, Plex, local music, offline cache, and casting because they share the same player status area. - The status area now reserves one stable height, keeping track metadata, the progress bar, and transport controls in place. - Long playback errors stay on one line with an ellipsis instead of expanding the layout. ### Better large-text support - The stable status area grows with the system text scale. - Larger accessibility text remains readable without overlapping or moving the controls. - A widget regression test verifies the transition from `Playing from Navidrome` to `Buffering…` to `Playing from Cache` without vertical movement. ## Upgrade and distribution notes - Normal in-place updates preserve accounts, settings, playlists, catalog, favorites, and cache. - No playback routing, seeking, provider, cache, or streaming behavior changed in this release. - Do not mix GitHub and F-Droid installations because the APKs use different signing keys and cannot update one another. - F-Droid builds and signs its own APKs from the source tag; GitHub Release APKs are signed by the upstream project. No ads, no tracking, no analytics, no telemetry. Linthra plays music you already own or that your own server provides.
  • Aug 5, 2026 0.1.14
    # Linthra v0.1.14 release notes **Linthra is an Android music player for local files and self-hosted music servers.** v0.1.14 improves album browsing, fixes compilation and collaboration grouping, adds full light/dark appearance support, and makes first-time server synchronization clearer. - **Version:** `0.1.14` (`versionName`), `versionCode` `114999` - **Platform:** Android - **Application ID:** `io.github.thezupzup.linthra` - **License:** MPL-2.0 ## What's new
    More…
    ### Compilation and collaboration albums stay together - Linthra now prefers a provider-namespaced album ID when grouping tracks. - Tracks from the same album remain grouped even when each track credits a different artist or collaborator. - Jellyfin and Plex also use their album-artist metadata when available; local files use an embedded album-artist tag when present. - Navidrome/Subsonic albums use the server-provided album ID without guessing an album artist. - Existing catalogs and settings are preserved by an additive database migration. - Allow or start a library sync after updating so existing tracks receive the new album metadata. ### A responsive album grid - The Albums tab now shows two cover-focused columns on phones instead of one full-width row per album. - Wider screens gain additional columns only when enough space is available. - Album artwork remains square, while long titles and artist names are safely truncated. - Tap and long-press behavior remains unchanged, including album navigation and bulk playlist actions. - Layout and semantics adapt to larger text sizes and accessibility tools. ### System, Light, and Dark appearance modes - Linthra now follows the phone's light or dark setting by default. - Settings → Appearance includes explicit System, Light, and Dark choices. - The selected mode is restored before the first frame, avoiding a theme flash at startup. - Light palettes were retuned and tested for readable contrast while preserving Linthra's visual identity. ### Clearer first synchronization - Empty-library screens now recognize active Jellyfin, Navidrome/Subsonic, and Plex synchronization. - Linthra names the source being synchronized when one source is active, and uses a general message when several are active. - Plex users are no longer shown the unrelated local-folder prompt while their server library is scanning. - Navidrome/Subsonic users no longer see a misleading empty-catalog message while the first sync is still filling the library. ## Release and F-Droid reliability - The release version remains fully defined in `pubspec.yaml`, with the matching in-app version enforced by tests. - F-Droid can detect the `v0.1.14` tag automatically and derive the three per-ABI version codes: `1149991`, `1149992`, and `1149993`. - Dependency resolution remains locked through the committed `pubspec.lock` and `flutter pub get --enforce-lockfile`. - Pull-request CI validates the Android release lint path before the immutable stable tag is created. - The stable publisher verifies the universal APK, AAB, and all three signed per-ABI APKs on the GitHub Release. ## Upgrade and distribution notes - Normal in-place updates preserve accounts, settings, playlists, catalog, favorites, and cache. - Run or allow one server-library sync after updating to populate the new album identifiers for existing tracks. - Do not mix GitHub and F-Droid installations because the APKs use different signing keys and cannot update one another. - F-Droid builds and signs its own APKs from the source tag; GitHub Release APKs are signed by the upstream project. No ads, no tracking, no analytics, no telemetry. Linthra plays music you already own or that your own server provides.
  • Aug 4, 2026 0.1.13
    ## F-Droid release reliability fix Linthra v0.1.13 carries forward the clean-reinstall protection intended for v0.1.12 while fixing the Android release-only lint failure that prevented v0.1.12 from producing APK and AAB artifacts. ### What’s new * Fixed the `lintVitalRelease` failure that blocked Android and F-Droid release builds. * Updated Android backup rules to use only storage domains supported by the pinned Android lint schema. * Added `lintVitalRelease` to pull-request CI so release-only Android resource errors are caught before a stable tag is created. * Preserved clean reinstall behavior: uninstalling and reinstalling Linthra no longer restores obsolete songs, settings, server state, or inaccessible folder references.
    More…
    * Normal in-place updates continue to preserve accounts, playlists, settings, catalog, and cache. * No database migration, UI feature, or playback behavior change is included in this release. ### Technical details * Removed unsupported `device_root`, `device_file`, `device_database`, and `device_sharedpref` backup domains. * Retained the supported `root`, `file`, `database`, `sharedpref`, and `external` exclusions. * Retained `android:allowBackup="false"` for debug, profile, and release builds. * Strengthened regression tests to prevent unsupported `device_*` domains from being reintroduced. * Implemented in PR #304. ### Upgrade notes Existing users can update normally without losing their data. Users who uninstall Linthra before reinstalling will receive a clean library rather than stale state restored by Android. GitHub and F-Droid builds use different signing keys and cannot update one another. Continue using the same installation source you currently use. No ads, no tracking, no analytics, no telemetry.
  • Aug 3, 2026 0.1.11
    # Linthra v0.1.11 — release notes **Linthra is an Android music player for local files and self-hosted music servers.** v0.1.11 is a **folder-browsing and Android navigation release**. It adds a real server-folder view for Jellyfin and Navidrome/Subsonic and makes the Android system Back button follow Linthra's navigation before exiting the app. - **Version:** `0.1.11` (`versionName`), `versionCode` `111999` - **Platform:** Android - **Application ID:** `io.github.thezupzup.linthra`
    More…
    - **License:** [MPL-2.0](../../LICENSE) - **Get it:** Available from the [GitHub Releases page](https://github.com/TheZupZup/Linthra/releases) first (signed APKs); [Obtainium](https://github.com/ImranR98/Obtainium) can track this repository for updates. The [F-Droid](https://f-droid.org/packages/io.github.thezupzup.linthra/) build follows after F-Droid detects the tag and completes its build process. ## What's new ### Browse by folder hierarchy - **New Folders tab.** Library now includes a Folders tab when a compatible Jellyfin or Navidrome/Subsonic server is connected. - **Real server structure.** Browse the hierarchy exposed by the server instead of relying only on Linthra's flat Songs, Albums, and Artists views. - **Direct playback.** Songs found inside a folder can be started immediately using Linthra's existing playback queue and track actions. - **Separate connected sources.** Jellyfin and Navidrome/Subsonic roots are shown independently when both are connected. - **Lightweight navigation.** Linthra requests one folder level at a time rather than recursively downloading the complete directory tree. - **Friendly states.** Loading, empty-folder, error, and retry states are handled inside the folder browser. ### Android Back navigation - **Nested folders return correctly.** Android Back moves to the previous folder before leaving the Folders tab. - **Detail screens return normally.** Album, artist, playlist, player, support, and settings-detail screens return to their parent screen. - **Main tabs return to Library.** Back from the root of Playlists, Downloads, or Settings returns to Library instead of closing Linthra immediately. - **Exit only from the true root.** Linthra closes normally only when Back is pressed from the root of Library with no internal state left to dismiss. - **Existing tab history is preserved.** The independent navigation stack and scroll position of each bottom-navigation tab remain intact. ## Technical summary - **Provider-neutral folder capability** ([PR #289](https://github.com/TheZupZup/Linthra/pull/289), closes [#282](https://github.com/TheZupZup/Linthra/issues/282)): a small optional folder-browsing contract lets supported providers expose root folders and one immediate child level without changing the normal music-source interface. - **Jellyfin folder browser:** reads music roots from `/Library/MediaFolders` and direct child folders/tracks from `/Items` with non-recursive requests. - **Navidrome/Subsonic folder browser:** reads music roots through `getMusicFolders`, indexes through `getIndexes`, and nested directories through `getMusicDirectory`. - **Credential-safe identifiers:** folder IDs stay opaque and never include an authenticated URL, password, token, or other secret. - **Central Android Back handling** ([PR #289](https://github.com/TheZupZup/Linthra/pull/289), closes [#285](https://github.com/TheZupZup/Linthra/issues/285)): root and branch navigators now cooperate so internal state is handled before the app exits. No dependency, Drift schema, account, playlist, download, cache, or media-library data migration is included in this release. ## Manual QA completed - [x] Browse a real Jellyfin folder hierarchy. - [x] Open nested folders and start a song directly from Folders. - [x] Use Android Back to return through nested folders. - [x] Use Android Back across Linthra detail screens and main tabs. - [x] Exit normally from the Library root. - [x] Dart formatting, Flutter analysis, full tests, privacy scan, Android debug build, and GitHub Sponsor simulation passed on the feature PR. ## Upgrade and distribution notes - No settings reset or database migration is required. - **Don't mix install sources.** A GitHub-release APK is signed with Linthra's key, while the F-Droid build is signed with F-Droid's key; the two cannot update each other. Stay with one source. - F-Droid detects stable tags automatically and builds from source. The local metadata mirror can be updated after tagging with the final tag commit SHA and per-ABI version codes. No ads, no tracking, no analytics, no telemetry. Linthra plays music you already own or that your own server provides.