npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

abmeta

v0.5.2

Published

A TypeScript CLI tool that scans an input directory, resolves audiobook metadata via multiple book APIs, writes ID3/M4B tags, downloads cover art, and restructures files into an Audiobookshelf-compatible layout.

Readme

abmeta

Audiobook metadata tagger and organizer for Audiobookshelf.

npm TypeScript License

abmeta scans an unstructured directory of audiobook files, resolves metadata from multiple book APIs, writes proper ID3v2/ffmpeg tags, downloads cover art, and copies the result into an organized output tree — or uploads it directly to an Audiobookshelf server.


Prerequisites

  • Node.js ≥ 22
  • ffmpeg on PATH (required for M4B metadata writing)
    • macOS: brew install ffmpeg
    • Ubuntu/Debian: sudo apt install ffmpeg
    • Windows: winget install ffmpeg

Quick start

npx abmeta --config config.yaml

Or with CLI flags instead of a config file:

npx abmeta -i /path/to/audiobooks -o /path/to/output --hardcover-key sk-...

Preview before writing:

npx abmeta --config config.yaml --dry-run

Interactively pick which folders to process:

npx abmeta -i /path/to/audiobooks -o /path/to/output --include

Docker

docker compose up organize
# or just preview:
docker compose --profile check up dry-run

Features

  • Two output modes — restructure to an Author/Series/Book/ filesystem tree, or upload in-place to an Audiobookshelf instance.
  • Multi-provider metadata resolution — Audible (ASIN catalog search), Audnexus (narrator + cover), Open Library (ISBN/ASIN), Hardcover (series data), Lubimyczytac (Polish-language scraper).
  • Language-based provider routing — LLM detects book language from path structure; Spanish books routed to audible.es, Polish books to Lubimyczytac.
  • LLM-verified pipeline — an LLM acts as verifier between metadata discovery and write, returning trust / flag / retry judgments.
  • Multi-file book detection — groups files by directory and filename stems, assigns sequential track numbers.
  • Interactive folder picker — --include flag launches a searchable multi-select prompt to choose which folders to process.
  • Cover art handling — downloads from providers, resizes to 500×500 via sharp, embeds as APIC in ID3 tags, preserves existing covers.
  • Duplicate prevention — checks for existing ASINs and matching title+author before uploading to Audiobookshelf.
  • Fallback to local — when the ABS upload fails (network, auth, server error), the tool falls back to local filesystem output.
  • Sidecar preservation — keeps .nfo, .cue, .json, and synopsis files; discards junk.
  • Dry-run mode — preview all changes before writing.
  • Docker image — ready-to-run container with multi-stage build.

Configuration

Configuration is resolved from three sources (later overrides earlier):

  1. YAML config file (default: config.yaml)
  2. Environment variables (HARDCOVER_API_KEY, LLM_API_KEY, LLM_API_BASE_URL, ABS_API_TOKEN)
  3. CLI flags

Example config

input: /path/to/audiobooks
output: /path/to/output
hardcover_api_key: ""
dry_run: false
llm_model: "deepseek-v4-flash-free"
llm_api_key: ""
llm_api_base_url: "https://opencode.ai/zen/v1"
concurrency: 4
include:
  # - "Peters, Elizabeth"
  # - "Riordan, Rick"
log_level: info
output_mode: local           # "local" or "audiobookshelf"
abs_url: ""
abs_api_token: ""
abs_library_id: ""

CLI reference

Usage: abmeta [options]

Options:
  -c, --config <path>        Config file path (default: config.yaml)
  -i, --input <path>         Input directory
  -o, --output <path>        Output directory
  --hardcover-key <key>      Hardcover API key
  --llm-key <key>            LLM API key
  --llm-base-url <url>       LLM API base URL
  --concurrency <n>          Books to process in parallel (default: 4)
  --include                  Interactively select folders to process
  --dry-run                  Preview without writing
  --log-level <level>        debug | info | warn | error
  --abs-url <url>            Audiobookshelf server URL
  --abs-token <token>        Audiobookshelf API token
  --abs-library-id <id>      Audiobookshelf library ID
  -V, --version              Output version
  -h, --help                 Display help

Output modes

Local mode (default)

Restructures files into Author/Series/Book/ or Author/Book/ hierarchy, writes tagged copies, and preserves sidecar files. Originals remain untouched.

output/
  Author Name/
    Series Name/
      Book Title/
        cover.jpg
        01 - Chapter One.mp3
        02 - Chapter Two.mp3

Audiobookshelf mode

Uploads tagged files to an Audiobookshelf server via its API:

  1. Searches the library for duplicates by ASIN and title+author.
  2. Uploads files as a multipart form with title, author, and series metadata.
  3. Triggers a library scan, then looks up the item by title to get its ID.
  4. Patches full metadata (narrator, description, publisher, genres, ASIN, ISBN, cover), uploads cover art.

Note: When upload fails after retries (network error, server down, auth failure), the tool falls back to local output with a logged reason.


Architecture

                 ┌─────────────┐
                 │   Scanner   │  Walk input, detect multi-file books
                 └──────┬──────┘
                        │ BookSet
                        ▼
              ┌─────────────────┐
              │  Path Interpreter│  LLM: title, author, language
              └──────┬──────────┘
                     │
                     ▼
        ┌────────────────────────────┐
        │   Deterministic Search     │  Parallel provider search
        └────────────┬───────────────┘
                     │
         ┌───────────┼───────────┬──────────────┐
         ▼           ▼           ▼              ▼
      Audible   Open Library  Hardcover   Lubimyczytac
      (catalog)  (ISBN/ASIN)  (series)     (PL scraper)
         │           │           │              │
         └───────────┴───────────┴──────────────┘
                     │
                     ▼
              ┌──────────────┐
              │ Fuzzy Match   │  Match resolved title/author
              └──────┬───────┘
                     │
              ┌──────┴──────┐
              ▼              ▼
          Match OK       Fallthrough
              │              │
              ▼              ▼
      ┌───────────┐  ┌────────────┐
      │ Write     │  │  Verifier   │  LLM: resolve ambiguity
      │ Output    │  └─────┬──────┘
      └─────┬─────┘        │
            │       ┌──────┴──────┐
            │       ▼              ▼
            │   Write Output   Flag for
            │                  Review
            ▼
     ┌─────────────┐
     │  Tag & Write │  ID3/ffmpeg tags, cover art
     └──────┬──────┘
            │
     ┌──────┴──────┐
     ▼              ▼
  Local tree   Audiobookshelf
  (filesystem)  (upload API)

Provider chain

Audible (primary, ASIN + full metadata) → Open Library (ISBN/ASIN fallback) → Hardcover (series data) → Audnexus (ASIN enrichment). Polish-language books route to Lubimyczytac (cheerio scraper) instead of Audible. Language is auto-detected by the LLM during path interpretation.

LLM in the pipeline

Two LLM phases: (1) Path Interpreter — determines title, author, and language from the directory structure. (2) Verifier — resolves ambiguous provider matches that fail fuzzy-matching. Most books skip the verifier entirely.


Project structure

src/
  index.ts              CLI entry (commander), config load + merge
  agent.ts              Sequential per-book orchestration loop
  orchestrator.ts       Output writer: tags files, dispatches to local or ABS mode
  scanner.ts            Input walker, audio detection, multi-file grouping
  config.ts             YAML loader, CLI override merge, validation
  types.ts              Shared interfaces
  utils.ts              Path helpers, sidecar classification, file copy
  inference.ts          Book identity inference from paths and tags
  providers/
    abs-client.ts       Audiobookshelf REST client
    abs-upload.ts       ABS upload saga (dedup, upload, scan, PATCH, cover, verify)
    asin.ts             ASIN validation + cache (.wayfinder/cache/asin.json)
    audible.ts          Audible catalog search (api.audible.{region})
    audnexus.ts         Audnexus API client (ASIN-based enrichment)
    cover-art.ts        Cover download, resize (sharp), local lookup
    hardcover.ts        Hardcover GraphQL client
    lubimyczytac.ts     Lubimyczytac.pl scraper (Polish-language books, cheerio)
    metadata-resolver.ts
    open-library.ts     Open Library search + editions
  taggers/
    index.ts            ID3v2 writer (node-id3), ffmpeg (M4B), cover embed
tests/
    *.test.ts            Unit tests (vitest)
    e2e/                 Docker-based end-to-end tests

Development

# Build
npm run build

# Type-check
npm run typecheck

# Lint
npm run lint

# Unit tests
npm test

# E2E tests (requires Docker)
npm run test:e2e

E2E tests

The E2E suite spins up an ephemeral Audiobookshelf container via ghcr.io/advplyr/audiobookshelf:latest, provisions a root user and library, runs the full upload pipeline, and tears down the container.

npm run test:e2e

Tests run sequentially: upload → metadata verification → duplicate skip → real-book upload → fallback on container kill.


Roadmap

  • Web UI mode — interactive folder selection served from the Docker container on a port, bringing the CLI picker experience to headless deployments.

Tech stack

| Area | Choice | |------|--------| | Runtime | Node.js 22, TypeScript (strict, ESM, ES2022) | | CLI | commander | | Config | js-yaml | | ID3 tags | node-id3 | | M4B metadata | ffmpeg | | Cover art | sharp | | HTML scraping | cheerio | | Testing | vitest | | Linting | ESLint + @typescript-eslint | | Container | Docker (Alpine, multi-stage) |