@probityrules/jsmediatags 4.0.0

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 (53) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE.md +36 -0
  3. package/README.md +548 -0
  4. package/build/ArrayBufferFileReader.d.ts +12 -0
  5. package/build/ArrayBufferFileReader.js +27 -0
  6. package/build/ArrayFileReader.d.ts +11 -0
  7. package/build/ArrayFileReader.js +30 -0
  8. package/build/BlobFileReader.d.ts +12 -0
  9. package/build/BlobFileReader.js +47 -0
  10. package/build/ByteArrayUtils.d.ts +9 -0
  11. package/build/ByteArrayUtils.js +46 -0
  12. package/build/ChunkedFileData.d.ts +28 -0
  13. package/build/ChunkedFileData.js +171 -0
  14. package/build/DecodedString.d.ts +6 -0
  15. package/build/DecodedString.js +2 -0
  16. package/build/FLACTagContents.d.ts +19 -0
  17. package/build/FLACTagContents.js +54 -0
  18. package/build/FLACTagReader.d.ts +103 -0
  19. package/build/FLACTagReader.js +320 -0
  20. package/build/ID3v1TagReader.d.ts +10 -0
  21. package/build/ID3v1TagReader.js +176 -0
  22. package/build/ID3v2FrameReader.d.ts +25 -0
  23. package/build/ID3v2FrameReader.js +582 -0
  24. package/build/ID3v2TagContents.d.ts +82 -0
  25. package/build/ID3v2TagContents.js +318 -0
  26. package/build/ID3v2TagReader.d.ts +13 -0
  27. package/build/ID3v2TagReader.js +118 -0
  28. package/build/MP4TagContents.d.ts +17 -0
  29. package/build/MP4TagContents.js +52 -0
  30. package/build/MP4TagReader.d.ts +19 -0
  31. package/build/MP4TagReader.js +291 -0
  32. package/build/MediaFileReader.d.ts +46 -0
  33. package/build/MediaFileReader.js +168 -0
  34. package/build/MediaTagReader.d.ts +18 -0
  35. package/build/MediaTagReader.js +76 -0
  36. package/build/NodeFileReader.d.ts +12 -0
  37. package/build/NodeFileReader.js +103 -0
  38. package/build/ReactNativeFileReader.d.ts +12 -0
  39. package/build/ReactNativeFileReader.js +48 -0
  40. package/build/StringUtils.d.ts +7 -0
  41. package/build/StringUtils.js +102 -0
  42. package/build/XhrFileReader.d.ts +41 -0
  43. package/build/XhrFileReader.js +238 -0
  44. package/build/jsmediatags.d.ts +45 -0
  45. package/build/jsmediatags.js +219 -0
  46. package/build/registerNodeFileReaders.d.ts +5 -0
  47. package/build/registerNodeFileReaders.js +19 -0
  48. package/build/registerNodeFileReaders.noop.d.ts +2 -0
  49. package/build/registerNodeFileReaders.noop.js +3 -0
  50. package/build/types.d.ts +77 -0
  51. package/build/types.js +2 -0
  52. package/dist/jsmediatags.min.js +2 -0
  53. package/package.json +110 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [4.0.0] - 2026-06-02
9
+
10
+ Published to npm as **`@probityrules/jsmediatags`** from [probityrules/jsmediatags](https://github.com/probityrules/jsmediatags).
11
+
12
+ ### Added
13
+
14
+ - TypeScript source with published `.d.ts` declarations (`build/jsmediatags.d.ts`).
15
+ - Promise-based API: `read(location)` without callbacks, `readAsync()`, and matching methods on `Reader` and `MediaTagReader`. Callbacks remain supported.
16
+ - `package.json` `"exports"` map with `types`, `browser`, and `default` conditions.
17
+ - GitHub Actions CI (build, browser bundle, test).
18
+ - `prepublishOnly` script to build Node and browser artifacts before publish.
19
+ - esbuild browser bundles (`dist/jsmediatags.js`, `dist/jsmediatags.min.js`).
20
+ - Jest test suite in root `test/` with TypeScript tests and shared helpers.
21
+
22
+ ### Changed
23
+
24
+ - **Breaking:** `main` entry is now `build/jsmediatags.js` (compile TypeScript with `npm run build` before use, or consume from npm where artifacts are prebuilt).
25
+ - **Breaking:** Node.js `>=18` required.
26
+ - **Breaking:** Browser bundle is an esbuild IIFE exposing `jsmediatags` globally, replacing the previous Browserify/Closure Compiler UMD build.
27
+ - **Breaking:** `browser` field points at `dist/jsmediatags.min.js`.
28
+ - Migrated from Flow to TypeScript; shared types live in `src/types.ts` (formerly `FlowTypes.ts`).
29
+ - Dev tooling: TypeScript (`tsc`), esbuild, Jest 29, ts-jest.
30
+ - `optionalPeerDependencies` replaced with standard `peerDependencies` and `peerDependenciesMeta` for `buffer` and `react-native-fs`.
31
+
32
+ ### Removed
33
+
34
+ - Flow, Babel, Browserify, Watchify, and Google Closure Compiler from the build pipeline.
35
+ - Bower (`bower.json`).
36
+ - Unused `react` / `react-native` devDependencies (React Native support remains via optional peers and source).
37
+
38
+ ### Fixed
39
+
40
+ - ID3v2 frame flag defaults when partial flags are provided.
41
+ - `XhrFileReader` `Content-Length` parsing return type.
42
+
43
+ ## [3.9.7] and earlier
44
+
45
+ See [git history](https://github.com/aadsm/jsmediatags/commits/master) for releases prior to the 4.0 modernization.
package/LICENSE.md ADDED
@@ -0,0 +1,36 @@
1
+ [BSD License](http://opensource.org/licenses/BSD-3-Clause)
2
+
3
+ Copyright (c) 2009 Opera Software ASA
4
+
5
+ Copyright (c) 2015 António Afonso
6
+
7
+ Copyright (c) 2008 Jacob Seidelin, http://blog.nihilogic.dk/
8
+
9
+ Copyright (c) 2010 Joshua Kifer
10
+
11
+ All rights reserved.
12
+
13
+ Redistribution and use in source and binary forms, with or without modification,
14
+ are permitted provided that the following conditions are met:
15
+
16
+ * Redistributions of source code must retain the above copyright notice, this
17
+ list of conditions and the following disclaimer.
18
+
19
+ * Redistributions in binary form must reproduce the above copyright notice,
20
+ this list of conditions and the following disclaimer in the documentation
21
+ and/or other materials provided with the distribution.
22
+
23
+ * Neither the name Facebook nor the names of its contributors may be used to
24
+ endorse or promote products derived from this software without specific
25
+ prior written permission.
26
+
27
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
28
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
31
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
34
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,548 @@
1
+ # JS MediaTags
2
+
3
+ Read ID3, MP4, and FLAC metadata from audio files in Node.js, browsers, and React Native. Successor to [JavaScript-ID3-Reader](https://github.com/aadsm/JavaScript-ID3-Reader).
4
+
5
+ This repository is a **fork and modernization** of [aadsm/jsmediatags](https://github.com/aadsm/jsmediatags), the original library and its maintenance home. Development here targets **4.0.0** (TypeScript, updated tooling, and packaging). It is not guaranteed to be merged upstream; treat [aadsm/jsmediatags](https://github.com/aadsm/jsmediatags) as the canonical project history and this fork as an upgraded continuation.
6
+
7
+ **npm:** [`@probityrules/jsmediatags`](https://www.npmjs.com/package/@probityrules/jsmediatags) (published from this fork; includes compiled `build/` and browser bundle only, not `src/`).
8
+
9
+ **Requirements:** Node.js **18+**. See [CHANGELOG.md](CHANGELOG.md) for **4.0.0** breaking changes if upgrading from 3.x.
10
+
11
+ ## Donations
12
+
13
+ A few people have asked me about donations (or even crowdfunding). I would prefer you to consider making a donation to the ["Girls Who Code" NPO](https://www.classy.org/checkout/donation?eid=77372). If you do please send me a message so I can add you as a contributor.
14
+
15
+ ## [Contributors](CONTRIBUTORS.md)
16
+
17
+ ## [Contributing](CONTRIBUTING.md)
18
+
19
+ ## Current Support
20
+
21
+ * File Readers
22
+ * NodeJS
23
+ * XMLHttpRequest
24
+ * Blob
25
+ * File
26
+ * Buffers/Arrays
27
+ * React Native
28
+ * Tag Readers
29
+ * ID3v1
30
+ * ID3v2 (with unsynchronisation support!)
31
+ * MP4
32
+ * FLAC
33
+
34
+ ## How to use
35
+
36
+ ### Node.js
37
+
38
+ ```bash
39
+ npm install @probityrules/jsmediatags
40
+ ```
41
+
42
+ The published package includes compiled JavaScript and TypeScript declarations (`build/jsmediatags.d.ts`). Source (`src/`) is not shipped on npm.
43
+
44
+ #### Callback API
45
+
46
+ ```javascript
47
+ // Simple API - will fetch all tags
48
+ var jsmediatags = require("@probityrules/jsmediatags");
49
+
50
+ jsmediatags.read("./music-file.mp3", {
51
+ onSuccess: function(tag) {
52
+ console.log(tag);
53
+ },
54
+ onError: function(error) {
55
+ console.log(':(', error.type, error.info);
56
+ }
57
+ });
58
+ ```
59
+
60
+ ```javascript
61
+ // Advanced API
62
+ var jsmediatags = require("@probityrules/jsmediatags");
63
+
64
+ new jsmediatags.Reader("http://www.example.com/music-file.mp3")
65
+ .setTagsToRead(["title", "artist"])
66
+ .read({
67
+ onSuccess: function(tag) {
68
+ console.log(tag);
69
+ },
70
+ onError: function(error) {
71
+ console.log(':(', error.type, error.info);
72
+ }
73
+ });
74
+ ```
75
+
76
+ #### Promise API
77
+
78
+ Omit callbacks to get a `Promise`, or call `readAsync` explicitly. Rejections use the same `{ type, info, ... }` objects as `onError`.
79
+
80
+ ```javascript
81
+ const jsmediatags = require("@probityrules/jsmediatags");
82
+
83
+ // read(location) without callbacks
84
+ const tag = await jsmediatags.read("./music-file.mp3");
85
+
86
+ // readAsync(location)
87
+ const tag2 = await jsmediatags.readAsync("./music-file.mp3");
88
+
89
+ // Reader instance
90
+ const tag3 = await new jsmediatags.Reader("./music-file.mp3")
91
+ .setTagsToRead(["title", "artist"])
92
+ .read();
93
+ ```
94
+
95
+ ```javascript
96
+ try {
97
+ const tag = await jsmediatags.readAsync("./music-file.mp3");
98
+ console.log(tag.tags.title);
99
+ } catch (error) {
100
+ console.log(error.type, error.info);
101
+ }
102
+ ```
103
+
104
+ ### Browser
105
+
106
+ Copy [`dist/jsmediatags.min.js`](https://github.com/aadsm/jsmediatags/blob/master/dist/jsmediatags.min.js) into your app and load it with a script tag. The bundle is also on [cdnjs](https://cdnjs.com/libraries/jsmediatags).
107
+
108
+ The browser build is an **IIFE** that assigns a global `jsmediatags` object:
109
+
110
+ ```html
111
+ <script src="jsmediatags.min.js"></script>
112
+ <script>
113
+ jsmediatags.read(fileInput.files[0]).then(function(tag) {
114
+ console.log(tag);
115
+ });
116
+ </script>
117
+ ```
118
+
119
+ When installed via npm, bundlers can `require("@probityrules/jsmediatags")` or `import jsmediatags from "@probityrules/jsmediatags"` and resolve the Node build; the `"browser"` export condition points at the minified bundle for browser-targeted builds.
120
+
121
+ It supports loading files from remote hosts, Blob and File objects:
122
+
123
+ ```javascript
124
+ // Callback API
125
+ jsmediatags.read("http://www.example.com/music-file.mp3", {
126
+ onSuccess: function(tag) {
127
+ console.log(tag);
128
+ },
129
+ onError: function(error) {
130
+ console.log(error);
131
+ }
132
+ });
133
+
134
+ // Promise API
135
+ const tag = await jsmediatags.read("https://www.example.com/music-file.mp3");
136
+ ```
137
+
138
+ Note that the URI has to include the scheme (e.g.: https://), as relative URIs are not supported.
139
+
140
+ ```javascript
141
+ // From Blob
142
+ jsmediatags.read(blob, ...);
143
+ ```
144
+
145
+ ```javascript
146
+ // From File
147
+ inputTypeFile.addEventListener("change", function(event) {
148
+ var file = event.target.files[0];
149
+ jsmediatags.read(file, ...);
150
+ }, false);
151
+ ```
152
+
153
+ ### React Native
154
+
155
+ Install the library, then the optional peer dependencies used by the React Native file reader:
156
+
157
+ ```bash
158
+ npm install @probityrules/jsmediatags
159
+ npm install buffer react-native-fs
160
+ ```
161
+
162
+ (`buffer` and `react-native-fs` are declared as optional `peerDependencies` in `package.json`.)
163
+
164
+ Usage is the same as in Node.js:
165
+
166
+ ```js
167
+ const jsmediatags = require('@probityrules/jsmediatags');
168
+
169
+ // Callback API
170
+ new jsmediatags.Reader('/path/to/song.mp3')
171
+ .read({
172
+ onSuccess: (tag) => {
173
+ console.log(tag);
174
+ },
175
+ onError: (error) => {
176
+ console.log(error.type, error.info);
177
+ }
178
+ });
179
+
180
+ // Promise API
181
+ const tag = await jsmediatags.readAsync('/path/to/song.mp3');
182
+ // or
183
+ const tag2 = await new jsmediatags.Reader('/path/to/song.mp3').read();
184
+ ```
185
+
186
+ ### Articles
187
+
188
+ * [Cordova : lire les metadatas des mp3s avec jsmediatags](http://blog.luce.pro/2016/02/28/Phonegap-lire-les-metadatas-des-mp3s-avec-jsmediatags/)
189
+
190
+ ## Documentation
191
+
192
+ ### The Output
193
+
194
+ This is an example of the object passed to the `jsmediatags.read`'s `onSuccess` callback.
195
+
196
+ #### ID3v2
197
+
198
+ ```javascript
199
+ {
200
+ type: "ID3",
201
+ version: "2.4.0",
202
+ major: 4,
203
+ revision: 0,
204
+ tags: {
205
+ artist: "Sam, The Kid",
206
+ album: "Pratica(mente)",
207
+ track: "12",
208
+ TPE1: {
209
+ id: "TPE1",
210
+ size: 14,
211
+ description: "Lead performer(s)/Soloist(s)",
212
+ data: "Sam, The Kid"
213
+ },
214
+ TALB: {
215
+ id: "TALB",
216
+ size: 16,
217
+ description: "Album/Movie/Show title",
218
+ data: "Pratica(mente)"
219
+ },
220
+ TRCK: {
221
+ id: "TRCK",
222
+ size: 3,
223
+ description: "Track number/Position in set",
224
+ data: "12",
225
+ }
226
+ },
227
+ size: 34423,
228
+ flags: {
229
+ unsynchronisation: false,
230
+ extended_header: false,
231
+ experimental_indicator: false,
232
+ footer_present: false
233
+ }
234
+ }
235
+ ```
236
+
237
+ #### MP4
238
+
239
+ ```javascript
240
+ {
241
+ type: "MP4",
242
+ ftyp: "M4A",
243
+ version: 0,
244
+ tags: {
245
+ "©too": {
246
+ id: "©too",
247
+ size: 35,
248
+ description: 'Encoding Tool',
249
+ data: 'Lavf53.24.2'
250
+ }
251
+ }
252
+ }
253
+ ```
254
+
255
+ #### FLAC
256
+
257
+ ```javascript
258
+ {
259
+ type: "FLAC",
260
+ version: "1",
261
+ tags: {
262
+ title: "16/12/95",
263
+ artist: "Sam, The Kid",
264
+ album: "Pratica(mente)",
265
+ track: "12",
266
+ picture: ...
267
+ }
268
+ }
269
+ ```
270
+
271
+ The `tags` property includes all tags that were found or specified to be read.
272
+ Since each tag type (e.g.: ID3, MP4) uses different tag names for the same type of data (e.g.: the artist name) the most common tags are also available under human readable names (aka shortcuts). In this example, `artist` will point to `TPE1.data`, `album` to `TALB.data` and so forth.
273
+
274
+ The expected tag object depends on the type of tag read (ID3, MP4, etc.) but they all share a common structure:
275
+
276
+ ```javascript
277
+ {
278
+ type: <the tag type: ID3, MP4, etc.>
279
+ tags: {
280
+ <shortcut name>: <points to a tags data>
281
+ <tag name>: {
282
+ id: <tag name>,
283
+ data: <the actual tag data>
284
+ }
285
+ }
286
+ }
287
+ ```
288
+
289
+ ### Shortcuts
290
+
291
+ These are the supported shortcuts.
292
+
293
+ * `title`
294
+ * `artist`
295
+ * `album`
296
+ * `year`
297
+ * `comment`
298
+ * `track`
299
+ * `genre`
300
+ * `picture`
301
+ * `lyrics`
302
+
303
+ ### Picture data
304
+
305
+ The `picture` tag contains an array buffer of all the bytes of the album artwork image as well as the content type of the image. The data can be converted and displayed as an image using:
306
+
307
+ ```javascript
308
+ const picture = result.tags.picture;
309
+ let base64String = "";
310
+ for (let i = 0; i < picture.data.length; i++) {
311
+ base64String += String.fromCharCode(picture.data[i]);
312
+ }
313
+ img.src = `data:${picture.format};base64,${window.btoa(base64String)}`;
314
+ ```
315
+
316
+ ### HTTP Access Control (CORS)
317
+
318
+ When using HTTP [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) requests you need to make sure that the server is configured to receive `If-Modified-Since` and `Range` headers with the request.
319
+ This can be configured by returning the `Access-Control-Allow-Headers` HTTP header with the OPTIONS request response.
320
+
321
+ Similarly, you should also allow for the browser to read the `Content-Length` and `Content-Range` headers. This can be configured by returning the `Access-Control-Expose-Headers` HTTP header.
322
+
323
+ In short, the following headers are expected:
324
+
325
+ ```http
326
+ Access-Control-Allow-Headers: If-Modified-Since, Range
327
+ Access-Control-Expose-Headers: Content-Length, Content-Range
328
+ ```
329
+
330
+ This library still works without these options configured on the server. However it will download the entire file instead of only the necessary bytes for reading the tags.
331
+
332
+ ### File and Tag Readers
333
+
334
+ This library uses file readers (MediaFileReader API) to read the file itself and media tag readers (MediaTagReader API) to parse the tags in the file.
335
+
336
+ By default the library will automatically pick the most appropriate file reader depending on the file location. In the common case this will be the URL or local path where the file is located.
337
+
338
+ A similar approach is taken for the tag reader. The most appropriate tag reader will be selected depending on the tag signature found in the file.
339
+
340
+ However, you can specify exactly which file reader or tag reader to use using the advanced API.
341
+
342
+ New file and tag readers can be implemented by extending the MediaFileReader and MediaTagReader classes. Check the **Development** section below for more information.
343
+
344
+ ### TypeScript
345
+
346
+ Types are published with the package. Import the default export and optionally use tag types from the compiled declarations:
347
+
348
+ ```typescript
349
+ import jsmediatags from "@probityrules/jsmediatags";
350
+ import type { TagType } from "@probityrules/jsmediatags/types";
351
+
352
+ const tag: TagType = await jsmediatags.readAsync("./music-file.mp3");
353
+ ```
354
+
355
+ When developing this repo locally, shared source types live in [`src/types.ts`](src/types.ts).
356
+
357
+ ### Reference
358
+
359
+ * `jsmediatags.read(location, callbacks?)` — Read tags from a file path, URL, Blob, or Buffer. Returns `void` with callbacks, or `Promise<Tag>` when callbacks are omitted.
360
+ * `jsmediatags.readAsync(location)` — Same as `read(location)` without callbacks.
361
+
362
+ * `jsmediatags.Reader`
363
+ * `setTagsToRead(tags: Array<string>)` — Specify which tags to read
364
+ * `setFileReader(fileReader: typeof MediaFileReader)` — Use this particular file reader
365
+ * `setTagReader(tagReader: typeof MediaTagReader)` — Use this particular tag reader
366
+ * `read(callbacks?)` — Read the tags. With callbacks returns `void`; without callbacks returns `Promise<Tag>`.
367
+ * `readAsync()` — Same as `read()` without callbacks.
368
+
369
+ * `jsmediatags.Config`
370
+ * `addFileReader(fileReader: typeof MediaFileReader)` - Add a new file reader to the automatic detection system.
371
+ * `addTagReader(tagReader: typeof MediaTagReader)` - Add a new tag reader to the automatic detection system.
372
+ * `setDisallowedXhrHeaders(disallowedXhrHeaders: Array<string>)` - Prevent the library from using specific http headers. This can be useful when dealing with CORS enabled servers you don't control.
373
+ * `setXhrTimeoutInSec(timeoutInSec: number)` - Sets the timeout time for http requests. Set it to 0 for no timeout at all. It defaults to 30s.
374
+
375
+ ## Development
376
+
377
+ Source code is written in TypeScript. Run `npm run build` to compile the Node/CommonJS output into the `build` directory.
378
+
379
+ ### NodeJS Development
380
+
381
+ Run `npm run build` to generate proper JavaScript code into the `build` directory.
382
+
383
+ ```javascript
384
+ var NodeFileReader = require('./build/NodeFileReader');
385
+ var ID3v2TagReader = require('./build/ID3v2TagReader');
386
+ ...
387
+ ```
388
+
389
+ Run `npm run watch` to automatically recompile the source code whenever a file is changed.
390
+
391
+ ### Browser Development
392
+
393
+ Run `npm run dist` to generate browser bundles with esbuild: `dist/jsmediatags.js` (debug) and `dist/jsmediatags.min.js` (production). Both expose a global `jsmediatags` object when loaded via a script tag.
394
+
395
+ Run `npm run dist-watch` to rebuild the browser bundle whenever a source file changes.
396
+
397
+ ### New File Readers
398
+
399
+ Extend the `MediaFileReader` class to implement a new file reader. Methods to implement are:
400
+
401
+ * init
402
+ * loadRange
403
+ * getBytesLoaded
404
+ * getByteAt
405
+
406
+ Current Implementations:
407
+
408
+ * [NodeFileReader](https://github.com/aadsm/jsmediatags/blob/master/src/NodeFileReader.ts) (NodeJS)
409
+ * [XhrFileReader](https://github.com/aadsm/jsmediatags/blob/master/src/XhrFileReader.ts) (Browser and NodeJS)
410
+ * [BlobFileReader](https://github.com/aadsm/jsmediatags/blob/master/src/BlobFileReader.ts) (Blob and File)
411
+
412
+ ### New Tag Readers
413
+
414
+ Extend the `MediaTagReader` class to implement a new tag reader. Methods to implement are:
415
+
416
+ * getTagIdentifierByteRange
417
+ * canReadTagFormat
418
+ * \_loadData
419
+ * \_parseData
420
+
421
+ Current Implementations:
422
+
423
+ * [ID3v1TagReader](https://github.com/aadsm/jsmediatags/blob/master/src/ID3v1TagReader.ts)
424
+ * [ID3v2TagReader](https://github.com/aadsm/jsmediatags/blob/master/src/ID3v2TagReader.ts)
425
+ * [MP4TagReader](https://github.com/aadsm/jsmediatags/blob/master/src/MP4TagReader.ts)
426
+ * [FLACTagReader](https://github.com/aadsm/jsmediatags/blob/master/src/FLACTagReader.ts)
427
+
428
+ ### Publishing
429
+
430
+ The package is published to npm as **`@probityrules/jsmediatags`**. Only distributable artifacts are included (`build/`, `dist/jsmediatags.min.js`, docs); `src/` and `test/` stay in the repository only.
431
+
432
+ ```bash
433
+ npm run build && npm run dist # prepublishOnly runs this automatically
434
+ npm publish --access public
435
+ ```
436
+
437
+ ### Unit Testing
438
+
439
+ Tests live in the [`test/`](test/) directory. Run `npm test` to execute the suite, or `npm run test:watch` during development. CI runs `npm run build`, `npm run dist`, and `npm test` on every push and pull request.
440
+
441
+ ## Upgrading from 3.x to 4.0
442
+
443
+ 4.0 is a modernization release. The tag-reading API is backward compatible if you keep using callbacks, but packaging and runtime expectations changed:
444
+
445
+ | Topic | 3.x | 4.0 |
446
+ | --- | --- | --- |
447
+ | Node.js | Older versions often worked | **Node 18+** required |
448
+ | npm `main` | Previous layout | `build/jsmediatags.js` (prebuilt on publish) |
449
+ | Browser bundle | Browserify / UMD-style | **esbuild IIFE** (`dist/jsmediatags.min.js`) |
450
+ | Source | Flow / JavaScript | **TypeScript** |
451
+ | Promise API | Not built in | `read()` / `readAsync()` without callbacks |
452
+ | React Native extras | `optionalPeerDependencies` | Standard **optional** `peerDependencies` |
453
+
454
+ See [CHANGELOG.md](CHANGELOG.md) for the full list.
455
+
456
+ ## JavaScript-ID3-Reader
457
+
458
+ If you want to migrate your project from [JavaScript-ID3-Reader](https://github.com/aadsm/JavaScript-ID3-Reader) to `jsmediatags` use the following guiding examples:
459
+
460
+ ### All tags
461
+
462
+ **JavaScript-ID3-Reader:**
463
+
464
+ ```javascript
465
+ ID3.loadTags("filename.mp3", function() {
466
+ var tags = ID3.getAllTags("filename.mp3");
467
+ alert(tags.artist + " - " + tags.title + ", " + tags.album);
468
+ });
469
+ ```
470
+
471
+ **jsmediatags:**
472
+
473
+ ```javascript
474
+ jsmediatags.read("filename.mp3", {
475
+ onSuccess: function(tag) {
476
+ var tags = tag.tags;
477
+ alert(tags.artist + " - " + tags.title + ", " + tags.album);
478
+ }
479
+ });
480
+ ```
481
+
482
+ ### Specific tags
483
+
484
+ **JavaScript-ID3-Reader:**
485
+
486
+ ```javascript
487
+ ID3.loadTags("filename.mp3", function() {
488
+ var tags = ID3.getAllTags("filename.mp3");
489
+ alert(tags.COMM.data + " - " + tags.TCON.data + ", " + tags.WXXX.data);
490
+ },
491
+ {tags: ["COMM", "TCON", "WXXX"]});
492
+ ```
493
+
494
+ **jsmediatags:**
495
+
496
+ ```javascript
497
+ new jsmediatags.Reader("filename.mp3")
498
+ .setTagsToRead(["COMM", "TCON", "WXXX"])
499
+ .read({
500
+ onSuccess: function(tag) {
501
+ var tags = tag.tags;
502
+ alert(tags.COMM.data + " - " + tags.TCON.data + ", " + tags.WXXX.data);
503
+ }
504
+ });
505
+ ```
506
+
507
+ ### Error handling
508
+
509
+ **JavaScript-ID3-Reader:**
510
+
511
+ ```javascript
512
+ ID3.loadTags("http://localhost/filename.mp3", function() {
513
+ var tags = ID3.getAllTags("http://localhost/filename.mp3");
514
+ alert(tags.comment + " - " + tags.track + ", " + tags.lyrics);
515
+ },
516
+ {
517
+ tags: ["comment", "track", "lyrics"],
518
+ onError: function(reason) {
519
+ if (reason.error === "xhr") {
520
+ console.log("There was a network error: ", reason.xhr);
521
+ }
522
+ }
523
+ });
524
+ ```
525
+
526
+ **jsmediatags:**
527
+
528
+ ```javascript
529
+ new jsmediatags.Reader("filename.mp3")
530
+ .setTagsToRead(["comment", "track", "lyrics"])
531
+ .read({
532
+ onSuccess: function(tag) {
533
+ var tags = tag.tags;
534
+ alert(tags.comment + " - " + tags.track + ", " + tags.lyrics);
535
+ },
536
+ onError: function(error) {
537
+ if (error.type === "xhr") {
538
+ console.log("There was a network error: ", error.xhr);
539
+ }
540
+ }
541
+ });
542
+ ```
543
+
544
+ ## Goals
545
+
546
+ * Improve the API of JavaScript-ID3-Reader
547
+ * Readable TypeScript source with published types and tests
548
+ * Support Node.js, browsers, and React Native
@@ -0,0 +1,12 @@
1
+ declare const MediaFileReader: any;
2
+ import type { LoadCallbackType } from "./types";
3
+ declare class ArrayBufferFileReader extends MediaFileReader {
4
+ private _buffer;
5
+ private _fileData;
6
+ constructor(buffer: ArrayBuffer);
7
+ static canReadFile(file: unknown): boolean;
8
+ _init(callbacks: LoadCallbackType): void;
9
+ loadRange(range: [number, number], callbacks: LoadCallbackType): void;
10
+ getByteAt(offset: number): number;
11
+ }
12
+ export = ArrayBufferFileReader;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ const ChunkedFileData = require("./ChunkedFileData");
3
+ const MediaFileReader = require("./MediaFileReader");
4
+ class ArrayBufferFileReader extends MediaFileReader {
5
+ constructor(buffer) {
6
+ super();
7
+ this._buffer = buffer;
8
+ this._fileData = new ChunkedFileData();
9
+ }
10
+ static canReadFile(file) {
11
+ return typeof ArrayBuffer === "function" && file instanceof ArrayBuffer;
12
+ }
13
+ _init(callbacks) {
14
+ this._size = this._buffer.byteLength;
15
+ setTimeout(callbacks.onSuccess, 1);
16
+ }
17
+ loadRange(range, callbacks) {
18
+ const arrayBuf = this._buffer.slice(range[0], range[1] + 1);
19
+ const viewData = new Uint8Array(arrayBuf);
20
+ this._fileData.addData(range[0], viewData);
21
+ callbacks.onSuccess();
22
+ }
23
+ getByteAt(offset) {
24
+ return this._fileData.getByteAt(offset);
25
+ }
26
+ }
27
+ module.exports = ArrayBufferFileReader;
@@ -0,0 +1,11 @@
1
+ declare const MediaFileReader: any;
2
+ import type { Byte, LoadCallbackType } from "./types";
3
+ declare class ArrayFileReader extends MediaFileReader {
4
+ private _array;
5
+ constructor(array: Byte[]);
6
+ static canReadFile(file: unknown): boolean;
7
+ init(callbacks: LoadCallbackType): void;
8
+ loadRange(range: [number, number], callbacks: LoadCallbackType): void;
9
+ getByteAt(offset: number): Byte;
10
+ }
11
+ export = ArrayFileReader;