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 +51 -10
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/src/folder-api.d.ts.map +1 -1
- package/dist/src/folder-api.js +19 -26
- package/dist/src/simple.d.ts +106 -0
- package/dist/src/simple.d.ts.map +1 -1
- package/dist/src/simple.js +148 -0
- package/package.json +1 -1
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 &
|
|
307
|
+
## ⚡ Performance & Best Practices
|
|
308
308
|
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
|
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,
|
|
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"}
|
package/dist/src/folder-api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TagLib } from "./taglib.js";
|
|
2
|
-
import {
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
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
|
-
|
|
205
|
-
duplicates.set(key, group);
|
|
206
|
-
}
|
|
199
|
+
duplicates.set(key, group);
|
|
207
200
|
}
|
|
208
201
|
}
|
|
209
202
|
for (const [key, files] of duplicates.entries()) {
|
package/dist/src/simple.d.ts
CHANGED
|
@@ -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.
|
package/dist/src/simple.d.ts.map
CHANGED
|
@@ -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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"}
|
package/dist/src/simple.js
CHANGED
|
@@ -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