@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.
- package/CHANGELOG.md +45 -0
- package/LICENSE.md +36 -0
- package/README.md +548 -0
- package/build/ArrayBufferFileReader.d.ts +12 -0
- package/build/ArrayBufferFileReader.js +27 -0
- package/build/ArrayFileReader.d.ts +11 -0
- package/build/ArrayFileReader.js +30 -0
- package/build/BlobFileReader.d.ts +12 -0
- package/build/BlobFileReader.js +47 -0
- package/build/ByteArrayUtils.d.ts +9 -0
- package/build/ByteArrayUtils.js +46 -0
- package/build/ChunkedFileData.d.ts +28 -0
- package/build/ChunkedFileData.js +171 -0
- package/build/DecodedString.d.ts +6 -0
- package/build/DecodedString.js +2 -0
- package/build/FLACTagContents.d.ts +19 -0
- package/build/FLACTagContents.js +54 -0
- package/build/FLACTagReader.d.ts +103 -0
- package/build/FLACTagReader.js +320 -0
- package/build/ID3v1TagReader.d.ts +10 -0
- package/build/ID3v1TagReader.js +176 -0
- package/build/ID3v2FrameReader.d.ts +25 -0
- package/build/ID3v2FrameReader.js +582 -0
- package/build/ID3v2TagContents.d.ts +82 -0
- package/build/ID3v2TagContents.js +318 -0
- package/build/ID3v2TagReader.d.ts +13 -0
- package/build/ID3v2TagReader.js +118 -0
- package/build/MP4TagContents.d.ts +17 -0
- package/build/MP4TagContents.js +52 -0
- package/build/MP4TagReader.d.ts +19 -0
- package/build/MP4TagReader.js +291 -0
- package/build/MediaFileReader.d.ts +46 -0
- package/build/MediaFileReader.js +168 -0
- package/build/MediaTagReader.d.ts +18 -0
- package/build/MediaTagReader.js +76 -0
- package/build/NodeFileReader.d.ts +12 -0
- package/build/NodeFileReader.js +103 -0
- package/build/ReactNativeFileReader.d.ts +12 -0
- package/build/ReactNativeFileReader.js +48 -0
- package/build/StringUtils.d.ts +7 -0
- package/build/StringUtils.js +102 -0
- package/build/XhrFileReader.d.ts +41 -0
- package/build/XhrFileReader.js +238 -0
- package/build/jsmediatags.d.ts +45 -0
- package/build/jsmediatags.js +219 -0
- package/build/registerNodeFileReaders.d.ts +5 -0
- package/build/registerNodeFileReaders.js +19 -0
- package/build/registerNodeFileReaders.noop.d.ts +2 -0
- package/build/registerNodeFileReaders.noop.js +3 -0
- package/build/types.d.ts +77 -0
- package/build/types.js +2 -0
- package/dist/jsmediatags.min.js +2 -0
- package/package.json +110 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const MediaTagReader = require('./MediaTagReader');
|
|
3
|
+
const MediaFileReader = require('./MediaFileReader');
|
|
4
|
+
/* The first 4 bytes of a FLAC file describes the header for the file. If these
|
|
5
|
+
* bytes respectively read "fLaC", we can determine it is a FLAC file.
|
|
6
|
+
*/
|
|
7
|
+
const FLAC_HEADER_SIZE = 4;
|
|
8
|
+
/* FLAC metadata is stored in blocks containing data ranging from STREAMINFO to
|
|
9
|
+
* VORBIS_COMMENT, which is what we want to work with.
|
|
10
|
+
*
|
|
11
|
+
* Each metadata header is 4 bytes long, with the first byte determining whether
|
|
12
|
+
* it is the last metadata block before the audio data and what the block type is.
|
|
13
|
+
* This first byte can further be split into 8 bits, with the first bit being the
|
|
14
|
+
* last-metadata-block flag, and the last three bits being the block type.
|
|
15
|
+
*
|
|
16
|
+
* Since the specification states that the decimal value for a VORBIS_COMMENT block
|
|
17
|
+
* type is 4, the two possibilities for the comment block header values are:
|
|
18
|
+
* - 00000100 (Not a last metadata comment block, value of 4)
|
|
19
|
+
* - 10000100 (A last metadata comment block, value of 132)
|
|
20
|
+
*
|
|
21
|
+
* Similarly, the picture block header values are 6 and 128.
|
|
22
|
+
*
|
|
23
|
+
* All values for METADATA_BLOCK_HEADER can be found here.
|
|
24
|
+
* https://xiph.org/flac/format.html#metadata_block_header
|
|
25
|
+
*/
|
|
26
|
+
const COMMENT_HEADERS = [4, 132];
|
|
27
|
+
const PICTURE_HEADERS = [6, 134];
|
|
28
|
+
// These are the possible image types as defined by the FLAC specification.
|
|
29
|
+
const IMAGE_TYPES = [
|
|
30
|
+
"Other",
|
|
31
|
+
"32x32 pixels 'file icon' (PNG only)",
|
|
32
|
+
"Other file icon",
|
|
33
|
+
"Cover (front)",
|
|
34
|
+
"Cover (back)",
|
|
35
|
+
"Leaflet page",
|
|
36
|
+
"Media (e.g. label side of CD)",
|
|
37
|
+
"Lead artist/lead performer/soloist",
|
|
38
|
+
"Artist/performer",
|
|
39
|
+
"Conductor",
|
|
40
|
+
"Band/Orchestra",
|
|
41
|
+
"Composer",
|
|
42
|
+
"Lyricist/text writer",
|
|
43
|
+
"Recording Location",
|
|
44
|
+
"During recording",
|
|
45
|
+
"During performance",
|
|
46
|
+
"Movie/video screen capture",
|
|
47
|
+
"A bright coloured fish",
|
|
48
|
+
"Illustration",
|
|
49
|
+
"Band/artist logotype",
|
|
50
|
+
"Publisher/Studio logotype"
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Class representing a MediaTagReader that parses FLAC tags.
|
|
54
|
+
*/
|
|
55
|
+
class FLACTagReader extends MediaTagReader {
|
|
56
|
+
/**
|
|
57
|
+
* Gets the byte range for the tag identifier.
|
|
58
|
+
*
|
|
59
|
+
* Because the Vorbis comment block is not guaranteed to be in a specified
|
|
60
|
+
* location, we can only load the first 4 bytes of the file to confirm it
|
|
61
|
+
* is a FLAC first.
|
|
62
|
+
*
|
|
63
|
+
* @return {ByteRange} The byte range that identifies the tag for a FLAC.
|
|
64
|
+
*/
|
|
65
|
+
static getTagIdentifierByteRange() {
|
|
66
|
+
return {
|
|
67
|
+
offset: 0,
|
|
68
|
+
length: FLAC_HEADER_SIZE
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Determines whether or not this reader can read a certain tag format.
|
|
73
|
+
*
|
|
74
|
+
* This checks that the first 4 characters in the file are fLaC, which
|
|
75
|
+
* according to the FLAC file specification should be the characters that
|
|
76
|
+
* indicate a FLAC file.
|
|
77
|
+
*
|
|
78
|
+
* @return {boolean} True if the header is fLaC, false otherwise.
|
|
79
|
+
*/
|
|
80
|
+
static canReadTagFormat(tagIdentifier) {
|
|
81
|
+
var id = String.fromCharCode.apply(String, tagIdentifier.slice(0, 4));
|
|
82
|
+
return id === 'fLaC';
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Function called to load the data from the file.
|
|
86
|
+
*
|
|
87
|
+
* To begin processing the blocks, the next 4 bytes after the initial 4 bytes
|
|
88
|
+
* (bytes 4 through 7) are loaded. From there, the rest of the loading process
|
|
89
|
+
* is passed on to the _loadBlock function, which will handle the rest of the
|
|
90
|
+
* parsing for the metadata blocks.
|
|
91
|
+
*
|
|
92
|
+
* @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
|
|
93
|
+
* @param {LoadCallbackType} callbacks - The callback to call once _loadData is completed.
|
|
94
|
+
*/
|
|
95
|
+
_loadData(mediaFileReader, callbacks) {
|
|
96
|
+
var self = this;
|
|
97
|
+
mediaFileReader.loadRange([4, 7], {
|
|
98
|
+
onSuccess: function () {
|
|
99
|
+
self._loadBlock(mediaFileReader, 4, callbacks);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Special internal function used to parse the different FLAC blocks.
|
|
105
|
+
*
|
|
106
|
+
* The FLAC specification doesn't specify a specific location for metadata to resign, but
|
|
107
|
+
* dictates that it may be in one of various blocks located throughout the file. To load the
|
|
108
|
+
* metadata, we must locate the header first. This can be done by reading the first byte of
|
|
109
|
+
* each block to determine the block type. After the block type comes a 24 bit integer that stores
|
|
110
|
+
* the length of the block as big endian. Using this, we locate the block and store the offset for
|
|
111
|
+
* parsing later.
|
|
112
|
+
*
|
|
113
|
+
* After each block has been parsed, the _nextBlock function is called in order
|
|
114
|
+
* to parse the information of the next block. All blocks need to be parsed in order to find
|
|
115
|
+
* all of the picture and comment blocks.
|
|
116
|
+
*
|
|
117
|
+
* More info on the FLAC specification may be found here:
|
|
118
|
+
* https://xiph.org/flac/format.html
|
|
119
|
+
* @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
|
|
120
|
+
* @param {number} offset - The offset to start checking the header from.
|
|
121
|
+
* @param {LoadCallbackType} callbacks - The callback to call once the header has been found.
|
|
122
|
+
*/
|
|
123
|
+
_loadBlock(mediaFileReader, offset, callbacks) {
|
|
124
|
+
var self = this;
|
|
125
|
+
/* As mentioned above, this first byte is loaded to see what metadata type
|
|
126
|
+
* this block represents.
|
|
127
|
+
*/
|
|
128
|
+
var blockHeader = mediaFileReader.getByteAt(offset);
|
|
129
|
+
/* The last three bytes (integer 24) contain a value representing the length
|
|
130
|
+
* of the following metadata block. The 1 is added in order to shift the offset
|
|
131
|
+
* by one to get the last three bytes in the block header.
|
|
132
|
+
*/
|
|
133
|
+
var blockSize = mediaFileReader.getInteger24At(offset + 1, true);
|
|
134
|
+
/* This conditional checks if blockHeader (the byte retrieved representing the
|
|
135
|
+
* type of the header) is one the headers we are looking for.
|
|
136
|
+
*
|
|
137
|
+
* If that is not true, the block is skipped over and the next range is loaded:
|
|
138
|
+
* - offset + 4 + blockSize adds 4 to skip over the initial metadata header and
|
|
139
|
+
* blockSize to skip over the block overall, placing it at the head of the next
|
|
140
|
+
* metadata header.
|
|
141
|
+
* - offset + 4 + 4 + blockSize does the same thing as the previous block with
|
|
142
|
+
* the exception of adding another 4 bytes to move it to the end of the new metadata
|
|
143
|
+
* header.
|
|
144
|
+
*/
|
|
145
|
+
if (COMMENT_HEADERS.indexOf(blockHeader) !== -1) {
|
|
146
|
+
/* 4 is added to offset to move it to the head of the actual metadata.
|
|
147
|
+
* The range starting from offsetMatadata (the beginning of the block)
|
|
148
|
+
* and offsetMetadata + blockSize (the end of the block) is loaded.
|
|
149
|
+
*/
|
|
150
|
+
var offsetMetadata = offset + 4;
|
|
151
|
+
mediaFileReader.loadRange([offsetMetadata, offsetMetadata + blockSize], {
|
|
152
|
+
onSuccess: function () {
|
|
153
|
+
self._commentOffset = offsetMetadata;
|
|
154
|
+
self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else if (PICTURE_HEADERS.indexOf(blockHeader) !== -1) {
|
|
159
|
+
var offsetMetadata = offset + 4;
|
|
160
|
+
mediaFileReader.loadRange([offsetMetadata, offsetMetadata + blockSize], {
|
|
161
|
+
onSuccess: function () {
|
|
162
|
+
self._pictureOffset = offsetMetadata;
|
|
163
|
+
self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Internal function used to load the next range and respective block.
|
|
173
|
+
*
|
|
174
|
+
* If the metadata block that was identified is not the last block before the
|
|
175
|
+
* audio blocks, the function will continue loading the next blocks. If it is
|
|
176
|
+
* the last block (identified by any values greater than 127, see FLAC spec.),
|
|
177
|
+
* the function will determine whether a comment block had been identified.
|
|
178
|
+
*
|
|
179
|
+
* If the block does not exist, the error callback is called. Otherwise, the function
|
|
180
|
+
* will call the success callback, allowing data parsing to begin.
|
|
181
|
+
* @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
|
|
182
|
+
* @param {number} offset - The offset that the existing header was located at.
|
|
183
|
+
* @param {number} blockHeader - An integer reflecting the header type of the block.
|
|
184
|
+
* @param {number} blockSize - The size of the previously processed header.
|
|
185
|
+
* @param {LoadCallbackType} callbacks - The callback functions to be called.
|
|
186
|
+
*/
|
|
187
|
+
_nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks) {
|
|
188
|
+
var self = this;
|
|
189
|
+
if (blockHeader > 127) {
|
|
190
|
+
if (!self._commentOffset) {
|
|
191
|
+
if (callbacks.onError) {
|
|
192
|
+
callbacks.onError({
|
|
193
|
+
type: "loadData",
|
|
194
|
+
info: "Comment block could not be found.",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
callbacks.onSuccess();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
mediaFileReader.loadRange([offset + 4 + blockSize, offset + 4 + 4 + blockSize], {
|
|
204
|
+
onSuccess: function () {
|
|
205
|
+
self._loadBlock(mediaFileReader, offset + 4 + blockSize, callbacks);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parses the data and returns the tags.
|
|
212
|
+
*
|
|
213
|
+
* This is an overview of the VorbisComment format and what this function attempts to
|
|
214
|
+
* retrieve:
|
|
215
|
+
* - First 4 bytes: a long that contains the length of the vendor string.
|
|
216
|
+
* - Next n bytes: the vendor string encoded in UTF-8.
|
|
217
|
+
* - Next 4 bytes: a long representing how many comments are in this block
|
|
218
|
+
* For each comment that exists:
|
|
219
|
+
* - First 4 bytes: a long representing the length of the comment
|
|
220
|
+
* - Next n bytes: the comment encoded in UTF-8.
|
|
221
|
+
* The comment string will usually appear in a format similar to:
|
|
222
|
+
* ARTIST=me
|
|
223
|
+
*
|
|
224
|
+
* Note that the longs and integers in this block are encoded in little endian
|
|
225
|
+
* as opposed to big endian for the rest of the FLAC spec.
|
|
226
|
+
* @param {MediaFileReader} data - The MediaFileReader to parse the file with.
|
|
227
|
+
* @param {Array<string>} [tags] - Optional tags to also be retrieved from the file.
|
|
228
|
+
* @return {TagType} - An object containing the tag information for the file.
|
|
229
|
+
*/
|
|
230
|
+
_parseData(data, _tags) {
|
|
231
|
+
const commentOffset = this._commentOffset;
|
|
232
|
+
var vendorLength = data.getLongAt(commentOffset, false);
|
|
233
|
+
var offsetVendor = commentOffset + 4;
|
|
234
|
+
/* This line is able to retrieve the vendor string that the VorbisComment block
|
|
235
|
+
* contains. However, it is not part of the tags that JSMediaTags normally retrieves,
|
|
236
|
+
* and is therefore commented out.
|
|
237
|
+
*/
|
|
238
|
+
// var vendor = data.getStringWithCharsetAt(offsetVendor, vendorLength, "utf-8").toString();
|
|
239
|
+
var offsetList = vendorLength + offsetVendor;
|
|
240
|
+
/* To get the metadata from the block, we first get the long that contains the
|
|
241
|
+
* number of actual comment values that are existent within the block.
|
|
242
|
+
*
|
|
243
|
+
* As we loop through all of the comment blocks, we get the data length in order to
|
|
244
|
+
* get the right size string, and then determine which category that string falls under.
|
|
245
|
+
* The dataOffset variable is constantly updated so that it is at the beginning of the
|
|
246
|
+
* comment that is currently being parsed.
|
|
247
|
+
*
|
|
248
|
+
* Additions of 4 here are used to move the offset past the first 4 bytes which only contain
|
|
249
|
+
* the length of the comment.
|
|
250
|
+
*/
|
|
251
|
+
var numComments = data.getLongAt(offsetList, false);
|
|
252
|
+
var dataOffset = offsetList + 4;
|
|
253
|
+
var title, artist, album, track, genre, picture;
|
|
254
|
+
for (let i = 0; i < numComments; i++) {
|
|
255
|
+
let dataLength = data.getLongAt(dataOffset, false);
|
|
256
|
+
let s = data.getStringWithCharsetAt(dataOffset + 4, dataLength, "utf-8").toString();
|
|
257
|
+
let d = s.indexOf("=");
|
|
258
|
+
let split = [s.slice(0, d), s.slice(d + 1)];
|
|
259
|
+
switch (split[0].toUpperCase()) {
|
|
260
|
+
case "TITLE":
|
|
261
|
+
title = split[1];
|
|
262
|
+
break;
|
|
263
|
+
case "ARTIST":
|
|
264
|
+
artist = split[1];
|
|
265
|
+
break;
|
|
266
|
+
case "ALBUM":
|
|
267
|
+
album = split[1];
|
|
268
|
+
break;
|
|
269
|
+
case "TRACKNUMBER":
|
|
270
|
+
track = split[1];
|
|
271
|
+
break;
|
|
272
|
+
case "GENRE":
|
|
273
|
+
genre = split[1];
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
dataOffset += 4 + dataLength;
|
|
277
|
+
}
|
|
278
|
+
/* If a picture offset was found and assigned, then the reader will start processing
|
|
279
|
+
* the picture block from that point.
|
|
280
|
+
*
|
|
281
|
+
* All the lengths for the picture data can be found online here:
|
|
282
|
+
* https://xiph.org/flac/format.html#metadata_block_picture
|
|
283
|
+
*/
|
|
284
|
+
if (this._pictureOffset) {
|
|
285
|
+
var imageType = data.getLongAt(this._pictureOffset, true);
|
|
286
|
+
var offsetMimeLength = this._pictureOffset + 4;
|
|
287
|
+
var mimeLength = data.getLongAt(offsetMimeLength, true);
|
|
288
|
+
var offsetMime = offsetMimeLength + 4;
|
|
289
|
+
var mime = data.getStringAt(offsetMime, mimeLength);
|
|
290
|
+
var offsetDescriptionLength = offsetMime + mimeLength;
|
|
291
|
+
var descriptionLength = data.getLongAt(offsetDescriptionLength, true);
|
|
292
|
+
var offsetDescription = offsetDescriptionLength + 4;
|
|
293
|
+
var description = data.getStringWithCharsetAt(offsetDescription, descriptionLength, "utf-8").toString();
|
|
294
|
+
var offsetDataLength = offsetDescription + descriptionLength + 16;
|
|
295
|
+
var dataLength = data.getLongAt(offsetDataLength, true);
|
|
296
|
+
var offsetData = offsetDataLength + 4;
|
|
297
|
+
var imageData = data.getBytesAt(offsetData, dataLength);
|
|
298
|
+
picture = {
|
|
299
|
+
format: mime,
|
|
300
|
+
type: IMAGE_TYPES[imageType],
|
|
301
|
+
description: description,
|
|
302
|
+
data: imageData
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
var tag = {
|
|
306
|
+
type: "FLAC",
|
|
307
|
+
version: "1",
|
|
308
|
+
tags: {
|
|
309
|
+
title: title,
|
|
310
|
+
artist: artist,
|
|
311
|
+
album: album,
|
|
312
|
+
track: track,
|
|
313
|
+
genre: genre,
|
|
314
|
+
picture: picture,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
return tag;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
module.exports = FLACTagReader;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare const MediaTagReader: any;
|
|
2
|
+
declare const MediaFileReader: any;
|
|
3
|
+
import type { LoadCallbackType, ByteRange, TagType } from "./types";
|
|
4
|
+
declare class ID3v1TagReader extends MediaTagReader {
|
|
5
|
+
static getTagIdentifierByteRange(): ByteRange;
|
|
6
|
+
static canReadTagFormat(tagIdentifier: Array<number>): boolean;
|
|
7
|
+
_loadData(mediaFileReader: InstanceType<typeof MediaFileReader>, callbacks: LoadCallbackType): void;
|
|
8
|
+
_parseData(data: InstanceType<typeof MediaFileReader>, tags: string[] | null): TagType;
|
|
9
|
+
}
|
|
10
|
+
export = ID3v1TagReader;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const MediaTagReader = require("./MediaTagReader");
|
|
3
|
+
const MediaFileReader = require("./MediaFileReader");
|
|
4
|
+
class ID3v1TagReader extends MediaTagReader {
|
|
5
|
+
static getTagIdentifierByteRange() {
|
|
6
|
+
return {
|
|
7
|
+
offset: -128,
|
|
8
|
+
length: 128,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
static canReadTagFormat(tagIdentifier) {
|
|
12
|
+
const id = String.fromCharCode.apply(String, tagIdentifier.slice(0, 3));
|
|
13
|
+
return id === "TAG";
|
|
14
|
+
}
|
|
15
|
+
_loadData(mediaFileReader, callbacks) {
|
|
16
|
+
const fileSize = mediaFileReader.getSize();
|
|
17
|
+
mediaFileReader.loadRange([fileSize - 128, fileSize - 1], callbacks);
|
|
18
|
+
}
|
|
19
|
+
_parseData(data, tags) {
|
|
20
|
+
const offset = data.getSize() - 128;
|
|
21
|
+
const title = data.getStringWithCharsetAt(offset + 3, 30).toString();
|
|
22
|
+
const artist = data.getStringWithCharsetAt(offset + 33, 30).toString();
|
|
23
|
+
const album = data.getStringWithCharsetAt(offset + 63, 30).toString();
|
|
24
|
+
const year = data.getStringWithCharsetAt(offset + 93, 4).toString();
|
|
25
|
+
const trackFlag = data.getByteAt(offset + 97 + 28);
|
|
26
|
+
let track = data.getByteAt(offset + 97 + 29);
|
|
27
|
+
let version;
|
|
28
|
+
let comment;
|
|
29
|
+
if (trackFlag == 0 && track != 0) {
|
|
30
|
+
version = "1.1";
|
|
31
|
+
comment = data.getStringWithCharsetAt(offset + 97, 28).toString();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
version = "1.0";
|
|
35
|
+
comment = data.getStringWithCharsetAt(offset + 97, 30).toString();
|
|
36
|
+
track = 0;
|
|
37
|
+
}
|
|
38
|
+
const genreIdx = data.getByteAt(offset + 97 + 30);
|
|
39
|
+
const genre = genreIdx < 255 ? GENRES[genreIdx] : "";
|
|
40
|
+
const tag = {
|
|
41
|
+
type: "ID3",
|
|
42
|
+
version: version,
|
|
43
|
+
tags: Object.assign({ title: title, artist: artist, album: album, year: year, comment: comment, genre: genre }, (track ? { track: track } : {})),
|
|
44
|
+
};
|
|
45
|
+
return tag;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const GENRES = [
|
|
49
|
+
"Blues",
|
|
50
|
+
"Classic Rock",
|
|
51
|
+
"Country",
|
|
52
|
+
"Dance",
|
|
53
|
+
"Disco",
|
|
54
|
+
"Funk",
|
|
55
|
+
"Grunge",
|
|
56
|
+
"Hip-Hop",
|
|
57
|
+
"Jazz",
|
|
58
|
+
"Metal",
|
|
59
|
+
"New Age",
|
|
60
|
+
"Oldies",
|
|
61
|
+
"Other",
|
|
62
|
+
"Pop",
|
|
63
|
+
"R&B",
|
|
64
|
+
"Rap",
|
|
65
|
+
"Reggae",
|
|
66
|
+
"Rock",
|
|
67
|
+
"Techno",
|
|
68
|
+
"Industrial",
|
|
69
|
+
"Alternative",
|
|
70
|
+
"Ska",
|
|
71
|
+
"Death Metal",
|
|
72
|
+
"Pranks",
|
|
73
|
+
"Soundtrack",
|
|
74
|
+
"Euro-Techno",
|
|
75
|
+
"Ambient",
|
|
76
|
+
"Trip-Hop",
|
|
77
|
+
"Vocal",
|
|
78
|
+
"Jazz+Funk",
|
|
79
|
+
"Fusion",
|
|
80
|
+
"Trance",
|
|
81
|
+
"Classical",
|
|
82
|
+
"Instrumental",
|
|
83
|
+
"Acid",
|
|
84
|
+
"House",
|
|
85
|
+
"Game",
|
|
86
|
+
"Sound Clip",
|
|
87
|
+
"Gospel",
|
|
88
|
+
"Noise",
|
|
89
|
+
"AlternRock",
|
|
90
|
+
"Bass",
|
|
91
|
+
"Soul",
|
|
92
|
+
"Punk",
|
|
93
|
+
"Space",
|
|
94
|
+
"Meditative",
|
|
95
|
+
"Instrumental Pop",
|
|
96
|
+
"Instrumental Rock",
|
|
97
|
+
"Ethnic",
|
|
98
|
+
"Gothic",
|
|
99
|
+
"Darkwave",
|
|
100
|
+
"Techno-Industrial",
|
|
101
|
+
"Electronic",
|
|
102
|
+
"Pop-Folk",
|
|
103
|
+
"Eurodance",
|
|
104
|
+
"Dream",
|
|
105
|
+
"Southern Rock",
|
|
106
|
+
"Comedy",
|
|
107
|
+
"Cult",
|
|
108
|
+
"Gangsta",
|
|
109
|
+
"Top 40",
|
|
110
|
+
"Christian Rap",
|
|
111
|
+
"Pop/Funk",
|
|
112
|
+
"Jungle",
|
|
113
|
+
"Native American",
|
|
114
|
+
"Cabaret",
|
|
115
|
+
"New Wave",
|
|
116
|
+
"Psychadelic",
|
|
117
|
+
"Rave",
|
|
118
|
+
"Showtunes",
|
|
119
|
+
"Trailer",
|
|
120
|
+
"Lo-Fi",
|
|
121
|
+
"Tribal",
|
|
122
|
+
"Acid Punk",
|
|
123
|
+
"Acid Jazz",
|
|
124
|
+
"Polka",
|
|
125
|
+
"Retro",
|
|
126
|
+
"Musical",
|
|
127
|
+
"Rock & Roll",
|
|
128
|
+
"Hard Rock",
|
|
129
|
+
"Folk",
|
|
130
|
+
"Folk-Rock",
|
|
131
|
+
"National Folk",
|
|
132
|
+
"Swing",
|
|
133
|
+
"Fast Fusion",
|
|
134
|
+
"Bebob",
|
|
135
|
+
"Latin",
|
|
136
|
+
"Revival",
|
|
137
|
+
"Celtic",
|
|
138
|
+
"Bluegrass",
|
|
139
|
+
"Avantgarde",
|
|
140
|
+
"Gothic Rock",
|
|
141
|
+
"Progressive Rock",
|
|
142
|
+
"Psychedelic Rock",
|
|
143
|
+
"Symphonic Rock",
|
|
144
|
+
"Slow Rock",
|
|
145
|
+
"Big Band",
|
|
146
|
+
"Chorus",
|
|
147
|
+
"Easy Listening",
|
|
148
|
+
"Acoustic",
|
|
149
|
+
"Humour",
|
|
150
|
+
"Speech",
|
|
151
|
+
"Chanson",
|
|
152
|
+
"Opera",
|
|
153
|
+
"Chamber Music",
|
|
154
|
+
"Sonata",
|
|
155
|
+
"Symphony",
|
|
156
|
+
"Booty Bass",
|
|
157
|
+
"Primus",
|
|
158
|
+
"Porn Groove",
|
|
159
|
+
"Satire",
|
|
160
|
+
"Slow Jam",
|
|
161
|
+
"Club",
|
|
162
|
+
"Tango",
|
|
163
|
+
"Samba",
|
|
164
|
+
"Folklore",
|
|
165
|
+
"Ballad",
|
|
166
|
+
"Power Ballad",
|
|
167
|
+
"Rhythmic Soul",
|
|
168
|
+
"Freestyle",
|
|
169
|
+
"Duet",
|
|
170
|
+
"Punk Rock",
|
|
171
|
+
"Drum Solo",
|
|
172
|
+
"Acapella",
|
|
173
|
+
"Euro-House",
|
|
174
|
+
"Dance Hall",
|
|
175
|
+
];
|
|
176
|
+
module.exports = ID3v1TagReader;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
declare const MediaFileReader: any;
|
|
2
|
+
type MediaReader = InstanceType<typeof MediaFileReader>;
|
|
3
|
+
import type { FrameReaderSignature, TagHeader, TagFrames, TagFrameHeader, TagFrameFlags } from './types';
|
|
4
|
+
declare class ID3v2FrameReader {
|
|
5
|
+
static getFrameReaderFunction(frameId: string): FrameReaderSignature | null;
|
|
6
|
+
/**
|
|
7
|
+
* All the frames consists of a frame header followed by one or more fields
|
|
8
|
+
* containing the actual information.
|
|
9
|
+
* The frame ID made out of the characters capital A-Z and 0-9. Identifiers
|
|
10
|
+
* beginning with "X", "Y" and "Z" are for experimental use and free for
|
|
11
|
+
* everyone to use, without the need to set the experimental bit in the tag
|
|
12
|
+
* header. Have in mind that someone else might have used the same identifier
|
|
13
|
+
* as you. All other identifiers are either used or reserved for future use.
|
|
14
|
+
* The frame ID is followed by a size descriptor, making a total header size
|
|
15
|
+
* of ten bytes in every frame. The size is calculated as frame size excluding
|
|
16
|
+
* frame header (frame size - 10).
|
|
17
|
+
*/
|
|
18
|
+
static readFrames(offset: number, end: number, data: MediaReader, id3header: TagHeader, tags?: Array<string> | null): TagFrames;
|
|
19
|
+
static _getFrameHeaderSize(id3header: TagHeader): number;
|
|
20
|
+
static _readFrameHeader(data: MediaReader, offset: number, id3header: TagHeader): TagFrameHeader;
|
|
21
|
+
static _readFrameFlags(data: MediaReader, offset: number): TagFrameFlags;
|
|
22
|
+
static _getFrameDescription(frameId: string): string;
|
|
23
|
+
static getUnsyncFileReader(data: MediaReader, offset: number, size: number): MediaReader;
|
|
24
|
+
}
|
|
25
|
+
export = ID3v2FrameReader;
|