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

@akabeko/music-metadata-editor

v1.0.0

Published

This is a library for reading and writing metadata of music files.

Readme

@akabeko/music-metadata-editor

Test License: MIT

English / Japanese

A Node.js + TypeScript library for reading and writing audio file metadata. Designed as a function-only API (no classes) with first-class support for ESM and Node.js 24+.

Supported containers / tag formats:

| Container | Read | Write | Notes | | --- | --- | --- | --- | | MP3 | ✓ | ✓ | ID3v2.3 / 2.4 + APE Tag + ID3v1 | | FLAC | ✓ | ✓ | Vorbis Comment + PICTURE block | | MP4 / M4A | ✓ | ✓ | iTunes-style atoms (moov/udta/meta/ilst) | | OGG | ✓ | ✓ | Vorbis / Opus comment headers | | APE | ✓ | ✓ | Monkey's Audio + APE Tag v1/v2 | | WAV (RIFF) | ✓ | ✓ | LIST INFO + BEXT + ID3 chunk | | AIFF | ✓ | ✓ | Native annotation chunks + ID3 chunk | | WMA / ASF | ✓ | ✓ | Content Description + Extended Content |

Install

pnpm add @akabeko/music-metadata-editor
# or: npm install @akabeko/music-metadata-editor

Requires Node.js 24 or newer.

Quick start

Load a track

loadTrack accepts both a file path (string) and pre-loaded bytes (Uint8Array). The returned Track is a Plain Object.

import { loadTrack } from "@akabeko/music-metadata-editor";

const track = await loadTrack("./song.mp3");
console.log(track.audioFormat);   // "mp3"
console.log(track.tag.title);     // "Hello"
console.log(track.tag.artist);    // "akabeko"
console.log(track.durationMs);    // 215000 (or `undefined` when not derivable)
console.log(track.pictures.length);

durationMs is a read-only audio-derived field. The reader computes it from sample-count / sample-rate / bitrate fields, and saveTrack never writes it back to the file (the writer recomputes it on the next read).

It is undefined when the source does not carry the values needed (e.g. a stripped-down fixture with no audio frames).

MP3 caveat: Only CBR streams are supported. VBR-encoded MP3 (Xing / Info / VBRI headers) is not parsed; on VBR files the returned duration is a CBR-based estimate, so it may diverge from the true playback time.

Save a modified track

import { loadTrack, saveTrack } from "@akabeko/music-metadata-editor";

const track = await loadTrack("./song.mp3");
const edited = {
  ...track,
  tag: { ...track.tag, title: "New Title", artist: "New Artist" },
};

// Overwrite the source file in place
await saveTrack(edited, { source: "./song.mp3" });

// Or write to a different path
await saveTrack(edited, { source: "./song.mp3", outputPath: "./out.mp3" });

// Or rebuild bytes without writing to a file
const bytes = await saveTrack(edited, { source: await readFile("./song.mp3") });

Edit cover art

import { loadTrack, saveTrack, PictureKind } from "@akabeko/music-metadata-editor";
import { readFile } from "node:fs/promises";

const track = await loadTrack("./song.mp3");
const cover = await readFile("./cover.jpg");
const edited = {
  ...track,
  pictures: [
    { mimeType: "image/jpeg", kind: PictureKind.CoverFront, data: cover },
  ],
};

await saveTrack(edited, { source: "./song.mp3" });

Edit lyrics

const edited = {
  ...track,
  lyrics: {
    language: "eng",
    description: "Lyrics",
    unsynchronized: "Hello, world\nLine two\n",
  },
};

await saveTrack(edited, { source: "./song.mp3" });

For synchronized lyrics, populate lyrics.synchronized with { timeMs, text }[] (sorted by timeMs).

Two-layer API

| Layer | Functions | When to use | | --- | --- | --- | | High-level | loadTrack, saveTrack | Most workflows. Returns a stable Track Plain Object with additionalFields / warnings defaults. | | Low-level | readMetadata, writeMetadata | When you need the raw MetadataReadResult or want to pass WriteOptions directly. |

Both layers honour the same ReadOptions (e.g. tagPriority for MP3) and format override for files without recognizable extensions or signatures.

import { readMetadata } from "@akabeko/music-metadata-editor";

const result = await readMetadata("./song.mp3", { tagPriority: ["ape", "id3v2", "id3v1"] });

Errors and warnings

All thrown errors are MmeError, a tagged Error with a defined code.

import { loadTrack, isMmeError } from "@akabeko/music-metadata-editor";

try {
  await loadTrack("./mystery.bin");
} catch (error) {
  if (isMmeError(error) && error.code === "unsupported-format") {
    // ...
  }
}

| Code | Meaning | | --- | --- | | unsupported-format | Format could not be detected, or no reader/writer is registered. | | invalid-tag | A tag block was found but its bytes were structurally invalid. | | truncated-input | The input ended before a required structure could be read in full. | | unsupported-feature | The input uses a feature not yet supported (e.g. compression / encryption). |

Recoverable problems do not throw — they are collected as non-fatal diagnostics on Track.warnings: readonly Warning[]. For example, a single malformed frame inside an otherwise valid tag falls into this category.

Field mapping

The mapping between each tag format and the common TagData shape is documented in docs/field-mapping.md.

Documentation

References

Reference implementation:

Specifications and supporting documentation: