Skip to content
sgernerPublic

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

23 stars

Watchers

1 watching

Forks

Latest commit

 

History

337 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Turnleaf

Turnleaf is an offline-first, mobile EPUB reader for Kavita. It is a local app only: there is no companion server, no proxy, and no hidden backend.

The goal is simple: connect to Kavita, download books, read them as paginated pages, and keep progress synchronized across devices without making reading feel like a web app.

Latest release: GitHub Releases

Tracked release notes: RELEASE_NOTES.md

If a Kavita refresh fails, open Settings → Diagnostics after reproducing it. Copy the log or use View diagnostics to select the text on Android, then paste it into your GitHub issue. The log includes endpoint statuses and unexpected field types, but excludes your server address, API key, book titles, and response bodies. It stays in memory until the app closes or you clear it.

GitHub release bodies are generated from the matching versioned section in RELEASE_NOTES.md; ## Unreleased records changes that are still in development.

Recent release notes

0.3.3

  • Improve mobile library filtering, view controls, and large-library performance.
  • Add reader appearance panels, bookmarks, highlights, notes, and in-book search.
  • Make native metadata refreshes transactional and cover loading cancellable.

0.3.2

  • Generate clean GitHub release notes without npm command output.

0.3.1

  • Guard library startup teardown and limit concurrent Kavita detail requests for large libraries.

0.3.0

  • Read with a monochrome e-ink theme and an optional keep-awake setting.
  • Discover EPUBs in numbered series volumes and Light Novel libraries.
  • Keep reader text clear of Android navigation bars and refresh progress when returning to the library.
  • Develop against a local Kavita Docker Compose instance.
  • Include patched production dependencies and updated Android tooling.

Screenshots

Library

Turnleaf library view

Global Settings

Turnleaf settings view

Reader

Turnleaf reader view

Reader Settings

Turnleaf reader settings view

Contents

Turnleaf table of contents view

Why this exists

I built Turnleaf because the existing options I tried did not fit the use case I wanted:

  • Kavita's PWA scrolls books instead of rendering proper pages, and it does not provide offline access.
  • Inkita also scrolls books.
  • Inkavi is missing an ePub dependency.
  • KOReader was difficult to get working reliably for cross-device sync.
  • Kover renders books as one continuous block of text without the indentation and paragraph spacing I wanted.

Turnleaf is the small, direct answer to those problems.

What Turnleaf does

  • Connects directly to a Kavita server with the Kavita REST API.
  • Browses only book-oriented library content.
  • Downloads EPUBs into app-private storage for offline reading.
  • Opens downloaded EPUBs instantly and reads them as paginated pages.
  • Turns pages with left and right taps.
  • Shows reader controls with a center tap.
  • Synchronizes reading progress back to Kavita.
  • Restores the correct semantic EPUB location after reopening.
  • Lets you tune the reading experience with font, size, margin, line-height, and theme controls.
  • Supports light and dark modes plus a theme selector.
  • Keeps credentials in native secure storage instead of localStorage.
  • Stores durable app data in SQLite.

Supported content

Turnleaf is intentionally narrow in scope.

Supported:

  • EPUB books in Kavita Book and Light Novel libraries, including books with illustrations
  • Text-first novels and long-form prose

Not supported:

  • Manga
  • Comics
  • PDFs
  • Audiobooks
  • Magazines
  • Image-based readers

That limitation is deliberate. Turnleaf is optimized for conventional book reading, not for every media type Kavita can host.

Tech stack

Turnleaf is built with:

  • Svelte 5
  • TypeScript with strict type checking
  • Vite
  • Capacitor
  • Skeleton UI
  • Tailwind CSS
  • EPUB.js for EPUB rendering
  • SQLite for local structured data
  • @capacitor-community/sqlite for durable app storage
  • @aparajita/capacitor-secure-storage for Keychain / Keystore-backed credentials
  • Capacitor Filesystem and File Transfer for native EPUB downloads
  • DOMPurify for sanitizing Kavita-provided HTML

Architecture

The app stays intentionally boring inside:

  • Svelte components own the UI.
  • Small domain modules handle Kavita, storage, downloads, sync, and reader state.
  • SQLite stores server configuration, book metadata, reading state, and sync queue entries.
  • Secure storage stores the credential reference and the actual secret.
  • Downloaded EPUBs live in app-private native storage.
  • Reader rendering is isolated inside a sandboxed EPUB.js iframe.

There is no repository layer, service locator, event bus, or backend abstraction for its own sake.

Current limitations

  • Only EPUB is supported.
  • I do not have a Mac, so iOS has only been scaffolded and synchronized as far as Linux allows.
  • Android is the only platform I have personally tested end-to-end.
  • The browser dev server is useful for UI work, but native secure storage and native EPUB file handling are still Capacitor features.

Because the app is a Capacitor wrapper around a Svelte application, it should build on macOS for iOS once Xcode is available, but that has not been verified from this machine.

Getting started

Prerequisites

  • Node.js 22 (see .nvmrc)
  • npm
  • For Android: Java 21, Android Studio, Android SDK, and an emulator or device
  • For iOS on macOS: Xcode and CocoaPods
  • Docker, if you want to run the local Kavita fixture

Install

npm ci
npm run verify

npm ci installs the dependencies and enables the repository's Git hooks. The single contributor check is npm run verify; it runs the production dependency audit, formatting check, lint, type check, unit tests, and web build.

Run the web app

npm run dev

Use this for fast UI iteration and browser-based testing of the Svelte app. Native storage, downloads, and secure credential storage require Capacitor builds.

When running the browser app against Kavita, the development proxy accepts loopback http:// and https:// targets such as http://localhost:5000. It rejects remote targets by default. To use a remote server, explicitly allow its HTTPS origin before starting Vite:

TURNLEAF_DEV_PROXY_ORIGINS="https://books.example.com:5000" npm run dev

The proxy accepts only HTTP(S), rejects URL credentials, forwards only the Kavita API headers it needs, limits request bodies to 1 MiB, and stops upstream requests after 12 seconds. It does not follow redirects or forward cookies, authorization, or forwarding headers. Plain HTTP is intentionally limited to loopback development servers.

Run a local Kavita server

Docker is optional, but it provides a repeatable server for onboarding, download, offline, and reader testing:

npm run dev:kavita
npm run dev

Complete the one-time Kavita setup in dev/README.md. Stop the fixture with npm run dev:kavita:down, or inspect it with npm run dev:kavita:logs.

Quality checks

npm run verify

Run npm run format separately when you intend to rewrite formatting.

Android setup

Turnleaf has been tested on Android. The repo includes the Capacitor Android project and release/debug build scripts.

export ANDROID_HOME="$HOME/Android/Sdk"
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"
npm run android:doctor
npm run android:debug

android:doctor checks the SDK path, API 36, Android Build Tools, and Java 17+ before a Gradle build. android:debug and android:release repeat that check, then pass the selected SDK path to both Capacitor sync and Gradle. If the SDK is installed somewhere else, set ANDROID_HOME or create the ignored android/local.properties file with its absolute path.

Useful follow-up commands:

npm run android:open
npm run android:smoke
npm run android:release

android:smoke installs the debug APK as app.turnleaf.reader.debug and verifies that the app process starts on a connected emulator or USB device. The .debug application ID lets it run alongside a signed production install. android:open and ios:open read an optional .env file when present, so a fresh checkout does not need one. Copy .env.example to .env only when you need to set an Android Studio path or a remote browser-proxy origin.

If you want to run from Android Studio, open the generated Android project after cap sync and use the usual emulator or device workflow.

iOS setup on macOS

The iOS Capacitor project exists and can be synchronized on Linux, but I have not built or tested it because I do not have a Mac.

On macOS:

xcode-select --install
brew install node cocoapods
npm ci
npm run build
npm run ios:sync
npm run ios:open

Then in Xcode:

  1. Open the generated app project.
  2. Select the App target.
  3. Set the development team and signing identity.
  4. Confirm the bundle identifier is correct.
  5. Build and run on a simulator or device.

If you are trying iOS, please report back what works and what does not.

Contributing

Contributions and forks are welcome. The complete setup, testing, Android validation, pull-request, and release-note workflow is in CONTRIBUTING.md.

Please keep changes small and direct:

  • Prefer the simplest implementation that solves the problem.
  • Avoid adding abstractions unless they earn their keep.
  • Keep EPUB reading, Kavita integration, and local storage behavior explicit.
  • Preserve offline-first behavior.
  • Do not add new dependencies unless they are clearly necessary.

GitHub Actions runs npm run verify, an Android debug build, an emulator startup smoke test, dependency review, and CodeQL scanning. PRs that touch native behavior should also be verified locally on the relevant platform when possible.

Use DEVICE_VALIDATION.md for the Android accessibility, network-isolation, and offline-reopen acceptance pass. CI also runs an emulator startup smoke test; that smoke test does not replace TalkBack or network-trace validation.

Before opening a pull request, run:

npm run verify

If your change touches native behavior, also run the relevant Capacitor or Android build command.

Screenshots for UI changes are appreciated, especially for reader, settings, and library work.

License

Turnleaf is released under the MIT License.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

23 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages