Vexxx-TV Android TV App - Coming to Venti Soon (Patreon)
Videos
Content
Vexxx TV — Features
A native Android TV client for Vexxx (Stash fork), built with Jetpack Compose for TV and ExoPlayer/Media3.
Setup & Onboarding
Dedicated setup screen shown on first launch and after disconnect.
Server URL and optional API key fields with appropriate keyboard types.
API key field is password-masked.
Tab-order focus: URL → API Key → Connect, navigable via remote.
Auto-focuses the URL field on screen entry.
Validates connection before navigating away; shows error if unreachable.
“Change Server” and “Disconnect” actions available from Settings at any time.
Navigation Shell
Persistent side-drawer (TvNavDrawer) wrapping Home, Browse, Search, and Settings — always accessible while outside the player.
Top-level destinations: Home, Browse (by content type), Search, Settings.
Jetpack Navigation handles the full back-stack including the player.
Home Screen
Hero Banner
Full-screen cross-fading background pulled from the focused scene’s screenshot.
Debounced 300 ms so rapid D-pad scrolling through cards doesn’t trigger unnecessary image loads.
Metadata panel (bottom-left): title, studio, performers, tags, release date, duration, resolution, star rating, and a direct Play button.
Blurred in SFW mode.
Carousels
Each scene carousel has a View All card at the end that navigates to the Browse screen.
Scroll position is saved and restored when returning from a detail screen.
Server library statistics footer (scene count, duration, etc.).
Browse Screen
Content Types
Tabs: Scenes · Performers · Studios · Galleries · Images · Groups · Tags
Grid & Pagination
Adaptive grid sized to card dimensions (e.g. 320 dp wide for scenes).
40 items per page with a pagination bar (Previous / Next, page X of Y).
Item count and current range displayed above the grid (1–40 of 412).
Search
Inline search field toggled via a button in the toolbar.
400 ms debounce so network requests are batched.
Per-tab query is preserved when switching between content types.
Active query displayed as a pill on the search button; click to clear.
Filters
Filter panel accessible via a Filters button (visible on tabs that support filtering).
Active filter count shown on the button badge.
Filter options are loaded lazily the first time the panel is opened.
Alpha-Jump
On the Scenes tab, pressing a letter key on a physical keyboard scrolls the grid to the first scene whose title begins with that letter.
A transient letter indicator confirms the jump and auto-dismisses after 800 ms.
Search
Universal search bar across scenes, performers, studios, tags, and groups simultaneously.
Requires at least 2 characters before querying the server.
Results displayed as horizontal carousels grouped by type.
Each section header shows the number of results returned vs. total matches (5 of 128).
Loading spinner shown inline in the search bar header.
Auto-focuses the text field on screen entry so typing can begin immediately.
“No results” and error states with descriptive messages.
Video Player
Playback Engine
ExoPlayer (Media3) with a pure-Compose ContentFrame surface — no AndroidView/PlayerView interop.
HLS streaming over the Vexxx server’s native stream endpoint.
OkHttpClient shared with Apollo GraphQL for connection pooling and API key authentication on every HLS request (playlist, key files, media segments).
MediaSession wired up so Bluetooth remotes, earphone buttons, and the Google TV system UI can control playback.
Track Selection & Codec
Prefers H.264 and caps video at 1080p to avoid software-decoding 4K on lower-end hardware.
Hardware tunneling enabled on real devices for efficient display pipeline use; disabled on emulators (Goldfish/Ranchu).
Audio offload enabled on capable hardware to reduce CPU load during long sessions.
Extension renderer mode ON (platform codecs first, software extensions as fallback).
Decoder fallback so ExoPlayer retries with another codec on init failure instead of crashing.
Seeking
TS timestamp search window widened ×3 for more accurate HLS seeks.
Constant bitrate seeking enabled so seeks start immediately without waiting for keyframe detection.
Resume & Progress
Resume position saved to the server every 10 seconds during playback.
Position restored on next open (converted between clip-relative and absolute file offsets for segment support).
“Resume at X:XX” indicator on the scene detail play button; a dialog lets the user choose Resume or Play from Start.
Play count recorded after 10 consecutive seconds of active playback.
Segment / Virtual Scene Support
Scenes with start_point and end_point fields are played as a clipped sub-region of the underlying file.
Resume positions and marker timestamps are stored/displayed as absolute file seconds, not clip-relative, keeping sync with the web app.
Chapters / Markers
Chapter tick marks drawn on the progress bar at each marker’s position.
Active chapter is tracked in real time (polling every 500 ms) and highlighted.
Chapter sidebar slides in from the right edge:
Shows all chapters with a 16:9 thumbnail, title, and timestamp.
Active chapter is visually highlighted.
Auto-scrolls to the active chapter as playback progresses.
D-pad focus is automatically placed on the active (or first) chapter when the sidebar opens.
Clicking a chapter seek bar chip on the scene detail screen deep-links directly into the player at that timestamp.
Controls Overlay
Fade-in/fade-out controls bar at the bottom of the screen.
Seek bar with live position and duration timestamps.
Buttons: Bookmarks (chapters toggle, only visible when the scene has markers), Seek Back 10 s, Play/Pause, Seek Forward 30 s.
Auto-hides after 5 seconds of playback with no interaction (pinned while the chapter sidebar is open).
D-pad focus moves automatically to the Play/Pause button when controls appear.
Scene title displayed above the seek bar while controls are visible.
Playback Queue & Auto-Advance
PlaybackQueue supports sequential scene playback (e.g. from a playlist).
Navigates to the next scene automatically when the current one ends.
Triggers a Google TV Watch Next row sync (via ChannelSyncWorker) on scene completion.
Lifecycle
Pauses automatically when the Activity goes to background (ON_STOP).
Player and MediaSession are fully released onCleared to prevent decoder/surface crashes.
Low-RAM Adaptation
Detects ActivityManager.isLowRamDevice() at runtime.
Low-RAM devices: min 10 s / max 20 s buffer, 12 MB byte cap.
Capable hardware: min 15 s / max 50 s buffer, auto byte limit.
Scene Detail
Full-screen blurred screenshot as background.
Metadata: title, studio chip (navigable), release date, director, rating, file info (resolution × height, duration, fps).
Description (up to 6 lines, ellipsised).
Play button — shows a Resume/Start-Over dialog if a save position exists.
More options dialog: O-counter (increment / decrement / reset), star rating (1–10), scene code, stream picker (multiple quality labels and MIME types).
Resume time indicator below the play button.
Tags — horizontal scrollable chips, each navigates to that Tag’s detail screen.
Chapters — horizontal scrollable chips showing timestamp + title; clicking one launches the player at that chapter.
Cast panel (right column): performer chips with thumbnail and name, each navigates to the Performer detail screen.
Related scenes from the same studio (horizontal carousel at the bottom).
Gallery Viewer
Full-screen image display with animated cross-fade between images.
Slideshow / Auto-Play — advances every 4 seconds, loops back to the first image at the end.
Auto-play toggle button in the top HUD; pauses on any manual navigation.
Image counter showing current position and total (e.g. 7 / 42).
Gallery title in the header.
Directional arrow hints shown at left/right edges when not at the boundary.
Chapter panel for galleries with defined sections:
Down arrow / Enter opens the panel; Up arrow closes it or moves to the previous chapter.
Up/Down navigate between chapters; Enter jumps to the selected chapter’s first image.
Back closes the panel before exiting the screen.
SFW blur applied to all images.
Performer Detail
Details Tab
Full-screen performer photo background (semi-transparent).
Name, disambiguation note, scene count badge, gender, rating, country.
Favourite toggle (heart button).
Portrait image (140 × 200 dp, rounded) — SFW-blurred.
Physical details: height, weight, measurements, eye colour, hair colour, ethnicity, country, birthdate, career length, tattoos, piercings.
Aliases horizontal row.
Tags horizontal row.
Biography text.
Scenes Tab
Paginated grid of all scenes featuring this performer.
Each scene card navigates to the Scene detail screen.
Studio Detail
Full-screen studio logo background.
Header: logo thumbnail, studio name, parent studio (if any), scene count, performer count, rating.
Description (single line, ellipsised).
Paginated scene grid with page range indicator.
Group Detail
Full-screen backdrop image (SFW-blurred).
Header: front-cover thumbnail (SFW-blurred), name, scene count, total duration, rating, director, studio, release date.
Synopsis (2 lines, ellipsised).
Tags row — each tag navigates to Tag detail.
Sub-groups horizontal carousel — each card shows the sub-group cover (SFW-blurred) and navigates to its own Group detail screen.
Paginated scene grid.
Tag Detail
Full-screen tag image background.
Header: tag icon, name, scene/performer/gallery counts.
Description.
Parent tags breadcrumb strip.
Child tags horizontal row — each navigates to that tag’s detail screen, showing its scene count.
Paginated scene grid.
Playlists
Smart Playlists (Home Screen)
Predefined curated playlists available as cards in a dedicated Home carousel.
Each entry navigates to the Playlist detail screen.
Playlist Detail
Left panel: cover image, title, description, scene count, total duration.
Play All — loads the playlist into the PlaybackQueue and navigates to the player at the selected index.
Shuffle — randomises the queue then starts playback.
Right panel: scrollable item list with track number, 16:9 thumbnail, title, duration, and a resume progress bar for scenes with a saved position.
Clicking an item navigates to that scene’s detail screen; “play from here” starts the queue from that position.
Safe-for-Work (SFW) Mode
A privacy toggle that blurs all media artwork app-wide, suitable for use in shared or public spaces.
Toggled in Settings; state persisted across sessions.
Provided via LocalSfwMode CompositionLocal at the navgraph root — no prop drilling required.
When enabled, a Modifier.blur(20 dp) (10 dp for performer portraits) is applied to every AsyncImage that displays media content.
A centred eye-slash SfwOverlayIcon is overlaid on every blurred surface to make the SFW state visually explicit.
D-Pad & Remote Navigation
Global
All interactive elements (cards, buttons, tabs) are Compose focus-traversal compatible.
Back button pops the nav back-stack; intercepted contextually (e.g. closes a panel before exiting a screen).
Player
Any key while controls are hidden: reveals controls; Left/Right also seeks ±10/30 s simultaneously.
While controls are visible: Compose focus handles Left/Right/Up/Down naturally between buttons (Bookmarks ← Seek Back ← Play/Pause → Seek Forward).
Chapters sidebar:
Bookmarks button opens the sidebar; D-pad focus automatically moves to the active (or first) chapter after 150 ms.
Left or Back closes the sidebar.
Up/Down traverse the chapter list via LazyColumn’s built-in scrolling.
Right is consumed (nothing to navigate beyond the right edge).
Back from the outer player while sidebar is open closes the sidebar rather than popping the back-stack.
Gallery Viewer
Left/Right: previous/next image.
Down: opens chapter panel (if chapters exist).
Up: closes chapter panel or moves to the previous chapter entry.
Enter / D-pad Centre: confirms chapter selection or opens the panel.
Back: closes chapter panel first, then exits the viewer.
Browse
Letter keys (A–Z) on a physical keyboard scroll the Scenes grid to the first matching title.