- Sync pagination measurement with rendered layout (page geometry, spacing, images, chapter extras) - Improve split algorithm with getLineForVerticalPosition and widow/orphan handling - Fix search crash from duplicate LazyColumn keys on empty guids - Switch BookCard cover to fixed-height vertical variant - Add ExoPlayer SimpleCache + CacheDataSource for streaming audio - Unify AuthorizationInterceptor for player via PlaybackAuthProvider - Bump version to 1.9.11 (27) and update AGENTS.md
124 lines
6.9 KiB
Markdown
124 lines
6.9 KiB
Markdown
# Book's Story — Bookshelf Fork
|
||
|
||
> Форк `Acclorite/book-story` под Bookshelf: audiobookshelf + bookshelf-api + TTS + offline.
|
||
|
||
## Stack
|
||
|
||
- **Язык:** Kotlin 100%
|
||
- **UI:** Jetpack Compose + Material3
|
||
- **DI:** Dagger Hilt
|
||
- **БД:** Room
|
||
- **Настройки:** DataStore
|
||
- **Сеть:** Retrofit + OkHttp + Kotlinx Serialization
|
||
- **Аудио:** ExoPlayer (Media3) + MediaSession
|
||
- **Фоновые задачи:** WorkManager
|
||
- **Читалка:** собственная Book's Story (jsoup, pdfbox, commonmark)
|
||
- **minSdk:** 31
|
||
- **compileSdk/targetSdk:** 36
|
||
|
||
## Goal
|
||
|
||
- Сохранить Material You reader Book's Story.
|
||
- Добавить поддержку bookshelf-api: библиотеки, поиск, TTS, подкасты, Яндекс/YouTube.
|
||
- Добавить аудиоплеер для аудиокниг из Audiobookshelf.
|
||
- Добавить offline-кэш и синхронизацию прогресса.
|
||
|
||
## Layout
|
||
|
||
- `app/src/main/java/org/dueattendant149/bookshelf/` — основной код
|
||
- `core/` — crash handler, typealias, commonmark parser
|
||
- `data/` — repository, Room, DataStore, mappers, parsers, DI
|
||
- `domain/` — models, use cases, repository interfaces
|
||
- `presentation/` — ViewModels, MVI screens, navigator
|
||
- `ui/` — Compose UI
|
||
- `bookshelf-api` backend находится в `~/bookshelf/bookshelf-api/` (отдельный проект)
|
||
- Lissen (который дорабатывается параллельно) — `~/bookshelf/lissen/`
|
||
|
||
## API endpoints
|
||
|
||
- **bookshelf-api:** `http://bookshelf-api:8073` (или `https://tts.dueattendant149.org` после DNS)
|
||
- `GET /api/v1/books/libraries`
|
||
- `GET /api/v1/books/{item_id}`
|
||
- `GET /api/v1/books/library/{id}/search?q=...`
|
||
- `POST /api/v1/search`
|
||
- `POST /api/v1/tts`, `GET /api/v1/tts/{job_id}`, `GET /api/v1/tts/{job_id}/download`
|
||
- `GET /api/v1/tts/engines`, `GET /api/v1/tts/voices`
|
||
- `POST /api/v1/download`, `GET /api/v1/download/list`
|
||
- `POST /api/v1/podcasts`, `POST /api/v1/sources/yandex`
|
||
- **Audiobookshelf (напрямую):** для аудио файлов и обложек
|
||
- `GET /api/items/{id}/file/{ino}`
|
||
- `GET /api/items/{id}/download`
|
||
- `GET /api/items/{id}/cover`
|
||
|
||
## Git
|
||
|
||
- **origin:** `https://git.dueattendant149.org/Atte149/book-story.git` (Forgejo)
|
||
- **upstream:** `https://github.com/Acclorite/book-story.git`
|
||
- **Лицензия:** GPL-3.0-only (как у оригинала)
|
||
|
||
## Build
|
||
|
||
```bash
|
||
./gradlew :app:assembleDebug
|
||
```
|
||
|
||
## Current Status
|
||
|
||
- Phase 1: fork + package rename completed.
|
||
- Phase 2: network layer (Retrofit, OkHttp, bookshelf-api + ABS clients) completed.
|
||
- Phase 3: data layer (remote Book fields, audio/ebook/cache tables, migration 16→17→18) completed.
|
||
- Phase 4: domain layer (ServerSettings, RemoteLibrary repository, use cases) completed.
|
||
- Phase 5a: UI scaffold (server settings screen, RemoteLibrary tab) completed.
|
||
- Phase 5b: UI/UX polish (icons, string resources, pull-to-refresh, empty/error states) completed.
|
||
- Phase 5c: server settings validation (health check, derive ABS URL, credential checks) completed.
|
||
- Phase 6: feature integration on `feature/ui-polish` completed:
|
||
- RemoteLibrary cache UI (offline-only filter, download/delete, progress indicator).
|
||
- Remote ebook opening in the existing reader.
|
||
- Audiobook player with ExoPlayer + MediaSession.
|
||
- TTS jobs screen via bookshelf-api.
|
||
- Reading and playback progress sync with periodic WorkManager worker.
|
||
- Current: `feature/ui-polish` builds and produces `app-debug.apk` (~58 MB). Debug APK uploaded as `KRait-debug-15.apk` to ownCloud + caddy download site.
|
||
- Polished: PlayerContent and TtsContent labels moved to `strings.xml`; TTS WorkManager observer leak fixed (`TtsModel` removes observer in `onCleared`).
|
||
- Raised `minSdk` from 26 to 31.
|
||
- Phase 7 (nav redesign): `MainActivity` tabs = Книги | Аудиокниги | Поиск | Настройки.
|
||
- `BooksModel` / `AudiobooksModel` extend `RemoteLibraryViewModel` with `mediaTypeFilter`.
|
||
- Library filter uses name fallback ("Books" / "Audiobooks") because ABS returns `mediaType: "book"` for both.
|
||
- `SearchModel` + `SearchContent` for global Librarr search (`/api/v1/search`).
|
||
- `ServerStatusMonitor` (singleton, pings `/health` every 30 s) → auto offline-only when down.
|
||
- `SettingsScreen` is a root tab — back button hidden when stack size ≤ 1.
|
||
- Phase 8 (RSVP speed reading): core tokenizer + engine + UI.
|
||
- `domain/model/rsvp/` — `RsvpToken`, `OrpTable`, `RsvpTokenizer`, `RsvpEngine`.
|
||
- `presentation/rsvp/` — `RsvpScreen`, `RsvpModel`, `RsvpState/Event/Effect`.
|
||
- `ui/rsvp/RsvpContent.kt` — word stage with prefix/pivot/suffix, focus guide ▲▼, controls bar.
|
||
- `ReaderTopBar` got a ⚡ button → `RsvpScreen(bookId)`.
|
||
- Persists reading progress on close via `UpdateBookUseCase`.
|
||
- Settings: `rsvpWpm` (100–900), `rsvpFontSize` (24–96 sp), `rsvpPauseOnParagraph`, `rsvpPauseOnChapter`, `rsvpPauseOnLongWords`, `rsvpShowFocusGuide`.
|
||
- Phase 9 (reader pagination + polish):
|
||
- Kindle-style paginated reading mode with `HorizontalPager`.
|
||
- Volume keys (Up/Down) mapped to page navigation via `VolumeKeyWindowCallback`.
|
||
- Pagination measurement/render synchronization: exact page geometry, real inter-item spacing, image sizing, chapter title extras.
|
||
- Algorithm improvements: `TextLayoutResult.getLineForVerticalPosition()` split point, better widow/orphan handling.
|
||
- Phase 10 (bugfixes):
|
||
- Fixed search crash caused by duplicate LazyColumn keys when search results have empty `guid`.
|
||
- Fixed `BookCard` intrinsic-measurement crash risk by switching cover to fixed-height vertical variant.
|
||
- Phase 11 (audio player hardening):
|
||
- ExoPlayer streaming cache via `SimpleCache` + `CacheDataSource` (512 MB external cache).
|
||
- Unified `AuthorizationInterceptor` for player, backed by `PlaybackAuthProvider` refreshed from `ServerSettings`.
|
||
- Current APK: `KRait-debug-27.apk` (1.9.11) on `books.dueattendant149.org/download`.
|
||
- Next: final APK rebuild after pushing to Forgejo.
|
||
|
||
## WARNs
|
||
|
||
- **Не пушить в `upstream` (Acclorite/book-story).** Только в `origin` (Forgejo).
|
||
- **Lissen остаётся живым проектом.** Book's Story fork — отдельная ветка развития.
|
||
- **Секреты** (ABS token, API keys) хранить только в `.env` / `credentials.json` / DataStore, никогда в коде.
|
||
- **Package:** `org.dueattendant149.bookshelf`. Все ссылки на `ua.acclorite.book_story` в коде заменены; README оставлен с оригинальными F-Droid ссылками.
|
||
|
||
## Typical tasks
|
||
|
||
- Добавить новый endpoint bookshelf-api
|
||
- Расширить `Book` / `BookEntity` для remote полей
|
||
- Добавить аудиоплеер экран
|
||
- Добавить TTS экран
|
||
- Поднять minSdk, добавить новые разрешения
|
||
- Обновить AGENTS.md при существенных изменениях архитектуры
|