feat: Audiobookshelf integration — browse, stream, chapters, sleep timer

- src/abs.js: full ABS API client + player engine
  - Login/token auth, library browsing, search
  - Playback session API (multi-file book support via startOffset)
  - Progress sync to ABS every 30s and on pause
  - Chapter navigation (prev/next/seek-to), ±10s / ±30s skip
  - Speed control (0.75–2×), sleep timer with countdown
- index.html: sidebar nav, audiobooks/detail pages, full-screen player overlay,
  ABS settings section (URL + credentials + library picker)
- state.js: abs + absPlayer state objects
- views.js: navigate() handles 'audiobooks' and 'abs-book-detail'
- styles.css: book grid, detail page, player overlay, pickers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-03 14:35:00 +02:00
1 parent 719d4d9afd
commit c17b7ea11a
7 files changed
+948

No files matched your search

+9
View File
@@ -35,6 +35,7 @@ export function navigate(page, data=null) {
closeSidebar();
if(['discover','new-releases','recommendations','random','spotify-importer'].includes(page)) switchNavMode('discover');
else if(['home','artists','albums','starred','playlists'].includes(page)) switchNavMode('library');
// ABS pages don't switch the bottom nav mode (they have their own sidebar section)
if(page==='home') loadHomeData();
if(page==='artists' && !document.getElementById('artists-grid').children.length) loadArtists();
@@ -50,6 +51,14 @@ export function navigate(page, data=null) {
if(page==='playlist-detail' && data) loadPlaylistDetail(data);
if(page==='recommendations') loadRecommendations();
if(page==='spotify-importer') loadSpotifyImporter();
if(page==='audiobooks') {
import('./abs.js').then(m => {
if (S.abs.currentLibraryId) m.loadAbsBooks(S.abs.currentLibraryId);
});
}
if(page==='abs-book-detail' && data) {
import('./abs.js').then(m => m.loadAbsBookDetail(data.id));
}
if(!S._navJumping) {
S._navStack = S._navStack.slice(0, S._navCursor + 1);