@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,582 @@
1
+ 'use strict';
2
+ const MediaFileReader = require('./MediaFileReader');
3
+ const StringUtils = require('./StringUtils');
4
+ const ArrayFileReader = require('./ArrayFileReader');
5
+ const FRAME_DESCRIPTIONS = {
6
+ // v2.2
7
+ "BUF": "Recommended buffer size",
8
+ "CNT": "Play counter",
9
+ "COM": "Comments",
10
+ "CRA": "Audio encryption",
11
+ "CRM": "Encrypted meta frame",
12
+ "ETC": "Event timing codes",
13
+ "EQU": "Equalization",
14
+ "GEO": "General encapsulated object",
15
+ "IPL": "Involved people list",
16
+ "LNK": "Linked information",
17
+ "MCI": "Music CD Identifier",
18
+ "MLL": "MPEG location lookup table",
19
+ "PIC": "Attached picture",
20
+ "POP": "Popularimeter",
21
+ "REV": "Reverb",
22
+ "RVA": "Relative volume adjustment",
23
+ "SLT": "Synchronized lyric/text",
24
+ "STC": "Synced tempo codes",
25
+ "TAL": "Album/Movie/Show title",
26
+ "TBP": "BPM (Beats Per Minute)",
27
+ "TCM": "Composer",
28
+ "TCO": "Content type",
29
+ "TCR": "Copyright message",
30
+ "TDA": "Date",
31
+ "TDY": "Playlist delay",
32
+ "TEN": "Encoded by",
33
+ "TFT": "File type",
34
+ "TIM": "Time",
35
+ "TKE": "Initial key",
36
+ "TLA": "Language(s)",
37
+ "TLE": "Length",
38
+ "TMT": "Media type",
39
+ "TOA": "Original artist(s)/performer(s)",
40
+ "TOF": "Original filename",
41
+ "TOL": "Original Lyricist(s)/text writer(s)",
42
+ "TOR": "Original release year",
43
+ "TOT": "Original album/Movie/Show title",
44
+ "TP1": "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group",
45
+ "TP2": "Band/Orchestra/Accompaniment",
46
+ "TP3": "Conductor/Performer refinement",
47
+ "TP4": "Interpreted, remixed, or otherwise modified by",
48
+ "TPA": "Part of a set",
49
+ "TPB": "Publisher",
50
+ "TRC": "ISRC (International Standard Recording Code)",
51
+ "TRD": "Recording dates",
52
+ "TRK": "Track number/Position in set",
53
+ "TSI": "Size",
54
+ "TSS": "Software/hardware and settings used for encoding",
55
+ "TT1": "Content group description",
56
+ "TT2": "Title/Songname/Content description",
57
+ "TT3": "Subtitle/Description refinement",
58
+ "TXT": "Lyricist/text writer",
59
+ "TXX": "User defined text information frame",
60
+ "TYE": "Year",
61
+ "UFI": "Unique file identifier",
62
+ "ULT": "Unsychronized lyric/text transcription",
63
+ "WAF": "Official audio file webpage",
64
+ "WAR": "Official artist/performer webpage",
65
+ "WAS": "Official audio source webpage",
66
+ "WCM": "Commercial information",
67
+ "WCP": "Copyright/Legal information",
68
+ "WPB": "Publishers official webpage",
69
+ "WXX": "User defined URL link frame",
70
+ // v2.3
71
+ "AENC": "Audio encryption",
72
+ "APIC": "Attached picture",
73
+ "ASPI": "Audio seek point index",
74
+ "CHAP": "Chapter",
75
+ "CTOC": "Table of contents",
76
+ "COMM": "Comments",
77
+ "COMR": "Commercial frame",
78
+ "ENCR": "Encryption method registration",
79
+ "EQU2": "Equalisation (2)",
80
+ "EQUA": "Equalization",
81
+ "ETCO": "Event timing codes",
82
+ "GEOB": "General encapsulated object",
83
+ "GRID": "Group identification registration",
84
+ "IPLS": "Involved people list",
85
+ "LINK": "Linked information",
86
+ "MCDI": "Music CD identifier",
87
+ "MLLT": "MPEG location lookup table",
88
+ "OWNE": "Ownership frame",
89
+ "PRIV": "Private frame",
90
+ "PCNT": "Play counter",
91
+ "POPM": "Popularimeter",
92
+ "POSS": "Position synchronisation frame",
93
+ "RBUF": "Recommended buffer size",
94
+ "RVA2": "Relative volume adjustment (2)",
95
+ "RVAD": "Relative volume adjustment",
96
+ "RVRB": "Reverb",
97
+ "SEEK": "Seek frame",
98
+ "SYLT": "Synchronized lyric/text",
99
+ "SYTC": "Synchronized tempo codes",
100
+ "TALB": "Album/Movie/Show title",
101
+ "TBPM": "BPM (beats per minute)",
102
+ "TCOM": "Composer",
103
+ "TCON": "Content type",
104
+ "TCOP": "Copyright message",
105
+ "TDAT": "Date",
106
+ "TDLY": "Playlist delay",
107
+ "TDRC": "Recording time",
108
+ "TDRL": "Release time",
109
+ "TDTG": "Tagging time",
110
+ "TENC": "Encoded by",
111
+ "TEXT": "Lyricist/Text writer",
112
+ "TFLT": "File type",
113
+ "TIME": "Time",
114
+ "TIPL": "Involved people list",
115
+ "TIT1": "Content group description",
116
+ "TIT2": "Title/songname/content description",
117
+ "TIT3": "Subtitle/Description refinement",
118
+ "TKEY": "Initial key",
119
+ "TLAN": "Language(s)",
120
+ "TLEN": "Length",
121
+ "TMCL": "Musician credits list",
122
+ "TMED": "Media type",
123
+ "TMOO": "Mood",
124
+ "TOAL": "Original album/movie/show title",
125
+ "TOFN": "Original filename",
126
+ "TOLY": "Original lyricist(s)/text writer(s)",
127
+ "TOPE": "Original artist(s)/performer(s)",
128
+ "TORY": "Original release year",
129
+ "TOWN": "File owner/licensee",
130
+ "TPE1": "Lead performer(s)/Soloist(s)",
131
+ "TPE2": "Band/orchestra/accompaniment",
132
+ "TPE3": "Conductor/performer refinement",
133
+ "TPE4": "Interpreted, remixed, or otherwise modified by",
134
+ "TPOS": "Part of a set",
135
+ "TPRO": "Produced notice",
136
+ "TPUB": "Publisher",
137
+ "TRCK": "Track number/Position in set",
138
+ "TRDA": "Recording dates",
139
+ "TRSN": "Internet radio station name",
140
+ "TRSO": "Internet radio station owner",
141
+ "TSOA": "Album sort order",
142
+ "TSOP": "Performer sort order",
143
+ "TSOT": "Title sort order",
144
+ "TSIZ": "Size",
145
+ "TSRC": "ISRC (international standard recording code)",
146
+ "TSSE": "Software/Hardware and settings used for encoding",
147
+ "TSST": "Set subtitle",
148
+ "TYER": "Year",
149
+ "TXXX": "User defined text information frame",
150
+ "UFID": "Unique file identifier",
151
+ "USER": "Terms of use",
152
+ "USLT": "Unsychronized lyric/text transcription",
153
+ "WCOM": "Commercial information",
154
+ "WCOP": "Copyright/Legal information",
155
+ "WOAF": "Official audio file webpage",
156
+ "WOAR": "Official artist/performer webpage",
157
+ "WOAS": "Official audio source webpage",
158
+ "WORS": "Official internet radio station homepage",
159
+ "WPAY": "Payment",
160
+ "WPUB": "Publishers official webpage",
161
+ "WXXX": "User defined URL link frame"
162
+ };
163
+ class ID3v2FrameReader {
164
+ static getFrameReaderFunction(frameId) {
165
+ var _a, _b, _c;
166
+ if (frameId in frameReaderFunctions) {
167
+ return (_a = frameReaderFunctions[frameId]) !== null && _a !== void 0 ? _a : null;
168
+ }
169
+ else if (frameId[0] === "T") {
170
+ return (_b = frameReaderFunctions["T*"]) !== null && _b !== void 0 ? _b : null;
171
+ }
172
+ else if (frameId[0] === "W") {
173
+ return (_c = frameReaderFunctions["W*"]) !== null && _c !== void 0 ? _c : null;
174
+ }
175
+ else {
176
+ return null;
177
+ }
178
+ }
179
+ /**
180
+ * All the frames consists of a frame header followed by one or more fields
181
+ * containing the actual information.
182
+ * The frame ID made out of the characters capital A-Z and 0-9. Identifiers
183
+ * beginning with "X", "Y" and "Z" are for experimental use and free for
184
+ * everyone to use, without the need to set the experimental bit in the tag
185
+ * header. Have in mind that someone else might have used the same identifier
186
+ * as you. All other identifiers are either used or reserved for future use.
187
+ * The frame ID is followed by a size descriptor, making a total header size
188
+ * of ten bytes in every frame. The size is calculated as frame size excluding
189
+ * frame header (frame size - 10).
190
+ */
191
+ static readFrames(offset, end, data, id3header, tags) {
192
+ var _a;
193
+ const frames = {};
194
+ var frameHeaderSize = this._getFrameHeaderSize(id3header);
195
+ // console.log('header', id3header);
196
+ while (
197
+ // we should be able to read at least the frame header
198
+ offset < (end - frameHeaderSize)) {
199
+ var header = this._readFrameHeader(data, offset, id3header);
200
+ var frameId = header.id;
201
+ // No frame ID sometimes means it's the last frame (GTFO).
202
+ if (!frameId) {
203
+ break;
204
+ }
205
+ var flags = header.flags;
206
+ var frameSize = header.size;
207
+ var frameDataOffset = offset + header.headerSize;
208
+ var frameData = data;
209
+ // console.log(offset, frameId, header.size + header.headerSize, flags && flags.format.unsynchronisation);
210
+ // advance data offset to the next frame data
211
+ offset += header.headerSize + header.size;
212
+ // skip unwanted tags
213
+ if (tags && tags.indexOf(frameId) === -1) {
214
+ continue;
215
+ }
216
+ // Workaround: MP3ext V3.3.17 places a non-compliant padding string at
217
+ // the end of the ID3v2 header. A string like "MP3ext V3.3.19(ansi)"
218
+ // is added multiple times at the end of the ID3 tag. More information
219
+ // about this issue can be found at
220
+ // https://github.com/aadsm/jsmediatags/issues/58#issuecomment-313865336
221
+ if (frameId === 'MP3e' || frameId === '\x00MP3' ||
222
+ frameId === '\x00\x00MP' || frameId === ' MP3') {
223
+ break;
224
+ }
225
+ if (flags && flags.format.unsynchronisation && !id3header.flags.unsynchronisation) {
226
+ frameData = this.getUnsyncFileReader(frameData, frameDataOffset, frameSize);
227
+ frameDataOffset = 0;
228
+ frameSize = frameData.getSize();
229
+ }
230
+ // the first 4 bytes are the real data size
231
+ // (after unsynchronisation && encryption)
232
+ if (flags && flags.format.data_length_indicator) {
233
+ // var frameDataSize = frameData.getSynchsafeInteger32At(frameDataOffset);
234
+ frameDataOffset += 4;
235
+ frameSize -= 4;
236
+ }
237
+ var readFrameFunc = ID3v2FrameReader.getFrameReaderFunction(frameId);
238
+ var parsedData = readFrameFunc
239
+ ? readFrameFunc.apply(this, [
240
+ frameDataOffset,
241
+ frameSize,
242
+ frameData,
243
+ (_a = flags) !== null && _a !== void 0 ? _a : null,
244
+ id3header,
245
+ ])
246
+ : null;
247
+ var desc = this._getFrameDescription(frameId);
248
+ var frame = {
249
+ id: frameId,
250
+ size: frameSize,
251
+ description: desc,
252
+ data: parsedData
253
+ };
254
+ if (frameId in frames) {
255
+ const existing = frames[frameId];
256
+ if (existing && !Array.isArray(existing) && existing.id) {
257
+ frames[frameId] = [existing];
258
+ }
259
+ frames[frameId].push(frame);
260
+ }
261
+ else {
262
+ frames[frameId] = frame;
263
+ }
264
+ }
265
+ return frames;
266
+ }
267
+ static _getFrameHeaderSize(id3header) {
268
+ var major = id3header.major;
269
+ if (major == 2) {
270
+ return 6;
271
+ }
272
+ else if (major == 3 || major == 4) {
273
+ return 10;
274
+ }
275
+ else {
276
+ return 0;
277
+ }
278
+ }
279
+ static _readFrameHeader(data, offset, id3header) {
280
+ var major = id3header.major;
281
+ var flags = null;
282
+ var frameHeaderSize = this._getFrameHeaderSize(id3header);
283
+ let frameId = "";
284
+ let frameSize = 0;
285
+ switch (major) {
286
+ case 2:
287
+ frameId = data.getStringAt(offset, 3);
288
+ frameSize = data.getInteger24At(offset + 3, true);
289
+ break;
290
+ case 3:
291
+ frameId = data.getStringAt(offset, 4);
292
+ frameSize = data.getLongAt(offset + 4, true);
293
+ break;
294
+ case 4:
295
+ frameId = data.getStringAt(offset, 4);
296
+ frameSize = data.getSynchsafeInteger32At(offset + 4);
297
+ break;
298
+ }
299
+ if (frameId == String.fromCharCode(0, 0, 0) ||
300
+ frameId == String.fromCharCode(0, 0, 0, 0)) {
301
+ frameId = "";
302
+ }
303
+ // if frameId is empty then it's the last frame
304
+ if (frameId) {
305
+ // read frame message and format flags
306
+ if (major > 2) {
307
+ flags = this._readFrameFlags(data, offset + 8);
308
+ }
309
+ }
310
+ return {
311
+ "id": frameId || "",
312
+ "size": frameSize || 0,
313
+ "headerSize": frameHeaderSize || 0,
314
+ "flags": flags
315
+ };
316
+ }
317
+ static _readFrameFlags(data, offset) {
318
+ return {
319
+ message: {
320
+ tag_alter_preservation: data.isBitSetAt(offset, 6),
321
+ file_alter_preservation: data.isBitSetAt(offset, 5),
322
+ read_only: data.isBitSetAt(offset, 4)
323
+ },
324
+ format: {
325
+ grouping_identity: data.isBitSetAt(offset + 1, 7),
326
+ compression: data.isBitSetAt(offset + 1, 3),
327
+ encryption: data.isBitSetAt(offset + 1, 2),
328
+ unsynchronisation: data.isBitSetAt(offset + 1, 1),
329
+ data_length_indicator: data.isBitSetAt(offset + 1, 0)
330
+ }
331
+ };
332
+ }
333
+ static _getFrameDescription(frameId) {
334
+ if (frameId in FRAME_DESCRIPTIONS) {
335
+ return FRAME_DESCRIPTIONS[frameId];
336
+ }
337
+ else {
338
+ return 'Unknown';
339
+ }
340
+ }
341
+ static getUnsyncFileReader(data, offset, size) {
342
+ var frameData = data.getBytesAt(offset, size);
343
+ for (var i = 0; i < frameData.length - 1; i++) {
344
+ if (frameData[i] === 0xff && frameData[i + 1] === 0x00) {
345
+ frameData.splice(i + 1, 1);
346
+ }
347
+ }
348
+ return new ArrayFileReader(frameData);
349
+ }
350
+ }
351
+ const frameReaderFunctions = {};
352
+ frameReaderFunctions['APIC'] = function readPictureFrame(offset, length, data, flags, id3header) {
353
+ var start = offset;
354
+ var charset = getTextEncoding(data.getByteAt(offset));
355
+ let format;
356
+ switch (id3header && id3header.major) {
357
+ case 2:
358
+ format = data.getStringAt(offset + 1, 3);
359
+ offset += 4;
360
+ break;
361
+ case 3:
362
+ case 4: {
363
+ const fmt = data.getStringWithCharsetAt(offset + 1, length - 1);
364
+ format = fmt.toString();
365
+ offset += 1 + fmt.bytesReadCount;
366
+ break;
367
+ }
368
+ default:
369
+ throw new Error("Couldn't read ID3v2 major version.");
370
+ }
371
+ var bite = data.getByteAt(offset);
372
+ var type = PICTURE_TYPE[bite];
373
+ var desc = data.getStringWithCharsetAt(offset + 1, length - (offset - start) - 1, charset);
374
+ offset += 1 + desc.bytesReadCount;
375
+ return {
376
+ "format": format,
377
+ "type": type,
378
+ "description": desc.toString(),
379
+ "data": data.getBytesAt(offset, (start + length) - offset)
380
+ };
381
+ };
382
+ // ID3v2 chapters according to http://id3.org/id3v2-chapters-1.0
383
+ frameReaderFunctions['CHAP'] = function readChapterFrame(offset, length, data, flags, id3header) {
384
+ var originalOffset = offset;
385
+ var result = {};
386
+ var id = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
387
+ result.id = id.toString();
388
+ offset += id.bytesReadCount;
389
+ result.startTime = data.getLongAt(offset, true);
390
+ offset += 4;
391
+ result.endTime = data.getLongAt(offset, true);
392
+ offset += 4;
393
+ result.startOffset = data.getLongAt(offset, true);
394
+ offset += 4;
395
+ result.endOffset = data.getLongAt(offset, true);
396
+ offset += 4;
397
+ var remainingLength = length - (offset - originalOffset);
398
+ result.subFrames = ID3v2FrameReader.readFrames(offset, offset + remainingLength, data, id3header, undefined);
399
+ return result;
400
+ };
401
+ // ID3v2 table of contents according to http://id3.org/id3v2-chapters-1.0
402
+ frameReaderFunctions['CTOC'] = function readTableOfContentsFrame(offset, length, data, flags, id3header) {
403
+ var originalOffset = offset;
404
+ var result = {
405
+ childElementIds: [],
406
+ };
407
+ var id = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
408
+ result.id = id.toString();
409
+ offset += id.bytesReadCount;
410
+ result.topLevel = data.isBitSetAt(offset, 1);
411
+ result.ordered = data.isBitSetAt(offset, 0);
412
+ offset++;
413
+ result.entryCount = data.getByteAt(offset);
414
+ offset++;
415
+ const entryCount = result.entryCount;
416
+ for (var i = 0; i < entryCount; i++) {
417
+ var childId = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length - (offset - originalOffset)));
418
+ result.childElementIds.push(childId.toString());
419
+ offset += childId.bytesReadCount;
420
+ }
421
+ var remainingLength = length - (offset - originalOffset);
422
+ result.subFrames = ID3v2FrameReader.readFrames(offset, offset + remainingLength, data, id3header, undefined);
423
+ return result;
424
+ };
425
+ frameReaderFunctions['COMM'] = function readCommentsFrame(offset, length, data, flags, id3header) {
426
+ var start = offset;
427
+ var charset = getTextEncoding(data.getByteAt(offset));
428
+ var language = data.getStringAt(offset + 1, 3);
429
+ var shortdesc = data.getStringWithCharsetAt(offset + 4, length - 4, charset);
430
+ offset += 4 + shortdesc.bytesReadCount;
431
+ var text = data.getStringWithCharsetAt(offset, (start + length) - offset, charset);
432
+ return {
433
+ language: language,
434
+ short_description: shortdesc.toString(),
435
+ text: text.toString()
436
+ };
437
+ };
438
+ frameReaderFunctions['COM'] = frameReaderFunctions['COMM'];
439
+ frameReaderFunctions['PIC'] = function (offset, length, data, flags, id3header) {
440
+ return frameReaderFunctions['APIC'](offset, length, data, flags, id3header);
441
+ };
442
+ frameReaderFunctions['PCNT'] = function readCounterFrame(offset, length, data, flags, id3header) {
443
+ // FIXME: implement the rest of the spec
444
+ return data.getLongAt(offset, false);
445
+ };
446
+ frameReaderFunctions['CNT'] = frameReaderFunctions['PCNT'];
447
+ frameReaderFunctions['SYLT'] = function readSynchronizedLyricsFrame(offset, length, data, flags, id3header) {
448
+ var start = offset;
449
+ var contentTypes = ['other', 'lyrics', 'transcription', 'movement', 'events', 'chord', 'trivia'];
450
+ var timeStampFormats = ['unset', 'frames', 'milliseconds'];
451
+ var charset = getTextEncoding(data.getByteAt(offset));
452
+ offset += 1;
453
+ var language = data.getStringAt(offset, 3);
454
+ offset += 3;
455
+ var timeStampFormat = timeStampFormats[data.getByteAt(offset)];
456
+ offset += 1;
457
+ var contentType = contentTypes[data.getByteAt(offset)];
458
+ offset += 1;
459
+ var descriptor = data.getStringWithCharsetAt(offset, length + start - offset, charset);
460
+ offset += descriptor.bytesReadCount;
461
+ var synchronisedText = [];
462
+ while (offset < length + start) {
463
+ const line = data.getStringWithCharsetAt(offset, length + start - offset, charset);
464
+ offset += line.bytesReadCount;
465
+ synchronisedText.push({
466
+ text: line.toString(),
467
+ timeStamp: data.getLongAt(offset, true)
468
+ });
469
+ offset += 4;
470
+ }
471
+ return {
472
+ language: language,
473
+ timeStampFormat: timeStampFormat,
474
+ contentType: contentType,
475
+ descriptor: descriptor.toString(),
476
+ synchronisedText: synchronisedText
477
+ };
478
+ };
479
+ frameReaderFunctions['T*'] = function readTextFrame(offset, length, data, flags, id3header) {
480
+ var charset = getTextEncoding(data.getByteAt(offset));
481
+ return data.getStringWithCharsetAt(offset + 1, length - 1, charset).toString();
482
+ };
483
+ frameReaderFunctions['TXXX'] = function readTextFrame(offset, length, data, flags, id3header) {
484
+ var charset = getTextEncoding(data.getByteAt(offset));
485
+ return getUserDefinedFields(offset, length, data, charset);
486
+ };
487
+ frameReaderFunctions['WXXX'] = function readUrlFrame(offset, length, data, flags, id3header) {
488
+ if (length === 0) {
489
+ return null;
490
+ }
491
+ var charset = getTextEncoding(data.getByteAt(offset));
492
+ return getUserDefinedFields(offset, length, data, charset);
493
+ };
494
+ frameReaderFunctions['W*'] = function readUrlFrame(offset, length, data, flags, id3header) {
495
+ if (length === 0) {
496
+ return null;
497
+ }
498
+ return data.getStringWithCharsetAt(offset, length, 'iso-8859-1').toString();
499
+ };
500
+ frameReaderFunctions['TCON'] = function readGenreFrame(offset, length, data, flags) {
501
+ const fn = frameReaderFunctions["T*"];
502
+ var text = fn.apply(this, arguments);
503
+ return text.replace(/^\(\d+\)/, '');
504
+ };
505
+ frameReaderFunctions['TCO'] = frameReaderFunctions['TCON'];
506
+ frameReaderFunctions['USLT'] = function readLyricsFrame(offset, length, data, flags, id3header) {
507
+ var start = offset;
508
+ var charset = getTextEncoding(data.getByteAt(offset));
509
+ var language = data.getStringAt(offset + 1, 3);
510
+ var descriptor = data.getStringWithCharsetAt(offset + 4, length - 4, charset);
511
+ offset += 4 + descriptor.bytesReadCount;
512
+ var lyrics = data.getStringWithCharsetAt(offset, (start + length) - offset, charset);
513
+ return {
514
+ language: language,
515
+ descriptor: descriptor.toString(),
516
+ lyrics: lyrics.toString()
517
+ };
518
+ };
519
+ frameReaderFunctions['ULT'] = frameReaderFunctions['USLT'];
520
+ frameReaderFunctions['UFID'] = function readLyricsFrame(offset, length, data, flags, id3header) {
521
+ var ownerIdentifier = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
522
+ offset += ownerIdentifier.bytesReadCount;
523
+ var identifier = data.getBytesAt(offset, length - ownerIdentifier.bytesReadCount);
524
+ return {
525
+ ownerIdentifier: ownerIdentifier.toString(),
526
+ identifier: identifier
527
+ };
528
+ };
529
+ function getTextEncoding(bite) {
530
+ var charset;
531
+ switch (bite) {
532
+ case 0x00:
533
+ charset = 'iso-8859-1';
534
+ break;
535
+ case 0x01:
536
+ charset = 'utf-16';
537
+ break;
538
+ case 0x02:
539
+ charset = 'utf-16be';
540
+ break;
541
+ case 0x03:
542
+ charset = 'utf-8';
543
+ break;
544
+ default:
545
+ charset = 'iso-8859-1';
546
+ }
547
+ return charset;
548
+ }
549
+ // Handles reading description/data from either http://id3.org/id3v2.3.0#User_defined_text_information_frame
550
+ // and http://id3.org/id3v2.3.0#User_defined_URL_link_frame
551
+ function getUserDefinedFields(offset, length, data, charset) {
552
+ var userDesc = data.getStringWithCharsetAt(offset + 1, length - 1, charset);
553
+ var userDefinedData = data.getStringWithCharsetAt(offset + 1 + userDesc.bytesReadCount, length - 1 - userDesc.bytesReadCount, charset);
554
+ return {
555
+ user_description: userDesc.toString(),
556
+ data: userDefinedData.toString()
557
+ };
558
+ }
559
+ const PICTURE_TYPE = [
560
+ "Other",
561
+ "32x32 pixels 'file icon' (PNG only)",
562
+ "Other file icon",
563
+ "Cover (front)",
564
+ "Cover (back)",
565
+ "Leaflet page",
566
+ "Media (e.g. label side of CD)",
567
+ "Lead artist/lead performer/soloist",
568
+ "Artist/performer",
569
+ "Conductor",
570
+ "Band/Orchestra",
571
+ "Composer",
572
+ "Lyricist/text writer",
573
+ "Recording Location",
574
+ "During recording",
575
+ "During performance",
576
+ "Movie/video screen capture",
577
+ "A bright coloured fish",
578
+ "Illustration",
579
+ "Band/artist logotype",
580
+ "Publisher/Studio logotype"
581
+ ];
582
+ module.exports = ID3v2FrameReader;
@@ -0,0 +1,82 @@
1
+ import type { ByteArray, TagHeaderFlags, TagFrameFlags } from './types';
2
+ declare class ID3v2TagContents {
3
+ _size: number;
4
+ _major: number;
5
+ _revision: number;
6
+ _contents: ByteArray;
7
+ _frames: {
8
+ [key: string]: Array<ByteArray>;
9
+ };
10
+ _extendedHeader: Record<string, number>;
11
+ _hasExtendedHeader: boolean;
12
+ _nextFrameOffset: number;
13
+ constructor(major: number, revision: number);
14
+ toArray(): ByteArray;
15
+ setFlags(flags: TagHeaderFlags): ID3v2TagContents;
16
+ _updateFlags(flags: Partial<TagHeaderFlags>, binaryFlags?: number): ID3v2TagContents;
17
+ setCrc(crc: ByteArray): ID3v2TagContents;
18
+ setTagIsUpdate(): ID3v2TagContents;
19
+ /**
20
+ * For some applications it might be desired to restrict a tag in more
21
+ * ways than imposed by the ID3v2 specification. Note that the
22
+ * presence of these restrictions does not affect how the tag is
23
+ * decoded, merely how it was restricted before encoding. If this flag
24
+ * is set the tag is restricted as follows:
25
+ *
26
+ * Flag data length $01
27
+ * Restrictions %ppqrrstt
28
+ *
29
+ * p - Tag size restrictions
30
+
31
+ * 00 No more than 128 frames and 1 MB total tag size.
32
+ * 01 No more than 64 frames and 128 KB total tag size.
33
+ * 10 No more than 32 frames and 40 KB total tag size.
34
+ * 11 No more than 32 frames and 4 KB total tag size.
35
+ *
36
+ * q - Text encoding restrictions
37
+ *
38
+ * 0 No restrictions
39
+ * 1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or
40
+ * UTF-8 [UTF-8].
41
+ *
42
+ * r - Text fields size restrictions
43
+ *
44
+ * 00 No restrictions
45
+ * 01 No string is longer than 1024 characters.
46
+ * 10 No string is longer than 128 characters.
47
+ * 11 No string is longer than 30 characters.
48
+ *
49
+ * Note that nothing is said about how many bytes is used to
50
+ * represent those characters, since it is encoding dependent. If a
51
+ * text frame consists of more than one string, the sum of the
52
+ * strungs is restricted as stated.
53
+ *
54
+ * s - Image encoding restrictions
55
+ *
56
+ * 0 No restrictions
57
+ * 1 Images are encoded only with PNG [PNG] or JPEG [JFIF].
58
+ *
59
+ * t - Image size restrictions
60
+ *
61
+ * 00 No restrictions
62
+ * 01 All images are 256x256 pixels or smaller.
63
+ * 10 All images are 64x64 pixels or smaller.
64
+ * 11 All images are exactly 64x64 pixels, unless required
65
+ * otherwise.
66
+ */
67
+ setTagRestrictions(size: number, textEncoding: number, textSize: number, imageEncoding: number, imageSize: number): ID3v2TagContents;
68
+ /**
69
+ * noFlagsDataLength - The data length if all flags were set to 0,
70
+ * for instance, the length before compression and unsynchronisation.
71
+ * This field is only needed when data_length_indicator flag is set.
72
+ */
73
+ addFrame(id: string, data: ByteArray, flags?: TagFrameFlags, noFlagsDataLength?: number): ID3v2TagContents;
74
+ _addExtendedHeaderData(tagKey: string, tagData: ByteArray): void;
75
+ _initExtendedHeader(): void;
76
+ _updateSize(): void;
77
+ _setBitAtOffset(offset: number, bit: number): void;
78
+ _getData(offset: number, length: number): ByteArray;
79
+ _setData(offset: number, data: ByteArray): void;
80
+ _addData(offset: number, data: ByteArray): void;
81
+ }
82
+ export = ID3v2TagContents;