taglib-wasm 0.1.0 → 0.2.4

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/README.md CHANGED
@@ -1,18 +1,21 @@
1
1
  # taglib-wasm
2
2
 
3
- [TagLib](https://taglib.org/) is the de-facto standard library for reading and editing metadata tags (Title, Album, Artist, etc.) in all popular audio formats. See [“Goals & Features”](https://taglib.org/) for the reasons TagLib is so great.
3
+ [TagLib](https://taglib.org/) is the most robust, de-facto standard for reading and editing metadata tags (Title, Album, Artist, etc.) in all popular audio formats. See [“Goals & Features”](https://taglib.org/) for the reasons TagLib is so great.
4
4
 
5
- `taglib-wasm` makes the robust, industry-standard TagLib tagging library available to browser, Deno, Node.js, and Bun apps for the first time, thanks to the magic of [Wasm](https://webassembly.org/) ([WebAssembly](https://webassembly.org/)).
5
+ `taglib-wasm` is designed to be **TagLib for JavaScript/TypeScript** platforms specifically Deno, Node.js, Bun, web browsers, and Cloudflare Workers. It does this by leveraging technologies including [TagLib](https://taglib.org/) itself, [Emscripten](https://emscripten.org/), and [Wasm](https://webassembly.org/) ([WebAssembly](https://webassembly.org/)).
6
6
 
7
- ### Why?
7
+ > [!NOTE]
8
+ > I’m personally using this to solve a problem for another project I’m creating, but this project is still very much a baby. You may experience tantrums at this stage of `taglib-wasm`’s development.
8
9
 
9
- In the process of building my own utility to improve the metadata of my own music collection, I discovered that the JavaScipt/TypeScipt ecosystem has no battle-tested audio tagging library that supports reading and writing music metadata to all popular audio formats.
10
+ ## Why?
11
+
12
+ In the process of building a utility to improve the metadata of my music collection, I discovered that the JavaScipt/TypeScipt ecosystem had no battle-tested audio tagging library that supports reading and writing music metadata to all popular audio formats.
10
13
 
11
14
  [`mp3tag.js`](https://mp3tag.js.org/) is mature and active, but only supports MP3 files and ID3 tags. TagLib was an ideal choice from a maturity and capabilities point of view, but wrappers like `node-taglib` appeared to be dormant, and I wanted to avoid making users install platform-specific dependencies whenever possible.
12
15
 
13
16
  ## 🎯 Features
14
17
 
15
- - **✅ Universal compatibility** – Works in browsers, Deno, Node.js, and Bun
18
+ - **✅ Universal compatibility** – Works with Deno, Node.js, Bun, web browsers, and Cloudflare Workers
16
19
  - **✅ TypeScript first** – Complete type definitions and modern API
17
20
  - **✅ Full audio format support** – Supports all audio formats supported by TagLib
18
21
  - **✅ Format abstraction** – `taglib-wasm` deals with how tags are read from/written to in different file formats
@@ -22,23 +25,28 @@ In the process of building my own utility to improve the metadata of my own musi
22
25
 
23
26
  ## 📦 Installation
24
27
 
25
- ```bash
26
- # For Deno projects
27
- import { TagLib } from "jsr:@taglib/wasm";
28
+ ### Deno
29
+
30
+ ```typescript
31
+ import { TagLib } from "jsr:@charleswiltgen/taglib-wasm";
32
+ ```
28
33
 
29
- # For NPM/Node.js projects
34
+ ### Node.js
35
+
36
+ ```bash
30
37
  npm install taglib-wasm
38
+ ```
39
+ ### Bun
31
40
 
32
- # For Bun projects
41
+ ```bash
33
42
  bun add taglib-wasm
34
43
  ```
35
-
36
44
  ## 🚀 Quick Start
37
45
 
38
46
  ### Deno
39
47
 
40
48
  ```typescript
41
- import { TagLib } from "./src/mod.ts";
49
+ import { TagLib } from "jsr:@charleswiltgen/taglib-wasm";
42
50
 
43
51
  // Initialize TagLib WASM
44
52
  const taglib = await TagLib.initialize();
@@ -63,7 +71,7 @@ file.setAlbum("New Album");
63
71
 
64
72
  console.log("Updated tags:", file.tag());
65
73
 
66
- // Advanced metadata (format-agnostic)
74
+ // Automatic tag mapping (format-agnostic)
67
75
  file.setAcoustidFingerprint("AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
68
76
  file.setAcoustidId("e7359e88-f1f7-41ed-b9f6-16e58e906997");
69
77
  file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
@@ -75,7 +83,7 @@ file.dispose();
75
83
  ### Bun
76
84
 
77
85
  ```typescript
78
- import { TagLib } from 'taglib-wasm';
86
+ import { TagLib } from "taglib-wasm";
79
87
 
80
88
  // Initialize TagLib WASM
81
89
  const taglib = await TagLib.initialize();
@@ -100,7 +108,7 @@ file.setAlbum("New Album");
100
108
 
101
109
  console.log("Updated tags:", file.tag());
102
110
 
103
- // Advanced metadata (format-agnostic)
111
+ // Automatic tag mapping (format-agnostic)
104
112
  file.setAcoustidFingerprint("AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
105
113
  file.setAcoustidId("e7359e88-f1f7-41ed-b9f6-16e58e906997");
106
114
  file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
@@ -112,8 +120,8 @@ file.dispose();
112
120
  ### Node.js
113
121
 
114
122
  ```typescript
115
- import { TagLib } from 'taglib-wasm';
116
- import { readFile } from 'fs/promises';
123
+ import { TagLib } from "taglib-wasm";
124
+ import { readFile } from "fs/promises";
117
125
 
118
126
  // Initialize TagLib WASM
119
127
  const taglib = await TagLib.initialize();
@@ -138,7 +146,7 @@ file.setAlbum("New Album");
138
146
 
139
147
  console.log("Updated tags:", file.tag());
140
148
 
141
- // Advanced metadata (format-agnostic)
149
+ // Automatic tag mapping (format-agnostic)
142
150
  file.setAcoustidFingerprint("AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
143
151
  file.setAcoustidId("e7359e88-f1f7-41ed-b9f6-16e58e906997");
144
152
  file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
@@ -150,7 +158,7 @@ file.dispose();
150
158
  ### Browser
151
159
 
152
160
  ```typescript
153
- import { TagLib } from 'taglib-wasm';
161
+ import { TagLib } from "taglib-wasm";
154
162
 
155
163
  // Initialize TagLib WASM
156
164
  const taglib = await TagLib.initialize();
@@ -177,7 +185,7 @@ file.setAlbum("New Album");
177
185
 
178
186
  console.log("Updated tags:", file.tag());
179
187
 
180
- // Advanced metadata (format-agnostic)
188
+ // Automatic tag mapping (format-agnostic)
181
189
  file.setAcoustidFingerprint("AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
182
190
  file.setAcoustidId("e7359e88-f1f7-41ed-b9f6-16e58e906997");
183
191
  file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
@@ -186,6 +194,61 @@ file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
186
194
  file.dispose();
187
195
  ```
188
196
 
197
+ ### Cloudflare Workers
198
+
199
+ ```typescript
200
+ import { TagLib } from "taglib-wasm/workers";
201
+
202
+ export default {
203
+ async fetch(request: Request): Promise<Response> {
204
+ if (request.method === "POST") {
205
+ try {
206
+ // Initialize TagLib WASM
207
+ const taglib = await TagLib.initialize({
208
+ memory: { initial: 8 * 1024 * 1024 }, // 8MB for Workers
209
+ });
210
+
211
+ // Get audio data from request
212
+ const audioData = new Uint8Array(await request.arrayBuffer());
213
+ const file = taglib.openFile(audioData);
214
+
215
+ // Read metadata
216
+ const tags = file.tag();
217
+ const props = file.audioProperties();
218
+
219
+ // Extract metadata
220
+ const metadata = {
221
+ title: tags.title,
222
+ artist: tags.artist,
223
+ album: tags.album,
224
+ year: tags.year,
225
+ genre: tags.genre,
226
+ duration: props.length,
227
+ bitrate: props.bitrate,
228
+ format: file.format(),
229
+ };
230
+
231
+ // Clean up
232
+ file.dispose();
233
+
234
+ return Response.json({
235
+ success: true,
236
+ metadata,
237
+ fileSize: audioData.length,
238
+ });
239
+ } catch (error) {
240
+ return Response.json({
241
+ error: "Failed to process audio file",
242
+ message: (error as Error).message,
243
+ }, { status: 500 });
244
+ }
245
+ }
246
+
247
+ return new Response("Send POST request with audio file", { status: 400 });
248
+ },
249
+ };
250
+ ```
251
+
189
252
  ## 📋 Supported Formats
190
253
 
191
254
  All formats are **fully tested and working**:
@@ -197,11 +260,12 @@ All formats are **fully tested and working**:
197
260
  - ✅ **WAV** – INFO chunk metadata
198
261
  - 🔄 **Additional formats**: Opus, APE, MPC, WavPack, TrueAudio, and more
199
262
 
200
- ## 🎯 Advanced Metadata Support
263
+ ## 🎯 Automatic Tag Mapping
201
264
 
202
- TagLib WASM supports **format-agnostic tag naming** so you don’t have to worry about how the same tag is stored differently in different audio container formats.
265
+ TagLib WASM supports **automatic tag mapping** so you don’t have to worry about how the same tag is stored differently in different audio container formats.
203
266
 
204
267
  ### AcoustID example
268
+
205
269
  ```typescript
206
270
  // Single API works for ALL formats (MP3, FLAC, OGG, MP4)
207
271
  file.setAcoustidFingerprint("AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
@@ -214,6 +278,7 @@ file.setAcoustidId("e7359e88-f1f7-41ed-b9f6-16e58e906997");
214
278
  ```
215
279
 
216
280
  ### MusicBrainz example
281
+
217
282
  ```typescript
218
283
  // Professional music database integration
219
284
  file.setMusicBrainzTrackId("f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab");
@@ -222,6 +287,7 @@ file.setMusicBrainzArtistId("12345678-90ab-cdef-1234-567890abcdef");
222
287
  ```
223
288
 
224
289
  ### Volume example
290
+
225
291
  ```typescript
226
292
  // ReplayGain support (automatic format mapping)
227
293
  file.setReplayGainTrackGain("-6.54 dB");
@@ -234,6 +300,7 @@ file.setAppleSoundCheck("00000150 00000150 00000150 00000150...");
234
300
  ```
235
301
 
236
302
  ### Extended fields
303
+
237
304
  ```typescript
238
305
  // Advanced metadata fields
239
306
  file.setExtendedTag({
@@ -249,7 +316,7 @@ file.setExtendedTag({
249
316
  });
250
317
  ```
251
318
 
252
- **📖 See [ADVANCED_METADATA.md](ADVANCED_METADATA.md) for complete documentation**
319
+ **📖 See [docs/Automatic-Tag-Mapping.md](docs/Automatic-Tag-Mapping.md) for complete documentation**
253
320
 
254
321
  ## 🏗️ Development
255
322
 
@@ -272,7 +339,7 @@ deno task test
272
339
 
273
340
  ### Project Structure
274
341
 
275
- ```
342
+ ```text
276
343
  src/
277
344
  ├── mod.ts # Main module exports
278
345
  ├── taglib.ts # Core TagLib and AudioFile classes
@@ -284,7 +351,7 @@ build/
284
351
  ├── taglib.js # Generated Emscripten JavaScript
285
352
  └── taglib.wasm # Compiled WebAssembly module
286
353
 
287
- test-files/ # Sample audio files for testing
354
+ tests/ # Test files and sample audio files
288
355
  tests/ # Test suite
289
356
  examples/ # Usage examples for different runtimes
290
357
  ├── deno/ # Deno-specific examples
@@ -307,12 +374,12 @@ bun run test-systematic.ts
307
374
  # Run with Node.js
308
375
  npm test
309
376
 
310
- # Results: 5/5 formats working ✅ across all runtimes
311
- # ✅ WAV - 44.1kHz, stereo, tag reading/writing
312
- # ✅ MP3 - 44.1kHz, stereo, ID3 tag support
313
- # ✅ FLAC - 44.1kHz, stereo, Vorbis comments
314
- # ✅ OGG - 44.1kHz, stereo, Vorbis comments
315
- # ✅ M4A - 44.1kHz, stereo, iTunes metadata
377
+ # Results: All formats working ✅ across all runtimes
378
+ # ✅ WAV - INFO chunk metadata support
379
+ # ✅ MP3 - ID3v1/v2 tag support
380
+ # ✅ FLAC - Vorbis comments and properties
381
+ # ✅ OGG - Vorbis comments
382
+ # ✅ M4A - iTunes-compatible metadata atoms
316
383
  ```
317
384
 
318
385
  ## 🔧 Technical Implementation
@@ -337,9 +404,9 @@ npm test
337
404
 
338
405
  ```typescript
339
406
  class TagLib {
340
- static async initialize(config?: TagLibConfig): Promise<TagLib>
341
- openFile(buffer: Uint8Array): AudioFile
342
- getModule(): TagLibModule
407
+ static async initialize(config?: TagLibConfig): Promise<TagLib>;
408
+ openFile(buffer: Uint8Array): AudioFile;
409
+ getModule(): TagLibModule;
343
410
  }
344
411
  ```
345
412
 
@@ -348,51 +415,51 @@ class TagLib {
348
415
  ```typescript
349
416
  class AudioFile {
350
417
  // Validation
351
- isValid(): boolean
352
- format(): string
418
+ isValid(): boolean;
419
+ format(): string;
353
420
 
354
421
  // Properties
355
- audioProperties(): AudioProperties
356
- tag(): TagData
422
+ audioProperties(): AudioProperties;
423
+ tag(): TagData;
357
424
 
358
425
  // Tag Writing
359
- setTitle(title: string): void
360
- setArtist(artist: string): void
361
- setAlbum(album: string): void
362
- setComment(comment: string): void
363
- setGenre(genre: string): void
364
- setYear(year: number): void
365
- setTrack(track: number): void
426
+ setTitle(title: string): void;
427
+ setArtist(artist: string): void;
428
+ setAlbum(album: string): void;
429
+ setComment(comment: string): void;
430
+ setGenre(genre: string): void;
431
+ setYear(year: number): void;
432
+ setTrack(track: number): void;
366
433
 
367
434
  // File Operations
368
- save(): boolean
369
- dispose(): void
435
+ save(): boolean;
436
+ dispose(): void;
370
437
 
371
- // Advanced Metadata (Format-Agnostic)
372
- extendedTag(): ExtendedTag
373
- setExtendedTag(tag: Partial<ExtendedTag>): void
438
+ // Automatic Tag Mapping (Format-Agnostic)
439
+ extendedTag(): ExtendedTag;
440
+ setExtendedTag(tag: Partial<ExtendedTag>): void;
374
441
 
375
442
  // AcoustID Integration
376
- setAcoustidFingerprint(fingerprint: string): void
377
- getAcoustidFingerprint(): string | undefined
378
- setAcoustidId(id: string): void
379
- getAcoustidId(): string | undefined
443
+ setAcoustidFingerprint(fingerprint: string): void;
444
+ getAcoustidFingerprint(): string | undefined;
445
+ setAcoustidId(id: string): void;
446
+ getAcoustidId(): string | undefined;
380
447
 
381
448
  // MusicBrainz Integration
382
- setMusicBrainzTrackId(id: string): void
383
- getMusicBrainzTrackId(): string | undefined
449
+ setMusicBrainzTrackId(id: string): void;
450
+ getMusicBrainzTrackId(): string | undefined;
384
451
 
385
452
  // Volume Normalization
386
- setReplayGainTrackGain(gain: string): void
387
- getReplayGainTrackGain(): string | undefined
388
- setReplayGainTrackPeak(peak: string): void
389
- getReplayGainTrackPeak(): string | undefined
390
- setReplayGainAlbumGain(gain: string): void
391
- getReplayGainAlbumGain(): string | undefined
392
- setReplayGainAlbumPeak(peak: string): void
393
- getReplayGainAlbumPeak(): string | undefined
394
- setAppleSoundCheck(iTunNORM: string): void
395
- getAppleSoundCheck(): string | undefined
453
+ setReplayGainTrackGain(gain: string): void;
454
+ getReplayGainTrackGain(): string | undefined;
455
+ setReplayGainTrackPeak(peak: string): void;
456
+ getReplayGainTrackPeak(): string | undefined;
457
+ setReplayGainAlbumGain(gain: string): void;
458
+ getReplayGainAlbumGain(): string | undefined;
459
+ setReplayGainAlbumPeak(peak: string): void;
460
+ getReplayGainAlbumPeak(): string | undefined;
461
+ setAppleSoundCheck(iTunNORM: string): void;
462
+ getAppleSoundCheck(): string | undefined;
396
463
  }
397
464
  ```
398
465
 
@@ -401,10 +468,10 @@ class AudioFile {
401
468
  ```typescript
402
469
  interface TagLibConfig {
403
470
  memory?: {
404
- initial?: number; // Initial memory size (default: 16MB)
405
- maximum?: number; // Maximum memory size (default: 256MB)
471
+ initial?: number; // Initial memory size (default: 16MB)
472
+ maximum?: number; // Maximum memory size (default: 256MB)
406
473
  };
407
- debug?: boolean; // Enable debug output
474
+ debug?: boolean; // Enable debug output
408
475
  }
409
476
  ```
410
477
 
@@ -412,14 +479,14 @@ interface TagLibConfig {
412
479
 
413
480
  TagLib WASM works seamlessly across all major JavaScript runtimes:
414
481
 
415
- | Runtime | Status | Installation | Performance | TypeScript |
416
- |---------|--------|--------------|-------------|------------|
417
- | **Deno** | ✅ Full | `jsr:@taglib/wasm` | Excellent | Native |
418
- | **Bun** | ✅ Full | `bun add taglib-wasm` | Excellent | Native |
419
- | **Node.js** | ✅ Full | `npm install taglib-wasm` | Good | Via loader |
420
- | **Browser** | ✅ Full | CDN/bundler | Good | Via build |
482
+ | Runtime | Status | Installation | Performance | TypeScript |
483
+ | ----------- | ------- | --------------------------------- | ----------- | ---------- |
484
+ | **Deno** | ✅ Full | `jsr:@charleswiltgen/taglib-wasm` | Excellent | Native |
485
+ | **Bun** | ✅ Full | `bun add taglib-wasm` | Excellent | Native |
486
+ | **Node.js** | ✅ Full | `npm install taglib-wasm` | Good | Via loader |
487
+ | **Browser** | ✅ Full | CDN/bundler | Good | Via build |
421
488
 
422
- **📖 See [RUNTIME_COMPATIBILITY.md](RUNTIME_COMPATIBILITY.md) for detailed runtime information**
489
+ **📖 See [docs/Runtime-Compatibility.md](docs/Runtime-Compatibility.md) for detailed runtime information**
423
490
 
424
491
  ## 🚧 Known Limitations
425
492
 
@@ -446,7 +513,3 @@ Contributions welcome! Areas of interest:
446
513
 
447
514
  - [TagLib](https://taglib.org/) – Excellent audio metadata library
448
515
  - [Emscripten](https://emscripten.org/) – WebAssembly compilation toolchain
449
-
450
- ---
451
-
452
- **Status**: Production Ready - Universal audio metadata handling across all JavaScript runtimes.
package/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview Main module exports for TagLib WASM
3
+ *
4
+ * TagLib v2.1 compiled to WebAssembly with TypeScript bindings
5
+ * for universal audio metadata handling.
6
+ */
7
+
8
+ export { AudioFile, TagLib } from "./src/taglib.ts";
9
+ export type {
10
+ AudioFormat,
11
+ AudioProperties,
12
+ ExtendedTag,
13
+ FieldMapping,
14
+ METADATA_MAPPINGS,
15
+ Picture,
16
+ PictureType,
17
+ PropertyMap,
18
+ Tag,
19
+ TagLibConfig,
20
+ } from "./src/types.ts";
21
+ export type { TagLibModule } from "./src/wasm.ts";
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "taglib-wasm",
3
- "version": "0.1.0",
3
+ "version": "0.2.4",
4
4
  "description": "TagLib compiled to WebAssembly with TypeScript bindings for universal audio metadata handling",
5
- "main": "src/mod.ts",
6
- "types": "src/mod.ts",
5
+ "main": "index.ts",
6
+ "types": "index.ts",
7
+ "exports": {
8
+ ".": "./index.ts",
9
+ "./workers": "./src/workers.ts"
10
+ },
7
11
  "files": [
12
+ "index.ts",
8
13
  "src/**/*",
9
14
  "build/taglib.wasm",
10
15
  "build/taglib.js",
@@ -15,13 +20,14 @@
15
20
  "build:wasm": "./build/build-wasm.sh",
16
21
  "build:ts": "tsc",
17
22
  "build": "npm run build:wasm && npm run build:ts",
18
- "test": "deno run --allow-read test-systematic.ts",
19
- "test:bun": "bun run test-systematic.ts",
20
- "test:node": "node --loader ts-node/esm test-systematic.ts",
23
+ "test": "deno run --allow-read tests/test-systematic.ts",
24
+ "test:bun": "bun run tests/test-systematic.ts",
25
+ "test:node": "node --loader ts-node/esm tests/test-systematic.ts",
21
26
  "update-taglib": "./scripts/update-taglib.sh",
22
- "publish:npm": "npm publish",
23
- "publish:jsr": "deno publish",
24
- "publish:all": "npm run publish:npm && npm run publish:jsr"
27
+ "publish:npm": "echo 'Use GitHub Actions workflow for publishing'",
28
+ "publish:github": "echo 'Use GitHub Actions workflow for publishing'",
29
+ "publish:jsr": "echo 'Use GitHub Actions workflow for publishing'",
30
+ "publish:all": "echo 'Use GitHub Actions workflow for publishing'"
25
31
  },
26
32
  "keywords": [
27
33
  "taglib",
@@ -37,6 +43,8 @@
37
43
  "deno",
38
44
  "node",
39
45
  "browser",
46
+ "cloudflare",
47
+ "workers",
40
48
  "replaygain",
41
49
  "musicbrainz",
42
50
  "acoustid"
@@ -45,7 +53,10 @@
45
53
  "license": "MIT",
46
54
  "repository": {
47
55
  "type": "git",
48
- "url": "https://github.com/CharlesWiltgen/taglib-wasm.git"
56
+ "url": "git+https://github.com/CharlesWiltgen/taglib-wasm.git"
57
+ },
58
+ "publishConfig": {
59
+ "registry": "https://registry.npmjs.org/"
49
60
  },
50
61
  "bugs": {
51
62
  "url": "https://github.com/CharlesWiltgen/taglib-wasm/issues"