Universal Reader: Distraction-Free Reading & Continuous Audio Narration¶
Universal Reader is a self-hosted, local-first semantic document reader and continuous audio synthesizer. It transforms digital documents, web articles, and scratchpad notes into cleanly formatted, typography-optimized reading views paired with seamless, gapless Text-to-Speech (TTS) narration. Designed for long-form listening, deep reading, and personal knowledge management (PKM), Universal Reader connects to local TTS backends (such as Universal TTS Gateway) or cloud providers, pairing audio playback with an interactive Kindle-grade reader.
- GitHub Repository: Universal-Reader
- Docker Image:
ghcr.io/binuengoor/universal-reader:latest
Overview¶
Reading long-form documentation, technical whitepapers, e-books, and saved web articles often requires switching between disparate read-it-later apps, PDF viewers, and rudimentary screen readers that recite syntax errors, URLs, and table borders.
Universal Reader bridges the gap between text reading and podcast-like audio narration. It ingests multi-format documents, breaks them into sentence-aligned semantic blocks, cleans syntax noise through an intelligent conversational pre-processor, and pre-caches audio using a lookahead sliding buffer for zero-latency gapless playback. Readers can comfortably follow along visually with auto-scrolling text, listen in the background via hardware media keys and lock-screen controls, or export complete multi-chapter audiobooks as single MP3 files.
Key Features¶
1. Multiformat Document Intake & Ingestion¶
- Native Document Parsing: Direct file upload and parsing for PDF (
pymupdf), ePub (ebooklib), Word (.docx), Markdown (.md), and plain text (.txt). - Web Article Ingestion: Paste any URL to scrape readable article content, extract titles, and convert formatting to markdown powered by
trafilatura. - Quick Scratchpad: Instant manual entry for pasted meeting notes, ideas, or transcripts with automatic title generation.
- PWA Web Share Target: Share articles and links directly from mobile browsers (iOS and Android) into your library with one tap.
2. Semantic Chunking & Lookahead Audio Narration¶
- Sentence-Boundary Chunking: Intelligent text segmentation into 250–500 character blocks without splitting phrases or mid-sentence clauses.
- Lookahead Sliding Buffer: While block \(N\) plays, blocks \(N+1\) and \(N+2\) are pre-fetched and synthesized in the background, ensuring immediate zero-latency gapless audio transitions.
- Continuous Playback & Natural Pacing: Automatically advances across paragraphs with a configurable inter-block pause (0ms–1500ms) to emulate natural human breathing and pauses.
- Full-Document MP3 Export: Concatenate all synthesized audio chunks into a single downloadable MP3 file for offline listening in any podcast or media player.
3. Conversational Speech Pre-Processor¶
- Markdown Syntax Stripping: Strips raw URLs, citation brackets (
[1]), image markup, and heading hashes (#) so the TTS voice never reads literal formatting syntax. - Table-to-Speech Normalization: Converts markdown grid tables (
| col | col |) into flowing conversational sentences instead of reciting pipe delimiters. - Code Block Formatting: Converts shell commands and code blocks (
```bash ... ```) into spoken descriptions (e.g., "Command in bash: docker compose up -d") rather than reciting brackets, semicolons, and curly braces. - Phonetic Glossary: Define pronunciation overrides for technical jargon, acronyms, and names.
- LLM Assistance (Optional): Connect an OpenAI-compatible LLM (e.g., Groq
qwen/qwen3.8-27b) for automated note titling, categorization (up to 50 global tags), and deep conversational rewriting.
4. Kindle-Style Reader & Typography¶
- Universal Display Control (
Aa): Easily switch reading themes and typography settings:- Warm Sepia:
#fbf0d9parchment paper with rich espresso#433422typography. - Clean Light: Crisp modern white paper aesthetic.
- OLED Dark: True deep black background with softened high-contrast text.
- Warm Sepia:
- Typography Controls: Choose between Bookerly (Serif), Modern Sans, or Technical Mono fonts, with granular font scaling (14px–32px), line height adjustments (1.4x, 1.7x, 2.1x), and column width limits.
- Interactive Table of Contents: Automatically detects Markdown headings to build a dynamic navigation drawer with section block counts and active-chapter indicators.
- Auto-Scroll Follow-Along: Keeps the actively playing block centered in view. Includes a manual scroll override that pauses auto-scrolling when reading ahead, with a 1-click "Resume" floating pill.
- Saved Reading Progress: Remembers
last_block_indexper document and restores your scroll position automatically upon opening. - In-Document Search: Instant full-text search (
Cmd+F/Ctrl+F) with match highlights and step-through cycling.
5. Persistent Audio Suite¶
- Sticky Bottom Player: Full playback bar with scrub slider, \(\pm 10\)s jump buttons, speed selector (\(0.75\times\) to \(2.0\times\)), block counters, and sleep timer (15m, 30m, 45m, 60m, or end of document).
- Floating Mini-Player: Persists playback across the Document Library and Editor views, allowing uninterrupted listening while managing documents.
- MediaSession API Integration: Supports hardware media keys, Bluetooth headset controls, and lock-screen playback controls with real-time scrub state.
- Voice & Engine Picker: Filter and select voices across Universal TTS, Edge TTS, Kokoro, Piper, and Google Cloud, with favorite voice pinning.
6. Local-First Zero-Database Storage¶
- Documents and audio chunks are stored directly on the local filesystem under
/data/documents/<doc_id>/(meta.json,document.md,chunks.json,audio_cache/). - No external relational database (PostgreSQL/MySQL) or Redis instances required.
Architecture Overview¶
┌─────────────────────────────────────────┐
│ Universal Reader (:3003) │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Vite React SPA (Tailwind CSS) │ │
│ └───────────────▲─────────────────┘ │
│ │ /api/* │
│ ┌───────────────▼─────────────────┐ │
│ │ FastAPI Backend Engine │ │
│ └──────┬───────────────┬──────────┘ │
└──────────┼───────────────┼──────────────┘
│ │
OpenAI Speech │ │ Chat Completions
API Proxy │ │ (Auto-title, cleanup)
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Universal TTS │ │ Groq LLM │
│ (Port 8000) │ │ (API Endpoint) │
└──────────────────┘ └──────────────────┘
- Backend: Python 3.11+ / FastAPI, Uvicorn, Pydantic, HTTPX.
- Frontend: React 19, Vite, Tailwind CSS, Lucide Icons, Marked, DOMPurify.
- Port: Serves both API endpoints (
/api/*) and compiled static assets on port9025internally (mapped to3003on the host).
Installation & Setup¶
Option 1: Docker Compose (Recommended)¶
Universal Reader can run standalone or alongside Universal TTS Gateway:
services:
universal-reader:
image: ghcr.io/binuengoor/universal-reader:latest
container_name: universal-reader
restart: unless-stopped
ports:
- "3003:9025"
volumes:
- ./data:/data
environment:
- TTS_BASE_URL=http://universal-tts:8000/v1
- TTS_API_KEY=not-needed
- DEFAULT_MODEL=edge-tts
- DEFAULT_VOICE=en-US-ChristopherNeural
# Optional LLM integration for auto-titling and text cleanup
- LLM_BASE_URL=https://api.groq.com/openai/v1
- LLM_API_KEY=gsk_your_groq_api_key
- LLM_MODEL=qwen/qwen3.8-27b
Start the container:
docker compose up -d
Access the interface in your browser at http://<server-ip>:3003.
Option 2: Full Stack Compose (Universal Reader + Universal TTS)¶
services:
universal-tts:
image: ghcr.io/binuengoor/universal-tts:latest
container_name: universal-tts
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./tts-config.yaml:/app/config.yaml:ro
- ./tts-models:/app/models
universal-reader:
image: ghcr.io/binuengoor/universal-reader:latest
container_name: universal-reader
restart: unless-stopped
ports:
- "3003:9025"
volumes:
- ./reader-data:/data
environment:
- TTS_BASE_URL=http://universal-tts:8000/v1
- DEFAULT_MODEL=edge-tts
- DEFAULT_VOICE=en-US-AriaNeural
depends_on:
- universal-tts
Option 3: Local Development¶
# 1. Clone repository
git clone https://github.com/binuengoor/universal-reader.git
cd universal-reader
# 2. Backend setup
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn backend.main:app --host 0.0.0.0 --port 9025 --reload
# 3. Frontend setup (in a separate terminal)
cd ../frontend
npm install
npm run dev
Keyboard Shortcuts¶
| Shortcut | Action |
|---|---|
| Space | Toggle Play / Pause audio |
| J / K | Skip to Next / Previous sentence block |
| [ / ] | Decrease / Increase playback speed (\(\pm 0.1\times\)) |
| 0 | Reset playback speed to \(1.0\times\) |
| Cmd + F / Ctrl + F | Open in-document search bar |
| Esc | Close side drawers / return to Document Library |
| ? | Toggle Keyboard Shortcuts HUD |
API Reference Overview¶
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Service health status check |
GET |
/api/documents |
List all documents with tags, metadata, and reading progress |
POST |
/api/documents/upload |
Ingest and chunk file (.pdf, .epub, .docx, .md, .txt) |
POST |
/api/documents/url |
Ingest article from URL via Trafilatura |
POST |
/api/documents/create |
Create document from scratchpad note |
GET |
/api/documents/{id} |
Retrieve document content and chunked blocks |
PUT |
/api/documents/{id} |
Edit markdown document and recalculate chunks |
DELETE |
/api/documents/{id} |
Delete document and clear cached audio blocks |
GET |
/api/documents/{id}/blocks/{b}/audio |
Stream or synthesize specific audio chunk |
GET |
/api/documents/{id}/export-audio |
Concatenate and export document narration as a single MP3 |
GET |
/api/settings |
Retrieve active TTS, LLM, and reading preferences |
POST |
/api/settings |
Save preferences to /data/config.json |
GET |
/api/voices |
Proxy voices available in upstream TTS gateway |
GET |
/api/tags |
List all category tags across library |
License¶
Distributed under the MIT License. See LICENSE for details.