Repository: github.com/SkyeClover/AudibleFromTheCommandLine
Terminal-first helper for your Audible library: sign in once (including SMS / authenticator prompts), index titles and ASINs into a local SQLite database, then open the normal web player by title without clicking through the library every time.
Playback still happens in a browser (Chromium/Chrome/Edge when available, otherwise your OS default). DRM stays in the browser. This project is not affiliated with Audible or Amazon and is not an official product; the library list uses the unofficial audible Python package (internal API), which can break if Amazon changes endpoints or policies.
Contributing: see CONTRIBUTING.md. Security: see SECURITY.md.
- Run
audctlwith no arguments (oraudctl setupfirst if you prefer explicit steps). - If no API credentials exist yet, you are prompted for email and password (password is hidden). Amazon may ask for authenticator codes, SMS/email codes, or a CAPTCHA—follow the on-screen prompts. Wrong password / account lockouts surface as clear errors instead of a generic failure. At the SMS/email verification step, the tool submits Amazon’s page first (so a code can actually be sent), then offers
[r]resend if the page exposes a resend control—if nothing arrives, check spam, wait a minute, confirm-mmarketplace matches your account, or finish sign-in in a normal browser. - You are offered a browser for a one-time web login as well (Chromium/Chrome/Edge when available, otherwise the OS default—see
AUDCTL_PREFER_DEFAULT_BROWSER). Accept unless you only care about metadata: the web player needs browser cookies for audio. - Your library is synced into
$XDG_STATE_HOME/audctl/library.db(ASIN, title, authors, narrators, runtime when the API returns them). - A terminal UI opens: filter with
/, S sync, T toggle “tracked”, P open the web player for the selected row (same browser strategy asaudctl play).
- Run
audctl(oraudctl tui) to open the same UI. Useaudctl syncto refresh the index after new purchases.
After sync, audctl play --title "…" resolves against the SQLite index (tracked titles first), then opens /webplayer?asin=…. If Chromium/Chrome/Edge is not on PATH, audctl play falls back to the system default browser using the same multi-strategy opener as web login (webbrowser, then Windows start / rundll32, xdg-open, etc.). If every method fails, the URL is printed and the command exits with code 7—set AUDCTL_CHROMIUM_BINARY or open the printed URL manually.
From the project directory (with your venv activated if you use one):
audctl reset --force --yes --purge-browser-profileThat removes API credentials (audible_credentials.json), library index (library.db), optional legacy library_index.json, and optionally the audctl Chromium profile (web cookies). It does not delete $XDG_CONFIG_HOME/audctl/config.toml (marketplace, paths, etc.).
Then run:
audctlYou should get the first-time prompts again (or run audctl setup explicitly).
| Goal | Command |
|---|---|
| Full local reset (re-test setup from scratch) | audctl reset --force then confirm; add --yes to skip the prompt; add --purge-browser-profile to also wipe the Chromium data dir. |
Web session only (Chromium cookies for audctl play) |
Sign out in the browser, or audctl logout --purge-profile --force. |
| Amazon account | Use Amazon / Audible account pages to sign out or remove “Audible on iPhone” style devices; audctl cannot change your Amazon password. |
- Python 3.10 or newer (3.13 supported; the
audiblewheel set may lag on very new interpreters—see PyPI). - Network access for login and sync.
From a clone of the GitHub repository:
git clone https://github.com/SkyeClover/AudibleFromTheCommandLine.git
cd AudibleFromTheCommandLine
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"Or install from the clone root with pipx (no dev extras):
cd AudibleFromTheCommandLine
pipx install .Entry point: audctl (or python -m audctl).
| Key | Action |
|---|---|
/ |
Focus the filter box |
S |
Re-sync library from Audible (background) |
T |
Toggle “tracked” for the highlighted row |
P |
Open web player for that ASIN (Chromium or default browser) |
Q |
Quit |
| Command | Description |
|---|---|
| (no args) | First-time setup if needed, then TUI. |
audctl setup |
API login wizard (-m / --marketplace for country code). |
audctl sync |
Refresh SQLite index from your library. |
audctl tui |
Open the TUI only. |
audctl login |
Web sign-in for playback cookies (Chromium when available, else default browser). |
audctl play / resolve / urls / stop / … |
Same as before (see --help). |
audctl init-config |
Write config.toml (--marketplace sets host + country together). |
audctl status |
Profile paths, API credential presence, library row count. |
audctl reset |
Delete local credentials + library DB (+ optional --purge-browser-profile). Requires --force; use --yes for scripts. |
audctl logout |
Instructions, or --purge-profile --force to delete only the Chromium profile. |
audctl serve |
HTTP JSON API on http://127.0.0.1:8765 by default (see below). |
Use a systemd user unit so the API survives reboots after you log in (or use linger so it starts at boot without a GUI session).
cd ~/AudibleFromTheCommandLine
python3 -m venv .venv && .venv/bin/pip install -e .
mkdir -p ~/.config/systemd/user
cp deploy/systemd/audctl-serve.service ~/.config/systemd/user/
# Edit the file if your clone path is not ~/AudibleFromTheCommandLine
systemctl --user daemon-reload
systemctl --user enable --now audctl-serve.serviceBoot before any user logs in (headless or pre-login):
sudo loginctl enable-linger "$USER"Optional secrets (e.g. AUDCTL_HTTP_TOKEN): add EnvironmentFile=-%h/AudibleFromTheCommandLine/deploy/audctl-serve.env under [Service] in the unit, then create that file with KEY=value lines.
If you prefer a container (Chromium inside the image + host X11 + bind-mounted audctl config/state), use deploy/docker-compose.yml. Copy deploy/audctl-docker.env.example → deploy/.env, adjust paths, then:
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --buildThis publishes 8765 on the host. Axiom in Docker can use http://host.docker.internal:8765/v1/play. The image uses Debian’s /usr/bin/chromium (not snap); your mounted profile directory should be the one audctl is configured to use.
Run on the machine that has your Audible login / browser (or use host.docker.internal from a container with correct networking).
audctl serve --host 127.0.0.1 --port 8765Use --host 0.0.0.0 --port 8765 only when other machines or Docker containers must reach the API on the LAN (prefer firewall + AUDCTL_HTTP_TOKEN).
Discovery: GET / returns a list of routes and short descriptions.
| Method | Path | Body (JSON) | Response |
|---|---|---|---|
GET |
/ |
— | Service name, version, endpoint list. |
GET |
/health |
— | { "status": "ok" } |
GET |
/v1/status |
— | Same fields as audctl status (paths, library_items, credentials present, …). |
POST |
/v1/play |
{ "asin": "B0…" } and/or { "title": "…" }, optional headless, offscreen, offscreen_position |
Opens web player or search; search defaults to offscreen when not headless. Returns via, pid, url, asin, resolver. |
POST |
/v1/stop |
{ "signal": "term" } or "kill" |
Best-effort: signals Chromium using the configured profile (see audctl stop). |
POST |
/v1/sync |
{} |
Refreshes library DB (requires prior audctl setup). |
POST |
/v1/resolve |
{ "title": "…" } and/or { "asin": "B0…" } |
{ "ok": true, "result": { … } } (same shape as CLI resolve --json). |
Examples:
curl -sS http://127.0.0.1:8765/
curl -sS http://127.0.0.1:8765/v1/status
curl -sS -X POST http://127.0.0.1:8765/v1/play -H 'Content-Type: application/json' -d '{"asin":"B012345678","headless":false}'
curl -sS -X POST http://127.0.0.1:8765/v1/play -H 'Content-Type: application/json' -d '{"title":"Some Book","offscreen":true}'
curl -sS -X POST http://127.0.0.1:8765/v1/stop -H 'Content-Type: application/json' -d '{"signal":"term"}'
curl -sS -X POST http://127.0.0.1:8765/v1/resolve -H 'Content-Type: application/json' -d '{"title":"Some Book"}'
curl -sS -X POST http://127.0.0.1:8765/v1/sync -H 'Content-Type: application/json' -d '{}'Security: by default there is no authentication and responses use CORS * for simple local scripting. Set AUDCTL_HTTP_TOKEN to require Authorization: Bearer <token> on every route except GET / and GET /health. Bind to 127.0.0.1 only; if you must expose the API, put TLS + auth (reverse proxy, API gateway) in front.
| Area | Works | Caveats |
|---|---|---|
| Library index | audctl sync via unofficial audible client; SQLite for fast local match. |
Subject to Amazon / Audible changes; respect their ToS. |
| 2FA / SMS | Prompted in the terminal during setup. |
CAPTCHA flows may need you to read a URL or image per Amazon’s challenge. |
| Playback | Chromium + official web player URL. | Separate from API tokens—you still need a logged-in browser profile for audio. |
| Snap Chromium | SNAP_USER_COMMON default profile path. |
You may need AUDCTL_CHROMIUM_PROFILE_DIR under ~/snap/chromium/common/… if SingletonLock errors appear. |
| Variable / file | Purpose |
|---|---|
$XDG_CONFIG_HOME/audctl/config.toml |
audible_host, marketplace_country, chromium_profile_dir, etc. |
$AUDCTL_MARKETPLACE |
Marketplace country code (us, uk, …). |
$AUDCTL_AUDIBLE_HOST |
Override web host for player URLs. |
$AUDCTL_CHROMIUM_PROFILE_DIR |
Chromium profile for web session. |
$AUDCTL_PREFER_DEFAULT_BROWSER |
If 1 / true, skip Chromium and always use the OS default browser for web login. |
$AUDCTL_ALLOW_SEARCH_SCRAPE |
Last-resort HTML search for resolve when nothing else matches. |
$AUDCTL_HTTP_TOKEN |
If set, audctl serve requires Authorization: Bearer … (except GET / and GET /health). |
$AUDCTL_CHROME_OFFSCREEN_POSITION |
X,Y for --offscreen Chromium launches (default 10000,200). |
$AUDCTL_LIBRARY_INDEX |
Legacy JSON [{title, asin}] if you still use it (SQLite is preferred). |
API credentials are stored under $XDG_STATE_HOME/audctl/audible_credentials.json (encrypted by the audible library). Config files written by audctl init-config use mode 600 on POSIX.
MIT — see LICENSE. Changelog: CHANGELOG.md.
python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytestSee CONTRIBUTING.md for branching, PR expectations, and the checklist after you create the GitHub remote (e.g. add [project.urls] in pyproject.toml). CI runs pytest on Ubuntu and Windows for Python 3.10–3.13 (see .github/workflows/ci.yml).
- MPRIS /
playerctlfor pause–resume. - Home Assistant–friendly envelopes for
serve.