The action-row buttons lost their modifier in the icon-only rework and
became unfocusable, so D-pad DOWN off the paused seek bar landed nowhere
(requestFocus failed with "not initialized"). The modifier is attached
to the button again and the seek bar ↔ buttons directions are wired
explicitly, because the default focus search skips the bar.
Pill visuals use the new state language: no border, gray pill = focused,
red glyph = subscribed/rated; the sidebar panels keep the D-pad inside
their lists (consumed at the edges). BACK/Esc acts on ACTION_DOWN only —
its trailing UP saw the panel already closed and exited the video — and
panels return focus to the pill that opened them.
Playlist deletion is a requested scope addition: holding OK on a row
asks via a dialog (DELETE /video-playlists/{id}); the toggle moves to
key release so the hold cannot double-act. Holding also exposed an
activation bug: the CENTER helper consumed only ACTION_DOWN and the
release leaked into the underlying clickable — now consumed, repeats
swallowed, so Create (and the cards) fire exactly once per press.
An info panel shows the video description with clickable links: inline
(pointer) plus a focusable link row list (D-pad); PeerTube video and
channel links play/drill in-app, other links open the browser.
Closes #12
|
||
|---|---|---|
| app | ||
| docs | ||
| gradle | ||
| scripts | ||
| .gitignore | ||
| AGENTS.md | ||
| BACKLOG.md | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LICENSE | ||
| README.md | ||
| settings.gradle.kts | ||
| TESTS.md | ||
JTube TV
JTube TV is an Android TV app for PeerTube. It puts a PeerTube instance on the big screen the way SmartTube puts YouTube there: browse from the couch, play with the remote, nothing else in the way.
It talks to any PeerTube instance over the REST API. The default is tube.jeena.net, my own instance, where most videos are private family uploads. Signing in matters because "My videos" shows them all, privacy levels included.
What it looks like
Screenshots come from a demo instance serving real, CC-licensed open-movie content, courtesy of the Blender Foundation movies and the A propos de PeerTube channel. All of it plays in the app.
The home screen. Continue watching picks up at the position the server saved, new videos first, page after page.
A slide-in drawer opens with the left D-pad button. My videos shows your own uploads, every privacy level included, with a badge on anything not public.
Channels, one row per owner, with video and play counts on every card.
The player speaks remote: play and pause, seek back and forward, a seek bar with position and duration. Watching is reported to the server every 20 seconds, so where you left off survives the app.
What it does in v0.1
- Sign in once. The app exchanges your username and password for OAuth tokens and stores only those, encrypted with the Android Keystore. The password itself is never kept.
- Home with Continue watching and New videos.
- Browse the instance's public videos, and search them by title.
- My videos: every video you own, private, internal and unlisted included.
- Channels: local channels with their videos, plus your subscriptions and your server-side watch history.
- Player: HLS, with a progressive MP4 fallback, resume from the saved position, and watching reports.
What it deliberately does not do (yet, or ever): uploading, editing, deleting, managing subscriptions. That's tracked in BACKLOG.md.
Build
Requirements: JDK 17 or newer (21 recommended) and an Android SDK with platform 35. The Gradle wrapper is checked in, so no local Gradle install is needed.
./gradlew :app:assembleDebug
Then put it on the TV:
adb connect <tv-ip>:<port>
adb install -r app/build/outputs/apk/debug/app-debug.apk
Architecture
A single-module app, deliberately small:
data/api— Retrofit interface and kotlinx-serialization DTOs for the PeerTube API.data/auth— TokenStore, the encrypted preference storage for tokens.data/network— OkHttp/Retrofit wiring: dynamic base URL, bearer token interceptor, single-flight token refresh.data/PeerTubeRepository.kt— one suspend-call surface for the whole UI.ui/— Compose for TV screens, one for each of the destinations above.- No DI framework, no database. The service locator is
AppGraph.
License
JTube TV is free software under GPL-3.0-or-later.