Skip to content

About

Firefox extension that reads web pages aloud with Kokoro TTS — run the server on your own machine or in Docker on your home server.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

13 Commits

Folders and files

Repository files navigation

Kokoro Reader

The Kokoro Reader toolbar popup in dark and light themes: playback controls, the sentence currently being read, and voice, speed and volume settings.

A Firefox extension that reads web pages aloud using Kokoro running locally on your own machine. No cloud TTS, no API keys, no telemetry — the page text goes to 127.0.0.1 and nowhere else.

It extracts the article body (not the nav and footer), splits it into sentences, and synthesizes the next few while the current one plays, so playback is continuous instead of pausing between sentences.

Firefox extension  ──POST /tts──>  kokoro_server.py  ──>  Kokoro-82M
  extract.js     page text → chunks      local HTTP, WAV 24 kHz mono
  background.js  queue + prefetch + playback

Two parts, both required: the extension is the front end; the Python server does the synthesis. The extension alone does nothing.

Requirements

  • Firefox 140+
  • Python 3.10+
  • ~400 MB disk for the model (downloaded once, automatically)
  • espeak-ng installed system-wide (Kokoro falls back to it for unusual words) — sudo dnf install espeak-ng / sudo apt install espeak-ng / brew install espeak-ng
  • A GPU is optional. CPU synthesis is roughly real-time; a GPU is comfortably faster.

Install

1. The server

git clone https://github.com/fswolf/kokoro-reader.git
cd kokoro-reader/server
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
./start_server.sh

First start downloads the model and takes a minute. When it prints Kokoro reader server on http://127.0.0.1:8899 it's ready. Check it:

curl -s localhost:8899/health

Leave it running. If you'd rather not keep a terminal open, see Tray app below, or the systemd unit at the bottom of this file.

2. The extension

Grab the signed .xpi from Releases, then in Firefox: about:addons → gear icon → Install Add-on From File.

Or load it from source (for development)

about:debugging#/runtime/this-firefox → Load Temporary Add-on → pick extension/manifest.json. This version disappears when Firefox restarts.

Use

Ctrl+Shift+U read page / pause / resume
Ctrl+Shift+Y stop
Toolbar button same, plus voice, speed and volume
Right-click a selection Read selection with Kokoro

The dot beside the popup title is green when the server is reachable. Changing voice or speed re-synthesizes the current sentence immediately, so you can audition voices mid-page.

Default voice is am_adam. Also good: am_michael, am_onyx, bm_george, bm_lewis (male), af_bella, af_heart, bf_emma (female). The popup lists whatever the server reports.

Tray app

Optional. server/kokoro_tray.py runs the server as a child process and puts it in the system tray, so it starts from your app launcher instead of a terminal. The menu has a live status line, start/stop/restart, test voice, and quit (which stops the server too).

sudo dnf install python3-gobject libayatana-appindicator-gtk3
# Debian/Ubuntu: sudo apt install python3-gi gir1.2-ayatanaappindicator3-0.1

cp server/kokoro-reader-tray.desktop ~/.local/share/applications/
update-desktop-database ~/.local/share/applications

Then launch "Kokoro Reader" from your launcher.

  • The .desktop file assumes the repo is at ~/kokoro-reader. Elsewhere, edit its Exec= line — and quote the path if it contains spaces, because Exec splits on whitespace and an unquoted path fails silently: Exec=python3 "/home/you/My Projects/kokoro-reader/server/kokoro_tray.py"
  • On Wayland the tray is your bar's job: Waybar needs "tray" in modules-right, or the app runs but nothing draws the icon.
  • KOKORO_TRAY_AUTOSTART=0 starts the tray without starting the server.
  • Nothing happens when launched? Run python3 server/kokoro_tray.py to see the error.

macOS

Server and extension work the same. Three differences.

Dependencies via Homebrew:

brew install python espeak-ng

No tray app — kokoro_tray.py needs GTK and AppIndicator, which are Linux-only. Run server/start_server.sh from Terminal, or start it at login with launchd:

<!-- ~/Library/LaunchAgents/local.kokoro-reader.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
  <key>Label</key>            <string>local.kokoro-reader</string>
  <key>ProgramArguments</key> <array>
    <string>/Users/YOU/kokoro-reader/server/start_server.sh</string>
  </array>
  <key>RunAtLoad</key>        <true/>
  <key>KeepAlive</key>        <true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/local.kokoro-reader.plist

Apple Silicon — set KOKORO_DEVICE=mps in start_server.sh to use the GPU via Metal. Leave it unset for CPU if torch complains.

Docker (Unraid)

Running the server on a NAS keeps it always-on and lets every machine on the LAN use it. A prebuilt image is published to ghcr.io/fswolf/kokoro-reader on every push, so there's nothing to build.

Docker tab → Add Container, then:

Field Value
Name kokoro-reader
Icon URL https://raw.githubusercontent.com/fswolf/kokoro-reader/main/docs/icon.png (Advanced View)
Repository ghcr.io/fswolf/kokoro-reader:latest
Network Type Host

Add two entries with Add another Path, Port, Variable, Label or Device:

Config Type Name Key / Container Path Value / Host Path
Path Model Cache /cache/huggingface /mnt/user/appdata/kokoro-reader/cache
Variable CPU Threads OMP_NUM_THREADS 6

Apply. The image is ~1.5 GB, and the first start downloads the model (~330 MB), so give it a minute, then:

curl -s http://YOUR-SERVER:8899/health

Put that URL in the extension popup under Server. Firefox prompts for permission to reach the host — the manifest grants only loopback up front.

  • Network Type. Host needs no port mapping. With Bridge, add a Port: container 8899, host 8899, TCP.
  • Model Cache keeps the weights across container updates. Without it they re-download every time.
  • CPU Threads — set it to your number of performance cores, not total threads. On hybrid Intel chips (12th gen and later), extra threads land on E-cores and every sentence waits for the slowest one. Measured on an i5-12600K (6 P-cores): 6 threads ≈ 0.5 s per sentence, 8 threads ≈ 0.9 s.
  • Updates. Push to main → GitHub rebuilds the image → Unraid shows "update ready".

Check synthesis speed before committing to it. Latency lands right before each sentence, and a NAS CPU is usually slower than a desktop:

time curl -s -X POST http://YOUR-SERVER:8899/tts \
  -H 'Content-Type: application/json' \
  -d '{"text":"The quick brown fox jumps over the lazy dog."}' -o /dev/null

Under a second for that sentence and the extension's prefetch hides it entirely.

Building the image yourself / Docker Compose

docker/docker-compose.yml builds from source — use it with Unraid's Compose Manager plugin or plain docker compose. Clone the repo, point context at it, and Compose Up.

git clone https://github.com/fswolf/kokoro-reader.git /mnt/user/appdata/kokoro-reader/src
docker build -f docker/Dockerfile -t kokoro-reader:latest /mnt/user/appdata/kokoro-reader/src

KOKORO_HOST must be 0.0.0.0 inside the container or a published port reaches nothing — the image sets it. If a build fails on a dependency, try python:3.11-slim in the Dockerfile.

Configuration

Server, via env vars (set them in server/start_server.sh):

Variable Default
KOKORO_PORT 8899
KOKORO_VOICE am_adam default voice
KOKORO_LANG a a American, b British, plus others Kokoro supports
KOKORO_DEVICE auto set cuda to force GPU
KOKORO_HOST 127.0.0.1 leave it — see Security

Extension, in the popup: voice, speed, volume, and the server URL.

Tuning

  • Chunk size — MAX = 300 / HARD = 420 in extension/extract.js. Smaller starts talking sooner but breaks prosody more often between sentences.
  • Lookahead — lookahead: 2 in extension/background.js. Each chunk in flight is one request; raise it on a GPU so synthesis stays ahead of playback.
  • Extraction misses the article — pickRoot() scores candidates by paragraph text length with a link-density penalty and prefers <article>/<main>. Sites with unusual markup may need a selector added to the explicit query.
  • Abbreviations read as letters — protect() hides dots inside e.g., U.S., Dr., decimals and initials so the sentence splitter can't break them. Add cases to ABBR.

Security

The server binds to 127.0.0.1 and has no authentication, which is fine for a loopback socket. Don't change KOKORO_HOST to 0.0.0.0 on a shared or untrusted network — that would let anyone on it synthesize arbitrary text on your machine.

Running it in Docker does expose it, by necessity — the container binds 0.0.0.0 so the published port works. That's reasonable on a home LAN and the same posture as most NAS services, but keep the port off the internet: don't forward it, and don't put it behind a public reverse proxy without adding auth in front.

The extension declares data_collection_permissions: none and means it: page text is POSTed to your local server, nothing is stored, nothing leaves the machine.

Known limitations

  • Can't read PDFs or about: pages — Firefox doesn't allow script injection there.
  • No word or sentence highlighting yet.
  • Reads the whole extracted article from the top; no read-from-click-point.
  • If the server logs 200 but you hear nothing, it's Firefox's autoplay policy on the background page — set media.autoplay.default to 0 in about:config.

Run the server on login

# ~/.config/systemd/user/kokoro-reader.service
[Unit]
Description=Kokoro Reader TTS server

[Service]
ExecStart=%h/kokoro-reader/server/start_server.sh
Restart=on-failure

[Install]
WantedBy=default.target
systemctl --user enable --now kokoro-reader

Building and signing

Firefox won't permanently install an unsigned add-on. To build your own signed copy, get API credentials from AMO:

npm i -g web-ext
cd extension
export WEB_EXT_API_KEY='user:...' WEB_EXT_API_SECRET='...'
web-ext sign --channel=unlisted

Support

If Kokoro Reader is useful to you, you can sponsor its development:

Sponsor

License

MIT — see LICENSE.

Kokoro-82M is by hexgrad, Apache 2.0.

About

Firefox extension that reads web pages aloud with Kokoro TTS — run the server on your own machine or in Docker on your home server.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages