Metadata-Version: 2.3
Name: dpo-reader
Version: 0.1.0
Summary: Convert Discourse threads to multi-voice audio using TTS
Keywords: discourse,tts,text-to-speech,audio,bark,piper
Author: Jacob Coffee
Author-email: Jacob Coffee <jacob@z7x.org>
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Dist: httpx>=0.27
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: scipy>=1.11
Requires-Dist: numpy>=1.24
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.12
Requires-Dist: textual>=0.50
Requires-Dist: sounddevice>=0.4
Requires-Dist: bark>=0.1
Requires-Dist: dpo-reader[piper] ; extra == 'all'
Requires-Dist: piper-tts>=1.2 ; extra == 'piper'
Requires-Python: >=3.10, <3.14
Project-URL: Repository, https://github.com/JacobCoffee/dpo-reader
Project-URL: Documentation, https://jacobcoffee.github.io/dpo-reader
Project-URL: Issue Tracker, https://github.com/JacobCoffee/dpo-reader/issues
Provides-Extra: all
Provides-Extra: piper
Description-Content-Type: text/markdown

# DPO Reader

<p align="center">
  <em>Turn Discourse threads into podcasts. Each author gets their own voice.</em>
</p>

<p align="center">
  <a href="https://pypi.org/project/dpo-reader/">
    <img src="https://img.shields.io/pypi/v/dpo-reader.svg" alt="PyPI Version">
  </a>
  <a href="https://pypi.org/project/dpo-reader/">
    <img src="https://img.shields.io/pypi/pyversions/dpo-reader.svg" alt="Python Versions">
  </a>
  <a href="https://github.com/JacobCoffee/dpo-reader/blob/main/LICENSE">
    <img src="https://img.shields.io/github/license/JacobCoffee/dpo-reader.svg" alt="License">
  </a>
</p>

---

I got tired of skimming long forum threads. DPO Reader converts them to audio so I can listen while doing other things. Point it at any Discourse thread and it'll synthesize the whole thing with different voices for each participant.

## Install

```bash
# uv (recommended)
uv tool install dpo-reader

# Or run directly without installing
uvx dpo-reader listen "https://discuss.python.org/t/your-thread"

# pipx works too
pipx install dpo-reader
```

## Usage

```bash
# Basic: generate audio and play it
dpo-reader listen "https://discuss.python.org/t/your-thread"

# Interactive TUI with read-along highlighting
dpo-reader listen "https://discuss.python.org/t/your-thread" --ui

# Start from a specific post (the /50 in the URL does this automatically)
dpo-reader listen "https://discuss.python.org/t/your-thread/12345/50" --ui

# Or explicitly with -s
dpo-reader listen "https://discuss.python.org/t/your-thread" -s 50

# Export without playing
dpo-reader export "https://discuss.python.org/t/your-thread" -o thread.wav

# See what you're getting into before generating
dpo-reader info "https://discuss.python.org/t/your-thread"
dpo-reader preview "https://discuss.python.org/t/your-thread"
```

## Options

```
-o, --output PATH         Output file (default: output.wav)
-e, --engine ENGINE       openai | bark | piper
-s, --start-post INT      Start from this post number
-n, --max-posts INT       Limit number of posts
--ui                      Interactive TUI with controls
--no-attribution          Skip "Author says:" prefix
--no-play                 Don't auto-play after generating
-c, --cache-dir PATH      Cache audio chunks (useful if generation crashes)
-p, --pause FLOAT         Seconds between posts (default: 1.5)
-f, --file PATH           Load from local JSON (testing)
```

## TTS Engines

| Engine | Quality | Speed | Notes |
|--------|---------|-------|-------|
| OpenAI | Best | Fast | Needs API key, costs money |
| Bark | Excellent | Slow (~10s/sentence) | Local, wants a GPU |
| Piper | Good | Fast (~0.1s/sentence) | Local, CPU-only |

**Bark** is the default. It runs locally and produces natural-sounding speech with good intonation. A GPU helps a lot but isn't strictly required.

**OpenAI** (`-e openai`) sounds the best if you have an API key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) and set `OPENAI_API_KEY` in your environment or a `.env` file.

**Piper** (`-e piper`) is the lightweight option. Install with `uv pip install dpo-reader[piper]`. Good for batch processing or machines without GPUs.

## TUI Controls

When using `--ui`:

| Key | Action |
|-----|--------|
| Space | Play/Pause |
| ←/→ | Skip 5 seconds |
| ↑/↓ | Speed up/down |
| n/p | Next/Previous post |
| l | Toggle logs |
| q | Quit |

## Requirements

Python 3.10-3.13. The `onnxruntime` dependency doesn't support 3.14 yet.

## Development

```bash
git clone https://github.com/JacobCoffee/dpo-reader.git
cd dpo-reader
make dev

make lint        # Linting
make type-check  # Type checking
make test        # Tests
make ci          # All of the above

# Test TTS locally
make test-listen  # Piper
make test-bark    # Bark
```

## License

MIT
