taglib-wasm 0.3.3 → 0.3.9

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.
Files changed (68) hide show
  1. package/CONTRIBUTING.md +293 -0
  2. package/NOTICE +34 -0
  3. package/README.md +122 -511
  4. package/dist/index.d.ts +132 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +137 -0
  7. package/dist/index.ts +220 -0
  8. package/dist/src/constants.d.ts +201 -0
  9. package/dist/src/constants.d.ts.map +1 -0
  10. package/dist/src/constants.ts +227 -0
  11. package/dist/src/errors.d.ts +89 -0
  12. package/dist/src/errors.d.ts.map +1 -0
  13. package/dist/src/errors.ts +237 -0
  14. package/dist/src/file-utils.d.ts +205 -0
  15. package/dist/src/file-utils.d.ts.map +1 -0
  16. package/dist/src/file-utils.ts +467 -0
  17. package/dist/src/file.js +47 -0
  18. package/dist/src/global.d.ts +10 -0
  19. package/dist/src/mod.d.ts +9 -0
  20. package/dist/src/mod.d.ts.map +1 -0
  21. package/dist/src/mod.ts +19 -0
  22. package/dist/src/simple.d.ts +347 -0
  23. package/dist/src/simple.d.ts.map +1 -0
  24. package/dist/src/simple.ts +659 -0
  25. package/dist/src/taglib.d.ts +502 -0
  26. package/dist/src/taglib.d.ts.map +1 -0
  27. package/dist/src/taglib.ts +959 -0
  28. package/dist/src/types.d.ts +323 -0
  29. package/dist/src/types.d.ts.map +1 -0
  30. package/dist/src/types.ts +538 -0
  31. package/dist/src/utils/file.d.ts +15 -0
  32. package/dist/src/utils/file.d.ts.map +1 -0
  33. package/dist/src/utils/file.ts +82 -0
  34. package/dist/src/utils/write.d.ts +15 -0
  35. package/dist/src/utils/write.d.ts.map +1 -0
  36. package/dist/src/utils/write.ts +61 -0
  37. package/dist/src/wasm-workers.d.ts +33 -0
  38. package/dist/src/wasm-workers.d.ts.map +1 -0
  39. package/dist/src/wasm-workers.ts +176 -0
  40. package/dist/src/wasm.d.ts +97 -0
  41. package/dist/src/wasm.d.ts.map +1 -0
  42. package/dist/src/wasm.ts +133 -0
  43. package/dist/src/web-utils.d.ts +180 -0
  44. package/dist/src/web-utils.d.ts.map +1 -0
  45. package/dist/src/web-utils.ts +347 -0
  46. package/dist/src/workers.d.ts +219 -0
  47. package/dist/src/workers.d.ts.map +1 -0
  48. package/dist/src/workers.ts +465 -0
  49. package/dist/src/write.js +33 -0
  50. package/dist/taglib-wrapper.d.ts +5 -0
  51. package/dist/taglib-wrapper.js +14 -0
  52. package/dist/taglib.wasm +0 -0
  53. package/index.ts +100 -7
  54. package/package.json +40 -16
  55. package/src/errors.ts +237 -0
  56. package/src/file-utils.ts +467 -0
  57. package/src/global.d.ts +10 -0
  58. package/src/simple.ts +399 -84
  59. package/src/taglib.ts +522 -28
  60. package/src/types.ts +1 -1
  61. package/src/utils/file.ts +82 -0
  62. package/src/utils/write.ts +61 -0
  63. package/src/wasm-workers.ts +13 -4
  64. package/src/wasm.ts +1 -1
  65. package/src/web-utils.ts +347 -0
  66. package/src/workers.ts +32 -13
  67. package/build/taglib.js +0 -2407
  68. package/build/taglib.wasm +0 -0
package/README.md CHANGED
@@ -1,48 +1,48 @@
1
1
  # TagLib-Wasm
2
2
 
3
- > TagLib for TypeScript platforms: Deno, Node.js, Bun, browsers, and Cloudflare
4
- > Workers
5
-
6
- This is the Wasm version of [**TagLib**](https://taglib.org/), the most robust,
7
- de-facto standard for reading and editing metadata tags (Title, Album, Artist,
8
- etc.) in all popular audio formats. `taglib-wasm` exists because the
9
- JavaScipt/TypeScipt ecosystem had no battle-tested audio tagging library that
10
- supports reading and writing music metadata to all popular audio formats — until
11
- now!
12
-
13
- `taglib-wasm` stands on the shoulders of giants, including
3
+ [![npm version](https://img.shields.io/npm/v/taglib-wasm.svg?logo=nodedotjs&logoColor=f5f5f5)](https://www.npmjs.com/package/taglib-wasm)
4
+ [![npm downloads](https://img.shields.io/npm/dm/taglib-wasm.svg)](https://www.npmjs.com/package/taglib-wasm)
5
+ [![License](https://img.shields.io/npm/l/taglib-wasm.svg)](https://github.com/CharlesWiltgen/taglib-wasm/blob/main/LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178c6.svg?logo=typescript&logoColor=f5f5f5)](https://www.typescriptlang.org/)
7
+ [![Built with Emscripten](https://img.shields.io/badge/Built%20with-Emscripten-4B9BFF.svg)](https://emscripten.org/)
8
+ <br>[![Deno](https://img.shields.io/badge/Deno-000000?logo=deno&logoColor=white)](https://deno.land/)
9
+ [![Node.js](https://img.shields.io/badge/Node.js-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/)
10
+ [![Bun](https://img.shields.io/badge/Bun-000000?logo=bun&logoColor=white)](https://bun.sh/)
11
+ [![Cloudflare Workers](https://img.shields.io/badge/Cloudflare%20Workers-F38020?logo=cloudflare&logoColor=white)](https://workers.cloudflare.com/)
12
+ [![Electron](https://img.shields.io/badge/Electron-47848F?logo=electron&logoColor=white)](https://www.electronjs.org/)
13
+ [![Browser](https://img.shields.io/badge/Browser-4285F4?logo=googlechrome&logoColor=white)]()
14
+
15
+ **TagLib-Wasm** is the universal tagging library for TypeScript platforms: Deno,
16
+ Node.js, Bun, Cloudflare Workers, Electron, and browsers. It’s the answer to the
17
+ question:
18
+
19
+ > “What if [**TagLib**](https://taglib.org/), but TypeScript?”
20
+
21
+ This project exists because the TypeScipt/JavaScript ecosystem had no
22
+ battle-tested audio tagging library that supports reading and writing music
23
+ metadata to all popular audio formats. It aspires to be a universal solution for
24
+ all **TypeScript**-capable platforms — Deno, Node.js, Bun, Electron, Cloudflare
25
+ Workers, and browsers.
26
+
27
+ TagLib-Wasm stands on the shoulders of giants, including
14
28
  [TagLib](https://taglib.org/) itself, [Emscripten](https://emscripten.org/), and
15
29
  [Wasm](https://webassembly.org/) ([WebAssembly](https://webassembly.org/)).
16
-
17
- `taglib-wasm` aspires to be a universal solution for **JavaScript/TypeScript**
18
- platforms — Deno, Node.js, Bun, web browsers, and Cloudflare Workers. Note: This
19
- project is a baby, and you’re likely to experience some surprises at this stage
20
- of its development. I’m extremely motivated to help address them, since I’ll
21
- also be depending on this project.
22
-
23
- ## 🤔 Why?
24
-
25
- Because there’s nothing like it. [`mp3tag.js`](https://mp3tag.js.org/) is mature
26
- and active, but only supports MP3 files and ID3 tags. TagLib was an ideal choice
27
- from a maturity and capabilities point of view, but wrappers like `node-taglib`
28
- appeared to be dormant, and I wanted to avoid making users install
29
- platform-specific dependencies whenever possible.
30
+ TagLib itself is legendary and a core dependency of many music apps.
30
31
 
31
32
  ## 🎯 Features
32
33
 
33
- - **✅ Universal compatibility** – Works with Deno, Node.js, Bun, web browsers,
34
- and Cloudflare Workers
35
- - **✅ TypeScript first** – Complete type definitions and modern API
36
34
  - **✅ Full audio format support** – Supports all audio formats supported by
37
35
  TagLib
38
- - **✅ Format abstraction** – `taglib-wasm` deals with how tags are read
39
- from/written to in different file formats
36
+ - **✅ TypeScript first** – Complete type definitions and modern API
37
+ - **✅ Wide TS/JS runtime support** Deno, Node.js, Bun, Electron, Cloudflare
38
+ Workers, and browsers
39
+ - **✅ Format abstraction** – Handles container format details automagically
40
+ when possible
40
41
  - **✅ Zero dependencies** – Self-contained Wasm bundle
41
- - **✅ Memory efficient** – In-memory processing without filesystem access
42
42
  - **✅ Production ready** – Growing test suite helps ensure safety and
43
43
  reliability
44
- - **🆕 Two API styles** – Choose between Simple (3 functions) or Core (full
45
- control) APIs
44
+ - **✅ Two API styles** – Use the Simple API (3 functions), or the full “Core”
45
+ API for more advanced applications
46
46
 
47
47
  ## 📦 Installation
48
48
 
@@ -83,307 +83,103 @@ npx tsx your-script.ts
83
83
  bun add taglib-wasm
84
84
  ```
85
85
 
86
- ## 🚀 Quick Start
87
-
88
- ### Simple API
89
-
90
- This was inspired by [go-taglib](https://github.com/sentriz/go-taglib), a
91
- similar project for Go created at about the same time.
92
-
93
- ```typescript
94
- import { readProperties, readTags, writeTags } from "taglib-wasm/simple";
95
-
96
- // Read tags
97
- const tags = await readTags("song.mp3");
98
- console.log(tags.title, tags.artist, tags.album);
86
+ ### Electron
99
87
 
100
- // Write tags
101
- await writeTags("song.mp3", {
102
- title: "New Title",
103
- artist: "New Artist",
104
- album: "New Album",
105
- });
106
-
107
- // Read audio properties
108
- const props = await readProperties("song.mp3");
109
- console.log(`Duration: ${props.length}s, Bitrate: ${props.bitrate} kbps`);
88
+ ```bash
89
+ npm install taglib-wasm
110
90
  ```
111
91
 
112
- ### Core API
113
-
114
- The Core API provides full control for more advanced applications.
92
+ Works in both main and renderer processes:
115
93
 
116
94
  ```typescript
95
+ // Main process
117
96
  import { TagLib } from "taglib-wasm";
118
97
 
119
- // Initialize taglib-wasm
120
- const taglib = await TagLib.initialize();
121
-
122
- // Load audio file from buffer
123
- const audioData = await readFile("song.mp3"); // Node.js/Bun: fs.readFile, Deno: Deno.readFile
124
- const file = taglib.openFile(audioData);
125
-
126
- // Read metadata
127
- const tags = file.tag();
128
- const props = file.audioProperties();
129
-
130
- console.log(`Title: ${tags.title}`);
131
- console.log(`Artist: ${tags.artist}`);
132
- console.log(`Duration: ${props.length}s`);
133
- console.log(`Bitrate: ${props.bitrate} kbps`);
134
-
135
- // Write metadata
136
- const tag = file.tag();
137
- tag.setTitle("New Title");
138
- tag.setArtist("New Artist");
139
- tag.setAlbum("New Album");
140
-
141
- // Save changes
142
- file.save();
143
-
144
- console.log("Updated tags:", file.tag());
145
-
146
- // Clean up
147
- file.dispose();
98
+ // Renderer process (with nodeIntegration: true)
99
+ const { TagLib } = require("taglib-wasm");
148
100
  ```
149
101
 
150
- ### Tag Constants
102
+ ## 🚀 Quick Start
151
103
 
152
- taglib-wasm provides type-safe tag constants with IDE autocomplete:
104
+ ### Simple API (Recommended)
153
105
 
154
106
  ```typescript
155
- import { Tags } from "taglib-wasm";
107
+ import { readTags, updateTags } from "taglib-wasm/simple";
156
108
 
157
- // Use constants for better type safety and autocomplete
158
- const properties = file.properties();
159
-
160
- // Read properties
161
- const title = properties[Tags.Title]?.[0];
162
- const albumArtist = properties[Tags.AlbumArtist]?.[0];
163
- const musicBrainzId = properties[Tags.MusicBrainzArtistId]?.[0];
109
+ // Read tags - just one function call!
110
+ const tags = await readTags("song.mp3");
111
+ console.log(tags.title, tags.artist, tags.album);
164
112
 
165
- // Write properties
166
- file.setProperties({
167
- [Tags.Title]: ["My Song"],
168
- [Tags.AlbumArtist]: ["Various Artists"],
169
- [Tags.Bpm]: ["128"],
113
+ // Update tags in-place - even simpler!
114
+ await updateTags("song.mp3", {
115
+ title: "New Title",
116
+ artist: "New Artist",
117
+ album: "New Album",
170
118
  });
171
-
172
- // All constants provide IDE autocomplete
173
- Tags.Title; // → "TITLE"
174
- Tags.Artist; // → "ARTIST"
175
- Tags.AlbumArtist; // → "ALBUMARTIST"
176
- Tags.TrackGain; // → "REPLAYGAIN_TRACK_GAIN"
177
- // ... and many more
178
119
  ```
179
120
 
180
- See [Tag Name Constants](docs/Tag-Name-Constants.md) for the complete list of
181
- available tags and format-specific mappings.
182
-
183
- ## Platform examples
184
-
185
- ### Deno
186
-
187
- ```typescript
188
- import { TagLib } from "npm:taglib-wasm";
189
-
190
- // Initialize taglib-wasm
191
- const taglib = await TagLib.initialize();
192
-
193
- // Load audio file from filesystem
194
- const audioData = await Deno.readFile("song.mp3");
195
- const file = taglib.openFile(audioData);
196
-
197
- // Read metadata
198
- const tags = file.tag();
199
- const props = file.audioProperties();
200
-
201
- console.log(`Title: ${tags.title}`);
202
- console.log(`Artist: ${tags.artist}`);
203
- console.log(`Duration: ${props.length}s`);
204
- console.log(`Bitrate: ${props.bitrate} kbps`);
205
-
206
- // Write metadata
207
- const tag = file.tag();
208
- tag.setTitle("New Title");
209
- tag.setArtist("New Artist");
210
- tag.setAlbum("New Album");
211
-
212
- // Save changes
213
- file.save();
214
-
215
- console.log("Updated tags:", file.tag());
216
-
217
- // Clean up
218
- file.dispose();
219
- ```
220
-
221
- ### Node.js
121
+ ### Core API (Advanced)
222
122
 
223
123
  ```typescript
224
124
  import { TagLib } from "taglib-wasm";
225
- import { readFile } from "fs/promises";
226
125
 
227
126
  // Initialize taglib-wasm
228
127
  const taglib = await TagLib.initialize();
229
128
 
230
- // Load audio file from filesystem
231
- const audioData = await readFile("song.mp3");
232
- const file = taglib.openFile(audioData);
233
-
234
- // Read metadata
235
- const tags = file.tag();
236
- const props = file.audioProperties();
237
-
238
- console.log(`Title: ${tags.title}`);
239
- console.log(`Artist: ${tags.artist}`);
240
- console.log(`Duration: ${props.length}s`);
241
- console.log(`Bitrate: ${props.bitrate} kbps`);
129
+ // Load audio file
130
+ const file = await taglib.open("song.mp3");
242
131
 
243
- // Write metadata
132
+ // Read and update metadata
244
133
  const tag = file.tag();
245
134
  tag.setTitle("New Title");
246
135
  tag.setArtist("New Artist");
247
- tag.setAlbum("New Album");
248
136
 
249
137
  // Save changes
250
138
  file.save();
251
139
 
252
- console.log("Updated tags:", file.tag());
253
-
254
140
  // Clean up
255
141
  file.dispose();
256
142
  ```
257
143
 
258
- ### Bun
144
+ ### Working with Cover Art
259
145
 
260
146
  ```typescript
261
- import { TagLib } from "taglib-wasm";
262
-
263
- // Initialize taglib-wasm
264
- const taglib = await TagLib.initialize();
265
-
266
- // Load from file system (Bun's native file API)
267
- const audioData = await Bun.file("song.mp3").arrayBuffer();
268
- const file = taglib.openFile(new Uint8Array(audioData));
269
-
270
- // Read metadata
271
- const tags = file.tag();
272
- const props = file.audioProperties();
147
+ import { getCoverArt, setCoverArt } from "taglib-wasm/simple";
273
148
 
274
- console.log(`Title: ${tags.title}`);
275
- console.log(`Artist: ${tags.artist}`);
276
- console.log(`Duration: ${props.length}s`);
277
- console.log(`Bitrate: ${props.bitrate} kbps`);
278
-
279
- // Write metadata
280
- const tag = file.tag();
281
- tag.setTitle("New Title");
282
- tag.setArtist("New Artist");
283
- tag.setAlbum("New Album");
284
-
285
- // Save changes
286
- file.save();
287
-
288
- console.log("Updated tags:", file.tag());
149
+ // Extract cover art
150
+ const coverData = await getCoverArt("song.mp3");
151
+ if (coverData) {
152
+ await Deno.writeFile("cover.jpg", coverData);
153
+ }
289
154
 
290
- // Clean up
291
- file.dispose();
155
+ // Set new cover art
156
+ const imageData = await Deno.readFile("new-cover.jpg");
157
+ await setCoverArt("song.mp3", imageData, "image/jpeg");
292
158
  ```
293
159
 
294
- ### Browser
295
-
296
- ```typescript
297
- import { TagLib } from "taglib-wasm";
160
+ ## 📚 Documentation
298
161
 
299
- // Initialize taglib-wasm
300
- const taglib = await TagLib.initialize();
162
+ **[📖 View Full Documentation](https://charleswiltgen.github.io/taglib-wasm/)**
301
163
 
302
- // Load from file input or fetch
303
- const fileInput = document.querySelector('input[type="file"]');
304
- const audioFile = fileInput.files[0];
305
- const audioData = new Uint8Array(await audioFile.arrayBuffer());
306
- const file = taglib.openFile(audioData);
164
+ ### Getting Started
307
165
 
308
- // Read metadata
309
- const tags = file.tag();
310
- const props = file.audioProperties();
166
+ - [Installation Guide](https://charleswiltgen.github.io/taglib-wasm/guide/installation.html)
167
+ - [Quick Start Tutorial](https://charleswiltgen.github.io/taglib-wasm/guide/quick-start.html)
168
+ - [All Examples](https://charleswiltgen.github.io/taglib-wasm/guide/examples.html)
311
169
 
312
- console.log(`Title: ${tags.title}`);
313
- console.log(`Artist: ${tags.artist}`);
314
- console.log(`Duration: ${props.length}s`);
315
- console.log(`Bitrate: ${props.bitrate} kbps`);
170
+ ### Guides
316
171
 
317
- // Write metadata
318
- const tag = file.tag();
319
- tag.setTitle("New Title");
320
- tag.setArtist("New Artist");
321
- tag.setAlbum("New Album");
172
+ - [API Reference](https://charleswiltgen.github.io/taglib-wasm/API.html)
173
+ - [Platform Examples](https://charleswiltgen.github.io/taglib-wasm/guide/platform-examples.html)
174
+ - [Working with Cover Art](https://charleswiltgen.github.io/taglib-wasm/guide/cover-art.html)
175
+ - [Cloudflare Workers Setup](https://charleswiltgen.github.io/taglib-wasm/guide/workers-setup.html)
176
+ - [Error Handling](https://charleswiltgen.github.io/taglib-wasm/Error-Handling.html)
322
177
 
323
- // Save changes
324
- file.save();
178
+ ### Development
325
179
 
326
- console.log("Updated tags:", file.tag());
327
-
328
- // Clean up
329
- file.dispose();
330
- ```
331
-
332
- ### Cloudflare Workers
333
-
334
- ```typescript
335
- import { TagLib } from "taglib-wasm/workers";
336
-
337
- export default {
338
- async fetch(request: Request): Promise<Response> {
339
- if (request.method === "POST") {
340
- try {
341
- // Initialize taglib-wasm with Workers-specific configuration
342
- // See docs/Cloudflare-Workers.md for memory configuration details
343
- const taglib = await TagLib.initialize({
344
- memory: { initial: 8 * 1024 * 1024 }, // 8MB for Workers
345
- });
346
-
347
- // Get audio data from request
348
- const audioData = new Uint8Array(await request.arrayBuffer());
349
- const file = taglib.openFile(audioData);
350
-
351
- // Read metadata
352
- const tags = file.tag();
353
- const props = file.audioProperties();
354
-
355
- // Extract metadata
356
- const metadata = {
357
- title: tags.title,
358
- artist: tags.artist,
359
- album: tags.album,
360
- year: tags.year,
361
- genre: tags.genre,
362
- duration: props.length,
363
- bitrate: props.bitrate,
364
- format: file.format(),
365
- };
366
-
367
- // Clean up
368
- file.dispose();
369
-
370
- return Response.json({
371
- success: true,
372
- metadata,
373
- fileSize: audioData.length,
374
- });
375
- } catch (error) {
376
- return Response.json({
377
- error: "Failed to process audio file",
378
- message: (error as Error).message,
379
- }, { status: 500 });
380
- }
381
- }
382
-
383
- return new Response("Send POST request with audio file", { status: 400 });
384
- },
385
- };
386
- ```
180
+ - [Testing Guide](https://charleswiltgen.github.io/taglib-wasm/development/testing.html)
181
+ - [Future Improvements](https://charleswiltgen.github.io/taglib-wasm/development/improvements.html)
182
+ - [Contributing](https://charleswiltgen.github.io/taglib-wasm/CONTRIBUTING.html)
387
183
 
388
184
  ## 📋 Supported Formats
389
185
 
@@ -396,81 +192,33 @@ export default {
396
192
  - ✅ **.wav** – INFO chunk metadata
397
193
  - ✅ **Legacy formats** – Opus, APE, MPC, WavPack, TrueAudio, and more
398
194
 
399
- ## 🎯 Extended Metadata with PropertyMap
195
+ ## 🎯 Key Features
400
196
 
401
- `taglib-wasm` provides a **PropertyMap API** for accessing extended metadata
402
- beyond the basic tags. This allows you to read and write format-specific fields
403
- and custom metadata.
197
+ ### Extended Metadata Support
404
198
 
405
- ### AcoustID example
199
+ Beyond basic tags, taglib-wasm supports extended metadata:
406
200
 
407
201
  ```typescript
408
202
  import { Tags } from "taglib-wasm";
409
203
 
410
- // Using PropertyMap API to set extended metadata with tag constants
204
+ // AcoustID fingerprints
411
205
  file.setProperty(
412
206
  Tags.AcoustidFingerprint,
413
207
  "AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...",
414
208
  );
415
- file.setProperty(Tags.AcoustidId, "e7359e88-f1f7-41ed-b9f6-16e58e906997");
416
-
417
- // Or using string property names
418
- file.setProperty("ACOUSTID_FINGERPRINT", "AQADtMmybfGO8NCNEESLnzHyXNOHeHnG...");
419
209
 
420
- // Note: Property keys may vary by format
421
- // Use file.properties() to see all available properties
422
- file.save(); // Don't forget to save!
423
- ```
424
-
425
- ### MusicBrainz example
426
-
427
- ```typescript
428
- // MusicBrainz metadata using PropertyMap with tag constants
210
+ // MusicBrainz IDs
429
211
  file.setProperty(
430
212
  Tags.MusicBrainzTrackId,
431
213
  "f4d1b6b8-8c1e-4d9a-9f2a-1234567890ab",
432
214
  );
433
- file.setProperty(
434
- Tags.MusicBrainzAlbumId,
435
- "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
436
- );
437
- file.setProperty(
438
- Tags.MusicBrainzArtistId,
439
- "12345678-90ab-cdef-1234-567890abcdef",
440
- );
441
- ```
442
-
443
- ### Volume example
444
215
 
445
- ```typescript
446
- // ReplayGain volume normalization with tag constants
216
+ // ReplayGain volume normalization
447
217
  file.setProperty(Tags.TrackGain, "-6.54 dB");
448
218
  file.setProperty(Tags.TrackPeak, "0.987654");
449
- file.setProperty(Tags.AlbumGain, "-8.12 dB");
450
- file.setProperty(Tags.AlbumPeak, "0.995432");
451
219
  ```
452
220
 
453
- ### Extended fields
454
-
455
- ```typescript
456
- // Using PropertyMap to set multiple properties at once
457
- const properties = file.properties(); // Get current properties
458
-
459
- // Set extended metadata with tag constants
460
- file.setProperties({
461
- [Tags.AlbumArtist]: ["Various Artists"],
462
- [Tags.Composer]: ["Composer Name"],
463
- [Tags.Bpm]: ["120"],
464
- [Tags.Compilation]: ["1"],
465
- [Tags.DiscNumber]: ["1"],
466
- [Tags.TrackTotal]: ["12"],
467
- // Note: Property keys vary by format
468
- });
469
-
470
- // Or set individual properties
471
- file.setProperty(Tags.AlbumArtist, "Various Artists");
472
- file.setProperty(Tags.Composer, "Composer Name");
473
- ```
221
+ [View all supported tag constants →](https://charleswiltgen.github.io/taglib-wasm/Tag-Name-Constants.html)
474
222
 
475
223
  ## 🏗️ Development
476
224
 
@@ -481,199 +229,62 @@ file.setProperty(Tags.Composer, "Composer Name");
481
229
  # Install via: https://emscripten.org/docs/getting_started/downloads.html
482
230
 
483
231
  # Clone and build
484
- git clone <repository>
232
+ git clone https://github.com/CharlesWiltgen/taglib-wasm.git
485
233
  cd taglib-wasm
486
234
 
487
235
  # Build Wasm module
488
- deno task build:wasm
236
+ npm run build:wasm
489
237
 
490
238
  # Run tests
491
- deno task test
492
- ```
493
-
494
- ### Project Structure
495
-
496
- ```text
497
- src/
498
- ├── mod.ts # Main module exports
499
- ├── taglib.ts # Core TagLib and AudioFile classes
500
- ├── types.ts # TypeScript type definitions
501
- └── wasm.ts # Wasm module interface and utilities
502
-
503
- build/
504
- ├── build-wasm.sh # Complete build script with C++ wrapper
505
- ├── taglib.js # Generated Emscripten JavaScript
506
- └── taglib.wasm # Compiled WebAssembly module
507
-
508
- tests/ # Test suite and sample audio files
509
- examples/ # Usage examples for different runtimes
510
- ├── deno/ # Deno-specific examples
511
- ├── bun/ # Bun-specific examples
512
- ├── basic-usage.ts # General usage example
513
- └── *.ts # Advanced feature examples
514
- ```
515
-
516
- ## 🧪 Testing
517
-
518
- Comprehensive test suite validates all functionality:
519
-
520
- ```bash
521
- # Run with Deno
522
- deno run --allow-read test-systematic.ts
523
-
524
- # Run with Bun
525
- bun run test-systematic.ts
526
-
527
- # Run with Node.js
528
239
  npm test
529
-
530
- # Results: All formats working ✅ across all runtimes
531
- # ✅ WAV - INFO chunk metadata support
532
- # ✅ MP3 - ID3v1/v2 tag support
533
- # ✅ FLAC - Vorbis comments and properties
534
- # ✅ OGG - Vorbis comments
535
- # ✅ M4A - MPEG-4 (AAC and Apple Lossless) metadata
536
- ```
537
-
538
- ## 🔧 Technical Implementation
539
-
540
- ### Key architecture decisions
541
-
542
- 1. **Memory Management**: Uses Emscripten's `allocate()` for reliable JS↔Wasm
543
- data transfer
544
- 2. **Buffer-Based Processing**: `TagLib::ByteVectorStream` enables in-memory
545
- file processing
546
- 3. **C++ Wrapper**: Custom C functions bridge TagLib's C++ API to Wasm exports
547
- 4. **Type Safety**: Complete TypeScript definitions for all audio formats and
548
- metadata
549
-
550
- ### Critical implementation details
551
-
552
- - **ByteVectorStream**: Enables processing audio files from memory buffers
553
- without filesystem
554
- - **ID-based Object Management**: C++ objects managed via integer IDs for memory
555
- safety
556
- - **Emscripten allocate()**: Ensures proper memory synchronization between JS
557
- and Wasm
558
- - **UTF-8 String Handling**: Proper encoding for international metadata
559
-
560
- ## 📚 API Reference
561
-
562
- ### TagLib class
563
-
564
- ```typescript
565
- class TagLib {
566
- static async initialize(config?: TagLibConfig): Promise<TagLib>;
567
- openFile(buffer: Uint8Array): AudioFile;
568
- getModule(): TagLibModule;
569
- }
570
- ```
571
-
572
- ### AudioFile class
573
-
574
- ```typescript
575
- class AudioFile {
576
- // Validation
577
- isValid(): boolean;
578
- getFormat(): string;
579
-
580
- // Properties
581
- audioProperties(): AudioProperties;
582
-
583
- // Tag Access (returns Tag object with getters and setters)
584
- tag(): Tag;
585
-
586
- // PropertyMap API for extended metadata
587
- properties(): PropertyMap;
588
- setProperties(properties: PropertyMap): void;
589
- getProperty(key: string): string | undefined;
590
- setProperty(key: string, value: string): void;
591
-
592
- // MP4-specific methods
593
- isMP4(): boolean;
594
- getMP4Item(key: string): string | undefined;
595
- setMP4Item(key: string, value: string): void;
596
- removeMP4Item(key: string): void;
597
-
598
- // File Operations
599
- save(): boolean;
600
- getFileBuffer(): Uint8Array;
601
- dispose(): void;
602
- }
603
- ```
604
-
605
- ### Tag interface
606
-
607
- ```typescript
608
- interface Tag {
609
- // Basic metadata (getters)
610
- title: string;
611
- artist: string;
612
- album: string;
613
- comment: string;
614
- genre: string;
615
- year: number;
616
- track: number;
617
-
618
- // Setters
619
- setTitle(value: string): void;
620
- setArtist(value: string): void;
621
- setAlbum(value: string): void;
622
- setComment(value: string): void;
623
- setGenre(value: string): void;
624
- setYear(value: number): void;
625
- setTrack(value: number): void;
626
- }
627
240
  ```
628
241
 
629
- ### PropertyMap type
630
-
631
- ```typescript
632
- type PropertyMap = { [key: string]: string[] };
633
- ```
634
-
635
- ## 📖 Additional Documentation
636
-
637
- - [**Tag Name Constants**](docs/Tag-Name-Constants.md) - Comprehensive reference
638
- for standard tag names and cross-format mapping
639
- - [**Automatic Tag Mapping**](docs/Automatic-Tag-Mapping.md) - How taglib-wasm
640
- handles format-specific tag differences
641
- - [**Implementation Details**](docs/Implementation.md) - Technical details about
642
- the Wasm implementation
643
- - [**Runtime Compatibility**](docs/Runtime-Compatibility.md) - Platform-specific
644
- setup and considerations
242
+ [View full development guide →](CONTRIBUTING.md)
645
243
 
646
244
  ## 🌐 Runtime Compatibility
647
245
 
648
246
  `taglib-wasm` works across all major JavaScript runtimes:
649
247
 
650
- | Runtime | Status | Installation | Performance | TypeScript |
651
- | ----------- | ------- | ------------------------- | ----------- | ---------- |
652
- | **Deno** | ✅ Full | `npm:taglib-wasm` | Excellent | Native |
653
- | **Bun** | ✅ Full | `bun add taglib-wasm` | Excellent | Native |
654
- | **Node.js** | ✅ Full | `npm install taglib-wasm` | Good | Native/tsx |
655
- | **Browser** | ✅ Full | CDN/bundler | Good | Via build |
656
-
657
- **📖 See [docs/Runtime-Compatibility.md](docs/Runtime-Compatibility.md) for
658
- detailed runtime information**
248
+ | Runtime | Status | Installation | Notes |
249
+ | ---------------------- | ------- | ------------------------- | ------------------------- |
250
+ | **Deno** | ✅ Full | `npm:taglib-wasm` | Native TypeScript |
251
+ | **Node.js** | ✅ Full | `npm install taglib-wasm` | TypeScript via tsx |
252
+ | **Bun** | ✅ Full | `bun add taglib-wasm` | Native TypeScript |
253
+ | **Browser** | ✅ Full | Via bundler | Full API support |
254
+ | **Cloudflare Workers** | ✅ Full | `taglib-wasm/workers` | Memory-optimized build |
255
+ | **Electron** | ✅ Full | `npm install taglib-wasm` | Main & renderer processes |
659
256
 
660
257
  ## 🚧 Known Limitations
661
258
 
662
- - **File Writing** – Saves only affect in-memory representation (no filesystem
663
- persistence)
664
- - **Large Files** – Memory usage scales with file size (entire file loaded into
665
- memory)
666
- - **Concurrent Access** – Not thread-safe (JavaScript single-threaded nature)
259
+ - **Memory Usage** – Entire file must be loaded into memory (may be an issue for
260
+ very large files)
261
+ - **Concurrent Access** – Not thread-safe (JavaScript single-threaded nature
262
+ mitigates this)
263
+ - **Cloudflare Workers** – Limited to 128MB memory per request; files larger
264
+ than ~100MB may fail
667
265
 
668
266
  ## 🤝 Contributing
669
267
 
670
- Contributions welcome!
268
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md)
269
+ for details on our code of conduct and the process for submitting pull requests.
671
270
 
672
271
  ## 📄 License
673
272
 
674
- - **This project**: MIT License (see [LICENSE](LICENSE))
675
- - **TagLib library**: LGPL/MPL dual license (see
676
- [lib/taglib/COPYING.LGPL](lib/taglib/COPYING.LGPL))
273
+ This project uses dual licensing:
274
+
275
+ - **TypeScript/JavaScript code** – MIT License (see [LICENSE](LICENSE))
276
+ - **WebAssembly binary (taglib.wasm)** – LGPL-2.1-or-later (inherited from
277
+ TagLib)
278
+
279
+ The TagLib library is dual-licensed under LGPL/MPL. When compiled to
280
+ WebAssembly, the resulting binary must comply with LGPL requirements. This
281
+ means:
282
+
283
+ - You can use taglib-wasm in commercial projects
284
+ - If you modify the TagLib C++ code, you must share those changes
285
+ - You must provide a way for users to relink with a modified TagLib
286
+
287
+ For details, see [lib/taglib/COPYING.LGPL](lib/taglib/COPYING.LGPL)
677
288
 
678
289
  ## 🙏 Acknowledgments
679
290