diff --git a/README.md b/README.md index 92e06f2..02db801 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,103 @@ # JTube TV -An Android TV client for [PeerTube](https://joinpeertube.org/) instances, inspired by -how SmartTube works for YouTube. It talks to **any PeerTube instance** -(the default is [JTube](https://tube.jeena.net) — my own instance) over the -[PeerTube REST API](https://docs.joinpeertube.org/api-rest-reference.html). +

+ The JTube TV logo, a little orange TV +

-## Features (v0.1) +JTube TV is an Android TV app for [PeerTube](https://joinpeertube.org/). 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. -- **Setup flow** — enter instance URL, username and password once; the app exchanges - them for OAuth tokens via `POST /api/v1/users/token` and 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. +It talks to any PeerTube instance over the +[REST API](https://docs.joinpeertube.org/api-rest-reference.html). The default +is [tube.jeena.net](https://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. -Out of scope for now (see `BACKLOG.md`): uploading, editing, subscribing/unsubscribing, -deleting, creating anything other than history entries. +## What it looks like + +Screenshots were taken against a demo instance with placeholder content, on an +emulator. The app itself is on a dark theme, made for a 10-foot couch view. + +The home screen. Continue watching picks up at the position the server saved, +new videos first, page after page. + +

+ Home screen with Continue watching and New videos rows +

+ +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. + +

+ Menu drawer with the destinations +

+ +

+ My videos grid with Private and Internal badges +

+ +Channels, one row per owner, with video and play counts on every card. + +

+ Channels screen with channel cards +

+ +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. + +

+ Player with controls, seek bar and title +

+ +## 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](BACKLOG.md). ## 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). +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. ```bash ./gradlew :app:assembleDebug ``` -Install on a TV device: +Then put it on the TV: ```bash adb connect : 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 -## Architecture overview +A single-module app, deliberately small: -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. `MainActivity` is the only activity. -- `JTubeApp.kt` — tiny service locator (`AppGraph`); no DI framework on purpose. +- `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: [GPL-3.0-or-later](LICENSE) — see the -[fsf.org license page](https://www.gnu.org/licenses/) for details. \ No newline at end of file +JTube TV is free software under [GPL-3.0-or-later](LICENSE). \ No newline at end of file diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..e1d9e0f --- /dev/null +++ b/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/docs/jtube-logo.svg b/docs/jtube-logo.svg new file mode 100644 index 0000000..d85b393 --- /dev/null +++ b/docs/jtube-logo.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/screenshots/channels.png b/docs/screenshots/channels.png new file mode 100644 index 0000000..e8a42bb Binary files /dev/null and b/docs/screenshots/channels.png differ diff --git a/docs/screenshots/drawer.png b/docs/screenshots/drawer.png new file mode 100644 index 0000000..dd9d0c7 Binary files /dev/null and b/docs/screenshots/drawer.png differ diff --git a/docs/screenshots/home.png b/docs/screenshots/home.png new file mode 100644 index 0000000..2cba91d Binary files /dev/null and b/docs/screenshots/home.png differ diff --git a/docs/screenshots/myvideos.png b/docs/screenshots/myvideos.png new file mode 100644 index 0000000..7756e9d Binary files /dev/null and b/docs/screenshots/myvideos.png differ diff --git a/docs/screenshots/player.png b/docs/screenshots/player.png new file mode 100644 index 0000000..624a2d4 Binary files /dev/null and b/docs/screenshots/player.png differ diff --git a/docs/screenshots/setup.png b/docs/screenshots/setup.png new file mode 100644 index 0000000..aff2db3 Binary files /dev/null and b/docs/screenshots/setup.png differ