bookpeek
bookpeek scans the opening seconds of an audiobook and extracts the spoken
title, title candidates, authors, and narrators without requiring an online AI
service or API key. By default it runs Whisper and Vosk together, merges their
extraction evidence, and keeps both raw transcripts under transcripts. Long
pauses in the intro become hard sentence breaks so cues like read by … do not
swallow the next section. Title candidates can come from Audible-style
introductions, ID3 tags, filenames, folders, and chapter text, with scores
indicating which candidate was preferred.
Online results are grouped by provider under online_matches, with separate
authors and works arrays. Goodreads author results with zero similarity
are omitted when any positive-scoring author exists; otherwise authors with at
least ten works are retained as a fallback.
The result's top-level title, author, and narrators fields contain the
final values after provider validation (narrators are de-duplicated
case-insensitively with proper name casing). The nested extraction object
remains the unmodified transcript/metadata extraction.
Audnexus results appear under online_matches.audnexus.works and include
matched Audible identifiers, authors, narrators, region, and confidence scores.
Verified narrator names are also collected under
online_matches.audnexus.narrators.
Install
First-time setup
There are only two steps:
- Install
ffmpeg, which decodes audiobook files:
# macOS with Homebrew
brew install ffmpeg
# Debian/Ubuntu
sudo apt update && sudo apt install ffmpeg
- Run the installer:
./install.sh
The installer bootstraps Poetry if necessary, installs Whisper and Vosk plus
online enrichment, downloads spaCy's English model, and creates
~/.local/bin/bookpeek. ASR model weights are not downloaded during
install; the first bookpeek scan prompts for them (or use -d to download
automatically). If ffmpeg is missing, the installer prints the appropriate
commands and exits. Add ~/.local/bin to your PATH if the bookpeek
command is not found.
# Skip Open Library / Goodreads packages (ASR engines are still installed):
./install.sh --offline
On Apple Silicon, Whisper uses Metal automatically when device = "auto".
Vosk is installed from the matching bookpeek GitHub Release wheel because
upstream PyPI does not publish macOS arm64 wheels for 0.3.45. Whisper and Vosk
model files download into ~/.config/bookpeek/models/ (and the usual Hugging
Face cache for Whisper) on first use.
Usage
By default, bookpeek uses both Whisper and Vosk. Pass --engine whisper or
--engine vosk to use only one backend. It scans 30 seconds first; if that
only produces an Audible bumper such as This is Audible, it automatically
retries at 60 seconds and then 90 seconds. A normal introduction stops after
the first successful scan.
# Scan an audiobook file (Whisper + Vosk by default, then merge evidence):
bookpeek scan /path/to/book.m4b
# Scan a folder; bookpeek uses the first audio file alphabetically:
bookpeek scan /path/to/audiobook-folder/
# Use only the small CPU-friendly Vosk engine:
bookpeek scan /path/to/book.m4b --seconds 42 --engine vosk
# Force Whisper's tiny English model on the CPU:
bookpeek scan /path/to/book.m4b --engine whisper --model tiny.en --device cpu
# Choose Whisper and Vosk models independently for the default dual scan:
bookpeek scan /path/to/book.m4b --whisper-model base.en --vosk-model vosk-model-small-en-us-0.15
# Automatically download any missing ASR models (Vosk zip / Whisper weights).
# Vosk models are stored under ~/.config/bookpeek/models/ next to config.toml:
bookpeek scan /path/to/book.m4b -d
# Search (only) the specific Audible regions, in this order:
bookpeek scan /path/to/book.m4b --regions uk,ca,au
# Enable Open Library, Goodreads, and Audnexus enrichment for this scan:
bookpeek scan /path/to/book.m4b -w
# Force a completely offline scan, even if config enables enrichment:
bookpeek scan /path/to/book.m4b --offline
# Print the active configuration:
bookpeek config show
# Create a new config file with bookpeek's defaults:
# (Saves to ~/.config/bookpeek/config.toml; use --force to overwrite.)
bookpeek config new
Example response
The JSON result includes the extracted metadata and online provider matches:
{
"path": "/path/to/The Blighted Stars.m4b",
"title": "The Blighted Stars (The Devoured Worlds, #1)",
"author": "Megan E. O'Keefe",
"narrators": [
"Ciaran Saward"
],
"extraction": {
"title": "The Blighted Stars",
"title_candidates": [
{
"text": "The Blighted Stars",
"source": "id3_title",
"score": 0.9
},
{
"text": "The Devoured Worlds 01 - The Blighted Stars",
"source": "folder",
"score": 0.65
}
],
"author": "Megan E. O'Keefe",
"narrators": [
"Kieran Sord"
]
},
"online_matches": {
"audnexus": {
"authors": [
{
"asin": "B00IMSE6VQ",
"name": "Megan E. O'Keefe",
"region": "us",
"score": 1.0
}
],
"works": [
{
"asin": "B0BJ4JLW57",
"title": "The Blighted Stars",
"authors": ["Megan E. O'Keefe"],
"narrators": ["Ciaran Saward"],
"region": "us",
"isbn": "9781668615331",
"score": 0.933,
"narrator_score": 0.667,
"match_reason": "title_author"
}
],
"narrators": ["Ciaran Saward"]
},
"goodreads": {
"authors": [],
"works": [
{
"title": "The Blighted Stars (The Devoured Worlds, #1)",
"title_complete": "The Blighted Stars (The Devoured Worlds, #1)",
"author": "Megan E. O'Keefe",
"score": 0.857
}
]
},
"openlibrary": {
"authors": [],
"works": [
{
"title": "Devoured Worlds Series, 3-book collection ...",
"author": "Megan E. O'Keefe",
"score": 0.632
}
]
}
}
}
Configuration is read from ~/.config/bookpeek/config.toml; command-line
options override it. Downloaded Vosk models are stored under
~/.config/bookpeek/models/ so config and models share one directory tree.
bookpeek config new creates that file with the default settings. It will not
overwrite an existing config unless bookpeek config new --force is used.
[asr]
engine = "both"
whisper_model = "tiny.en"
vosk_model = "vosk-model-small-en-us-0.15"
device = "auto"
seconds = 30
[extract]
spacy_model = "en_core_web_sm"
[enrich]
enabled = false # set true to always perform web lookup
openlibrary = true
goodreads = true
audnexus = true
# Search order matters: earlier regions win ties and are returned first.
audible_regions = ["us", "uk", "ca", "au"]
Supported Audnexus/Audible regions are us, uk, ca, and au.
audible_regions is an ordered priority list, not just a set of enabled
regions: if equivalent matches are found in multiple stores, the first
region listed wins and its result is returned first. --regions replaces this
priority order for one scan, so --regions ca,us gives Canada precedence over
the US.
-w / --online may query Open Library, Goodreads, and Audnexus. Goodreads
support is installed as a package dependency. Set
[enrich].enabled = true to perform that lookup on every scan without passing
the flag. Use --offline to override that setting for a single scan. Narrator
lookup is performed through Audible catalog search followed by Audnexus
metadata lookup when matching is enabled.
CI and PyPI releases
GitHub Actions runs tests, Ruff, and mypy on pushes to main and pull
requests. After those checks pass, a change to the package version on main
automatically creates the matching GitHub release, which triggers PyPI
publishing through Trusted Publishing.
To release a new version:
poetry run python scripts/set_version.py 0.2.0
git add pyproject.toml src/bookpeek/__init__.py
git commit -m "Bump package version"
git push origin main
The repository's PyPI project must have a Trusted Publisher configured for the
GitHub repository, workflow .github/workflows/publish.yml, and pypi
environment before the first release.
Homebrew releases update brandonscript/homebrew-tap automatically when the
HOMEBREW_TAP_TOKEN repository secret is configured. The token needs
fine-grained Contents: Read and write access to that tap repository. Without
the secret, the Python release still succeeds and CI reports that the tap
update was skipped.
Development
poetry run pytest
poetry run ruff check .
poetry run mypy src/
The provider URL smoke test is opt-in because it makes network requests:
BOOKPEEK_LIVE=1 poetry run pytest tests/test_urls_live.py
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bookpeek-0.2.0.tar.gz.
File metadata
- Download URL: bookpeek-0.2.0.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba0df4d99c07dd5628291c7e65731917407e967335b83b10a1cf6c7c7ed57d83
|
|
| MD5 |
04b0b236dabfeb9cb93cc2d502cda6af
|
|
| BLAKE2b-256 |
161d7b72d2557d640d36afd3adaa87c31de23bae1228ad62ea28c27168f477a0
|
Provenance
The following attestation bundles were made for bookpeek-0.2.0.tar.gz:
Publisher:
publish.yml on brandonscript/bookpeek
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bookpeek-0.2.0.tar.gz -
Subject digest:
ba0df4d99c07dd5628291c7e65731917407e967335b83b10a1cf6c7c7ed57d83 - Sigstore transparency entry: 2398406405
- Sigstore integration time:
-
Permalink:
brandonscript/bookpeek@8972838ec321907c74a5d5fa1f07da2d84ab0fd7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brandonscript
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8972838ec321907c74a5d5fa1f07da2d84ab0fd7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file bookpeek-0.2.0-py3-none-any.whl.
File metadata
- Download URL: bookpeek-0.2.0-py3-none-any.whl
- Upload date:
- Size: 33.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
262c4e75041313f6034122edbc6a5faab2be4e5b2654c2a6d7b53750dc47dc6a
|
|
| MD5 |
dd38726fd8d186059a9854291b9af141
|
|
| BLAKE2b-256 |
da6fef290e45849648fd6c623ee2881d3932a3104cfec30ca2a1d33c7ad94e3c
|
Provenance
The following attestation bundles were made for bookpeek-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on brandonscript/bookpeek
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bookpeek-0.2.0-py3-none-any.whl -
Subject digest:
262c4e75041313f6034122edbc6a5faab2be4e5b2654c2a6d7b53750dc47dc6a - Sigstore transparency entry: 2398407351
- Sigstore integration time:
-
Permalink:
brandonscript/bookpeek@8972838ec321907c74a5d5fa1f07da2d84ab0fd7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brandonscript
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8972838ec321907c74a5d5fa1f07da2d84ab0fd7 -
Trigger Event:
release
-
Statement type: