147 lines
4.1 KiB
JavaScript
147 lines
4.1 KiB
JavaScript
import * as Token from 'token-types';
|
|
import * as util from '../common/Util.js';
|
|
/**
|
|
* The picture type according to the ID3v2 APIC frame
|
|
* Ref: http://id3.org/id3v2.3.0#Attached_picture
|
|
*/
|
|
export const AttachedPictureType = {
|
|
0: 'Other',
|
|
1: "32x32 pixels 'file icon' (PNG only)",
|
|
2: 'Other file icon',
|
|
3: 'Cover (front)',
|
|
4: 'Cover (back)',
|
|
5: 'Leaflet page',
|
|
6: 'Media (e.g. label side of CD)',
|
|
7: 'Lead artist/lead performer/soloist',
|
|
8: 'Artist/performer',
|
|
9: 'Conductor',
|
|
10: 'Band/Orchestra',
|
|
11: 'Composer',
|
|
12: 'Lyricist/text writer',
|
|
13: 'Recording Location',
|
|
14: 'During recording',
|
|
15: 'During performance',
|
|
16: 'Movie/video screen capture',
|
|
17: 'A bright coloured fish',
|
|
18: 'Illustration',
|
|
19: 'Band/artist logotype',
|
|
20: 'Publisher/Studio logotype'
|
|
};
|
|
/**
|
|
* https://id3.org/id3v2.3.0#Synchronised_lyrics.2Ftext
|
|
*/
|
|
export const LyricsContentType = {
|
|
other: 0,
|
|
lyrics: 1,
|
|
text: 2,
|
|
movement_part: 3,
|
|
events: 4,
|
|
chord: 5,
|
|
trivia_pop: 6,
|
|
};
|
|
export const TimestampFormat = {
|
|
notSynchronized: 0,
|
|
mpegFrameNumber: 1,
|
|
milliseconds: 2
|
|
};
|
|
/**
|
|
* 28 bits (representing up to 256MB) integer, the msb is 0 to avoid 'false syncsignals'.
|
|
* 4 * %0xxxxxxx
|
|
*/
|
|
export const UINT32SYNCSAFE = {
|
|
get: (buf, off) => {
|
|
return buf[off + 3] & 0x7f | ((buf[off + 2]) << 7) |
|
|
((buf[off + 1]) << 14) | ((buf[off]) << 21);
|
|
},
|
|
len: 4
|
|
};
|
|
/**
|
|
* ID3v2 header
|
|
* Ref: http://id3.org/id3v2.3.0#ID3v2_header
|
|
* ToDo
|
|
*/
|
|
export const ID3v2Header = {
|
|
len: 10,
|
|
get: (buf, off) => {
|
|
return {
|
|
// ID3v2/file identifier "ID3"
|
|
fileIdentifier: new Token.StringType(3, 'ascii').get(buf, off),
|
|
// ID3v2 versionIndex
|
|
version: {
|
|
major: Token.INT8.get(buf, off + 3),
|
|
revision: Token.INT8.get(buf, off + 4)
|
|
},
|
|
// ID3v2 flags
|
|
flags: {
|
|
// Unsynchronisation
|
|
unsynchronisation: util.getBit(buf, off + 5, 7),
|
|
// Extended header
|
|
isExtendedHeader: util.getBit(buf, off + 5, 6),
|
|
// Experimental indicator
|
|
expIndicator: util.getBit(buf, off + 5, 5),
|
|
footer: util.getBit(buf, off + 5, 4)
|
|
},
|
|
size: UINT32SYNCSAFE.get(buf, off + 6)
|
|
};
|
|
}
|
|
};
|
|
export const ExtendedHeader = {
|
|
len: 10,
|
|
get: (buf, off) => {
|
|
return {
|
|
// Extended header size
|
|
size: Token.UINT32_BE.get(buf, off),
|
|
// Extended Flags
|
|
extendedFlags: Token.UINT16_BE.get(buf, off + 4),
|
|
// Size of padding
|
|
sizeOfPadding: Token.UINT32_BE.get(buf, off + 6),
|
|
// CRC data present
|
|
crcDataPresent: util.getBit(buf, off + 4, 31)
|
|
};
|
|
}
|
|
};
|
|
export const TextEncodingToken = {
|
|
len: 1,
|
|
get: (uint8Array, off) => {
|
|
switch (uint8Array[off]) {
|
|
case 0x00:
|
|
return { encoding: 'latin1' }; // binary
|
|
case 0x01:
|
|
return { encoding: 'utf-16le', bom: true };
|
|
case 0x02:
|
|
return { encoding: 'utf-16le', bom: false };
|
|
case 0x03:
|
|
return { encoding: 'utf8', bom: false };
|
|
default:
|
|
return { encoding: 'utf8', bom: false };
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Used to read first portion of `SYLT` frame
|
|
*/
|
|
export const TextHeader = {
|
|
len: 4,
|
|
get: (uint8Array, off) => {
|
|
return {
|
|
encoding: TextEncodingToken.get(uint8Array, off),
|
|
language: new Token.StringType(3, 'latin1').get(uint8Array, off + 1)
|
|
};
|
|
}
|
|
};
|
|
/**
|
|
* Used to read first portion of `SYLT` frame
|
|
*/
|
|
export const SyncTextHeader = {
|
|
len: 6,
|
|
get: (uint8Array, off) => {
|
|
const text = TextHeader.get(uint8Array, off);
|
|
return {
|
|
encoding: text.encoding,
|
|
language: text.language,
|
|
timeStampFormat: Token.UINT8.get(uint8Array, off + 4),
|
|
contentType: Token.UINT8.get(uint8Array, off + 5)
|
|
};
|
|
}
|
|
};
|