Android implementation of shepherd-media #72
No reviewers
Labels
No labels
bug
duplicate
enhancement
future
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
albert/shepherd-launcher!72
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "u/albert/70/shepherd-media-android"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #70
Relies on #71's Android
depshelper to land firstthe icon for this app should be the same shield from the BLE management app (#71) but with a play triangle inside
Both video caches independently implemented the same evict-to-cap loop (sum sizes, sort by mtime ascending, delete oldest until within the byte cap). Extract it as a generic shepherd_media_app::lru::evict_to_cap over LruEntry { path, size, recency }, with an on_evict hook for paired bookkeeping. The Linux binary passes SystemTime recency and uses the hook to drop the paired .done sentinel + log; the Android app passes FileTime recency and a no-op hook. The rest of each cache stays platform-specific by design: the caches key files differently (item id + .done sentinels vs URL hash), and the ureq download/directory-scan logic differs enough that sharing it would need more parameters than it removes (and would pull ureq into this crate). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>@ -0,0 +1,411 @@//! Playback view: composites the player's GL output into the eframe surface and//! draws a touch-friendly control overlay.//!//! This is adapted from the Linux binary's `ui/playback.rs`, trimmed to touch +I'm not sure why you couldn't just import it
this was cleaned a ton in
7175688376shepherd-media/src/platform.rs::current() hardcoded PlatformInfo { platform: Platform::Linux }, duplicating core's PlatformInfo::current() (which cfg-selects the platform and already returns Linux for this target) — the same helper the Android app calls directly. Delete the module and point its five call sites at core. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>@ -0,0 +7,4 @@//!//! [`PosterPolicy::Never`] skips loading entirely. `WifiOnly` currently behaves//! like `Always`; gating it on a metered/Wi-Fi connection needs the Android//! connectivity JNI bridge, which is not wired yet.looks like some stale comments need to be removed
also couldn't this be shared too?
@ -0,0 +7,4 @@//! `NetworkOnMainThreadException` for any network on the main thread — so the//! grid screen resolves on a worker and polls the result.//!//! Not yet handled (they need the Android JNI bridges / youtubedl-android):more stale comments
@ -0,0 +7,4 @@//! is downloaded afterward so the next play is local. LRU eviction (by file//! mtime, touched on each cache hit) keeps the directory within the cap.//!//! Download and eviction are blocking and run off the UI thread.why does this need its own implementation
re: the remaining code "duplication": Claude had the following to say:
Code looks reasonable and works on a phone (Pixel 10a), just needs testing on more devices — particularly Fire TV and Google TV devices
URL fields can now be added via a form on a separate device to ease the TV workflow (still needs to be tested on an actual TV)
egui's spatial focus walks the vertically-aligned left-column buttons (Back / Browse / Add) and skips the offset field column, so a remote's Down never reached the fields — you had to press Right. - Drive Up/Down explicitly in tab order: capture each control's Response (Back, Id, Label, Source, Location, Browse/Phone, Add) and request_focus the previous/next, cancelling egui's spatial move. Down now steps through every control in order. - Source ComboBox, which egui only closes on a pointer click or Escape: - Enter now closes the popup (detect the kind change, Popup::close_all, and keep focus on the combo). - BACK dismisses an open popup instead of leaving the screen (snapshot popup-open before render; handle it ahead of the field/screen cases). Form Up/Down stepping is skipped while the popup is open. Verified on the AFTHA004: Down reaches every field; the Source dropdown opens, navigates, selects, and BACK dismisses it, all via remote. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Prefetch made the same item resolvable twice at once (a background prefetch racing the play). Both calls passed the watch URL as youtubedl-android's process id, and the library rejects a second execute() with a live id ("Process ID already exists"), failing the play — seen deploying to the Fire TV. Use a unique per-call process id (shepherd-resolve-<seq>), and have start_playback adopt an in-flight prefetch's receiver for the same item instead of starting a second concurrent resolve. Verified on the 32-bit Fire TV: HW decode + audio, no collision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The DRM-protected "full episode" videos that the Android app handles via the android player client also failed on Linux ("This video is not available"): the Linux binary resolves through mpv's ytdl_hook with the default player clients, which don't serve those. Its ytdl-format already falls back to a muxed stream (/best), so the only missing piece was the client. Set ytdl-raw-options in LibmpvPlayer::new to route yt-dlp through android_vr + android, matching the Android resolver — android_vr serves DASH without a PO token, android exposes the legacy progressive itag 18 the muxed fallback then selects for DRM uploads. The value is length-prefix quoted so mpv's key/value list parser doesn't split it on the comma between the client names. Shared core, but a no-op on Android (it pre-resolves and never runs ytdl_hook). Verified through the real LibmpvPlayer headless: the "full episode" that failed (CLOSED/unavailable) now Started; a normal video still resolves to 720p DASH. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>identified and fixed some performance (slow load) and UX (can't type URL) issues on Fire TV; refactored into Linux implementation as appropriate
behavior is now correct, just needs a more thorough code review
@ -0,0 +83,4 @@// yt-dlp bundled with a Python runtime, called over JNI from the Rust code// (see src/youtube.rs). Brings its own native libs/assets, packaged into// the APK automatically.implementation("io.github.junkfood02.youtubedl-android:library:0.18.1")Fine for now, but we’ll need to watch out for how maintained this is moving forward
@ -0,0 +84,4 @@- The cdylib cross-compiles for `aarch64-linux-android` and exports`android_main` / `ANativeActivity_onCreate`.## Not yet wired (next steps)This entire section seems to be stale