Skip to content

Releases: bilbospocketses/abs-app

Android TV v1.0.11

Choose a tag to compare

@bilbospocketses bilbospocketses released this 06 Jun 14:05
6df0acd

Android TV fork release v1.0.11 (on upstream audiobookshelf-app v0.13.0-beta).

Highlights

  • Fixed the long-standing grid focus column-drift bug — on virtualized bookshelf grids (library / series / collections / playlists), a fast Down-scroll could land focus in the wrong column (the last column). Root-caused to the native Android-TV focus engine re-homing focus when the LazyBookshelf virtualizer unmounts the focused card mid-scroll; fixed by tracking and re-asserting the user's intended column.
  • TV init hardening (I2) — inject the android-tv class at WebViewClient.onPageStarted so it lands before the Nuxt TV plugin boots (fixes the occasional "first navigation dead on cold start" race), with a JS-side poll fallback.
  • Hide "Go to Web Client" in the side drawer on Android TV — TV devices typically have no browser, so the action dead-ended; now hidden on TV (phone/tablet unchanged).
  • Spatial-nav performance (I4) — per-keypress getBoundingClientRect snapshotting removes repeated forced reflows.
  • Selector robustness (I5) — stable data-tv-* hooks replace fragile Tailwind-class selectors for the side drawer and play button.
  • Loading-overlay dots follow the focus-ring color on TV.

Verified via the full 13-batch on-device smoke on the Google TV Streamer 4K.

APK: abs-android-tv-release-1.0.11.apk
SHA256: 4B8A653D98CB1AE077A52253CA0D300D3CD675E991DBAAAF2C5C273B6BB21B67

android-tv-v1.0.10 - Internal refactor (modularize tv-navigation)

Choose a tag to compare

@bilbospocketses bilbospocketses released this 02 Jun 19:01
842131a

Internal refactor release - no user-visible changes. Behaves identically to v1.0.9.

Modularizes the Android TV navigation engine: the 1,675-line plugins/tv-navigation.js monolith is split into 18 focused modules under plugins/tv/ - behavior-preserving (every function keeps its name + signature; shared state moves into a tvContext singleton). Foundation for the upcoming upstream PR series.

Validated by the full 13-batch TV smoke walkthrough (64 TV + 3 phone checks) on Google TV Streamer 4K + Pixel 9 - zero regressions.

Also includes the repo-level security hardening pass (Dependabot, CodeQL, secret scanning, branch/tag rulesets, Sigstore release attestation) from the same timeframe.

Upstream base: v0.13.0-beta - APK: abs-android-tv-release-1.0.10.apk

android-tv-v1.0.9 — upstream v0.13.0-beta sync

Choose a tag to compare

@bilbospocketses bilbospocketses released this 14 May 17:40

Changed

  • Synced upstream advplyr/audiobookshelf-app to v0.13.0-beta (40 commits).
  • Cover image color sampling now uses CapacitorHttp, fixing the case where the WebView strips the origin header from cover requests.
  • Focus-regain progress sync no longer double-fetches when the app returns to the foreground while connected to a server.
  • 30+ second socket reconnects now reconcile media-open progress on resume.
  • Removed several debug log statements (upstream cleanup).

Added

  • Belarusian and Bulgarian language options (upstream).
  • Podcast episode results included in search (upstream).

Android TV v1.0.8

Choose a tag to compare

@bilbospocketses bilbospocketses released this 25 Apr 08:44

Android TV v1.0.8

Adds a user-customizable D-pad focus-ring color picker for Android TV, plus the underlying refactor that makes runtime color overrides possible.

Added

  • TV Settings → Focus Ring Color picker on the Settings page (Android TV only). Choose from 7 curated presets — ABS Green (default), Sky, Amber, Red, Violet, Yellow, White. Selection persists across app restarts (device-wide, like every other setting in this app) and applies live to every focus-ring surface — library cards, author cards, item detail covers, modal items, drawer rows, generic buttons/inputs, settings dropdowns, and player controls.
  • ★ glyph marks the in-use swatch; D-pad focus draws a black-then-colored ring around the focused swatch (readable even when the focused swatch matches the current focus color).
  • Picker is hidden on phone/tablet — zero footprint outside TV.

Changed

  • assets/css/tv-focus.css now defines the focus-ring color as a single --tv-focus-color CSS custom property on :root.android-tv. All 8 focus-ring presentations reference the variable instead of hardcoding #1ad691. A single setProperty call retints every surface.

Verification

26-item manual test checklist passed on Google TV Streamer 4K, plus phone-visibility check — see docs/superpowers/plans/2026-04-25-tv-focus-color-picker-test-checklist.md.

Sideload

abs-android-tv-release-1.0.8.apk

Android TV v1.0.7 — Fire TV Focus Debug Build

Choose a tag to compare

This is a diagnostic build, not a fix. Intended only for users investigating a Fire TV Stick 4K (2nd gen) / Fire OS 8 focus bug where D-pad navigation into Home/Library/Authors content is only possible while holding the down button during the connect phase.

If you are not actively helping diagnose this specific issue, use Android TV v1.0.8 instead.

Update 2026-04-24 — logs screen UX fix

The previous build in this tag had a usability problem: every D-pad keypress appended a new focus-debug log entry to the Settings → Logs screen, and the screen auto-scrolled to the bottom on each new entry, fighting users trying to D-pad up to the Copy/Share buttons.

This build reverses the display order on the Logs screen — newest entries appear at the top, right next to the Copy and Share buttons. New entries no longer yank the scroll position. Underlying log storage is unchanged, so the shared .txt file is still oldest-first as before. This is a temporary UX tweak scoped to this diagnostic branch only; the general-release Logs screen stays chronological.

Re-sideload this APK over the previous -firetv-focus-debug install to pick up the fix.

What this build does

Adds extra logging to the TV navigation plugin so that every focus attempt and every D-pad keypress is recorded to the in-app log viewer (Settings → Logs). Behaviour is otherwise identical to v1.0.7.

For the reporter

  1. Sideload this APK over your current v1.0.7 install.
  2. Open the app and navigate to Settings → Logs → ⋮ menu → Clear Logs, then close the app.
  3. Reproduce the failing case: open the app, don't touch the remote, wait until fully loaded, then press down once and try to navigate.
  4. Close the app and reproduce the working case: open the app and hold down during connect.
  5. Open Settings → Logs — newest entries are at the top alongside the Copy and Share buttons. Tap Share and send the log file to your email / cloud / etc.
  6. Attach the log to the GitHub issue so we can diagnose.

For developers

Branch: fire-tv-focus-handling. See docs/FIRE_TV_FOCUS_DEBUG.md on that branch for the full instrumentation layout and signal interpretation guide.

The actual fix will be a separate PR once the reporter's logs tell us whether we need a post-connect focus pulse (Option 1) or a synthetic user-interaction event (Option 2). Do not merge this instrumentation to master as-is.

Android TV v1.0.7

Choose a tag to compare

@bilbospocketses bilbospocketses released this 21 Apr 07:40

Post-v1.0.6 Regression Fixes — TV-only

Three pre-existing regressions surfaced during the v1.0.6 QA pass — each was present in v1.0.5 and earlier but not caught until now. All fixes are TV-gated and have zero effect on phone/tablet/iOS.

Fixes

History option no longer breaks the fullscreen player

  • Selecting History from the fullscreen audio player's ellipsis menu on TV used to collapse the player into a stale mini-player state (the mini player was retired in an earlier release). History is now hidden from the fullscreen ellipsis on TV. It remains accessible from book detail pages, the normal entry point.

Library sort modal D-pad wrap-around fixed

  • Pressing D-pad Down from the last option in a long sort modal (e.g. the 13-option library sort) used to wrap to a middle item instead of the first.
  • Caused by the focus-tracking overlay filter rejecting options scrolled out of view; fixed by allowing scrolled-off-screen items to remain part of the navigable set within overlays. scrollIntoView handles the visual scroll.

Playlist row play-button fingerprint preserved across player close

  • Starting playback from an individual book's play button inside a playlist, then closing the fullscreen player, used to land focus on the playlist's primary Play button instead of the row you started from.
  • Fixed by capturing the pre-playback focus at the earliest possible point (the state commit inside the click handler) and restoring it on close — overriding Android TV's native focus engine, which aggressively re-focuses a "nearby" button the instant the player's focused element unmounts.

Scope

  • Android TV only. All changes gated behind isAndroidTv or wired into TV-specific logic paths.
  • Phone / tablet / iOS: unchanged.

Testing

  • Full v1.0.5 + v1.0.6 combined manual checklist re-run 2026-04-21 — all 42 items pass.
  • Fix C primary regression verified on 3 different books × 3 different close methods (ellipsis "Close Player", remote Back, collapse span). All returned focus to the correct row play-button.

Android TV v1.0.6

Choose a tag to compare

@bilbospocketses bilbospocketses released this 21 Apr 03:33

Bug Fix Release — Screensaver Interrupting Playback

Addresses user-reported issue where the Chromecast with Google TV / Android TV Ambient Mode screensaver engaged during playback and killed audio. After ~30 minutes in screensaver state, users were returned to the TV Home screen with no way to resume where they left off.

Fixes

Screen-Wake Lock During Active Playback (TV-only)

  • Audio player now holds a screen-wake lock while playback is active, preventing Ambient Mode from engaging mid-chapter.
  • Per Android TV developer guidance, audio should continue through Ambient Mode automatically — but CCwGTV firmware behavior diverges from docs and stops playback regardless. This fix works around that platform quirk.
  • Wake lock is acquired on every play↔pause transition via the existing onPlayingUpdate native event, and released on every session-end path: pause, stop, session close, fullscreen-collapse-close, playback failure, and component destroy.

Scope

  • Active playback on TV: screen stays on; Ambient Mode never starts; audio never gets killed.
  • Paused on TV: wake lock released — screensaver engages normally after idle; standard Android TV "Home after 30 min" behavior applies (matches all other TV media apps).
  • Phone / tablet / iOS: zero behavior change — all new logic gated behind isAndroidTv Vuex state.

Implementation

  • components/app/AudioPlayer.vue — added updateKeepAwake(shouldKeepAwake) helper; wired into onPlayingUpdate (chokepoint for play↔pause state) and endPlayback (chokepoint for all session teardown).
  • Uses @capacitor-community/keep-awake plugin — already installed and used by the e-reader (Reader.vue); no new dependencies.
  • Try/catch around plugin calls logs errors without disrupting playback.

Testing

Validated via direct sideload on Chromecast with Google TV hardware. Full v1.0.5 + v1.0.6 combined manual test pass: 35 of 40 TV tests passing; 2 phone tests pending post-release sideload. Three pre-existing regressions surfaced during QA have been logged for post-v1.0.6 patch (playlist row play-button fingerprint, fullscreen ellipsis History route, long-list sort modal D-pad wrap) — none block this release.

Android TV v1.0.5

Choose a tag to compare

@bilbospocketses bilbospocketses released this 14 Apr 03:32

Bug Fix Release — Full Code Audit

Comprehensive code audit identified 35 findings (5 HIGH, 15 MEDIUM, 15 LOW). This release fixes all HIGH and actionable MEDIUM issues.

Fixes

Critical Safety (H2 + M1)

  • Vertical navigation setTimeout callbacks now wrapped in try/finally — if an exception occurs, the nav guard always clears instead of permanently disabling focus recovery
  • Added CSS.escape polyfill for older Android TV WebViews (Chrome < 46) that lack native support
  • Fixed unescaped CSS selectors in fingerprint system that could throw on special-character IDs

Double-Fire Prevention (H4)

  • Added .prevent modifier to 11 @keydown.enter handlers across 8 components (cards, toolbar, modal, drawer) — prevents Enter from firing both keydown and synthesized click on Android TV D-pad

Connect Page TV Detection (H1)

  • connect.vue now sets isAndroidTv in Vuex store on init — fixes broken TV layout on first launch when no server is saved (the blank layout bypasses default.vue where this was previously set)

Vuex Reactivity Fix (H3)

  • Replaced direct store.state.lastBookshelfScrollData = {} mutation with proper Vuex resetLastBookshelfScrollData mutation — fixes scroll position restoration on library tab switches

Phone/Tablet Safety (M2)

  • All TV-only listeners (focusout, store watchers, router hooks, eventBus) now gated behind android-tv initialization check — prevents focusFirstContentElement() from firing on phones when modals close

Focus Interval Stacking (M3 + M4)

  • refocusAfterContentChange now tracks and clears its interval before creating a new one — prevents parallel polling loops from fighting over focus
  • focusLossTimer cleared on route navigation — prevents stale focusout recovery from causing focus flash during page transitions

Player Controls + Accessibility (M10 + M14)

  • Hidden fullscreen player controls (v-show) now use dynamic tabindex — invisible jump-chapter buttons no longer receive D-pad focus
  • Removed blanket :not(.android-tv) *:focus { outline: none } rule — restores focus indicators for phone/tablet keyboard/accessibility users

Testing

33-item manual test checklist covering all fixes + regression tests.

Android TV v1.0.4

Choose a tag to compare

@bilbospocketses bilbospocketses released this 10 Apr 21:14

Back Arrow Fingerprint Restoration Fix

A single-line fix with major impact on user experience. The on-screen back arrow (top-left of detail pages) now restores focus to the correct card — identical behavior to the remote's hardware back button.

The Problem

When using the on-screen back arrow to return from a detail page (book, podcast, playlist, etc.) to a grid/list page, focus always jumped to the first card instead of returning to the card the user navigated from. The remote's back button worked correctly.

Users expect "back" to mean "back to where I was." The back arrow violated that expectation on every single detail page in the app.

Root Cause

The router.beforeEach hook in tv-navigation.js uses document.activeElement to determine the navigation context. It distinguishes between:

  • Forward navigation (clicking a library tab, search icon) — clears the destination's saved fingerprint so focus starts fresh
  • Back navigation (remote back button) — preserves the fingerprint for restoration

The on-screen back arrow lives inside #appbar. The isExplicitNavElement check matched any focused element inside #appbar, #bookshelf-navbar, or #bookshelf-toolbar — treating the back arrow identically to a forward navigation link. This caused the destination's saved fingerprint to be deleted just before navigation, so router.afterEach found no fingerprint and defaulted to the first card.

The remote back button was never affected because it fires via a Capacitor native listener while focus remains on a content card, bypassing the appbar check entirely.

Fix

Exclude the back arrow from the isExplicitNavElement check by detecting aria-label="Back". One condition added, zero side effects.

Affected Pages

Every detail page that has a back arrow — book details, podcast details, playlist details, collection details, series details, author details, episode details, history pages. All now correctly restore focus on back-arrow navigation.

Documentation

TV_FOCUS_SYSTEM.md updated with a new "Back Arrow vs Remote Back Button" section explaining the distinction and why the exclusion is necessary.

Android TV v1.0.3

Choose a tag to compare

@bilbospocketses bilbospocketses released this 10 Apr 20:28

Connect Page D-pad Navigation Overhaul

What started as a quick visual tweak to the server/user selection screen turned into a deep dive into Android TV WebView D-pad focus management. Every change below exists so that D-pad navigation on this screen feels completely intuitive — no user guide needed.

Visual Improvements

  • Focus box wraps username + server URL — both lines are now inside a single focusable container, so the D-pad highlight covers the full entry
  • Username matches server URL styling — same font size and color (text-base text-fg) instead of the previous text-lg text-white font-bold
  • Focus box breathing room — 6px symmetric padding on left/right edges prevents text cutoff at the focus ring boundary
  • GitHub links scrollable on TV — changed from position: fixed to normal document flow so D-pad can actually reach and scroll to them

D-pad Navigation

  • Full left/right sub-icon chain: Entry row →right→ ellipsis →right→ delete, then delete →left→ ellipsis →left→ back to entry row
  • Up/down always lands on the entry row, never on an adjacent row's icon — cross-row icon focus is intercepted and redirected
  • First entry scroll-to-top — focusing the first server entry always scrolls the page to the top, keeping the back arrow visible and reachable

Bugs Fixed

  • Double-jump on up/down from icons — native D-pad engine and programmatic focus were both moving focus, causing rows to be skipped
  • Bounce on right from ellipsis to delete — keydown events bubbling from icons to the parent entry row caused competing deferred focus calls
  • Left from ellipsis stuck — native D-pad cannot navigate from a child element to its parent; explicit handler added
  • Page oscillation on row 1 — native focus-scroll behavior caused the viewport to jitter when cycling between icons; all focus calls now save/restore scroll position
  • Left from entry row entering children — native D-pad was entering the row's children from the right side, landing on the delete icon

Technical Approach

The Android TV WebView's native D-pad spatial navigation has fundamental limitations inside nested focusable containers. The solution layers five mechanisms:

  1. dpadFocus() — defers .focus({ preventScroll: true }) via setTimeout(0) to execute after the native engine finishes; saves/restores scroll position
  2. handleIconFocus() (@focus) — intercepts cross-row focus on icons and redirects to the entry row; respects _dpadFocusActive flag to avoid interfering with in-flight deferred operations
  3. .prevent.stop on icon keydown — prevents both default behavior and event bubbling to the parent entry row
  4. lockScroll() — prevents scroll oscillation on dead-end key presses (e.g., right from delete icon)
  5. onEntryRowFocus() — deferred scroll-to-top when first entry receives focus

Documentation updated in TV_FOCUS_SYSTEM.md with full D-pad navigation map and mechanism table.