first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
# mp4-atom
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Parses iTunes-style metadata from MP4/M4A audio containers by walking the MPEG-4 ISO Base Media box (atom) tree. The parser navigates `moov → udta → meta → ilst` (with a fallback to `moov → meta → ilst` for non-standard files) and decodes all standard iTunes tag atoms into a normalised `Track` record.
The implementation is pure binary — it uses no external XML or MP4 libraries, operating directly on a `Uint8Array` with the shared `buffer-utils` helpers.
## Features
- Generic box/atom tree walker (`iterBoxes`) with graceful handling of corrupted sizes and EOF-marker boxes
- Supports both `moov/udta/meta/ilst` and `moov/meta/ilst` layouts
- Decodes UTF-8 text atoms: `©nam`, `©ART`, `©alb`, `aART`, `©day`, `©gen`, `©cmt`, `©lyr`
- Parses `trkn` and `disk` integer-pair atoms into `trackNumber / totalTracks` and `discNumber / totalDiscs`
- Handles `gnre` numeric genre index (1-based ID3v1 list) and `©gen` free-text genre
- Cover art extraction from `covr/data` with MIME-type detection (JPEG=0x0d, PNG=0x0e)
- Options: `skipCovers`, `maxCoverSize`
## Usage: Basic Example
```ts
import { parseMp4 } from "@suaveplan/audio-metadata/parsers/mp4-atom";
const track = parseMp4(m4aBuffer);
console.log(track.title); // "Bohemian Rhapsody"
console.log(track.year); // 1975
```
## Usage: Advanced Example
```ts
import { parseMp4 } from "@suaveplan/audio-metadata/parsers/mp4-atom";
const track = parseMp4(m4aBuffer, {
skipCovers: false,
maxCoverSize: 1024 * 1024, // 1 MiB limit
});
if (track.cover) {
console.log(track.cover.mimeType); // "image/jpeg" or "image/png"
console.log(track.cover.data.length); // bytes
}
```
## API Reference
### `parseMp4(buffer, options?)`
```ts
function parseMp4(
buffer: Uint8Array,
options?: {
skipCovers?: boolean;
maxCoverSize?: number;
},
): Track
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `buffer` | `Uint8Array` | Full MP4/M4A file buffer |
| `options.skipCovers` | `boolean` | Skip cover art extraction |
| `options.maxCoverSize` | `number` | Maximum cover bytes to accept (default 5 MiB) |
**Returns:** `Track` object; `{}` if no `ilst` atom is found.
## Implementation Notes
Each MP4 box starts with a 4-byte big-endian size (including the 8-byte header) followed by a 4-byte ASCII type code. A size of `0` means the box extends to the end of the file; a size of `1` means a 64-bit extended size follows — 64-bit boxes are skipped because they are not used for metadata in practice. The `meta` box includes a 4-byte version+flags prefix before its children, which `parseMp4` skips by advancing `dataOffset + 4` before searching for `ilst`. The `©` prefix in atom names (Unicode U+00A9) matches the raw Latin-1 byte `0xa9` written by all major encoders. Track/disc number parsing reads a 6-byte big-endian structure: 2 bytes padding, 2 bytes number, 2 bytes total.