Library Manager as a metadata provider plugin for Audiobookshelf (ABS). When ABS needs to identify or enrich audiobook metadata, it queries Library Manager, which leverages the full Skaldleita pipeline: GPU Whisper transcription, 50M+ book database matching, multi-source API lookups, and AI-powered consensus verification.
Current state: LM has an abs_client.py that pulls data FROM ABS (listening progress, library items, user management). This document covers the reverse direction — making LM available TO ABS as a metadata agent.
Audiobookshelf Library Manager Skaldleita (BookDB)
│ │ │
│ 1. "Identify this book" │ │
│ ─────────────────────────> │ │
│ (title, author, audio clip) │ │
│ │ 2. Audio → Whisper queue │
│ │ ─────────────────────────> │
│ │ │
│ │ 3. Metadata match (50M DB) │
│ │ <───────────────────────── │
│ │ │
│ │ 4. API enrichment │
│ │ (Audnexus, Google Books, │
│ │ OpenLibrary, Hardcover) │
│ │ │
│ │ 5. AI consensus verify │
│ │ (Gemini / OpenRouter) │
│ │ │
│ 6. Enriched metadata │ │
│ <───────────────────────── │ │
│ (author, title, narrator, │ │
│ series, year, confidence) │ │
ABS has a metadata provider plugin system. LM registers as a provider that ABS queries during its "Match" and "Quick Match" flows.
How it works:
- ABS sends search queries to LM's API
- LM runs its full pipeline (BookDB + multi-source + AI verification)
- LM returns structured metadata in ABS's expected format
- ABS users see LM results alongside other providers (Google Books, Audible, etc.)
LM endpoints needed:
GET /api/abs/search?query=<title>&author=<author>
→ Returns ABS-formatted search results
GET /api/abs/match?title=<title>&author=<author>&narrator=<narrator>
→ Returns single best match with confidence
POST /api/abs/identify-audio
→ Accepts audio clip, returns identification via Skaldleita Whisper
GET /api/abs/cover?title=<title>&author=<author>
→ Returns cover image URL if available
Pros: Native ABS integration, users see LM in their provider list Cons: ABS metadata provider API has a specific contract we must match exactly
LM runs alongside ABS and periodically scans the ABS library for books with missing/low-quality metadata, then pushes corrections back via ABS API.
How it works:
- LM uses existing
abs_client.pyto read ABS library - Identifies books with missing narrators, series info, etc.
- Runs its pipeline to find correct metadata
- Pushes updates back to ABS via API
Pros: Works without ABS plugin system, LM controls the schedule Cons: Delayed updates, LM needs write access to ABS
Register as metadata provider AND run background enrichment. Provider handles new additions; background scan catches existing gaps.
ABS expects providers to implement these operations:
// Search request
GET /search?query=Brandon+Sanderson+Mistborn
// Search response
{
"matches": [
{
"title": "The Final Empire",
"subtitle": "Mistborn Book 1",
"author": "Brandon Sanderson",
"narrator": "Michael Kramer",
"publisher": "Macmillan Audio",
"publishedYear": "2006",
"description": "...",
"cover": "https://...",
"isbn": "9780765350381",
"asin": "B002V1O7UE",
"series": [
{ "series": "Mistborn", "sequence": "1" }
],
"language": "en",
"duration": 95940
}
]
}| ABS Field | LM Source | Notes |
|---|---|---|
title |
BookProfile.title | Highest confidence value |
author |
BookProfile.author | Consensus from all sources |
narrator |
BookProfile.narrator | Often from audio credits (L2) or Audnexus |
series[].series |
BookProfile.series | From BookDB or API lookups |
series[].sequence |
BookProfile.series_num | Position in series |
publishedYear |
BookProfile.year | From API lookups |
cover |
External API | Audnexus or Google Books cover URL |
isbn |
API lookups | Google Books or OpenLibrary |
asin |
Audnexus | Audible ASIN if available |
duration |
Audio file analysis | From ffprobe or ABS library item |
language |
Gemini detection | Audio language detection (L2) |
description |
API enrichment | Google Books or OpenLibrary |
LM uses 0-100 confidence scores. ABS doesn't have a native confidence field, but we can:
- Only return results above a configurable threshold (default: 60)
- Sort results by confidence (best first)
- Include confidence in a custom field for display
library_manager/abs_provider.py # ABS metadata provider Blueprint
- /api/abs/search # Search endpoint
- /api/abs/match # Best-match endpoint
- /api/abs/identify # Audio identification endpoint
- /api/abs/covers/<isbn> # Cover proxy
Options:
- Shared secret — LM generates an API key, user enters it in ABS custom provider config
- Token exchange — ABS sends its API token, LM validates via ABS
/api/meendpoint - None (local only) — If both run on same machine, trust localhost
Recommend: Shared secret (simple, works across networks).
Add to the Integrations tab:
ABS Metadata Provider
├── Enable as ABS metadata source: [toggle]
├── Provider API Key: [auto-generated, copyable]
├── Minimum confidence threshold: [slider 0-100, default 60]
├── Include audio identification: [toggle, default on]
└── Provider URL for ABS config: http://<lm-host>:5757/api/abs
- A new API surface (
/api/abs/*) accessible from the network - Audio clip uploads from ABS to LM
- LM's metadata forwarded to ABS (already LM's core function)
- API key authentication on all
/api/abs/*endpoints - Rate limiting (reuse existing rate limiter infrastructure)
- Audio clip size limits (same as existing Skaldleita submission limits)
- Input validation on all query parameters (sanitize before pipeline)
- SSRF protection already in place for plugin endpoints (issue #236)
- No new filesystem access — ABS provider only reads/returns metadata
- Direct Skaldleita API passthrough (LM should be the intermediary, not a proxy)
- BookDB API keys or signing credentials
- Internal BookProfile objects (serialize to ABS format only)
- Direct database access
- New Blueprint:
abs_provider.py /api/abs/searchendpoint using existingsearch_bookdb()+ API lookups- API key auth
- Settings UI toggle
- Basic test with ABS custom provider
/api/abs/identifyendpoint- Accept audio clips from ABS
- Route through Skaldleita Whisper pipeline
- Return structured results
- Scan ABS library via existing
abs_client.py - Queue items with missing metadata
- Push enrichments back to ABS
- Configurable schedule (daily/weekly)
/api/abs/covers/<isbn>proxy endpoint- Cache covers locally
- Pull descriptions from Google Books / OpenLibrary enrichment
In ABS Settings → Providers → Custom:
Name: Library Manager
Base URL: http://<lm-ip>:5757/api/abs
API Key: <paste from LM settings>
Then in ABS, when matching a book:
- Click "Match" on a library item
- Select "Library Manager" as provider
- See results from LM's multi-source pipeline
- One-click apply metadata
- #257 — This feature
- #252-#256 — Integration fixes that improve the pipeline feeding this provider
- abs_client.py — Existing read-only ABS integration (complements this)