No description
  • Kotlin 99.4%
  • Nix 0.6%
Find a file
mrfluffy 577c2a11a7 Make navigating large wikis fast
Opening a location, faction or other non-character page in a big wiki
(338 characters, 529 other pages) froze the app for minutes: its
"Connections" were found on the main thread by resolving every name in
the wiki, with normalize compiling four regexes per call and unmatched
names never remembered. Each page also reloaded and rebuilt the whole
wiki.

- Compile normalize's regexes once.
- Find every page's backlinks in one pass, cached per wiki, and remember
  names that match no page.
- Normalise characters' names once for partial name matching.
- Share one loaded wiki between the wiki screens, and one built wiki
  per spoiler limit; one-off reads still query the database fresh.
- Build wikis off the main thread on the wiki screens and in the reader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 12:32:30 +00:00
app Make navigating large wikis fast 2026-11-04 12:32:30 +00:00
gradle Initial import of Reed 2026-11-03 14:32:09 +00:00
.envrc Initial import of Reed 2026-11-03 14:32:09 +00:00
.gitignore Initial import of Reed 2026-11-03 14:32:09 +00:00
build.gradle.kts Initial import of Reed 2026-11-03 14:32:09 +00:00
flake.lock Initial import of Reed 2026-11-03 14:32:09 +00:00
flake.nix Initial import of Reed 2026-11-03 14:32:09 +00:00
gradle.properties Initial import of Reed 2026-11-03 14:32:09 +00:00
gradlew Initial import of Reed 2026-11-03 14:32:09 +00:00
gradlew.bat Initial import of Reed 2026-11-03 14:32:09 +00:00
LICENSE Add GPL-3.0-or-later licence 2026-11-03 18:18:20 +00:00
README.md Add Claude and OpenAI-compatible AI providers 2026-11-03 23:29:28 +00:00
settings.gradle.kts Initial import of Reed 2026-11-03 14:32:09 +00:00

Reed

An Android ebook reader with series organisation, dictionary look-ups, and an AI-built wiki of each series: characters, places, factions, abilities, items, creatures and lore (via your own Ollama server, or Claude, OpenAI, Grok, Gemini and other cloud APIs with your own API key).

Features

Reading

  • EPUB, PDF, CBZ (comics), FB2 and TXT (FB2/TXT are converted to EPUB on import)
  • Paginated or continuous scroll; text size, font (incl. Literata and OpenDyslexic), margins, line/paragraph spacing, alignment, hyphenation
  • Light, sepia, dark and black themes; brightness, keep-screen-on, volume-key and tap-edge page turns
  • Table of contents, bookmarks, highlights in 5 colours with notes, full-text search
  • Read aloud (Android text-to-speech) with sentence highlighting and speed control

Library

  • Import files, whole folders, or "Open with Reed" from a file manager
  • Series detected from book metadata (Calibre/EPUB 3) or titles like "Unsouled (Cradle Book 1)"; reorder books, add/remove, rename
  • Shelves (your own collections), search, sort, filters (reading / unread / finished)

Look-ups while reading: select text and choose

  • Define: dictionary entry (Free Dictionary API / Wiktionary), plus "Explain in context" from your AI for invented words and names
  • Wiki: the wiki page for a character, place, technique and so on; if there's no page yet, ask the AI what it is, add it yourself, or mark it as another name of an existing page
  • PDFs and comics can't select text, so use the menu's Look up a word or name

Series wiki

  • Each series (or standalone book) has a wiki with categories: Characters, Locations, Factions, Abilities, Items, Creatures and Lore. The "All" tab shows the most important pages of each.
  • Character pages read like a fan wiki: an infobox (age, sex, species, rank, affiliations, first appearance, books), summary, appearance, personality, abilities, advancement (ranks/levels/stages reached, book by book), relationships, history per book, and "Mentioned in" links
  • LitRPG status log: status screens, level-ups, stat changes and skill descriptions are logged where they happen in the book. A character's Status shows a game-style window (level, class, race, stats, abilities with their level and full description, titles) at any point in the story, with what changed and a history of every update. In the reader, Status (menu) shows it as of where you are, so later level-ups stay hidden.
  • Other pages show what it is, details, key facts and connections (e.g. who uses a technique, who belongs to a faction)
  • Every page has a Series tab (everything up to your spoiler limit) and a tab per book showing the page as it stood in that book
  • Names on a page link to their own pages. Categories (groups, places, species, kinds, plus your own) can be browsed from the menu or by tapping one on a page.
  • Search within a wiki (names, other names, abilities, categories, text) or across every wiki from the Wiki tab
  • AI wiki: from a book's page, have the AI read the whole book, or only up to where you are (spoiler-free; continue later). "Analyse series" queues every book in order. It runs in the background, survives restarts, and resumes where it stopped.
  • Pages are kept per book, so the wiki and the reader hide information from books you haven't reached. The reader warns when a page covers more of the current book than you've read.
  • Find duplicates (wiki menu): the AI reads the whole wiki and lists pages that look like the same thing (a nickname, a title, a misspelling). For each one you pick the page and name to keep and merge, or say they're different so it isn't suggested again.
  • Edit names, other names, role/type, categories and notes; set a picture; merge pages

Building

The Nix flake provides the JDK, Gradle and Android SDK:

direnv allow            # or: nix develop
./gradlew assembleDebug # -> app/build/outputs/apk/debug/app-debug.apk

Install on a phone with USB debugging (or wireless debugging) enabled:

adb install -r app/build/outputs/apk/debug/app-debug.apk

./gradlew testDebugUnitTest runs the unit tests.

A test emulator: nix run .#emulator (add -no-window to run headless).

Release build (faster)

Debug builds are debuggable, so Android runs them without most of its optimisations: scrolling, page turns and the library screens are noticeably slower. For everyday reading, build a release APK instead.

Release builds must be signed. If you don't have a key, make one (keep the file and its password safe: every later update has to be signed with the same key):

keytool -genkeypair -v -keystore ~/reed-release.jks -alias upload \
  -keyalg RSA -keysize 4096 -validity 10000

Then point Gradle at it in ~/.gradle/gradle.properties (or $GRADLE_USER_HOME/gradle.properties if you set that), which keeps the password out of the repo. Use an absolute path; ~ isn't expanded here:

RELEASE_STORE_FILE=/home/you/reed-release.jks
RELEASE_STORE_PASSWORD=your-password
RELEASE_KEY_ALIAS=upload
# RELEASE_KEY_PASSWORD=...  only if the key's password differs from the store's

Build and install:

./gradlew assembleRelease # -> app/build/outputs/apk/release/app-release.apk
adb install -r app/build/outputs/apk/release/app-release.apk

The debug and release builds are signed with different keys, so one can't be installed over the other. Uninstall the debug build first; this deletes its library and wikis.

Setting up the AI

In Settings → AI, pick a Provider:

  • Ollama (your own server): free and private; runs on your own computer.
  • Claude, OpenAI, Grok, Google Gemini, OpenRouter, Mistral, DeepSeek or Groq: paste an API key from that provider ("Get an API key" opens the right page). The book's text is sent to them and they bill you per token, so analysing a whole book costs money. A Claude Pro/Max subscription can't be used here; Claude needs an API key from the Claude Console, billed separately.
  • Other (OpenAI-compatible): LM Studio, llama.cpp, vLLM and similar servers. Enter the address including /v1.

Then tap Connect, pick or type a model, open a book's page and choose Analyse up to where I am or Analyse whole book.

API keys are encrypted with a key kept in the Android Keystore. They aren't restored from a backup onto another phone, so enter them again there.

Ollama

  1. Make Ollama listen on your network. Set OLLAMA_HOST=0.0.0.0 in the service environment; on NixOS that's services.ollama.host = "0.0.0.0";.
  2. In Reed, choose Ollama, enter http://<your-pc-ip>:11434, tap Connect, and pick a model.

Tips:

  • qwen3.5:35b gave good results in testing, at about 1-1.5 min per 24k-character passage (a typical novel is 15-40 passages). Building the full wiki takes longer than characters alone used to, since the model writes more per passage.
  • Books analysed before the wiki existed only have characters. Use Start over on a book's page to add abilities, ranks and the other pages.
  • Passage size trades fewer requests against needing a bigger context window. The context size is picked automatically and sent as num_ctx.
  • "Let the model think" helps reasoning models a little, but is much slower. On Claude it raises the effort level (and turns on extended thinking where the model has it); on OpenAI-style APIs it sends reasoning_effort: high.
  • Use the Ollama provider for Ollama rather than its OpenAI-compatible /v1 address: only the native API lets Reed set the context window.

Project layout

app/src/main/java/xyz/mrfluffy/reed/
  ai/           AI clients (Ollama, Claude, OpenAI-compatible), prompts, text extraction,
                analysis pipeline + worker
  wiki/         Wiki pages, spoiler filtering, links, categories, search, dedupe
  data/         Room database, settings (DataStore)
  dictionary/   Dictionary look-ups
  library/      Import, TXT/FB2 to EPUB conversion, series/shelves
  readium/      Readium setup (EPUB/PDF engine)
  reader/       Reader activity, preferences, overlay UI and sheets
  ui/           Library, book, series, wiki and settings screens

License

Reed is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See LICENSE for the full text.