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/index.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  * import { TagLib } from "taglib-wasm";
13
13
  *
14
14
  * const taglib = await TagLib.initialize();
15
- * const file = await taglib.openFile(audioBuffer);
15
+ * const file = await taglib.open(audioBuffer);
16
16
  * const tag = file.tag();
17
17
  * console.log(tag.title);
18
18
  * file.dispose();
@@ -21,12 +21,12 @@
21
21
  * @example
22
22
  * ```typescript
23
23
  * // Using the Simple API
24
- * import { readTags, writeTags } from "taglib-wasm";
24
+ * import { readTags, applyTags } from "taglib-wasm";
25
25
  *
26
26
  * const tags = await readTags("song.mp3");
27
27
  * console.log(tags.artist);
28
28
  *
29
- * const modified = await writeTags("song.mp3", {
29
+ * const modified = await applyTags("song.mp3", {
30
30
  * artist: "New Artist",
31
31
  * album: "New Album"
32
32
  * });
@@ -45,13 +45,67 @@ export {
45
45
  TagLib,
46
46
  } from "./src/taglib.ts";
47
47
 
48
+ /**
49
+ * Error types for proper error handling and debugging.
50
+ * @see {@link TagLibError} - Base error class for all TagLib errors
51
+ * @see {@link TagLibInitializationError} - Wasm initialization failures
52
+ * @see {@link InvalidFormatError} - Invalid or corrupted file format
53
+ * @see {@link UnsupportedFormatError} - Valid but unsupported format
54
+ * @see {@link FileOperationError} - File read/write/save failures
55
+ * @see {@link MetadataError} - Tag reading/writing failures
56
+ * @see {@link MemoryError} - Wasm memory allocation issues
57
+ * @see {@link EnvironmentError} - Runtime/environment issues
58
+ */
59
+ export {
60
+ EnvironmentError,
61
+ FileOperationError,
62
+ InvalidFormatError,
63
+ isEnvironmentError,
64
+ isFileOperationError,
65
+ isInvalidFormatError,
66
+ isMemoryError,
67
+ isMetadataError,
68
+ isTagLibError,
69
+ isUnsupportedFormatError,
70
+ MemoryError,
71
+ MetadataError,
72
+ SUPPORTED_FORMATS,
73
+ TagLibError,
74
+ TagLibInitializationError,
75
+ UnsupportedFormatError,
76
+ } from "./src/errors.ts";
77
+
48
78
  /**
49
79
  * Simple API exports for easy tag reading and writing.
50
80
  * @see {@link readTags} - Read metadata from audio files
51
- * @see {@link writeTags} - Write metadata to audio files
81
+ * @see {@link applyTags} - Apply metadata changes and return modified buffer
82
+ * @see {@link updateTags} - Update metadata and save to disk
83
+ * @see {@link writeTags} - Deprecated alias for applyTags
52
84
  * @see {@link readProperties} - Read audio properties
85
+ * @see {@link readPictures} - Read cover art/pictures
86
+ * @see {@link applyPictures} - Apply pictures to audio files
87
+ * @see {@link getCoverArt} - Get primary cover art data
88
+ * @see {@link setCoverArt} - Set primary cover art
53
89
  */
54
- export { readProperties, readTags, writeTags } from "./src/simple.ts";
90
+ export {
91
+ readProperties,
92
+ readTags,
93
+ applyTags,
94
+ updateTags,
95
+ writeTags, // Deprecated but exported for backward compatibility
96
+ readPictures,
97
+ applyPictures,
98
+ addPicture,
99
+ clearPictures,
100
+ getCoverArt,
101
+ setCoverArt,
102
+ findPictureByType,
103
+ replacePictureByType,
104
+ getPictureMetadata,
105
+ isValidAudioFile,
106
+ getFormat,
107
+ clearTags
108
+ } from "./src/simple.ts";
55
109
 
56
110
  /**
57
111
  * Constants and utilities for tag name validation.
@@ -66,6 +120,41 @@ export {
66
120
  isValidTagName,
67
121
  Tags,
68
122
  } from "./src/constants.ts";
123
+ /**
124
+ * File I/O utilities for cover art operations.
125
+ * @see {@link exportCoverArt} - Export cover art to file
126
+ * @see {@link importCoverArt} - Import cover art from file
127
+ * @see {@link copyCoverArt} - Copy cover art between files
128
+ */
129
+ export {
130
+ exportCoverArt,
131
+ exportPictureByType,
132
+ exportAllPictures,
133
+ importCoverArt,
134
+ importPictureWithType,
135
+ loadPictureFromFile,
136
+ savePictureToFile,
137
+ copyCoverArt,
138
+ findCoverArtFiles
139
+ } from "./src/file-utils.ts";
140
+
141
+ /**
142
+ * Web browser utilities for cover art operations.
143
+ * @see {@link pictureToDataURL} - Convert picture to data URL
144
+ * @see {@link setCoverArtFromCanvas} - Set cover art from HTML canvas
145
+ * @see {@link displayPicture} - Display picture in HTML img element
146
+ */
147
+ export {
148
+ pictureToDataURL,
149
+ dataURLToPicture,
150
+ setCoverArtFromCanvas,
151
+ canvasToPicture,
152
+ imageFileToPicture,
153
+ displayPicture,
154
+ createPictureDownloadURL,
155
+ createPictureGallery
156
+ } from "./src/web-utils.ts";
157
+
69
158
  /**
70
159
  * Type exports for TypeScript users.
71
160
  * These types define the structure of metadata, audio properties,
@@ -83,13 +172,17 @@ export type {
83
172
  FieldMapping,
84
173
  FileType,
85
174
  Picture,
86
- PictureType,
87
175
  PropertyMap,
88
176
  Tag,
89
177
  TagLibConfig,
90
178
  TagName,
91
179
  } from "./src/types.ts";
92
180
 
181
+ /**
182
+ * Enum exports
183
+ */
184
+ export { PictureType } from "./src/types.ts";
185
+
93
186
  /**
94
187
  * Wasm module types for advanced usage.
95
188
  * @see {@link TagLibModule} - Full TagLib Wasm module interface
@@ -121,7 +214,7 @@ import type { TagLibModule } from "./src/wasm.ts";
121
214
  */
122
215
  export async function loadTagLibModule(): Promise<TagLibModule> {
123
216
  // Now that we're using ES6 modules, we can use dynamic import directly
124
- const { default: createTagLibModule } = await import("./build/taglib.js");
217
+ const { default: createTagLibModule } = await import("./build/taglib-wrapper.js");
125
218
  const module = await createTagLibModule();
126
219
  return module as TagLibModule;
127
220
  }
package/package.json CHANGED
@@ -1,34 +1,56 @@
1
1
  {
2
2
  "name": "taglib-wasm",
3
- "version": "0.3.3",
4
- "description": "TagLib compiled to WebAssembly with TypeScript bindings for universal audio metadata handling",
3
+ "version": "0.3.9",
4
+ "description": "TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
7
7
  "exports": {
8
- ".": "./index.ts",
9
- "./workers": "./src/workers.ts",
10
- "./simple": "./src/simple.ts"
8
+ ".": {
9
+ "types": "./index.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./workers": {
13
+ "types": "./src/workers.ts",
14
+ "default": "./dist/src/workers.js"
15
+ },
16
+ "./simple": {
17
+ "types": "./src/simple.ts",
18
+ "default": "./dist/src/simple.js"
19
+ }
11
20
  },
12
21
  "files": [
13
22
  "index.ts",
14
23
  "src/**/*",
15
- "build/taglib.wasm",
16
- "build/taglib.js",
24
+ "dist/**/*",
17
25
  "lib/taglib/COPYING*",
18
- "README.md"
26
+ "README.md",
27
+ "LICENSE",
28
+ "NOTICE",
29
+ "CONTRIBUTING.md"
19
30
  ],
20
31
  "scripts": {
21
32
  "build:wasm": "./build/build-wasm.sh",
22
- "build:ts": "tsc",
23
- "build": "npm run build:wasm && npm run build:ts",
24
- "test": "deno test --allow-read tests/taglib.test.ts",
25
- "test:bun": "bun test tests/taglib.test.ts",
26
- "test:node": "node --loader ts-node/esm --test tests/taglib.test.ts",
27
- "test:watch": "deno test --allow-read --watch tests/taglib.test.ts",
33
+ "build:ts": "tsc && node scripts/build-js.js",
34
+ "postbuild": "node scripts/postbuild.js",
35
+ "build": "npm run build:wasm && npm run build:ts && npm run postbuild",
36
+ "test": "deno test --allow-read --allow-write tests/",
37
+ "test:all": "deno test --allow-read --allow-write tests/index.test.ts",
38
+ "test:core": "deno test --allow-read --allow-write tests/taglib.test.ts",
39
+ "test:pictures": "deno test --allow-read --allow-write tests/picture-api.test.ts",
40
+ "test:edge": "deno test --allow-read --allow-write tests/edge-cases.test.ts",
41
+ "test:errors": "deno test --allow-read --allow-write tests/error-handling.test.ts",
42
+ "test:memory": "deno test --allow-read --allow-write tests/memory.test.ts",
43
+ "test:extended": "deno test --allow-read --allow-write tests/extended-metadata.test.ts",
44
+ "test:multi-runtime": "./tests/test-runtimes.sh",
45
+ "test:bun": "bun test tests/index.test.ts",
46
+ "test:node": "node --loader ts-node/esm --test tests/index.test.ts",
47
+ "test:watch": "deno test --allow-read --allow-write --watch tests/",
48
+ "test:coverage": "deno test --allow-read --allow-write --coverage=coverage tests/ && deno coverage coverage",
28
49
  "docs:dev": "cd docs && npm install && npm run dev",
29
50
  "docs:build": "cd docs && npm install && npm run build",
30
51
  "update-taglib": "./scripts/update-taglib.sh",
31
52
  "release": "./scripts/release.sh",
53
+ "prepublishOnly": "npm run build:ts && npm run postbuild",
32
54
  "publish:npm": "echo 'Use GitHub Actions workflow for publishing'",
33
55
  "publish:github": "echo 'Use GitHub Actions workflow for publishing'"
34
56
  },
@@ -51,12 +73,13 @@
51
73
  "browser",
52
74
  "cloudflare",
53
75
  "workers",
76
+ "electron",
54
77
  "replaygain",
55
78
  "musicbrainz",
56
79
  "acoustid"
57
80
  ],
58
- "author": "Your Name <your.email@example.com>",
59
- "license": "MIT",
81
+ "author": "Charles Wiltgen <cwiltgen@gmail.com>",
82
+ "license": "(MIT AND LGPL-2.1-or-later)",
60
83
  "repository": {
61
84
  "type": "git",
62
85
  "url": "git+https://github.com/CharlesWiltgen/taglib-wasm.git"
@@ -71,6 +94,7 @@
71
94
  "devDependencies": {
72
95
  "@types/emscripten": "^1.39.6",
73
96
  "@types/node": "^20.0.0",
97
+ "esbuild": "^0.25.5",
74
98
  "typescript": "^5.0.0"
75
99
  },
76
100
  "peerDependencies": {
package/src/errors.ts ADDED
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Custom error types for taglib-wasm with enhanced context and debugging information
3
+ */
4
+
5
+ /**
6
+ * List of audio formats supported by taglib-wasm
7
+ */
8
+ export const SUPPORTED_FORMATS = ['MP3', 'MP4', 'M4A', 'FLAC', 'OGG', 'WAV'] as const;
9
+
10
+ /**
11
+ * Error codes for programmatic error handling
12
+ */
13
+ export enum TagLibErrorCode {
14
+ INITIALIZATION_FAILED = 'INITIALIZATION_FAILED',
15
+ INVALID_FORMAT = 'INVALID_FORMAT',
16
+ UNSUPPORTED_FORMAT = 'UNSUPPORTED_FORMAT',
17
+ FILE_OPERATION_FAILED = 'FILE_OPERATION_FAILED',
18
+ METADATA_ERROR = 'METADATA_ERROR',
19
+ MEMORY_ERROR = 'MEMORY_ERROR',
20
+ ENVIRONMENT_ERROR = 'ENVIRONMENT_ERROR',
21
+ }
22
+
23
+ /**
24
+ * Base error class for all taglib-wasm errors
25
+ */
26
+ export class TagLibError extends Error {
27
+ constructor(
28
+ message: string,
29
+ public readonly code: TagLibErrorCode,
30
+ public readonly context?: Record<string, unknown>
31
+ ) {
32
+ super(message);
33
+ this.name = 'TagLibError';
34
+ Object.setPrototypeOf(this, TagLibError.prototype);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Error thrown when the Wasm module fails to initialize
40
+ */
41
+ export class TagLibInitializationError extends TagLibError {
42
+ constructor(message: string, context?: Record<string, unknown>) {
43
+ super(
44
+ createErrorMessage('Failed to initialize TagLib Wasm module', message),
45
+ TagLibErrorCode.INITIALIZATION_FAILED,
46
+ context
47
+ );
48
+ this.name = 'TagLibInitializationError';
49
+ Object.setPrototypeOf(this, TagLibInitializationError.prototype);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Error thrown when an audio file format is invalid or corrupted
55
+ */
56
+ export class InvalidFormatError extends TagLibError {
57
+ constructor(
58
+ message: string,
59
+ public readonly bufferSize?: number,
60
+ context?: Record<string, unknown>
61
+ ) {
62
+ const details = [`Invalid audio file format: ${message}`];
63
+
64
+ if (bufferSize !== undefined) {
65
+ details.push(`Buffer size: ${formatFileSize(bufferSize)}`);
66
+ if (bufferSize < 1024) {
67
+ details.push('Audio files must be at least 1KB to contain valid headers.');
68
+ }
69
+ }
70
+
71
+ super(
72
+ details.join('. '),
73
+ TagLibErrorCode.INVALID_FORMAT,
74
+ { ...context, bufferSize }
75
+ );
76
+ this.name = 'InvalidFormatError';
77
+ Object.setPrototypeOf(this, InvalidFormatError.prototype);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Error thrown when an audio format is recognized but not supported
83
+ */
84
+ export class UnsupportedFormatError extends TagLibError {
85
+ constructor(
86
+ public readonly format: string,
87
+ public readonly supportedFormats: readonly string[] = SUPPORTED_FORMATS,
88
+ context?: Record<string, unknown>
89
+ ) {
90
+ super(
91
+ `Unsupported audio format: ${format}. Supported formats: ${supportedFormats.join(', ')}`,
92
+ TagLibErrorCode.UNSUPPORTED_FORMAT,
93
+ { ...context, format, supportedFormats }
94
+ );
95
+ this.name = 'UnsupportedFormatError';
96
+ Object.setPrototypeOf(this, UnsupportedFormatError.prototype);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Error thrown during file operations (read, write, save)
102
+ */
103
+ export class FileOperationError extends TagLibError {
104
+ constructor(
105
+ public readonly operation: 'read' | 'write' | 'save',
106
+ message: string,
107
+ public readonly path?: string,
108
+ context?: Record<string, unknown>
109
+ ) {
110
+ const details = [`Failed to ${operation} file`];
111
+ if (path) {
112
+ details.push(`Path: ${path}`);
113
+ }
114
+ details.push(message);
115
+
116
+ super(
117
+ details.join('. '),
118
+ TagLibErrorCode.FILE_OPERATION_FAILED,
119
+ { ...context, operation, path }
120
+ );
121
+ this.name = 'FileOperationError';
122
+ Object.setPrototypeOf(this, FileOperationError.prototype);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Error thrown when metadata operations fail
128
+ */
129
+ export class MetadataError extends TagLibError {
130
+ constructor(
131
+ public readonly operation: 'read' | 'write',
132
+ message: string,
133
+ public readonly field?: string,
134
+ context?: Record<string, unknown>
135
+ ) {
136
+ const details = [`Failed to ${operation} metadata`];
137
+ if (field) {
138
+ details.push(`Field: ${field}`);
139
+ }
140
+ details.push(message);
141
+
142
+ super(
143
+ details.join('. '),
144
+ TagLibErrorCode.METADATA_ERROR,
145
+ { ...context, operation, field }
146
+ );
147
+ this.name = 'MetadataError';
148
+ Object.setPrototypeOf(this, MetadataError.prototype);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Error thrown when Wasm memory operations fail
154
+ */
155
+ export class MemoryError extends TagLibError {
156
+ constructor(message: string, context?: Record<string, unknown>) {
157
+ super(
158
+ createErrorMessage('Memory allocation failed', message),
159
+ TagLibErrorCode.MEMORY_ERROR,
160
+ context
161
+ );
162
+ this.name = 'MemoryError';
163
+ Object.setPrototypeOf(this, MemoryError.prototype);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Error thrown when the environment doesn't support required features
169
+ */
170
+ export class EnvironmentError extends TagLibError {
171
+ constructor(
172
+ public readonly environment: string,
173
+ message: string,
174
+ public readonly requiredFeature?: string,
175
+ context?: Record<string, unknown>
176
+ ) {
177
+ const details = [`Environment '${environment}' ${message}`];
178
+ if (requiredFeature) {
179
+ details.push(`Required feature: ${requiredFeature}`);
180
+ }
181
+
182
+ super(
183
+ details.join('. '),
184
+ TagLibErrorCode.ENVIRONMENT_ERROR,
185
+ { ...context, environment, requiredFeature }
186
+ );
187
+ this.name = 'EnvironmentError';
188
+ Object.setPrototypeOf(this, EnvironmentError.prototype);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Helper function to create consistent error messages
194
+ */
195
+ function createErrorMessage(prefix: string, details: string): string {
196
+ return `${prefix}: ${details}`;
197
+ }
198
+
199
+ /**
200
+ * Format file size in human-readable format
201
+ */
202
+ function formatFileSize(bytes: number): string {
203
+ if (bytes < 1024) return `${bytes} bytes`;
204
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
205
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
206
+ }
207
+
208
+ /**
209
+ * Type guards for error handling
210
+ */
211
+ export function isTagLibError(error: unknown): error is TagLibError {
212
+ return error instanceof TagLibError;
213
+ }
214
+
215
+ export function isInvalidFormatError(error: unknown): error is InvalidFormatError {
216
+ return error instanceof InvalidFormatError;
217
+ }
218
+
219
+ export function isUnsupportedFormatError(error: unknown): error is UnsupportedFormatError {
220
+ return error instanceof UnsupportedFormatError;
221
+ }
222
+
223
+ export function isFileOperationError(error: unknown): error is FileOperationError {
224
+ return error instanceof FileOperationError;
225
+ }
226
+
227
+ export function isMetadataError(error: unknown): error is MetadataError {
228
+ return error instanceof MetadataError;
229
+ }
230
+
231
+ export function isMemoryError(error: unknown): error is MemoryError {
232
+ return error instanceof MemoryError;
233
+ }
234
+
235
+ export function isEnvironmentError(error: unknown): error is EnvironmentError {
236
+ return error instanceof EnvironmentError;
237
+ }