2026-08-17 13:13:10 +12:00
|
|
|
|
<div align="center">
|
2026-07-27 08:16:20 +12:00
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
<img src="memby-icon.png" alt="Memby" width="128" height="128">
|
|
|
|
|
|
|
|
|
|
|
|
# Memby
|
|
|
|
|
|
|
|
|
|
|
|
**An independent Android TV client for Emby.**
|
|
|
|
|
|
|
|
|
|
|
|
A personalised television launcher, a full media player, a system screensaver and an
|
|
|
|
|
|
optional self-hosted gateway that shapes the experience for every viewer in the house.
|
|
|
|
|
|
|
|
|
|
|
|
[](LICENSE)
|
|
|
|
|
|
[](#build--install)
|
|
|
|
|
|
[](#build--install)
|
|
|
|
|
|
[](#tech-stack)
|
|
|
|
|
|
[](server/README.md)
|
2026-07-27 08:16:20 +12:00
|
|
|
|
|
2026-08-02 22:10:19 +12:00
|
|
|
|
Source: [g.sublogue.com/admin/memby](https://g.sublogue.com/admin/memby)
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Contents
|
|
|
|
|
|
|
|
|
|
|
|
- [How it works](#how-it-works)
|
|
|
|
|
|
- [Features](#features)
|
|
|
|
|
|
- [Browse and discover](#browse-and-discover)
|
|
|
|
|
|
- [Playback](#playback)
|
|
|
|
|
|
- [Profiles, televisions and administration](#profiles-televisions-and-administration)
|
|
|
|
|
|
- [Screensaver and updates](#screensaver-and-updates)
|
|
|
|
|
|
- [Tech stack](#tech-stack)
|
|
|
|
|
|
- [Build & install](#build--install)
|
|
|
|
|
|
- [Server address](#server-address)
|
|
|
|
|
|
- [First run](#first-run)
|
|
|
|
|
|
- [Running the gateway](#running-the-gateway)
|
|
|
|
|
|
- [Project layout](#project-layout)
|
|
|
|
|
|
- [Distributing builds](#distributing-builds)
|
|
|
|
|
|
- [One-time: a signing key](#one-time-a-signing-key)
|
|
|
|
|
|
- [NAS deployment release (recommended)](#nas-deployment-release-recommended)
|
|
|
|
|
|
- [Local PowerShell release (compatibility path)](#local-powershell-release-compatibility-path)
|
|
|
|
|
|
- [How TVs update themselves](#how-tvs-update-themselves)
|
|
|
|
|
|
- [Upgrading to v0.1.53](#upgrading-to-v0153)
|
|
|
|
|
|
- [Notes & limitations](#notes--limitations)
|
|
|
|
|
|
- [Licence](#licence)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
|
|
|
|
The client can talk to Emby directly, or through the **Memby gateway** — a Go service in
|
|
|
|
|
|
`server/` that runs in Docker alongside Postgres and Redis and owns auth, caching, search
|
|
|
|
|
|
and the shaping of TV screens. With a gateway the launcher is one request instead of four,
|
|
|
|
|
|
and the TV holds a revocable gateway token rather than a live Emby token.
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
direct: TV ──────────────────────────────► Emby
|
|
|
|
|
|
gateway: TV ──► Memby gateway ──► Emby (metadata + artwork)
|
|
|
|
|
|
TV ─────────────────────► Emby (video stream; never proxied by the gateway)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Which one a build uses is decided by `memby.gatewayUrl` in `gradle.properties`: set it and
|
|
|
|
|
|
the app is a thin client; leave it blank and the app talks to Emby directly. Both paths are
|
|
|
|
|
|
maintained — the direct path is the fallback when the container is down.
|
|
|
|
|
|
|
2026-07-27 08:16:20 +12:00
|
|
|
|
## Features
|
|
|
|
|
|
|
2026-08-09 16:04:40 +12:00
|
|
|
|
### Browse and discover
|
|
|
|
|
|
|
|
|
|
|
|
- Personalised, server-composed Home rows with a cached instant-start launcher.
|
|
|
|
|
|
- A cinematic featured hero that rotates through ranked films and series premieres.
|
|
|
|
|
|
- Continue Watching merged with Next Up, ordered by the viewer's recent activity.
|
|
|
|
|
|
- Favourites, latest films, recommendations, curated shelves and schedule rows.
|
|
|
|
|
|
- Dedicated Movies, TV Shows, Favourites and For You destinations.
|
|
|
|
|
|
- Instant search with an on-screen keyboard, voice input and session result caching.
|
|
|
|
|
|
- Optional, server-controlled genre browsing with paged film and series catalogues.
|
|
|
|
|
|
- A dedicated For You page combining viewing history, browsing signals, available time
|
|
|
|
|
|
and direct-play evidence; every recommendation explains why it was selected.
|
|
|
|
|
|
- More Like This, cast and technical details on film and series pages.
|
|
|
|
|
|
- Per-title IMDb, Rotten Tomatoes, Metacritic, Letterboxd and TMDb ratings where available.
|
|
|
|
|
|
- My Shows tracking, upcoming episodes, lifecycle badges and personal return alerts.
|
|
|
|
|
|
- Themes, seasonal colour schemes and optional launcher decorations.
|
|
|
|
|
|
|
|
|
|
|
|
### Playback
|
|
|
|
|
|
|
|
|
|
|
|
- Media3/ExoPlayer playback with direct play, compatible-stream remuxing and HLS fallback.
|
|
|
|
|
|
- Resume playback, progress reporting, watched state and immediate poster badge updates.
|
|
|
|
|
|
- Audio and subtitle track selection with per-viewer language preferences.
|
|
|
|
|
|
- Missing-subtitle search and download through Bazarr or OpenSubtitles when configured.
|
|
|
|
|
|
- Configurable Left/Right seeking with trickplay thumbnail previews.
|
|
|
|
|
|
- Skip-intro prompts or automatic skipping from Emby's chapter markers.
|
|
|
|
|
|
- Automatic next-episode playback with an on-screen countdown.
|
|
|
|
|
|
- Closing-credits presentation with the next episode alongside and adaptive 2× playback.
|
|
|
|
|
|
- Episode pages with season navigation, watched markers and estimated completion dates.
|
|
|
|
|
|
- In-player cast lookup, pause artwork, time-remaining reminders and service-status banners.
|
|
|
|
|
|
|
|
|
|
|
|
### Profiles, televisions and administration
|
|
|
|
|
|
|
|
|
|
|
|
- Multiple saved viewer profiles with quick switching from the navigation rail.
|
|
|
|
|
|
- Per-viewer settings synchronised through the gateway across every signed-in television.
|
|
|
|
|
|
- Device management, session revocation and stable television identity.
|
|
|
|
|
|
- Gateway-controlled feature flags, maintenance mode, forced app updates and live themes.
|
|
|
|
|
|
- Service alerts for new library items, aired episodes, deployments and Emby outages.
|
|
|
|
|
|
- A dependency-free web console for accounts, devices, settings history, features,
|
|
|
|
|
|
updates, library imports, recommendations, searches, row engagement and logs.
|
|
|
|
|
|
- Postgres catalogue import, Redis caching, full-text search and background recommendation
|
|
|
|
|
|
and ratings warming.
|
|
|
|
|
|
|
|
|
|
|
|
### Screensaver and updates
|
|
|
|
|
|
|
|
|
|
|
|
- A system `DreamService` screensaver with cross-fading library backdrops.
|
|
|
|
|
|
- Interactive screensaver controls for playback, favourites and artwork navigation.
|
|
|
|
|
|
- An in-app screensaver preview using the same rendering surface as the system Dream.
|
|
|
|
|
|
- Self-hosted signed APK updates with SHA-256, package and signing-key verification.
|
|
|
|
|
|
- Mandatory and optional update policy controlled by the gateway.
|
2026-07-27 08:16:20 +12:00
|
|
|
|
|
|
|
|
|
|
## Tech stack
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
| Layer | Built with |
|
|
|
|
|
|
| --- | --- |
|
|
|
|
|
|
| UI | Kotlin + Jetpack **Compose for TV** (`androidx.tv:tv-material3`) |
|
|
|
|
|
|
| Playback | **Media3 / ExoPlayer** |
|
|
|
|
|
|
| Networking | Retrofit + OkHttp + kotlinx.serialization, over one shared HTTP stack |
|
|
|
|
|
|
| Storage | DataStore for profiles, settings and cached launcher state |
|
|
|
|
|
|
| Images | Coil |
|
|
|
|
|
|
| Gateway | Go, with Postgres and Redis |
|
|
|
|
|
|
|
|
|
|
|
|
## Build & install
|
|
|
|
|
|
|
|
|
|
|
|
You need **JDK 17** and the **Android SDK** (Android Studio bundles both).
|
|
|
|
|
|
|
|
|
|
|
|
Open the folder in Android Studio (Giraffe/Koala or newer) and let it sync, **or** from a
|
|
|
|
|
|
terminal:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
|
# Android Studio writes local.properties automatically. If building from the CLI,
|
|
|
|
|
|
# point it at your SDK first:
|
|
|
|
|
|
"sdk.dir=C:\\Users\\<you>\\AppData\\Local\\Android\\Sdk" | Out-File -Encoding ascii local.properties
|
|
|
|
|
|
|
|
|
|
|
|
.\gradlew.bat assembleDebug # build the APK
|
|
|
|
|
|
.\gradlew.bat test # JVM unit tests
|
|
|
|
|
|
.\gradlew.bat installDebug # install to a connected Android TV / emulator
|
|
|
|
|
|
|
|
|
|
|
|
# Preferred for a TV already showing the Dream: clears Memby, installs, then reopens
|
|
|
|
|
|
# it so the old render surface cannot remain black. Pass -Serial when more than one
|
|
|
|
|
|
# device is attached.
|
|
|
|
|
|
.\deploy-debug.ps1 -Serial 192.168.20.3:41479
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The APK lands in `app/build/outputs/apk/debug/app-debug.apk`.
|
|
|
|
|
|
|
|
|
|
|
|
## Server address
|
|
|
|
|
|
|
|
|
|
|
|
Memby is built for one Emby server, so the address is baked into the APK instead of being
|
|
|
|
|
|
typed on a TV remote. Set it in `gradle.properties`:
|
|
|
|
|
|
|
|
|
|
|
|
```properties
|
|
|
|
|
|
memby.serverUrl=http://192.168.1.10:8096
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
It can also come from `~/.gradle/gradle.properties` (keeps it out of the repo) or a single
|
|
|
|
|
|
build: `.\gradlew.bat assembleDebug -Pmemby.serverUrl=http://192.168.1.10:8096`.
|
|
|
|
|
|
|
|
|
|
|
|
The value becomes `BuildConfig.EMBY_SERVER_URL`, read through `data/ServerConfig.kt`. When
|
|
|
|
|
|
it is set, the setup screen only asks for a username and password, and the address wins
|
|
|
|
|
|
over whatever a saved session recorded — so moving the server is a property change plus a
|
|
|
|
|
|
reinstall, with no user action. Leaving the property **blank** restores the original
|
|
|
|
|
|
behaviour: users type the address themselves.
|
|
|
|
|
|
|
|
|
|
|
|
## First run
|
|
|
|
|
|
|
|
|
|
|
|
1. Launch **Memby** from the Android TV launcher.
|
|
|
|
|
|
2. Sign in with your Emby username and password. (If the build has no hardwired server,
|
|
|
|
|
|
enter its address first, e.g. `http://192.168.1.10:8096`.)
|
|
|
|
|
|
3. **Preview screensaver** to test it, or **Set as system screensaver** to open the TV's
|
|
|
|
|
|
screensaver settings and choose "Memby Screensaver".
|
|
|
|
|
|
|
|
|
|
|
|
## Running the gateway
|
|
|
|
|
|
|
|
|
|
|
|
See [`server/README.md`](server/README.md) to run the container. In short, the gateway
|
|
|
|
|
|
imports Emby's catalogue into Postgres (once manually, then hourly for new episodes),
|
|
|
|
|
|
composes the home rows — including "Recommended from your watching history" — and serves an
|
|
|
|
|
|
admin console at `/admin/` for imports, an offline switch, and per-row engagement.
|
|
|
|
|
|
|
|
|
|
|
|
For Tracearr-powered recommendations, create a read-only public API key in Tracearr and set
|
|
|
|
|
|
`MEMBY_TRACEARR_URL` plus `MEMBY_TRACEARR_API_KEY` on the gateway (and optionally
|
|
|
|
|
|
`MEMBY_TRACEARR_SERVER_ID` when Tracearr monitors several servers). Tracearr credentials
|
|
|
|
|
|
remain server-side; the Android app only receives ranked Emby items and short reasons. The
|
|
|
|
|
|
gateway imports compact session signals into Postgres every five minutes and prepares an
|
|
|
|
|
|
over-provisioned per-user pool, so opening For You normally performs one indexed database
|
|
|
|
|
|
read. The live on-demand path remains available for cold starts and failed rebuilds.
|
2026-07-27 08:16:20 +12:00
|
|
|
|
|
|
|
|
|
|
## Project layout
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
app/src/main/java/com/ponzischeme89/memby/
|
|
|
|
|
|
MembyApp.kt Application; initialises the ServiceLocator
|
|
|
|
|
|
ServiceLocator.kt Manual DI (settings + repository)
|
|
|
|
|
|
data/
|
|
|
|
|
|
SettingsStore.kt DataStore-backed connection/session state
|
|
|
|
|
|
ServerConfig.kt Which backend this build talks to
|
2026-08-09 16:04:40 +12:00
|
|
|
|
EmbyRepository.kt Content, favourites, playback; dual gateway/direct paths
|
2026-07-27 08:16:20 +12:00
|
|
|
|
analytics/RowAnalytics.kt Row engagement buffering
|
|
|
|
|
|
model/ Emby + gateway DTOs (kotlinx.serialization)
|
|
|
|
|
|
remote/EmbyApi.kt Retrofit interface for Emby
|
|
|
|
|
|
remote/GatewayApi.kt Retrofit interface for the Memby gateway
|
|
|
|
|
|
ui/
|
|
|
|
|
|
MainActivity.kt Setup, profiles, home
|
|
|
|
|
|
HomeViewModel.kt Home state, row analytics, refresh
|
|
|
|
|
|
HomeComponents.kt Navigation rail, rows, cards
|
|
|
|
|
|
MaintenanceScreen.kt Full-screen offline state
|
|
|
|
|
|
settings/SettingsSheet.kt Settings panel
|
|
|
|
|
|
screensaver/ Shared slideshow + in-app preview host
|
|
|
|
|
|
player/PlayerActivity.kt Media3 playback
|
|
|
|
|
|
screensaver/MembyDreamService.kt System screensaver (hosts ScreensaverContent)
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
admin-ui/ The operations console (React, served by nginx)
|
2026-07-27 08:16:20 +12:00
|
|
|
|
server/ The Memby gateway (Go) — see server/README.md
|
2026-08-17 13:13:10 +12:00
|
|
|
|
benchmark/ Macrobenchmarks and baseline-profile generation
|
2026-07-27 08:16:20 +12:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-07-27 08:22:55 +12:00
|
|
|
|
## Distributing builds
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
Memby is handed out as an APK from your own web server or NAS, and updates itself from the
|
|
|
|
|
|
same folder.
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
|
|
|
|
|
### One-time: a signing key
|
|
|
|
|
|
|
|
|
|
|
|
Android identifies an app by `applicationId` **plus signing key**. Every update must be
|
2026-08-17 13:13:10 +12:00
|
|
|
|
signed with the *same* key, or the TV rejects it as a different app. Lose the key and every
|
|
|
|
|
|
user has to uninstall and reinstall.
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
|
keytool -genkeypair -v -keystore memby-release.jks -alias memby `
|
|
|
|
|
|
-keyalg RSA -keysize 4096 -validity 10000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Keep the `.jks` somewhere backed up and **outside the repo** (`*.jks` is gitignored), then
|
|
|
|
|
|
point `local.properties` at it — also gitignored:
|
|
|
|
|
|
|
|
|
|
|
|
```properties
|
|
|
|
|
|
memby.keystore=C:/keys/memby-release.jks
|
|
|
|
|
|
memby.keystorePassword=…
|
|
|
|
|
|
memby.keyAlias=memby
|
|
|
|
|
|
memby.keyPassword=…
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
Without these, `assembleRelease` still builds but the APK is unsigned and will not install.
|
|
|
|
|
|
The build prints a warning saying so.
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
### NAS deployment release (recommended)
|
2026-08-15 09:23:26 +12:00
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
`deploy-server.ps1` builds and publishes the TV app in the same operation that replaces the
|
|
|
|
|
|
gateway: it signs with the existing keystore, verifies the APK and publishes it through
|
|
|
|
|
|
`POST /admin/api/release` once the new gateway is healthy. A pushed semantic tag does the
|
|
|
|
|
|
same thing through `.gitea/workflows/release.yml`. The gateway builds nothing itself.
|
2026-08-15 09:23:26 +12:00
|
|
|
|
|
|
|
|
|
|
The signed APK and its checksum are stored in the `memby-releases` volume at
|
2026-08-17 13:13:10 +12:00
|
|
|
|
`/data/releases/memby-<version>.apk` and `/data/releases/memby-<version>.apk.sha256`. The
|
|
|
|
|
|
release-publish credential is a read-only Compose secret under `/run/secrets` and is never
|
|
|
|
|
|
copied into the image or repository.
|
|
|
|
|
|
|
|
|
|
|
|
Admin Console → App updates sets the update policy — latest version, APK URL, release
|
|
|
|
|
|
notes, and the required/destructive toggles.
|
2026-08-15 09:23:26 +12:00
|
|
|
|
|
|
|
|
|
|
### Local PowerShell release (compatibility path)
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-08-02 22:10:19 +12:00
|
|
|
|
.\release.ps1 -Version 0.1.54 -Notes "Faster home screen" `
|
|
|
|
|
|
-BaseUrl https://nas.example.com/memby `
|
|
|
|
|
|
-SourceUrl https://g.sublogue.com/admin/memby
|
2026-07-27 08:22:55 +12:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-17 13:13:10 +12:00
|
|
|
|
That workflow bumps `versionName`/`versionCode`, runs the tests, builds a signed APK, and
|
|
|
|
|
|
fills `dist/out/` with:
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
|
|
|
|
|
```
|
2026-08-17 13:13:10 +12:00
|
|
|
|
index.html the page people are sent to
|
|
|
|
|
|
latest.json the update manifest the app polls
|
|
|
|
|
|
memby-0.1.54.apk the build
|
2026-08-15 09:23:26 +12:00
|
|
|
|
memby-0.1.54.apk.sha256 the SHA-256 checksum
|
2026-08-17 13:13:10 +12:00
|
|
|
|
LICENSE GNU GPL v2 terms
|
|
|
|
|
|
NOTICE copyright and third-party acknowledgements
|
2026-07-27 08:22:55 +12:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Copy those to the folder the NAS serves. Old APKs can stay alongside — only `latest.json`
|
|
|
|
|
|
decides what the app offers, so rolling back is editing one file.
|
|
|
|
|
|
|
|
|
|
|
|
### How TVs update themselves
|
|
|
|
|
|
|
2026-08-09 16:04:40 +12:00
|
|
|
|
The gateway checks the running app version on launch and returns an optional or mandatory
|
|
|
|
|
|
update with its download address. Memby downloads the APK, verifies its checksum, package
|
|
|
|
|
|
and release signature, then commits it through Android's package installer. Update policy
|
2026-08-17 13:13:10 +12:00
|
|
|
|
and the download address are managed in the gateway's admin console; viewers do not need to
|
|
|
|
|
|
configure an update source on the television.
|
2026-07-27 08:22:55 +12:00
|
|
|
|
|
|
|
|
|
|
First install on each TV still has to be manual — the **Downloader** app pointed at the
|
|
|
|
|
|
landing page is the usual route, and the page explains it.
|
|
|
|
|
|
|
2026-07-27 08:16:20 +12:00
|
|
|
|
## Upgrading to v0.1.53
|
|
|
|
|
|
|
|
|
|
|
|
The package and install identity both became `com.ponzischeme89.memby` in this release
|
|
|
|
|
|
(previously `com.mattcohen.embyclientsname`). Android treats a new `applicationId` as a
|
|
|
|
|
|
different app, so on every TV:
|
|
|
|
|
|
|
|
|
|
|
|
1. Install v0.1.53 — it appears as a **second** Memby entry in the launcher.
|
|
|
|
|
|
2. Sign in again; the previous session does not carry over.
|
|
|
|
|
|
3. Uninstall the old app: `adb uninstall com.mattcohen.embyclientsname`.
|
2026-08-17 13:13:10 +12:00
|
|
|
|
4. Re-select Memby in the TV's Screensaver settings — the Dream's component name changed as
|
|
|
|
|
|
well, so the old selection no longer resolves.
|
2026-07-27 08:16:20 +12:00
|
|
|
|
|
|
|
|
|
|
## Notes & limitations
|
|
|
|
|
|
|
2026-08-02 22:10:19 +12:00
|
|
|
|
- Playback negotiates through Emby's `PlaybackInfo` endpoint, then streams directly from
|
|
|
|
|
|
Emby. The Wholphin/Jellyfin-derived capability engine reports Android's H.264 and HEVC
|
|
|
|
|
|
profiles, maximum levels and resolutions rather than assuming every decoder handles every
|
2026-08-17 13:13:10 +12:00
|
|
|
|
file. The Moonfin-derived audio path reports formats the TV can decode or bitstream,
|
|
|
|
|
|
offers automatic receiver detection and manual per-codec passthrough overrides, and
|
|
|
|
|
|
decodes the rest to PCM through Media3's FFmpeg renderer. Emby can preserve a supported
|
|
|
|
|
|
video stream while converting only incompatible audio or subtitles. If a vendor decoder
|
|
|
|
|
|
still fails, Media3 tries another decoder and Memby ultimately requests an H.264 HLS
|
|
|
|
|
|
transcode instead of abandoning playback.
|
|
|
|
|
|
- Cleartext HTTP is enabled so local `http://` servers work out of the box. For an
|
|
|
|
|
|
HTTPS-only server this is unnecessary but harmless.
|
2026-07-27 08:16:20 +12:00
|
|
|
|
- The device is remembered across sign-outs (stable `DeviceId`); credentials are cleared.
|
2026-08-02 22:10:19 +12:00
|
|
|
|
|
|
|
|
|
|
## Licence
|
|
|
|
|
|
|
|
|
|
|
|
Memby is free software licensed under the [GNU General Public License v2](LICENSE).
|
|
|
|
|
|
Copyright and third-party acknowledgements are recorded in [NOTICE](NOTICE). Distributed
|
2026-08-17 13:13:10 +12:00
|
|
|
|
APKs and server binaries must be accompanied by the corresponding source in accordance with
|
|
|
|
|
|
GPLv2. The Android TV app also exposes the source link, notices, and complete licence under
|
|
|
|
|
|
**Settings → About / Licences**.
|
2026-08-02 22:10:19 +12:00
|
|
|
|
|
|
|
|
|
|
Playback capability probing and device-profile generation contain GPLv2 adaptations from
|
|
|
|
|
|
[Wholphin](https://github.com/damontecres/Wholphin), itself derived in part from
|
2026-08-10 12:23:23 +12:00
|
|
|
|
[Jellyfin Android TV](https://github.com/jellyfin/jellyfin-androidtv). Surround-audio
|
|
|
|
|
|
capability detection, passthrough controls and software fallback are adapted from
|
|
|
|
|
|
[Moonfin](https://github.com/Moonfin-Client/Moonfin-Core) under GPLv2. Attribution and
|
2026-08-02 22:10:19 +12:00
|
|
|
|
modification notices are preserved in the adapted source files.
|