Multi-track relay (high): relay now tracks selectedTrackId driven by updateTracks(). LibassInterceptingTrackOutput drops samples for non-selected tracks and re-primes the header (via headerGeneration counter) when the selected track switches. NativeLibassSubtitleOverlay gates relayRenderer on embeddedSubtitle != null so disabling subs actually stops drawing. Duration inference (high): pendingBody is flushed in onSeekFlush() with lastInterEventMs capped to 5s, fixing the last-subtitle-never-shown problem. Duration cap lowered from 60s to 30s to reduce lingering on sparse dialogue. Font fallback (medium): LibassInjectingExtractorsFactory now accepts fontsDir and threads it through to setHeader(), matching what the local/external path already did. C++ nativeCreate uses fonts_dir for ass_set_fonts_dir and probes for a NotoSans-Regular.ttf default_font instead of passing nullptr. Render loop (medium): C++ nativeRender returns jint (1=has image, 0=no image). When detect_change==0 and bitmap dimensions are unchanged it skips memset+blend entirely and returns the cached last_had_image. Kotlin onDraw uses the int result to decide whether to draw and switches to postInvalidateDelayed(100) during subtitle-free periods instead of postInvalidateOnAnimation at 60 fps. Thread safety (low): ensure_api() replaced bool+flag with std::call_once so the first-call race between ExoPlayer's loader thread and main is eliminated. Subtitle matching (low): selectedNativeAssSubtitle now tries label then URL then (label+language) before falling back to language-only, preventing two external subs in the same language from selecting the wrong one. fetchSubtitleBytes switches to OkHttp and forwards StreamRequestPolicy headers so addon URLs that require Referer/auth don't 403. |
||
|---|---|---|
| .github/workflows | ||
| app | ||
| build-logic | ||
| core | ||
| data | ||
| gradle | ||
| player | ||
| .gitignore | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| README.md | ||
| settings.gradle.kts | ||
Fluxa
A fast, native media client for Android phones, tablets, and TV.
Browse catalogs, track what you watch, and play anything the Stremio addon ecosystem exposes.
What it does
Fluxa connects to any Stremio-compatible addon and turns it into a proper Android app: a home feed with genre and category browsing, a calendar of upcoming episodes, a library with continue-watching and resume positions, and two-way watch tracking with Trakt, MyAnimeList, and Simkl. Playback runs through Media3/ExoPlayer and MPV, including direct torrent/magnet support, with no telemetry.
The Android shell handles all platform I/O — HTTP, Room, ExoPlayer, audio, notifications — but the actual decision-making lives in fluxa-core, a headless Rust library that runs the same logic across Android and desktop targets. Rust never touches the network directly; it emits typed effects that the Kotlin layer fulfills.
Features
- Catalogs & discovery — home feed, genre/category grids, search across every installed addon, and a calendar of upcoming episodes for what you're following
- Library — watchlist, continue watching with resume position, and custom collections, with import support for existing lists
- Watch tracking — two-way sync with Trakt, MyAnimeList, and Simkl
- Playback — subtitle and audio track selection, intro/outro/recap skip, and direct torrent/magnet support
- Profiles — multiple local profiles on one install, each with its own library, addons, and sync accounts
- Addons — install and manage Stremio-compatible addons directly from the app
- TV-ready — a dedicated Android TV / Google TV interface, not a stretched phone layout
- Auto-update — checks for and installs new versions in-app
Download
Grab the latest build from Releases. Requires Android 8.0+ (API 26).
| Variant | Package | Target |
|---|---|---|
mobile |
com.fluxa.app.mobile |
Phone & tablet |
tv |
com.fluxa.app.tv |
Android TV / Google TV |
Each variant ships per-ABI APKs — pick the one matching your device, or let the in-app updater do it for you:
| ABI | Devices |
|---|---|
arm64-v8a |
Most phones/tablets/TVs from the last ~6 years |
armeabi-v7a |
Older 32-bit ARM devices |
x86 |
Intel-based Android (emulators, some set-top boxes) |
Building from source
git clone https://github.com/KhooLy/Fluxa.git
cd Fluxa
./gradlew :app:assembleMobileDebug
# or for TV
./gradlew :app:assembleTvDebug
Prerequisites
- JDK 17+
- Rust stable with the Android NDK targets (
aarch64-linux-android,armv7-linux-androideabi,i686-linux-android) - Android NDK (version pinned in
app/build.gradle.kts) fluxa-corechecked out as a sibling directory (../fluxa-core) — it also providesfluxa-streaming-engine(../fluxa-streaming-engine)
The Rust libraries (fluxa_core, fluxa_streaming_engine) are cross-compiled for all Android ABIs automatically as part of the Gradle build; no manual cargo build step is needed.
Architecture
Fluxa is split into two native Rust libraries and an Android Kotlin shell:
┌─────────────────────────────────────────────────────────┐
│ Android (Kotlin + Compose) │
│ UI · ViewModel · Repository · OkHttp · Room · Player │
├───────────────────────────┬─────────────────────────────┤
│ fluxa_core │ fluxa_streaming_engine │
│ Headless brain: state, │ Video proxy, Dolby Vision │
│ policy, stream planning │ rewrite, torrent engine │
└───────────────────────────┴─────────────────────────────┘
Rust never calls the network directly. Instead it emits typed effects that Kotlin executes:
Kotlin → dispatch(action)
← { state, effects: [{ id, type, payload }] }
Kotlin → executes each effect (OkHttp / Room / audio / ...)
→ completeEffect({ effectId, result })
← { state, effects: [...] }
This keeps fluxa_core fully portable — the same crate compiles for Android (JNI), desktop (native Rust), and future targets without any platform-specific code inside Rust.
Stack
Kotlin · Jetpack Compose · Rust · AndroidX Media3 / ExoPlayer · MPV · librqbit · UniFFI · Hilt · Room · OkHttp + Retrofit · Coil
Legal — Fluxa is a client-side interface for user-installed Stremio addons. It does not host, serve, or distribute any media content. All streams come from third-party addons chosen by the user. Fluxa is not affiliated with any addon developer, repository, or content provider. Users are responsible for ensuring they have the right to access what they stream.
Related projects
- Fluxa Desktop — the desktop counterpart to this app
- fluxa-core — the shared Rust library powering both