metadata-connect 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +196 -0
- package/dist/extract.d.ts +36 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +77 -0
- package/dist/extract.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/aiff.d.ts +9 -0
- package/dist/parsers/aiff.d.ts.map +1 -0
- package/dist/parsers/aiff.js +42 -0
- package/dist/parsers/aiff.js.map +1 -0
- package/dist/parsers/flac.d.ts +6 -0
- package/dist/parsers/flac.d.ts.map +1 -0
- package/dist/parsers/flac.js +172 -0
- package/dist/parsers/flac.js.map +1 -0
- package/dist/parsers/id3.d.ts +6 -0
- package/dist/parsers/id3.d.ts.map +1 -0
- package/dist/parsers/id3.js +329 -0
- package/dist/parsers/id3.js.map +1 -0
- package/dist/parsers/index.d.ts +6 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +6 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/mp4.d.ts +6 -0
- package/dist/parsers/mp4.d.ts.map +1 -0
- package/dist/parsers/mp4.js +295 -0
- package/dist/parsers/mp4.js.map +1 -0
- package/dist/parsers/utils.d.ts +40 -0
- package/dist/parsers/utils.d.ts.map +1 -0
- package/dist/parsers/utils.js +120 -0
- package/dist/parsers/utils.js.map +1 -0
- package/dist/reader.d.ts +6 -0
- package/dist/reader.d.ts.map +1 -0
- package/dist/reader.js +14 -0
- package/dist/reader.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chris Le
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# metadata-connect
|
|
2
|
+
|
|
3
|
+
Extract audio metadata from MP3, M4A, FLAC, and AIFF files with support for partial file reads - perfect for extracting metadata from remote files over the network without downloading entire files.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/metadata-connect)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Partial file reading** - Extract metadata by reading only file headers (10-200KB instead of entire files)
|
|
11
|
+
- **Multiple format support** - MP3 (ID3v2), M4A/MP4/AAC, FLAC, AIFF
|
|
12
|
+
- **Complete metadata extraction** - Title, artist, album, genre, year, BPM, key, and artwork
|
|
13
|
+
- **FileReader abstraction** - Works with any data source (local files, NFS, HTTP range requests, custom protocols)
|
|
14
|
+
- **Zero runtime dependencies** - Pure TypeScript implementation
|
|
15
|
+
- **TypeScript first** - Full type definitions included
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install metadata-connect
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Extract from a local file
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { extractMetadata, createBufferReader } from 'metadata-connect';
|
|
29
|
+
import { readFile } from 'fs/promises';
|
|
30
|
+
|
|
31
|
+
const buffer = await readFile('song.mp3');
|
|
32
|
+
const reader = createBufferReader(buffer, 'mp3');
|
|
33
|
+
const metadata = await extractMetadata(reader);
|
|
34
|
+
|
|
35
|
+
if (metadata) {
|
|
36
|
+
console.log(metadata.title); // "Song Title"
|
|
37
|
+
console.log(metadata.artist); // "Artist Name"
|
|
38
|
+
console.log(metadata.bpm); // 128
|
|
39
|
+
console.log(metadata.key); // "Am"
|
|
40
|
+
|
|
41
|
+
if (metadata.artwork) {
|
|
42
|
+
// metadata.artwork is a Buffer
|
|
43
|
+
// metadata.artworkMimeType is 'image/jpeg' | 'image/png' | 'image/gif'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Extract from a remote file (partial read)
|
|
49
|
+
|
|
50
|
+
The real power of metadata-connect is extracting metadata from remote files without downloading them entirely:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { extractMetadata } from 'metadata-connect';
|
|
54
|
+
import type { FileReader } from 'metadata-connect';
|
|
55
|
+
|
|
56
|
+
// Create a FileReader that fetches only the requested bytes
|
|
57
|
+
const reader: FileReader = {
|
|
58
|
+
size: fileSize, // Total file size (get from HEAD request or file stat)
|
|
59
|
+
extension: 'mp3',
|
|
60
|
+
async read(offset: number, length: number): Promise<Buffer> {
|
|
61
|
+
// Use HTTP Range requests, NFS, or any protocol
|
|
62
|
+
const response = await fetch(url, {
|
|
63
|
+
headers: { Range: `bytes=${offset}-${offset + length - 1}` }
|
|
64
|
+
});
|
|
65
|
+
return Buffer.from(await response.arrayBuffer());
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const metadata = await extractMetadata(reader);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API Reference
|
|
73
|
+
|
|
74
|
+
### `extractMetadata(reader: FileReader): Promise<ExtractedMetadata | null>`
|
|
75
|
+
|
|
76
|
+
Main extraction function. Returns metadata or null if the format is not supported or parsing fails.
|
|
77
|
+
|
|
78
|
+
### `createBufferReader(buffer: Buffer, extension: string): FileReader`
|
|
79
|
+
|
|
80
|
+
Create a FileReader from a Buffer for in-memory extraction.
|
|
81
|
+
|
|
82
|
+
### `isExtensionSupported(extension: string): boolean`
|
|
83
|
+
|
|
84
|
+
Check if a file extension is supported.
|
|
85
|
+
|
|
86
|
+
### `getSupportedExtensions(): string[]`
|
|
87
|
+
|
|
88
|
+
Get list of supported extensions: `['mp3', 'm4a', 'mp4', 'aac', 'flac', 'aiff', 'aif']`
|
|
89
|
+
|
|
90
|
+
### `getParserForExtension(extension: string): MetadataParser | null`
|
|
91
|
+
|
|
92
|
+
Get the parser function for a specific extension.
|
|
93
|
+
|
|
94
|
+
## Types
|
|
95
|
+
|
|
96
|
+
### `FileReader`
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
interface FileReader {
|
|
100
|
+
/** Total file size in bytes */
|
|
101
|
+
readonly size: number;
|
|
102
|
+
/** File extension (without dot), e.g., 'mp3', 'flac' */
|
|
103
|
+
readonly extension: string;
|
|
104
|
+
/** Read bytes from the file at a given offset */
|
|
105
|
+
read(offset: number, length: number): Promise<Buffer>;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `ExtractedMetadata`
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
interface ExtractedMetadata {
|
|
113
|
+
title?: string;
|
|
114
|
+
artist?: string;
|
|
115
|
+
album?: string;
|
|
116
|
+
genre?: string;
|
|
117
|
+
year?: number;
|
|
118
|
+
bpm?: number;
|
|
119
|
+
key?: string;
|
|
120
|
+
artwork?: Buffer;
|
|
121
|
+
artworkMimeType?: 'image/jpeg' | 'image/png' | 'image/gif';
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Format Support
|
|
126
|
+
|
|
127
|
+
| Format | Extension | Metadata Source |
|
|
128
|
+
|--------|-----------|-----------------|
|
|
129
|
+
| MP3 | `.mp3` | ID3v2.2, ID3v2.3, ID3v2.4 tags |
|
|
130
|
+
| M4A/MP4 | `.m4a`, `.mp4`, `.aac` | iTunes metadata atoms |
|
|
131
|
+
| FLAC | `.flac` | Vorbis comments + PICTURE blocks |
|
|
132
|
+
| AIFF | `.aiff`, `.aif` | ID3 chunk |
|
|
133
|
+
|
|
134
|
+
### Extracted Fields
|
|
135
|
+
|
|
136
|
+
| Field | MP3 | M4A | FLAC | AIFF |
|
|
137
|
+
|-------|-----|-----|------|------|
|
|
138
|
+
| Title | TIT2 | ©nam | TITLE | ID3 |
|
|
139
|
+
| Artist | TPE1 | ©ART | ARTIST | ID3 |
|
|
140
|
+
| Album | TALB | ©alb | ALBUM | ID3 |
|
|
141
|
+
| Genre | TCON | ©gen/gnre | GENRE | ID3 |
|
|
142
|
+
| Year | TYER/TDRC | ©day | DATE | ID3 |
|
|
143
|
+
| BPM | TBPM | tmpo | BPM/TEMPO | ID3 |
|
|
144
|
+
| Key | TKEY | - | KEY/INITIALKEY | ID3 |
|
|
145
|
+
| Artwork | APIC | covr | PICTURE | ID3 |
|
|
146
|
+
|
|
147
|
+
## Network Efficiency
|
|
148
|
+
|
|
149
|
+
The library is designed to minimize network transfer when reading from remote sources:
|
|
150
|
+
|
|
151
|
+
| Format | Typical Bytes Read |
|
|
152
|
+
|--------|-------------------|
|
|
153
|
+
| MP3 | 10-50 KB (ID3v2 tag at file start) |
|
|
154
|
+
| FLAC | 10 KB (metadata blocks at file start) |
|
|
155
|
+
| M4A/MP4 | 50-200 KB (atom tree traversal) |
|
|
156
|
+
| AIFF | 10-50 KB (ID3 chunk location varies) |
|
|
157
|
+
|
|
158
|
+
## Use Cases
|
|
159
|
+
|
|
160
|
+
- **DJ Software** - Extract track info from CDJs/controllers over network protocols
|
|
161
|
+
- **Media Servers** - Index large music libraries without reading entire files
|
|
162
|
+
- **Streaming Services** - Quick metadata lookup for remote storage
|
|
163
|
+
- **Browser Applications** - Extract metadata using fetch with Range headers
|
|
164
|
+
|
|
165
|
+
## Advanced Usage
|
|
166
|
+
|
|
167
|
+
### Using Individual Parsers
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { extractFromMp3, extractFromMp4, extractFromFlac } from 'metadata-connect';
|
|
171
|
+
|
|
172
|
+
// Use specific parser directly
|
|
173
|
+
const metadata = await extractFromMp3(reader);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Detecting Image Types
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { detectImageType } from 'metadata-connect';
|
|
180
|
+
|
|
181
|
+
const mimeType = detectImageType(imageBuffer);
|
|
182
|
+
// Returns 'image/jpeg' | 'image/png' | 'image/gif' | null
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Contributing
|
|
186
|
+
|
|
187
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
192
|
+
|
|
193
|
+
## Related Projects
|
|
194
|
+
|
|
195
|
+
- [music-metadata](https://github.com/borewit/music-metadata) - Full-featured audio metadata library (requires full file access)
|
|
196
|
+
- [node-id3](https://github.com/Zazama/node-id3) - ID3 tag reader/writer for Node.js
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ExtractedMetadata, FileReader, MetadataParser } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the appropriate parser for a file extension
|
|
4
|
+
*/
|
|
5
|
+
export declare function getParserForExtension(extension: string): MetadataParser | null;
|
|
6
|
+
/**
|
|
7
|
+
* Get list of supported file extensions
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSupportedExtensions(): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Check if a file extension is supported
|
|
12
|
+
*/
|
|
13
|
+
export declare function isExtensionSupported(extension: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Extract metadata from an audio file using the appropriate parser
|
|
16
|
+
*
|
|
17
|
+
* @param reader - FileReader interface for reading file data
|
|
18
|
+
* @returns Extracted metadata, or null if extraction fails or format is unsupported
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Create a reader from your transport layer
|
|
23
|
+
* const reader = createFileReader(device, path, fileSize);
|
|
24
|
+
*
|
|
25
|
+
* // Extract metadata
|
|
26
|
+
* const metadata = await extractMetadata(reader);
|
|
27
|
+
* if (metadata) {
|
|
28
|
+
* console.log(metadata.title, metadata.artist);
|
|
29
|
+
* if (metadata.artwork) {
|
|
30
|
+
* // Use artwork buffer
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractMetadata(reader: FileReader): Promise<ExtractedMetadata | null>;
|
|
36
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA6BhF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAG9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAEjD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAa3F"}
|
package/dist/extract.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { extractFromMp3 } from './parsers/id3.js';
|
|
2
|
+
import { extractFromMp4 } from './parsers/mp4.js';
|
|
3
|
+
import { extractFromFlac } from './parsers/flac.js';
|
|
4
|
+
import { extractFromAiff } from './parsers/aiff.js';
|
|
5
|
+
/**
|
|
6
|
+
* Map of file extensions to their metadata parsers
|
|
7
|
+
*/
|
|
8
|
+
const PARSER_MAP = {
|
|
9
|
+
// MP3
|
|
10
|
+
mp3: extractFromMp3,
|
|
11
|
+
// MP4/M4A/AAC
|
|
12
|
+
m4a: extractFromMp4,
|
|
13
|
+
mp4: extractFromMp4,
|
|
14
|
+
m4p: extractFromMp4,
|
|
15
|
+
m4b: extractFromMp4,
|
|
16
|
+
aac: extractFromMp4,
|
|
17
|
+
// FLAC
|
|
18
|
+
flac: extractFromFlac,
|
|
19
|
+
// AIFF
|
|
20
|
+
aiff: extractFromAiff,
|
|
21
|
+
aif: extractFromAiff,
|
|
22
|
+
aifc: extractFromAiff,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Get the appropriate parser for a file extension
|
|
26
|
+
*/
|
|
27
|
+
export function getParserForExtension(extension) {
|
|
28
|
+
const normalizedExt = extension.toLowerCase().replace(/^\./, '');
|
|
29
|
+
return PARSER_MAP[normalizedExt] ?? null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get list of supported file extensions
|
|
33
|
+
*/
|
|
34
|
+
export function getSupportedExtensions() {
|
|
35
|
+
return Object.keys(PARSER_MAP);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a file extension is supported
|
|
39
|
+
*/
|
|
40
|
+
export function isExtensionSupported(extension) {
|
|
41
|
+
return getParserForExtension(extension) !== null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract metadata from an audio file using the appropriate parser
|
|
45
|
+
*
|
|
46
|
+
* @param reader - FileReader interface for reading file data
|
|
47
|
+
* @returns Extracted metadata, or null if extraction fails or format is unsupported
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Create a reader from your transport layer
|
|
52
|
+
* const reader = createFileReader(device, path, fileSize);
|
|
53
|
+
*
|
|
54
|
+
* // Extract metadata
|
|
55
|
+
* const metadata = await extractMetadata(reader);
|
|
56
|
+
* if (metadata) {
|
|
57
|
+
* console.log(metadata.title, metadata.artist);
|
|
58
|
+
* if (metadata.artwork) {
|
|
59
|
+
* // Use artwork buffer
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export async function extractMetadata(reader) {
|
|
65
|
+
const parser = getParserForExtension(reader.extension);
|
|
66
|
+
if (!parser) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return await parser(reader);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Return null on any parsing error
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,GAAmC;IACjD,MAAM;IACN,GAAG,EAAE,cAAc;IAEnB,cAAc;IACd,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,cAAc;IAEnB,OAAO;IACP,IAAI,EAAE,eAAe;IAErB,OAAO;IACP,IAAI,EAAE,eAAe;IACrB,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,eAAe;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,MAAM,aAAa,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjE,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO,qBAAqB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAkB;IACtD,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAEvD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { extractMetadata, getParserForExtension, getSupportedExtensions, isExtensionSupported, } from './extract.js';
|
|
2
|
+
export type { FileReader, ExtractedMetadata, ArtworkMimeType, MetadataParser, } from './types.js';
|
|
3
|
+
export { PictureType } from './types.js';
|
|
4
|
+
export { createBufferReader } from './reader.js';
|
|
5
|
+
export { extractFromMp3, extractFromMp4, extractFromFlac, extractFromAiff, detectImageType, normalizeMimeType, } from './parsers/index.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Main extraction function
|
|
2
|
+
export { extractMetadata, getParserForExtension, getSupportedExtensions, isExtensionSupported, } from './extract.js';
|
|
3
|
+
export { PictureType } from './types.js';
|
|
4
|
+
// Reader utilities
|
|
5
|
+
export { createBufferReader } from './reader.js';
|
|
6
|
+
// Individual parsers (for advanced use cases)
|
|
7
|
+
export { extractFromMp3, extractFromMp4, extractFromFlac, extractFromAiff, detectImageType, normalizeMimeType, } from './parsers/index.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,8CAA8C;AAC9C,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ExtractedMetadata, FileReader } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract metadata from an AIFF file
|
|
4
|
+
*
|
|
5
|
+
* AIFF files can contain ID3v2 tags in an 'ID3 ' chunk.
|
|
6
|
+
* We look for this chunk and delegate to the ID3 parser.
|
|
7
|
+
*/
|
|
8
|
+
export declare function extractFromAiff(reader: FileReader): Promise<ExtractedMetadata | null>;
|
|
9
|
+
//# sourceMappingURL=aiff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiff.d.ts","sourceRoot":"","sources":["../../src/parsers/aiff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAuC3F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { extractFromMp3 } from './id3.js';
|
|
2
|
+
import { createBufferReader } from '../reader.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract metadata from an AIFF file
|
|
5
|
+
*
|
|
6
|
+
* AIFF files can contain ID3v2 tags in an 'ID3 ' chunk.
|
|
7
|
+
* We look for this chunk and delegate to the ID3 parser.
|
|
8
|
+
*/
|
|
9
|
+
export async function extractFromAiff(reader) {
|
|
10
|
+
// Read AIFF header (12 bytes minimum)
|
|
11
|
+
const header = await reader.read(0, 12);
|
|
12
|
+
if (header.length < 12 || header.toString('ascii', 0, 4) !== 'FORM') {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const formType = header.toString('ascii', 8, 12);
|
|
16
|
+
if (formType !== 'AIFF' && formType !== 'AIFC') {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const formSize = header.readUInt32BE(4);
|
|
20
|
+
const fileEnd = Math.min(8 + formSize, reader.size);
|
|
21
|
+
let offset = 12;
|
|
22
|
+
// Iterate through chunks looking for ID3 tag
|
|
23
|
+
while (offset + 8 < fileEnd) {
|
|
24
|
+
const chunkHeader = await reader.read(offset, 8);
|
|
25
|
+
if (chunkHeader.length < 8)
|
|
26
|
+
break;
|
|
27
|
+
const chunkId = chunkHeader.toString('ascii', 0, 4);
|
|
28
|
+
const chunkSize = chunkHeader.readUInt32BE(4);
|
|
29
|
+
if (chunkSize <= 0 || offset + 8 + chunkSize > fileEnd)
|
|
30
|
+
break;
|
|
31
|
+
// Check for ID3 chunk (can be 'ID3 ' or 'id3 ')
|
|
32
|
+
if (chunkId === 'ID3 ' || chunkId === 'id3 ') {
|
|
33
|
+
const id3Data = await reader.read(offset + 8, chunkSize);
|
|
34
|
+
const id3Reader = createBufferReader(id3Data, 'mp3');
|
|
35
|
+
return extractFromMp3(id3Reader);
|
|
36
|
+
}
|
|
37
|
+
// AIFF chunks are padded to even byte boundaries
|
|
38
|
+
offset += 8 + chunkSize + (chunkSize % 2);
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=aiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiff.js","sourceRoot":"","sources":["../../src/parsers/aiff.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAkB;IACtD,sCAAsC;IACtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAEpD,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,6CAA6C;IAC7C,OAAO,MAAM,GAAG,CAAC,GAAG,OAAO,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACjD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM;QAElC,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAE9C,IAAI,SAAS,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO;YAAE,MAAM;QAE9D,gDAAgD;QAChD,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;YACzD,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACrD,OAAO,cAAc,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;QAED,iDAAiD;QACjD,MAAM,IAAI,CAAC,GAAG,SAAS,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flac.d.ts","sourceRoot":"","sources":["../../src/parsers/flac.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAkJlF;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA4E3F"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { PictureType } from '../types.js';
|
|
2
|
+
import { normalizeMimeType, parseBpm, parseYear, cleanText } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Vorbis comment field names (case-insensitive)
|
|
5
|
+
*/
|
|
6
|
+
const VORBIS_FIELDS = {
|
|
7
|
+
TITLE: ['TITLE'],
|
|
8
|
+
ARTIST: ['ARTIST'],
|
|
9
|
+
ALBUM: ['ALBUM'],
|
|
10
|
+
GENRE: ['GENRE'],
|
|
11
|
+
DATE: ['DATE', 'YEAR'],
|
|
12
|
+
BPM: ['BPM', 'TEMPO'],
|
|
13
|
+
KEY: ['KEY', 'INITIALKEY'],
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Parse a FLAC PICTURE metadata block
|
|
17
|
+
*/
|
|
18
|
+
function parsePictureBlock(data) {
|
|
19
|
+
if (data.length < 32)
|
|
20
|
+
return null;
|
|
21
|
+
let offset = 0;
|
|
22
|
+
const pictureType = data.readUInt32BE(offset);
|
|
23
|
+
offset += 4;
|
|
24
|
+
const mimeLength = data.readUInt32BE(offset);
|
|
25
|
+
offset += 4;
|
|
26
|
+
if (offset + mimeLength > data.length)
|
|
27
|
+
return null;
|
|
28
|
+
const mimeType = data.toString('utf8', offset, offset + mimeLength);
|
|
29
|
+
offset += mimeLength;
|
|
30
|
+
const descLength = data.readUInt32BE(offset);
|
|
31
|
+
offset += 4 + descLength;
|
|
32
|
+
if (offset + 16 > data.length)
|
|
33
|
+
return null;
|
|
34
|
+
const width = data.readUInt32BE(offset);
|
|
35
|
+
offset += 4;
|
|
36
|
+
const height = data.readUInt32BE(offset);
|
|
37
|
+
offset += 4 + 8; // Skip depth and colors
|
|
38
|
+
const imageLength = data.readUInt32BE(offset);
|
|
39
|
+
offset += 4;
|
|
40
|
+
if (offset + imageLength > data.length)
|
|
41
|
+
return null;
|
|
42
|
+
const imageData = data.subarray(offset, offset + imageLength);
|
|
43
|
+
if (imageData.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
return {
|
|
46
|
+
data: imageData,
|
|
47
|
+
mimeType: normalizeMimeType(mimeType),
|
|
48
|
+
width: width > 0 ? width : undefined,
|
|
49
|
+
height: height > 0 ? height : undefined,
|
|
50
|
+
pictureType,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse a Vorbis comment block
|
|
55
|
+
* Format: vendor string length (32-bit LE) + vendor string + comment count (32-bit LE) + comments
|
|
56
|
+
* Each comment: length (32-bit LE) + "FIELD=value"
|
|
57
|
+
*/
|
|
58
|
+
function parseVorbisCommentBlock(data) {
|
|
59
|
+
const comments = {};
|
|
60
|
+
if (data.length < 8)
|
|
61
|
+
return comments;
|
|
62
|
+
let offset = 0;
|
|
63
|
+
// Skip vendor string
|
|
64
|
+
const vendorLength = data.readUInt32LE(offset);
|
|
65
|
+
offset += 4 + vendorLength;
|
|
66
|
+
if (offset + 4 > data.length)
|
|
67
|
+
return comments;
|
|
68
|
+
// Read comment count
|
|
69
|
+
const commentCount = data.readUInt32LE(offset);
|
|
70
|
+
offset += 4;
|
|
71
|
+
// Read each comment
|
|
72
|
+
for (let i = 0; i < commentCount && offset + 4 <= data.length; i++) {
|
|
73
|
+
const commentLength = data.readUInt32LE(offset);
|
|
74
|
+
offset += 4;
|
|
75
|
+
if (offset + commentLength > data.length)
|
|
76
|
+
break;
|
|
77
|
+
const comment = data.toString('utf8', offset, offset + commentLength);
|
|
78
|
+
offset += commentLength;
|
|
79
|
+
// Split on first '='
|
|
80
|
+
const eqIndex = comment.indexOf('=');
|
|
81
|
+
if (eqIndex > 0) {
|
|
82
|
+
const field = comment.substring(0, eqIndex).toUpperCase();
|
|
83
|
+
const value = comment.substring(eqIndex + 1);
|
|
84
|
+
// Only store first value for each field
|
|
85
|
+
if (!comments[field]) {
|
|
86
|
+
comments[field] = value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return comments;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Match a Vorbis comment field name against known field names
|
|
94
|
+
*/
|
|
95
|
+
function getFieldValue(comments, fieldNames) {
|
|
96
|
+
for (const name of fieldNames) {
|
|
97
|
+
const value = comments[name];
|
|
98
|
+
if (value)
|
|
99
|
+
return cleanText(value);
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Extract metadata from a FLAC file
|
|
105
|
+
*/
|
|
106
|
+
export async function extractFromFlac(reader) {
|
|
107
|
+
// Verify FLAC signature
|
|
108
|
+
const signature = await reader.read(0, 4);
|
|
109
|
+
if (signature.toString('ascii') !== 'fLaC') {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const metadata = {};
|
|
113
|
+
let frontCover = null;
|
|
114
|
+
let anyArtwork = null;
|
|
115
|
+
let offset = 4;
|
|
116
|
+
let isLastBlock = false;
|
|
117
|
+
while (!isLastBlock && offset < reader.size) {
|
|
118
|
+
// Read metadata block header (4 bytes)
|
|
119
|
+
const blockHeader = await reader.read(offset, 4);
|
|
120
|
+
if (blockHeader.length < 4)
|
|
121
|
+
break;
|
|
122
|
+
isLastBlock = (blockHeader[0] & 0x80) !== 0;
|
|
123
|
+
const blockType = blockHeader[0] & 0x7f;
|
|
124
|
+
const blockLength = (blockHeader[1] << 16) | (blockHeader[2] << 8) | blockHeader[3];
|
|
125
|
+
if (blockLength <= 0 || offset + 4 + blockLength > reader.size)
|
|
126
|
+
break;
|
|
127
|
+
// Process metadata blocks
|
|
128
|
+
if (blockType === 4 /* MetadataBlockType.VORBIS_COMMENT */) {
|
|
129
|
+
const commentData = await reader.read(offset + 4, blockLength);
|
|
130
|
+
const comments = parseVorbisCommentBlock(commentData);
|
|
131
|
+
// Extract metadata from Vorbis comments
|
|
132
|
+
metadata.title = metadata.title ?? getFieldValue(comments, VORBIS_FIELDS.TITLE);
|
|
133
|
+
metadata.artist = metadata.artist ?? getFieldValue(comments, VORBIS_FIELDS.ARTIST);
|
|
134
|
+
metadata.album = metadata.album ?? getFieldValue(comments, VORBIS_FIELDS.ALBUM);
|
|
135
|
+
metadata.genre = metadata.genre ?? getFieldValue(comments, VORBIS_FIELDS.GENRE);
|
|
136
|
+
const dateValue = getFieldValue(comments, VORBIS_FIELDS.DATE);
|
|
137
|
+
if (dateValue && !metadata.year) {
|
|
138
|
+
metadata.year = parseYear(dateValue);
|
|
139
|
+
}
|
|
140
|
+
const bpmValue = getFieldValue(comments, VORBIS_FIELDS.BPM);
|
|
141
|
+
if (bpmValue && !metadata.bpm) {
|
|
142
|
+
metadata.bpm = parseBpm(bpmValue);
|
|
143
|
+
}
|
|
144
|
+
metadata.key = metadata.key ?? getFieldValue(comments, VORBIS_FIELDS.KEY);
|
|
145
|
+
}
|
|
146
|
+
else if (blockType === 6 /* MetadataBlockType.PICTURE */) {
|
|
147
|
+
const pictureData = await reader.read(offset + 4, blockLength);
|
|
148
|
+
const artwork = parsePictureBlock(pictureData);
|
|
149
|
+
if (artwork) {
|
|
150
|
+
if (artwork.pictureType === PictureType.FrontCover) {
|
|
151
|
+
frontCover = artwork;
|
|
152
|
+
}
|
|
153
|
+
else if (!anyArtwork) {
|
|
154
|
+
anyArtwork = artwork;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
offset += 4 + blockLength;
|
|
159
|
+
}
|
|
160
|
+
// Use front cover if available, otherwise any artwork
|
|
161
|
+
const artwork = frontCover ?? anyArtwork;
|
|
162
|
+
if (artwork) {
|
|
163
|
+
metadata.artwork = artwork.data;
|
|
164
|
+
metadata.artworkMimeType = artwork.mimeType;
|
|
165
|
+
}
|
|
166
|
+
// Return null if no metadata was found
|
|
167
|
+
if (Object.keys(metadata).length === 0) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return metadata;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=flac.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flac.js","sourceRoot":"","sources":["../../src/parsers/flac.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id3.d.ts","sourceRoot":"","sources":["../../src/parsers/id3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AA4IlF;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAuG1F"}
|