@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
@@ -0,0 +1,291 @@
1
+ 'use strict';
2
+ const MediaTagReader = require('./MediaTagReader');
3
+ const MediaFileReader = require('./MediaFileReader');
4
+ class MP4TagReader extends MediaTagReader {
5
+ static getTagIdentifierByteRange() {
6
+ // The tag identifier is located in [4, 8] but since we'll need to reader
7
+ // the header of the first block anyway, we load it instead to avoid
8
+ // making two requests.
9
+ return {
10
+ offset: 0,
11
+ length: 16
12
+ };
13
+ }
14
+ static canReadTagFormat(tagIdentifier) {
15
+ var id = String.fromCharCode.apply(String, tagIdentifier.slice(4, 8));
16
+ return id === "ftyp";
17
+ }
18
+ _loadData(mediaFileReader, callbacks) {
19
+ // MP4 metadata isn't located in a specific location of the file. Roughly
20
+ // speaking, it's composed of blocks chained together like a linked list.
21
+ // These blocks are called atoms (or boxes).
22
+ // Each atom of the list can have its own child linked list. Atoms in this
23
+ // situation do not possess any data and are called "container" as they only
24
+ // contain other atoms.
25
+ // Other atoms represent a particular set of data, like audio, video or
26
+ // metadata. In order to find and load all the interesting atoms we need
27
+ // to traverse the entire linked list of atoms and only load the ones
28
+ // associated with metadata.
29
+ // The metadata atoms can be find under the "moov.udta.meta.ilst" hierarchy.
30
+ var self = this;
31
+ // Load the header of the first atom
32
+ mediaFileReader.loadRange([0, 16], {
33
+ onSuccess: function () {
34
+ self._loadAtom(mediaFileReader, 0, "", callbacks);
35
+ },
36
+ onError: callbacks.onError
37
+ });
38
+ }
39
+ _loadAtom(mediaFileReader, offset, parentAtomFullName, callbacks) {
40
+ if (offset >= mediaFileReader.getSize()) {
41
+ callbacks.onSuccess();
42
+ return;
43
+ }
44
+ var self = this;
45
+ // 8 is the size of the atomSize and atomName fields.
46
+ // When reading the current block we always read 8 more bytes in order
47
+ // to also read the header of the next block.
48
+ var atomSize = mediaFileReader.getLongAt(offset, true);
49
+ if (atomSize == 0 || isNaN(atomSize)) {
50
+ callbacks.onSuccess();
51
+ return;
52
+ }
53
+ var atomName = mediaFileReader.getStringAt(offset + 4, 4);
54
+ // console.log(parentAtomFullName, atomName, atomSize);
55
+ // Container atoms (no actual data)
56
+ if (this._isContainerAtom(atomName)) {
57
+ if (atomName == "meta") {
58
+ // The "meta" atom breaks convention and is a container with data.
59
+ offset += 4; // next_item_id (uint32)
60
+ }
61
+ var atomFullName = (parentAtomFullName ? parentAtomFullName + "." : "") + atomName;
62
+ if (atomFullName === "moov.udta.meta.ilst") {
63
+ mediaFileReader.loadRange([offset, offset + atomSize], callbacks);
64
+ }
65
+ else {
66
+ mediaFileReader.loadRange([offset + 8, offset + 8 + 8], {
67
+ onSuccess: function () {
68
+ self._loadAtom(mediaFileReader, offset + 8, atomFullName, callbacks);
69
+ },
70
+ onError: callbacks.onError
71
+ });
72
+ }
73
+ }
74
+ else {
75
+ mediaFileReader.loadRange([offset + atomSize, offset + atomSize + 8], {
76
+ onSuccess: function () {
77
+ self._loadAtom(mediaFileReader, offset + atomSize, parentAtomFullName, callbacks);
78
+ },
79
+ onError: callbacks.onError
80
+ });
81
+ }
82
+ }
83
+ _isContainerAtom(atomName) {
84
+ return ["moov", "udta", "meta", "ilst"].indexOf(atomName) >= 0;
85
+ }
86
+ _canReadAtom(atomName) {
87
+ return atomName !== "----";
88
+ }
89
+ _parseData(data, tagsToRead) {
90
+ const tags = {};
91
+ tagsToRead = this._expandShortcutTags(tagsToRead);
92
+ this._readAtom(tags, data, 0, data.getSize(), tagsToRead);
93
+ for (const name in SHORTCUTS) {
94
+ if (SHORTCUTS.hasOwnProperty(name)) {
95
+ const raw = tags[SHORTCUTS[name]];
96
+ const tag = raw;
97
+ if (tag) {
98
+ if (name === "track") {
99
+ const td = tag.data;
100
+ tags[name] = td.track;
101
+ }
102
+ else {
103
+ tags[name] = tag.data;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return {
109
+ type: "MP4",
110
+ ftyp: data.getStringAt(8, 4),
111
+ version: data.getLongAt(12, true),
112
+ tags: tags,
113
+ };
114
+ }
115
+ _readAtom(tags, data, offset, length, tagsToRead, parentAtomFullName, indent) {
116
+ indent = indent === undefined ? "" : indent + " ";
117
+ var seek = offset;
118
+ while (seek < offset + length) {
119
+ var atomSize = data.getLongAt(seek, true);
120
+ if (atomSize == 0) {
121
+ return;
122
+ }
123
+ var atomName = data.getStringAt(seek + 4, 4);
124
+ // console.log(seek, parentAtomFullName, atomName, atomSize);
125
+ if (this._isContainerAtom(atomName)) {
126
+ if (atomName == "meta") {
127
+ seek += 4; // next_item_id (uint32)
128
+ }
129
+ var atomFullName = (parentAtomFullName ? parentAtomFullName + "." : "") + atomName;
130
+ this._readAtom(tags, data, seek + 8, atomSize - 8, tagsToRead, atomFullName, indent);
131
+ return;
132
+ }
133
+ // Value atoms
134
+ if ((!tagsToRead || tagsToRead.indexOf(atomName) >= 0) &&
135
+ parentAtomFullName === "moov.udta.meta.ilst" &&
136
+ this._canReadAtom(atomName)) {
137
+ tags[atomName] = this._readMetadataAtom(data, seek);
138
+ }
139
+ seek += atomSize;
140
+ }
141
+ }
142
+ _readMetadataAtom(data, offset) {
143
+ // 16: size + name + size + "data" (4 bytes each)
144
+ // 8: 1 byte atom version & 3 bytes atom flags + 4 bytes NULL space
145
+ // 8: 4 bytes track + 4 bytes total
146
+ const METADATA_HEADER = 16;
147
+ var atomSize = data.getLongAt(offset, true);
148
+ var atomName = data.getStringAt(offset + 4, 4);
149
+ var klass = data.getInteger24At(offset + METADATA_HEADER + 1, true);
150
+ let type = TYPES[String(klass)];
151
+ let atomData;
152
+ var bigEndian = true;
153
+ if (atomName == "trkn") {
154
+ atomData = {
155
+ track: data.getShortAt(offset + METADATA_HEADER + 10, bigEndian),
156
+ total: data.getShortAt(offset + METADATA_HEADER + 14, bigEndian),
157
+ };
158
+ }
159
+ else if (atomName == "disk") {
160
+ atomData = {
161
+ disk: data.getShortAt(offset + METADATA_HEADER + 10, bigEndian),
162
+ total: data.getShortAt(offset + METADATA_HEADER + 14, bigEndian),
163
+ };
164
+ }
165
+ else {
166
+ var atomHeader = METADATA_HEADER + 4 + 4;
167
+ var dataStart = offset + atomHeader;
168
+ var dataLength = atomSize - atomHeader;
169
+ if (atomName === "covr" && type === "uint8") {
170
+ type = "jpeg";
171
+ }
172
+ switch (type) {
173
+ case "text":
174
+ atomData = data
175
+ .getStringWithCharsetAt(dataStart, dataLength, "utf-8")
176
+ .toString();
177
+ break;
178
+ case "uint8":
179
+ atomData = data.getShortAt(dataStart, false);
180
+ break;
181
+ case "int":
182
+ case "uint": {
183
+ const intReader = type == "int"
184
+ ? dataLength == 1
185
+ ? data.getSByteAt
186
+ : dataLength == 2
187
+ ? data.getSShortAt
188
+ : dataLength == 4
189
+ ? data.getSLongAt
190
+ : data.getLongAt
191
+ : dataLength == 1
192
+ ? data.getByteAt
193
+ : dataLength == 2
194
+ ? data.getShortAt
195
+ : data.getLongAt;
196
+ atomData = intReader.call(data, dataStart + (dataLength == 8 ? 4 : 0), true);
197
+ break;
198
+ }
199
+ case "jpeg":
200
+ case "png":
201
+ atomData = {
202
+ format: "image/" + type,
203
+ data: data.getBytesAt(dataStart, dataLength),
204
+ };
205
+ break;
206
+ }
207
+ }
208
+ return {
209
+ id: atomName,
210
+ size: atomSize,
211
+ description: ATOM_DESCRIPTIONS[atomName] || "Unknown",
212
+ data: atomData
213
+ };
214
+ }
215
+ getShortcuts() {
216
+ return SHORTCUTS;
217
+ }
218
+ }
219
+ /*
220
+ * https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35
221
+ */
222
+ const TYPES = {
223
+ "0": "uint8",
224
+ "1": "text",
225
+ "13": "jpeg",
226
+ "14": "png",
227
+ "21": "int",
228
+ "22": "uint"
229
+ };
230
+ const ATOM_DESCRIPTIONS = {
231
+ "©alb": "Album",
232
+ "©ART": "Artist",
233
+ "aART": "Album Artist",
234
+ "©day": "Release Date",
235
+ "©nam": "Title",
236
+ "©gen": "Genre",
237
+ "gnre": "Genre",
238
+ "trkn": "Track Number",
239
+ "©wrt": "Composer",
240
+ "©too": "Encoding Tool",
241
+ "©enc": "Encoded By",
242
+ "cprt": "Copyright",
243
+ "covr": "Cover Art",
244
+ "©grp": "Grouping",
245
+ "keyw": "Keywords",
246
+ "©lyr": "Lyrics",
247
+ "©cmt": "Comment",
248
+ "tmpo": "Tempo",
249
+ "cpil": "Compilation",
250
+ "disk": "Disc Number",
251
+ "tvsh": "TV Show Name",
252
+ "tven": "TV Episode ID",
253
+ "tvsn": "TV Season",
254
+ "tves": "TV Episode",
255
+ "tvnn": "TV Network",
256
+ "desc": "Description",
257
+ "ldes": "Long Description",
258
+ "sonm": "Sort Name",
259
+ "soar": "Sort Artist",
260
+ "soaa": "Sort Album",
261
+ "soco": "Sort Composer",
262
+ "sosn": "Sort Show",
263
+ "purd": "Purchase Date",
264
+ "pcst": "Podcast",
265
+ "purl": "Podcast URL",
266
+ "catg": "Category",
267
+ "hdvd": "HD Video",
268
+ "stik": "Media Type",
269
+ "rtng": "Content Rating",
270
+ "pgap": "Gapless Playback",
271
+ "apID": "Purchase Account",
272
+ "sfID": "Country Code",
273
+ "atID": "Artist ID",
274
+ "cnID": "Catalog ID",
275
+ "plID": "Collection ID",
276
+ "geID": "Genre ID",
277
+ "xid ": "Vendor Information",
278
+ "flvr": "Codec Flavor"
279
+ };
280
+ const SHORTCUTS = {
281
+ "title": "©nam",
282
+ "artist": "©ART",
283
+ "album": "©alb",
284
+ "year": "©day",
285
+ "comment": "©cmt",
286
+ "track": "trkn",
287
+ "genre": "©gen",
288
+ "picture": "covr",
289
+ "lyrics": "©lyr"
290
+ };
291
+ module.exports = MP4TagReader;
@@ -0,0 +1,46 @@
1
+ import type { DecodedString } from "./DecodedString";
2
+ import type { LoadCallbackType, CharsetType } from "./types";
3
+ declare class MediaFileReader {
4
+ protected _isInitialized: boolean;
5
+ protected _size: number;
6
+ constructor(_path?: unknown);
7
+ /**
8
+ * Decides if this media file reader is able to read the given file.
9
+ */
10
+ static canReadFile(_file: unknown): boolean;
11
+ /**
12
+ * This function needs to be called before any other function.
13
+ * Loads the necessary initial information from the file.
14
+ */
15
+ init(callbacks: LoadCallbackType): void;
16
+ _init(callbacks: LoadCallbackType): void;
17
+ /**
18
+ * @param range The start and end indexes of the range to load.
19
+ * Ex: [0, 7] load bytes 0 to 7 inclusive.
20
+ */
21
+ loadRange(range: [number, number], callbacks: LoadCallbackType): void;
22
+ /**
23
+ * @return The size of the file in bytes.
24
+ */
25
+ getSize(): number;
26
+ getByteAt(offset: number): number;
27
+ getBytesAt(offset: number, length: number): Array<number>;
28
+ isBitSetAt(offset: number, bit: number): boolean;
29
+ getSByteAt(offset: number): number;
30
+ getShortAt(offset: number, isBigEndian: boolean): number;
31
+ getSShortAt(offset: number, isBigEndian: boolean): number;
32
+ getLongAt(offset: number, isBigEndian: boolean): number;
33
+ getSLongAt(offset: number, isBigEndian: boolean): number;
34
+ getInteger24At(offset: number, isBigEndian: boolean): number;
35
+ getStringAt(offset: number, length: number): string;
36
+ getStringWithCharsetAt(offset: number, length: number, charset?: CharsetType | null): DecodedString;
37
+ getCharAt(offset: number): string;
38
+ /**
39
+ * The ID3v2 tag/frame size is encoded with four bytes where the most
40
+ * significant bit (bit 7) is set to zero in every byte, making a total of 28
41
+ * bits. The zeroed bits are ignored, so a 257 bytes long tag is represented
42
+ * as $00 00 02 01.
43
+ */
44
+ getSynchsafeInteger32At(offset: number): number;
45
+ }
46
+ export = MediaFileReader;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ const StringUtils = require("./StringUtils");
3
+ class MediaFileReader {
4
+ constructor(_path) {
5
+ this._isInitialized = false;
6
+ this._size = 0;
7
+ }
8
+ /**
9
+ * Decides if this media file reader is able to read the given file.
10
+ */
11
+ static canReadFile(_file) {
12
+ throw new Error("Must implement canReadFile function");
13
+ }
14
+ /**
15
+ * This function needs to be called before any other function.
16
+ * Loads the necessary initial information from the file.
17
+ */
18
+ init(callbacks) {
19
+ const self = this;
20
+ if (this._isInitialized) {
21
+ setTimeout(callbacks.onSuccess, 1);
22
+ }
23
+ else {
24
+ this._init({
25
+ onSuccess: function () {
26
+ self._isInitialized = true;
27
+ callbacks.onSuccess();
28
+ },
29
+ onError: callbacks.onError,
30
+ });
31
+ }
32
+ }
33
+ _init(callbacks) {
34
+ throw new Error("Must implement init function");
35
+ }
36
+ /**
37
+ * @param range The start and end indexes of the range to load.
38
+ * Ex: [0, 7] load bytes 0 to 7 inclusive.
39
+ */
40
+ loadRange(range, callbacks) {
41
+ throw new Error("Must implement loadRange function");
42
+ }
43
+ /**
44
+ * @return The size of the file in bytes.
45
+ */
46
+ getSize() {
47
+ if (!this._isInitialized) {
48
+ throw new Error("init() must be called first.");
49
+ }
50
+ return this._size;
51
+ }
52
+ getByteAt(offset) {
53
+ throw new Error("Must implement getByteAt function");
54
+ }
55
+ getBytesAt(offset, length) {
56
+ const bytes = new Array(length);
57
+ for (let i = 0; i < length; i++) {
58
+ bytes[i] = this.getByteAt(offset + i);
59
+ }
60
+ return bytes;
61
+ }
62
+ isBitSetAt(offset, bit) {
63
+ const iByte = this.getByteAt(offset);
64
+ return (iByte & (1 << bit)) != 0;
65
+ }
66
+ getSByteAt(offset) {
67
+ const iByte = this.getByteAt(offset);
68
+ if (iByte > 127) {
69
+ return iByte - 256;
70
+ }
71
+ else {
72
+ return iByte;
73
+ }
74
+ }
75
+ getShortAt(offset, isBigEndian) {
76
+ let iShort = isBigEndian
77
+ ? (this.getByteAt(offset) << 8) + this.getByteAt(offset + 1)
78
+ : (this.getByteAt(offset + 1) << 8) + this.getByteAt(offset);
79
+ if (iShort < 0) {
80
+ iShort += 65536;
81
+ }
82
+ return iShort;
83
+ }
84
+ getSShortAt(offset, isBigEndian) {
85
+ const iUShort = this.getShortAt(offset, isBigEndian);
86
+ if (iUShort > 32767) {
87
+ return iUShort - 65536;
88
+ }
89
+ else {
90
+ return iUShort;
91
+ }
92
+ }
93
+ getLongAt(offset, isBigEndian) {
94
+ const iByte1 = this.getByteAt(offset), iByte2 = this.getByteAt(offset + 1), iByte3 = this.getByteAt(offset + 2), iByte4 = this.getByteAt(offset + 3);
95
+ let iLong = isBigEndian
96
+ ? (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
97
+ : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
98
+ if (iLong < 0) {
99
+ iLong += 4294967296;
100
+ }
101
+ return iLong;
102
+ }
103
+ getSLongAt(offset, isBigEndian) {
104
+ const iULong = this.getLongAt(offset, isBigEndian);
105
+ if (iULong > 2147483647) {
106
+ return iULong - 4294967296;
107
+ }
108
+ else {
109
+ return iULong;
110
+ }
111
+ }
112
+ getInteger24At(offset, isBigEndian) {
113
+ const iByte1 = this.getByteAt(offset), iByte2 = this.getByteAt(offset + 1), iByte3 = this.getByteAt(offset + 2);
114
+ let iInteger = isBigEndian
115
+ ? (((iByte1 << 8) + iByte2) << 8) + iByte3
116
+ : (((iByte3 << 8) + iByte2) << 8) + iByte1;
117
+ if (iInteger < 0) {
118
+ iInteger += 16777216;
119
+ }
120
+ return iInteger;
121
+ }
122
+ getStringAt(offset, length) {
123
+ const string = [];
124
+ for (let i = offset, j = 0; i < offset + length; i++, j++) {
125
+ string[j] = String.fromCharCode(this.getByteAt(i));
126
+ }
127
+ return string.join("");
128
+ }
129
+ getStringWithCharsetAt(offset, length, charset) {
130
+ const bytes = this.getBytesAt(offset, length);
131
+ let string;
132
+ switch ((charset || "").toLowerCase()) {
133
+ case "utf-16":
134
+ case "utf-16le":
135
+ case "utf-16be":
136
+ string = StringUtils.readUTF16String(bytes, charset === "utf-16be");
137
+ break;
138
+ case "utf-8":
139
+ string = StringUtils.readUTF8String(bytes);
140
+ break;
141
+ default:
142
+ string = StringUtils.readNullTerminatedString(bytes);
143
+ break;
144
+ }
145
+ return string;
146
+ }
147
+ getCharAt(offset) {
148
+ return String.fromCharCode(this.getByteAt(offset));
149
+ }
150
+ /**
151
+ * The ID3v2 tag/frame size is encoded with four bytes where the most
152
+ * significant bit (bit 7) is set to zero in every byte, making a total of 28
153
+ * bits. The zeroed bits are ignored, so a 257 bytes long tag is represented
154
+ * as $00 00 02 01.
155
+ */
156
+ getSynchsafeInteger32At(offset) {
157
+ const size1 = this.getByteAt(offset);
158
+ const size2 = this.getByteAt(offset + 1);
159
+ const size3 = this.getByteAt(offset + 2);
160
+ const size4 = this.getByteAt(offset + 3);
161
+ const size = size4 & 0x7f |
162
+ ((size3 & 0x7f) << 7) |
163
+ ((size2 & 0x7f) << 14) |
164
+ ((size1 & 0x7f) << 21);
165
+ return size;
166
+ }
167
+ }
168
+ module.exports = MediaFileReader;
@@ -0,0 +1,18 @@
1
+ declare const MediaFileReader: any;
2
+ import type { CallbackType, LoadCallbackType, ByteRange, TagType } from "./types";
3
+ declare class MediaTagReader {
4
+ private _mediaFileReader;
5
+ private _tags;
6
+ constructor(mediaFileReader: InstanceType<typeof MediaFileReader>);
7
+ static getTagIdentifierByteRange(): ByteRange;
8
+ static canReadTagFormat(_tagIdentifier: Array<number>): boolean;
9
+ setTagsToRead(tags: string[] | null): this;
10
+ read(callbacks: CallbackType<TagType>): void;
11
+ read(): Promise<TagType>;
12
+ readAsync(): Promise<TagType>;
13
+ getShortcuts(): Record<string, string | string[]>;
14
+ _loadData(_mediaFileReader: InstanceType<typeof MediaFileReader>, _callbacks: LoadCallbackType): void;
15
+ _parseData(_mediaFileReader: InstanceType<typeof MediaFileReader>, _tags: string[] | null): TagType;
16
+ _expandShortcutTags(tagsWithShortcuts: string[] | null): string[] | null;
17
+ }
18
+ export = MediaTagReader;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ const MediaFileReader = require("./MediaFileReader");
3
+ class MediaTagReader {
4
+ constructor(mediaFileReader) {
5
+ this._mediaFileReader = mediaFileReader;
6
+ this._tags = null;
7
+ }
8
+ static getTagIdentifierByteRange() {
9
+ throw new Error("Must implement");
10
+ }
11
+ static canReadTagFormat(_tagIdentifier) {
12
+ throw new Error("Must implement");
13
+ }
14
+ setTagsToRead(tags) {
15
+ this._tags = tags;
16
+ return this;
17
+ }
18
+ read(callbacks) {
19
+ if (callbacks === undefined) {
20
+ return new Promise((resolve, reject) => {
21
+ this.read({ onSuccess: resolve, onError: reject });
22
+ });
23
+ }
24
+ const self = this;
25
+ this._mediaFileReader.init({
26
+ onSuccess: function () {
27
+ self._loadData(self._mediaFileReader, {
28
+ onSuccess: function () {
29
+ let tags;
30
+ try {
31
+ tags = self._parseData(self._mediaFileReader, self._tags);
32
+ }
33
+ catch (ex) {
34
+ const err = ex;
35
+ if (callbacks.onError) {
36
+ callbacks.onError({
37
+ type: "parseData",
38
+ info: err.message,
39
+ });
40
+ }
41
+ return;
42
+ }
43
+ callbacks.onSuccess(tags);
44
+ },
45
+ onError: callbacks.onError,
46
+ });
47
+ },
48
+ onError: callbacks.onError,
49
+ });
50
+ }
51
+ readAsync() {
52
+ return this.read();
53
+ }
54
+ getShortcuts() {
55
+ return {};
56
+ }
57
+ _loadData(_mediaFileReader, _callbacks) {
58
+ throw new Error("Must implement _loadData function");
59
+ }
60
+ _parseData(_mediaFileReader, _tags) {
61
+ throw new Error("Must implement _parseData function");
62
+ }
63
+ _expandShortcutTags(tagsWithShortcuts) {
64
+ if (!tagsWithShortcuts) {
65
+ return null;
66
+ }
67
+ let tags = [];
68
+ const shortcuts = this.getShortcuts();
69
+ for (let i = 0, tagOrShortcut; (tagOrShortcut = tagsWithShortcuts[i]); i++) {
70
+ tags = tags.concat(shortcuts[tagOrShortcut] ||
71
+ [tagOrShortcut]);
72
+ }
73
+ return tags;
74
+ }
75
+ }
76
+ module.exports = MediaTagReader;
@@ -0,0 +1,12 @@
1
+ declare const MediaFileReader: any;
2
+ import type { LoadCallbackType } from "./types";
3
+ declare class NodeFileReader extends MediaFileReader {
4
+ private _path;
5
+ private _fileData;
6
+ constructor(path: string);
7
+ static canReadFile(file: unknown): boolean;
8
+ getByteAt(offset: number): number;
9
+ _init(callbacks: LoadCallbackType): void;
10
+ loadRange(range: [number, number], callbacks: LoadCallbackType): void;
11
+ }
12
+ export = NodeFileReader;