libex-core
The Audible metadata library and libex-core command line behind
Libex. It runs on your own machine,
fetches from Audible, and returns the same JSON shapes the Libex API
publishes: books, chapters, series, authors, narrators, search and new
releases, in all eleven Audible marketplaces (us uk ca au de fr it es jp in br).
Libex also runs as a hosted API, and a free public instance is at libexdb.com. You do not need it to use this package.
pip install libex is a different, unrelated project. This one is
libex-core.
Install
pip install libex-core
pip install "libex-core[storage]" # adds the optional local store (SQLite)
pip install "libex-core[postgres]" # the store, with Postgres as well
Python 3.12 or newer. The base install depends on httpx and pydantic
only. The libex-core command is installed with the package, extras or not.
Set up the network first
Every request goes to Audible from this machine. Audible sees the address it comes from together with what you look up, which is part of your reading history tied to your connection, so the package makes you decide how to connect before it sends anything. The command line reads two environment variables, never an option, because a proxy URL can carry credentials that other processes could read from a command line:
| Variable | Meaning |
|---|---|
LIBEX_CORE_PROXY_URL |
An http:// or https:// proxy every request goes through. May carry credentials. |
LIBEX_CORE_ALLOW_DIRECT_EGRESS |
1, true, yes or on lets requests leave from this machine's own address when no proxy is set. Anything else, or unset, refuses. |
export LIBEX_CORE_PROXY_URL="http://user:password@proxy.example:8080"
libex-core config # {"transport":{"mode":"proxy","host":"proxy.example"}}
# or, knowing what it means:
export LIBEX_CORE_ALLOW_DIRECT_EGRESS=1
With neither set, a command that needs Audible exits with status 5 and says
what to set. libex-core config makes no request and never prints the proxy
URL. What Audible and a proxy can see is described in the
privacy notice.
Command line
Results are JSON on standard output; logs and errors go to standard error.
--region defaults to us. Book ASINs belong to one marketplace, so use the
region the book was published in.
libex-core book get ASIN --region us
libex-core book bulk ASIN1 ASIN2 --sort rating --order desc
libex-core book bulk --file asins.txt --language english
libex-core book chapters ASIN
libex-core series get SERIES_ASIN
libex-core series books SERIES_ASIN
libex-core series search "Mistborn"
libex-core author get B001IGFHW6
libex-core author search "Sanderson"
libex-core author books B001IGFHW6 --sort releaseDate
libex-core author books-by-name "Brandon Sanderson"
libex-core narrator books "Michael Kramer"
libex-core search --title "Hobbit" --author "Tolkien" --limit 5
libex-core quick-search "project hail mary"
libex-core abs search --title "Hobbit"
libex-core abs quick-search --keywords "project hail mary"
libex-core releases new --days 30
libex-core releases coming-soon --days 90 --category ID
libex-core releases categories --flat
libex-core COMMAND --help lists every option, including the filters
(--language, --genre, --longer-than and others) and --sort / --order
that the list commands share. libex-core completion bash (also zsh,
fish) prints a completion script.
When a list of books may not be whole, it is still printed, a notice naming why goes to standard error, and the status is 0.
Exit status
| Status | Meaning |
|---|---|
| 0 | Succeeded. |
| 1 | Unexpected error. Rerun with -vv for a traceback. |
| 2 | The command line was not understood, or an argument was rejected. |
| 3 | The requested item does not exist, or nothing matched. |
| 4 | Audible could not be reached or did not answer. Retrying later may succeed. |
| 5 | Configuration is missing or invalid, or the local store is off, missing its extra, unreachable or not ready. |
| 130 | Interrupted. |
| 141 | The reader of standard output went away. |
Local store
By default nothing is kept. Setting LIBEX_CORE_STORAGE turns on a local
database that lookups write what Audible answered into, under the same merge
rules as the hosted service, and that serves the stored copy when Audible is
unreachable. It needs the
storage extra.
LIBEX_CORE_STORAGE |
Store |
|---|---|
unset, empty or off |
none (default) |
sqlite |
libex.db in your user data directory: ~/.local/share/libex-core/ on Linux (or under $XDG_DATA_HOME), ~/Library/Application Support/libex-core/ on macOS, %LOCALAPPDATA%\libex-core\ on Windows |
| an absolute path | that SQLite file |
a sqlite:/// or postgresql:// URL |
that database (postgres extra for Postgres) |
export LIBEX_CORE_STORAGE=sqlite
libex-core db upgrade # creates the file; the only command that changes the schema
libex-core db status # exits 0 only when the store is ready
libex-core book get ASIN # now also stored
libex-core db book ASIN # read back from the store, no request to Audible
The other db commands read what is stored without contacting Audible:
books, chapters, author, author-books, series, series-books,
narrators, narrator-books, genres, plans, plan, vvab,
new-releases, coming-soon and stats. Each prints the shape of the hosted
API's /db route of the same name and exits 3 when it finds nothing. The
store is never upgraded implicitly, and a database that holds tables this
package did not create is refused untouched.
The store is a plaintext record of what you have looked up. On Linux and
macOS a new SQLite file is created readable by you only. The storage setting
can carry database credentials, so it is read from the environment, never
accepted as an option, and never printed. To delete a SQLite store, remove
the file and its -wal and -shm companions beside it.
Use it as a library
import asyncio
from libex_core.audible.client import LibexClient
from libex_core.exceptions import LibexException
from libex_core.lookup import get_book, search
async def main() -> None:
# The proxy decision is explicit and has no default: pass a proxy URL,
# or allow_direct_egress=True to send from this machine's own address.
asin = "..." # the book's ASIN
async with LibexClient(proxy_url="http://proxy.example:8080") as client:
try:
book = await get_book(client.get, asin, region="us")
print(book.title)
for hit in await search(client.get, title="Hobbit", limit=5):
print(hit.asin, hit.title)
except LibexException as exc:
print(exc.code, exc.message)
asyncio.run(main())
The library reads no environment variable; every setting is an argument.
Each lookup in libex_core.lookup takes the request callable (client.get)
first and region as a keyword, and returns a model from libex_core.models
(pydantic). Pass store= a libex_core.storage.LocalStore to use the local
store as above; without it nothing is persisted. Importing libex_core
itself imports nothing else, and the storage libraries load only when
libex_core.storage is used.
Links
- Source and issues: https://github.com/LibexHQ/Libex
- Changelog: https://github.com/LibexHQ/Libex/blob/main/libex_core/CHANGELOG.md
- Privacy: https://github.com/LibexHQ/Libex/blob/main/PRIVACY.md
- Hosted API: https://libexdb.com
- License: MIT
Metadata
Release files for libex-core 0.20.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| libex_core-0.20.0.tar.gz | 263.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| libex_core-0.20.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 573.2 kB
Release files / libex_core-0.20.0.tar.gz
| Download URL | libex_core-0.20.0.tar.gz |
|---|---|
| Size | 263.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83bca310f7d59fc77afad051374efdb7efdd7398df9bb8951c98ce8e5d67c747
|
|
BLAKE2b-256 checksum How to use checksums |
dfe9bcbcb8693684a2833a9b8e2edff3f130282610159aaf26ae1d1ce06a900b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / libex_core-0.20.0-py3-none-any.whl
| Download URL | libex_core-0.20.0-py3-none-any.whl |
|---|---|
| Size | 310.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8b31ab4f9b0cfc086814f2ace9b50e681654cd7dc7874c5ebe98f8141f2d8dd
|
|
BLAKE2b-256 checksum How to use checksums |
50b9c97912092f64db313af238648359c5be8996f1de957439bcad2451b9af16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log