taglib-wasm 0.4.2 → 0.4.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
@@ -304,13 +304,44 @@ file.setProperty(Tags.TrackPeak, "0.987654");
304
304
 
305
305
  [View all supported tag constants →](https://charleswiltgen.github.io/taglib-wasm/api/tag-name-constants.html)
306
306
 
307
- ## ⚡ Performance & Smart Partial Loading
307
+ ## ⚡ Performance & Best Practices
308
308
 
309
- `taglib-wasm` now supports Smart Partial Loading, dramatically improving
310
- performance for large audio files:
309
+ ### Batch Processing for Multiple Files
310
+
311
+ When processing multiple audio files, use the optimized batch APIs for dramatic performance improvements:
311
312
 
312
313
  ```typescript
313
- // Enable partial loading for large files (>50MB)
314
+ import { readMetadataBatch, readTagsBatch } from "taglib-wasm/simple";
315
+
316
+ // ❌ SLOW: Processing files one by one (can take 90+ seconds for 19 files)
317
+ for (const file of files) {
318
+ const tags = await readTags(file); // Re-initializes for each file
319
+ }
320
+
321
+ // ✅ FAST: Batch processing (10-20x faster)
322
+ const result = await readTagsBatch(files, {
323
+ concurrency: 8, // Process 8 files in parallel
324
+ onProgress: (processed, total) => {
325
+ console.log(`${processed}/${total} files processed`);
326
+ },
327
+ });
328
+
329
+ // ✅ FASTEST: Read complete metadata in one batch
330
+ const metadata = await readMetadataBatch(files, { concurrency: 8 });
331
+ ```
332
+
333
+ **Performance comparison for 19 audio files:**
334
+
335
+ - Sequential: ~90 seconds (4.7s per file)
336
+ - Batch (concurrency=4): ~8 seconds (11x faster)
337
+ - Batch (concurrency=8): ~5 seconds (18x faster)
338
+
339
+ ### Smart Partial Loading
340
+
341
+ For large audio files (>50MB), enable partial loading to dramatically reduce memory usage:
342
+
343
+ ```typescript
344
+ // Enable partial loading for large files
314
345
  const file = await taglib.open("large-concert.flac", {
315
346
  partial: true,
316
347
  maxHeaderSize: 2 * 1024 * 1024, // 2MB header
@@ -321,11 +352,6 @@ const file = await taglib.open("large-concert.flac", {
321
352
  const tags = file.tag();
322
353
  console.log(tags.title, tags.artist);
323
354
 
324
- // Make multiple changes efficiently
325
- tags.setTitle("Live at Madison Square Garden");
326
- tags.setArtist("The Beatles");
327
- tags.setAlbum("Greatest Live Performances");
328
-
329
355
  // Smart save - automatically loads full file when needed
330
356
  await file.saveToFile(); // Full file loaded only here
331
357
  ```
@@ -336,7 +362,22 @@ await file.saveToFile(); // Full file loaded only here
336
362
  - **Initial load**: 50x faster (50ms vs 2500ms)
337
363
  - **Memory peak**: 3.3MB instead of 1.5GB
338
364
 
339
- [View performance guide →](https://charleswiltgen.github.io/taglib-wasm/concepts/performance.html)
365
+ ### WebAssembly Streaming
366
+
367
+ For web applications, use CDN URLs to enable WebAssembly streaming compilation:
368
+
369
+ ```typescript
370
+ // ✅ FAST: Streaming compilation (200-400ms)
371
+ const taglib = await TagLib.initialize({
372
+ wasmUrl: "https://cdn.jsdelivr.net/npm/taglib-wasm@latest/dist/taglib.wasm",
373
+ });
374
+
375
+ // ❌ SLOWER: ArrayBuffer loading (400-800ms)
376
+ const wasmBinary = await fetch("taglib.wasm").then((r) => r.arrayBuffer());
377
+ const taglib = await TagLib.initialize({ wasmBinary });
378
+ ```
379
+
380
+ [View complete performance guide →](https://charleswiltgen.github.io/taglib-wasm/concepts/performance.html)
340
381
 
341
382
  ## 🏗️ Development
342
383
 
package/dist/index.d.ts CHANGED
@@ -62,8 +62,11 @@ export { EnvironmentError, FileOperationError, InvalidFormatError, isEnvironment
62
62
  * @see {@link applyPictures} - Apply pictures to audio files
63
63
  * @see {@link getCoverArt} - Get primary cover art data
64
64
  * @see {@link setCoverArt} - Set primary cover art
65
+ * @see {@link readTagsBatch} - Read tags from multiple files efficiently
66
+ * @see {@link readPropertiesBatch} - Read properties from multiple files efficiently
67
+ * @see {@link readMetadataBatch} - Read complete metadata from multiple files efficiently
65
68
  */
66
- export { addPicture, applyPictures, applyTags, clearPictures, clearTags, findPictureByType, getCoverArt, getFormat, getPictureMetadata, isValidAudioFile, readPictures, readProperties, readTags, replacePictureByType, setCoverArt, updateTags, } from "./src/simple.ts";
69
+ export { addPicture, applyPictures, applyTags, type BatchOptions, type BatchResult, clearPictures, clearTags, findPictureByType, getCoverArt, getFormat, getPictureMetadata, isValidAudioFile, readMetadataBatch, readPictures, readProperties, readPropertiesBatch, readTags, readTagsBatch, replacePictureByType, setCoverArt, updateTags, } from "./src/simple.ts";
67
70
  /**
68
71
  * Constants and utilities for tag name validation.
69
72
  * @see {@link Tags} - Standard tag name constants
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;GAKG;AACH,OAAO,EACL,aAAa,IAAI,SAAS,EAC1B,YAAY,EACZ,MAAM,GACP,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,aAAa,EACb,wBAAwB,EACxB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,oBAAoB,EACpB,WAAW,EACX,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,IAAI,GACL,MAAM,oBAAoB,CAAC;AAC5B;;;;;GAKG;AACH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;GAMG;AACH,OAAO,EACL,KAAK,iBAAiB,EACtB,oBAAoB,EACpB,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,UAAU,EACV,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AACH,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;GAQG;AACH,YAAY,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,WAAW,EACX,GAAG,EACH,OAAO,GACR,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;IAEtC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA0BvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;GAKG;AACH,OAAO,EACL,aAAa,IAAI,SAAS,EAC1B,YAAY,EACZ,MAAM,GACP,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,aAAa,EACb,wBAAwB,EACxB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,IAAI,GACL,MAAM,oBAAoB,CAAC;AAC5B;;;;;GAKG;AACH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;GAMG;AACH,OAAO,EACL,KAAK,iBAAiB,EACtB,oBAAoB,EACpB,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,UAAU,EACV,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AACH,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;GAQG;AACH,YAAY,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,WAAW,EACX,GAAG,EACH,OAAO,GACR,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;IAEtC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA0BvB"}
package/dist/index.js CHANGED
@@ -33,9 +33,12 @@ import {
33
33
  getFormat,
34
34
  getPictureMetadata,
35
35
  isValidAudioFile,
36
+ readMetadataBatch,
36
37
  readPictures,
37
38
  readProperties,
39
+ readPropertiesBatch,
38
40
  readTags,
41
+ readTagsBatch,
39
42
  replacePictureByType,
40
43
  setCoverArt,
41
44
  updateTags
@@ -144,9 +147,12 @@ export {
144
147
  loadPictureFromFile,
145
148
  loadTagLibModule,
146
149
  pictureToDataURL,
150
+ readMetadataBatch,
147
151
  readPictures,
148
152
  readProperties,
153
+ readPropertiesBatch,
149
154
  readTags,
155
+ readTagsBatch,
150
156
  replacePictureByType,
151
157
  savePictureToFile,
152
158
  scanFolder,
@@ -1 +1 @@
1
- {"version":3,"file":"folder-api.d.ts","sourceRoot":"","sources":["../../src/folder-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAuB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgBlD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,GAAG,CAAC;IACV,8DAA8D;IAC9D,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,qDAAqD;IACrD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,mCAAmC;IACnC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC9C,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgHD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAsF3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC,EACpD,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAChE,OAAO,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CA0CD;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,KAAK,CAAC,MAAM,GAAG,CAAuB,GAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CA4B3C;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"folder-api.d.ts","sourceRoot":"","sources":["../../src/folder-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,GAAG,EAAc,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgBlD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,GAAG,CAAC;IACV,8DAA8D;IAC9D,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,qDAAqD;IACrD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,mCAAmC;IACnC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC9C,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgHD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAuF3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC,EACpD,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAChE,OAAO,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CA0CD;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,KAAK,CAAC,MAAM,GAAG,CAAuB,GAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CA0B3C;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
@@ -1,5 +1,5 @@
1
1
  import { TagLib } from "./taglib.js";
2
- import { applyTags, readTags } from "./simple.js";
2
+ import { updateTags } from "./simple.js";
3
3
  function join(...paths) {
4
4
  return paths.filter((p) => p).join("/").replace(/\/+/g, "/");
5
5
  }
@@ -71,18 +71,13 @@ async function* walkDirectory(path, options = {}) {
71
71
  }
72
72
  async function processBatch(files, processor, concurrency) {
73
73
  const results = [];
74
- const executing = [];
75
- for (const file of files) {
76
- const promise = processor(file).then((result) => {
77
- results.push(result);
78
- });
79
- executing.push(promise);
80
- if (executing.length >= concurrency) {
81
- await Promise.race(executing);
82
- executing.splice(executing.findIndex((p) => p === promise), 1);
83
- }
74
+ for (let i = 0; i < files.length; i += concurrency) {
75
+ const chunk = files.slice(i, i + concurrency);
76
+ const chunkResults = await Promise.all(
77
+ chunk.map((file) => processor(file))
78
+ );
79
+ results.push(...chunkResults);
84
80
  }
85
- await Promise.all(executing);
86
81
  return results;
87
82
  }
88
83
  async function scanFolder(folderPath, options = {}) {
@@ -109,22 +104,22 @@ async function scanFolder(folderPath, options = {}) {
109
104
  try {
110
105
  const processor = async (filePath) => {
111
106
  try {
112
- const tags = await readTags(filePath);
113
- let properties;
114
- if (includeProperties) {
115
- const audioFile = await taglib.open(filePath);
116
- try {
107
+ const audioFile = await taglib.open(filePath);
108
+ try {
109
+ const tags = audioFile.tag();
110
+ let properties;
111
+ if (includeProperties) {
117
112
  const props = audioFile.audioProperties();
118
113
  if (props) {
119
114
  properties = props;
120
115
  }
121
- } finally {
122
- audioFile.dispose();
123
116
  }
117
+ processed++;
118
+ onProgress?.(processed, totalFound, filePath);
119
+ return { path: filePath, tags, properties };
120
+ } finally {
121
+ audioFile.dispose();
124
122
  }
125
- processed++;
126
- onProgress?.(processed, totalFound, filePath);
127
- return { path: filePath, tags, properties };
128
123
  } catch (error) {
129
124
  const err = error instanceof Error ? error : new Error(String(error));
130
125
  if (continueOnError) {
@@ -163,7 +158,7 @@ async function updateFolderTags(updates, options = {}) {
163
158
  const failed = [];
164
159
  const processor = async (update) => {
165
160
  try {
166
- await applyTags(update.path, update.tags);
161
+ await updateTags(update.path, update.tags);
167
162
  successful++;
168
163
  } catch (error) {
169
164
  const err = error instanceof Error ? error : new Error(String(error));
@@ -201,9 +196,7 @@ async function findDuplicates(folderPath, criteria = ["artist", "title"]) {
201
196
  if (key) {
202
197
  const group = duplicates.get(key) || [];
203
198
  group.push(file);
204
- if (group.length > 1) {
205
- duplicates.set(key, group);
206
- }
199
+ duplicates.set(key, group);
207
200
  }
208
201
  }
209
202
  for (const [key, files] of duplicates.entries()) {
@@ -340,6 +340,112 @@ export declare function getPictureMetadata(file: string | Uint8Array | ArrayBuff
340
340
  description?: string;
341
341
  size: number;
342
342
  }>>;
343
+ /**
344
+ * Options for batch operations
345
+ */
346
+ export interface BatchOptions {
347
+ /** Number of files to process concurrently (default: 4) */
348
+ concurrency?: number;
349
+ /** Continue processing on errors (default: true) */
350
+ continueOnError?: boolean;
351
+ /** Progress callback */
352
+ onProgress?: (processed: number, total: number, currentFile: string) => void;
353
+ }
354
+ /**
355
+ * Result from a batch operation
356
+ */
357
+ export interface BatchResult<T> {
358
+ /** Successful results */
359
+ results: Array<{
360
+ file: string;
361
+ data: T;
362
+ }>;
363
+ /** Errors encountered */
364
+ errors: Array<{
365
+ file: string;
366
+ error: Error;
367
+ }>;
368
+ /** Total processing time in milliseconds */
369
+ duration: number;
370
+ }
371
+ /**
372
+ * Read tags from multiple files efficiently
373
+ *
374
+ * This method is optimized for batch processing and reuses a single TagLib
375
+ * instance across all files, significantly improving performance compared
376
+ * to calling readTags() multiple times.
377
+ *
378
+ * @param files - Array of file paths or buffers to process
379
+ * @param options - Batch processing options
380
+ * @returns Batch result with tags and any errors
381
+ *
382
+ * @example
383
+ * ```typescript
384
+ * const files = ["song1.mp3", "song2.mp3", "song3.mp3"];
385
+ * const result = await readTagsBatch(files, {
386
+ * concurrency: 8,
387
+ * onProgress: (processed, total) => {
388
+ * console.log(`${processed}/${total} files processed`);
389
+ * }
390
+ * });
391
+ *
392
+ * for (const { file, data } of result.results) {
393
+ * console.log(`${file}: ${data.artist} - ${data.title}`);
394
+ * }
395
+ * ```
396
+ */
397
+ export declare function readTagsBatch(files: Array<string | Uint8Array | ArrayBuffer | File>, options?: BatchOptions): Promise<BatchResult<Tag>>;
398
+ /**
399
+ * Read audio properties from multiple files efficiently
400
+ *
401
+ * @param files - Array of file paths or buffers to process
402
+ * @param options - Batch processing options
403
+ * @returns Batch result with audio properties and any errors
404
+ *
405
+ * @example
406
+ * ```typescript
407
+ * const files = ["song1.mp3", "song2.mp3", "song3.mp3"];
408
+ * const result = await readPropertiesBatch(files);
409
+ *
410
+ * for (const { file, data } of result.results) {
411
+ * console.log(`${file}: ${data.length}s, ${data.bitrate}kbps`);
412
+ * }
413
+ * ```
414
+ */
415
+ export declare function readPropertiesBatch(files: Array<string | Uint8Array | ArrayBuffer | File>, options?: BatchOptions): Promise<BatchResult<AudioProperties | null>>;
416
+ /**
417
+ * Read both tags and properties from multiple files efficiently
418
+ *
419
+ * This is the most efficient way to get complete metadata from multiple files,
420
+ * as it reads both tags and properties in a single file open operation.
421
+ *
422
+ * @param files - Array of file paths or buffers to process
423
+ * @param options - Batch processing options
424
+ * @returns Batch result with complete metadata and any errors
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * const files = ["song1.mp3", "song2.mp3", "song3.mp3"];
429
+ * const result = await readMetadataBatch(files, {
430
+ * concurrency: 8,
431
+ * onProgress: (processed, total, file) => {
432
+ * console.log(`Processing ${file}: ${processed}/${total}`);
433
+ * }
434
+ * });
435
+ *
436
+ * for (const { file, data } of result.results) {
437
+ * console.log(`${file}:`);
438
+ * console.log(` Artist: ${data.tags.artist}`);
439
+ * console.log(` Title: ${data.tags.title}`);
440
+ * console.log(` Duration: ${data.properties?.length}s`);
441
+ * console.log(` Bitrate: ${data.properties?.bitrate}kbps`);
442
+ * }
443
+ * ```
444
+ */
445
+ export declare function readMetadataBatch(files: Array<string | Uint8Array | ArrayBuffer | File>, options?: BatchOptions): Promise<BatchResult<{
446
+ tags: Tag;
447
+ properties: AudioProperties | null;
448
+ }>>;
343
449
  /**
344
450
  * Re-export commonly used types for convenience.
345
451
  * These types define the structure of metadata and audio properties.
@@ -1 +1 @@
1
- {"version":3,"file":"simple.d.ts","sourceRoot":"","sources":["../../src/simple.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"simple.d.ts","sourceRoot":"","sources":["../../src/simple.ts"],"names":[],"mappings":"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"}
@@ -229,6 +229,151 @@ async function getPictureMetadata(file) {
229
229
  size: pic.data.length
230
230
  }));
231
231
  }
232
+ async function readTagsBatch(files, options = {}) {
233
+ const startTime = Date.now();
234
+ const {
235
+ concurrency = 4,
236
+ continueOnError = true,
237
+ onProgress
238
+ } = options;
239
+ const results = [];
240
+ const errors = [];
241
+ const taglib = await getTagLib();
242
+ let processed = 0;
243
+ const total = files.length;
244
+ for (let i = 0; i < files.length; i += concurrency) {
245
+ const chunk = files.slice(i, i + concurrency);
246
+ const chunkPromises = chunk.map(async (file, idx) => {
247
+ const fileIndex = i + idx;
248
+ const fileName = typeof file === "string" ? file : `file-${fileIndex}`;
249
+ try {
250
+ const audioFile = await taglib.open(file);
251
+ try {
252
+ if (!audioFile.isValid()) {
253
+ throw new InvalidFormatError(
254
+ "File may be corrupted or in an unsupported format"
255
+ );
256
+ }
257
+ const tags = audioFile.tag();
258
+ results.push({ file: fileName, data: tags });
259
+ } finally {
260
+ audioFile.dispose();
261
+ }
262
+ } catch (error) {
263
+ const err = error instanceof Error ? error : new Error(String(error));
264
+ errors.push({ file: fileName, error: err });
265
+ if (!continueOnError) {
266
+ throw err;
267
+ }
268
+ }
269
+ processed++;
270
+ onProgress?.(processed, total, fileName);
271
+ });
272
+ await Promise.all(chunkPromises);
273
+ }
274
+ return {
275
+ results,
276
+ errors,
277
+ duration: Date.now() - startTime
278
+ };
279
+ }
280
+ async function readPropertiesBatch(files, options = {}) {
281
+ const startTime = Date.now();
282
+ const {
283
+ concurrency = 4,
284
+ continueOnError = true,
285
+ onProgress
286
+ } = options;
287
+ const results = [];
288
+ const errors = [];
289
+ const taglib = await getTagLib();
290
+ let processed = 0;
291
+ const total = files.length;
292
+ for (let i = 0; i < files.length; i += concurrency) {
293
+ const chunk = files.slice(i, i + concurrency);
294
+ const chunkPromises = chunk.map(async (file, idx) => {
295
+ const fileIndex = i + idx;
296
+ const fileName = typeof file === "string" ? file : `file-${fileIndex}`;
297
+ try {
298
+ const audioFile = await taglib.open(file);
299
+ try {
300
+ if (!audioFile.isValid()) {
301
+ throw new InvalidFormatError(
302
+ "File may be corrupted or in an unsupported format"
303
+ );
304
+ }
305
+ const properties = audioFile.audioProperties();
306
+ results.push({ file: fileName, data: properties });
307
+ } finally {
308
+ audioFile.dispose();
309
+ }
310
+ } catch (error) {
311
+ const err = error instanceof Error ? error : new Error(String(error));
312
+ errors.push({ file: fileName, error: err });
313
+ if (!continueOnError) {
314
+ throw err;
315
+ }
316
+ }
317
+ processed++;
318
+ onProgress?.(processed, total, fileName);
319
+ });
320
+ await Promise.all(chunkPromises);
321
+ }
322
+ return {
323
+ results,
324
+ errors,
325
+ duration: Date.now() - startTime
326
+ };
327
+ }
328
+ async function readMetadataBatch(files, options = {}) {
329
+ const startTime = Date.now();
330
+ const {
331
+ concurrency = 4,
332
+ continueOnError = true,
333
+ onProgress
334
+ } = options;
335
+ const results = [];
336
+ const errors = [];
337
+ const taglib = await getTagLib();
338
+ let processed = 0;
339
+ const total = files.length;
340
+ for (let i = 0; i < files.length; i += concurrency) {
341
+ const chunk = files.slice(i, i + concurrency);
342
+ const chunkPromises = chunk.map(async (file, idx) => {
343
+ const fileIndex = i + idx;
344
+ const fileName = typeof file === "string" ? file : `file-${fileIndex}`;
345
+ try {
346
+ const audioFile = await taglib.open(file);
347
+ try {
348
+ if (!audioFile.isValid()) {
349
+ throw new InvalidFormatError(
350
+ "File may be corrupted or in an unsupported format"
351
+ );
352
+ }
353
+ const tags = audioFile.tag();
354
+ const properties = audioFile.audioProperties();
355
+ results.push({ file: fileName, data: { tags, properties } });
356
+ } finally {
357
+ audioFile.dispose();
358
+ }
359
+ } catch (error) {
360
+ const err = error instanceof Error ? error : new Error(String(error));
361
+ errors.push({ file: fileName, error: err });
362
+ if (!continueOnError) {
363
+ throw err;
364
+ }
365
+ }
366
+ processed++;
367
+ onProgress?.(processed, total, fileName);
368
+ });
369
+ await Promise.all(chunkPromises);
370
+ }
371
+ return {
372
+ results,
373
+ errors,
374
+ duration: Date.now() - startTime
375
+ };
376
+ }
232
377
  import { PictureType as PictureType2 } from "./types.js";
233
378
  export {
234
379
  Album,
@@ -252,9 +397,12 @@ export {
252
397
  getFormat,
253
398
  getPictureMetadata,
254
399
  isValidAudioFile,
400
+ readMetadataBatch,
255
401
  readPictures,
256
402
  readProperties,
403
+ readPropertiesBatch,
257
404
  readTags,
405
+ readTagsBatch,
258
406
  replacePictureByType,
259
407
  setCoverArt,
260
408
  updateTags
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taglib-wasm",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",