A PeerTube client for Android TV.
The home screen is now stacked horizontal rows ('Continue watching'
with red progress bars from server-reported positions, 'New videos'
paged) instead of one tall list - matching the SmartTube look the app
is modeled on. The player renders as an overlay so the list beneath
keeps its scroll and focus across BACK (was resetting to the top),
grid scroll state is saved per destination, cards render focus
scale/border via tv-material, thumbnails carry relative dates and
privacy badges only where meaningful, overscan margins guard the 1080p
safe area, and the setup screen got a password reveal, clipboard paste
helpers and an always-focusable validating Sign in.
UX review by Claude Opus 5.5 (claude CLI) on emulator screenshots;
remaining suggestions are triaged in BACKLOG.md.
|
||
|---|---|---|
| app | ||
| gradle | ||
| scripts | ||
| .gitignore | ||
| AGENTS.md | ||
| BACKLOG.md | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| README.md | ||
| settings.gradle.kts | ||
| TESTS.md | ||
JTube TV
An Android TV client for PeerTube instances, inspired by how SmartTube works for YouTube. It talks to any PeerTube instance (the default is JTube — my own instance) over the PeerTube REST API.
Features (v0.1)
- Setup flow — enter instance URL, username and password once; the app exchanges
them for OAuth tokens via
POST /api/v1/users/tokenand stores only the tokens (never the password), encrypted with the Android Keystore (EncryptedSharedPreferences). - Local videos — list public videos of the instance (
GET /api/v1/videos?isLocal=true). - My videos — all of the logged-in user's own videos, every privacy level included
(private, internal, unlisted —
GET /api/v1/users/me/videos). Non-public entries carry a privacy badge. - Channels — list channels local to the instance
(
GET /api/v1/video-channels?search=…&searchTarget=local) and browse each channel's videos. - Search — search local videos by title.
- Subscriptions — the videos in the user's subscription feed
(
GET /api/v1/users/me/subscriptions/videos). - History — the user's watch history as tracked by the server
(
GET /api/v1/users/me/history/videos). - Playback — HLS (or progressive MP4 fallback) playback with ExoPlayer/Media3.
Viewing is reported to the server (
POST /api/v1/videos/{shortUuid}/watching) so it shows up in server-side history. Private/internal media is streamed with the OAuth token attached to every playlist/segment request.
Out of scope for now (see BACKLOG.md): uploading, editing, subscribing/unsubscribing,
deleting, creating anything other than history entries.
Build
Requirements: JDK 17+ (JDK 21 recommended), Android SDK platform 35.
local.properties with sdk.dir=… is picked up automatically if present
(standard Android Gradle Plugin behavior).
./gradlew :app:assembleDebug
Install on a TV device:
adb connect <tv-ip>:<port>
adb install -r app/build/outputs/apk/debug/app-debug.apk
Building requires a JDK; the Gradle wrapper is checked in, so no local Gradle installation is needed.
Architecture overview
Single-module Android TV app (app/):
data/api— Retrofit interface + kotlinx-serialization DTOs for the PeerTube API.data/auth—TokenStore(EncryptedSharedPreferences), token acquisition/refresh.data/network— OkHttp/Retrofit wiring: dynamic base-URL interceptor, bearer-token interceptor, single-flight token refresh authenticator.data/PeerTubeRepository.kt— one suspend-call surface used by all view models.ui/— Compose for TV screens: Setup, Home (sidebar + list content), VideoList (local / my videos / subscriptions / history / search / channel), Channels, Player.MainActivityis the only activity.JTubeApp.kt— tiny service locator (AppGraph); no DI framework on purpose.
License
Not decided yet — TBD before first public release.