music-metadata 8.2.0 → 9.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/README.md +152 -132
- package/lib/ParserFactory.d.ts +1 -1
- package/lib/ParserFactory.js +1 -2
- package/lib/aiff/AiffParser.js +3 -4
- package/lib/aiff/AiffToken.d.ts +2 -4
- package/lib/aiff/AiffToken.js +7 -7
- package/lib/apev2/APEv2Parser.d.ts +1 -1
- package/lib/apev2/APEv2Parser.js +10 -12
- package/lib/apev2/APEv2TagMapper.js +1 -1
- package/lib/apev2/APEv2Token.d.ts +1 -1
- package/lib/asf/AsfObject.d.ts +15 -17
- package/lib/asf/AsfObject.js +52 -46
- package/lib/asf/AsfParser.js +6 -8
- package/lib/asf/AsfTagMapper.js +1 -1
- package/lib/asf/AsfUtil.d.ts +1 -3
- package/lib/asf/AsfUtil.js +4 -5
- package/lib/asf/GUID.d.ts +4 -5
- package/lib/asf/GUID.js +14 -11
- package/lib/common/BasicParser.d.ts +1 -1
- package/lib/common/FourCC.d.ts +1 -1
- package/lib/common/FourCC.js +5 -3
- package/lib/common/MetadataCollector.d.ts +3 -3
- package/lib/common/MetadataCollector.js +7 -8
- package/lib/common/RandomFileReader.d.ts +0 -1
- package/lib/common/Util.d.ts +1 -1
- package/lib/common/Util.js +4 -3
- package/lib/core.d.ts +16 -8
- package/lib/core.js +19 -5
- package/lib/dsdiff/DsdiffParser.js +1 -1
- package/lib/dsdiff/DsdiffToken.d.ts +1 -1
- package/lib/dsf/DsfChunk.d.ts +1 -1
- package/lib/flac/FlacParser.d.ts +1 -1
- package/lib/flac/FlacParser.js +6 -4
- package/lib/id3v1/ID3v1Parser.js +6 -6
- package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
- package/lib/id3v2/AbstractID3Parser.js +1 -1
- package/lib/id3v2/FrameParser.js +4 -3
- package/lib/id3v2/ID3v24TagMapper.d.ts +2 -3
- package/lib/id3v2/ID3v24TagMapper.js +14 -9
- package/lib/id3v2/ID3v2Parser.d.ts +1 -1
- package/lib/id3v2/ID3v2Parser.js +10 -17
- package/lib/id3v2/ID3v2Token.d.ts +1 -1
- package/lib/id3v2/ID3v2Token.js +2 -2
- package/lib/iff/index.d.ts +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -1
- package/lib/lyrics3/Lyrics3.js +1 -1
- package/lib/matroska/MatroskaDtd.js +12 -12
- package/lib/matroska/MatroskaParser.d.ts +1 -1
- package/lib/matroska/MatroskaParser.js +16 -20
- package/lib/matroska/types.d.ts +0 -1
- package/lib/mp4/Atom.d.ts +1 -1
- package/lib/mp4/AtomToken.d.ts +2 -3
- package/lib/mp4/AtomToken.js +2 -2
- package/lib/mp4/MP4Parser.js +20 -19
- package/lib/mp4/MP4TagMapper.js +1 -1
- package/lib/mpeg/ExtendedLameHeader.d.ts +1 -1
- package/lib/mpeg/MpegParser.js +4 -4
- package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
- package/lib/mpeg/XingTag.d.ts +1 -2
- package/lib/musepack/index.js +1 -1
- package/lib/musepack/sv7/BitReader.d.ts +1 -1
- package/lib/musepack/sv7/StreamVersion7.d.ts +1 -1
- package/lib/musepack/sv7/StreamVersion7.js +1 -1
- package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
- package/lib/musepack/sv8/StreamVersion8.js +1 -1
- package/lib/ogg/Ogg.d.ts +2 -2
- package/lib/ogg/OggParser.d.ts +1 -1
- package/lib/ogg/OggParser.js +5 -5
- package/lib/ogg/opus/Opus.d.ts +1 -1
- package/lib/ogg/opus/Opus.js +6 -6
- package/lib/ogg/opus/OpusParser.d.ts +2 -3
- package/lib/ogg/opus/OpusParser.js +2 -2
- package/lib/ogg/speex/Speex.d.ts +1 -1
- package/lib/ogg/speex/Speex.js +13 -13
- package/lib/ogg/speex/SpeexParser.d.ts +1 -2
- package/lib/ogg/theora/Theora.d.ts +1 -1
- package/lib/ogg/theora/Theora.js +6 -6
- package/lib/ogg/theora/TheoraParser.d.ts +4 -5
- package/lib/ogg/theora/TheoraParser.js +4 -4
- package/lib/ogg/vorbis/Vorbis.d.ts +3 -4
- package/lib/ogg/vorbis/Vorbis.js +11 -12
- package/lib/ogg/vorbis/VorbisDecoder.js +1 -1
- package/lib/ogg/vorbis/VorbisParser.d.ts +6 -7
- package/lib/ogg/vorbis/VorbisParser.js +11 -11
- package/lib/riff/RiffChunk.d.ts +1 -1
- package/lib/riff/RiffChunk.js +2 -2
- package/lib/riff/RiffInfoTagMap.js +16 -16
- package/lib/type.d.ts +9 -11
- package/lib/wav/BwfChunk.d.ts +1 -1
- package/lib/wav/WaveChunk.d.ts +2 -3
- package/lib/wav/WaveChunk.js +8 -7
- package/lib/wav/WaveParser.js +2 -2
- package/lib/wavpack/WavPackParser.js +1 -1
- package/lib/wavpack/WavPackToken.d.ts +1 -1
- package/lib/wavpack/WavPackToken.js +1 -1
- package/package.json +29 -28
package/lib/asf/AsfObject.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { IGetToken, ITokenizer } from 'strtok3/core';
|
|
3
|
-
import { Buffer } from 'node:buffer';
|
|
1
|
+
import type { IGetToken, ITokenizer } from 'strtok3';
|
|
4
2
|
import { IPicture, ITag } from '../type.js';
|
|
5
3
|
import GUID from './GUID.js';
|
|
6
4
|
/**
|
|
@@ -56,21 +54,21 @@ export interface IAsfTopLevelObjectHeader extends IAsfObjectHeader {
|
|
|
56
54
|
* Token for: 3. ASF top-level Header Object
|
|
57
55
|
* Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3
|
|
58
56
|
*/
|
|
59
|
-
export declare const TopLevelHeaderObjectToken: IGetToken<IAsfTopLevelObjectHeader,
|
|
57
|
+
export declare const TopLevelHeaderObjectToken: IGetToken<IAsfTopLevelObjectHeader, Uint8Array>;
|
|
60
58
|
/**
|
|
61
59
|
* Token for: 3.1 Header Object (mandatory, one only)
|
|
62
60
|
* Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_1
|
|
63
61
|
*/
|
|
64
|
-
export declare const HeaderObjectToken: IGetToken<IAsfObjectHeader,
|
|
62
|
+
export declare const HeaderObjectToken: IGetToken<IAsfObjectHeader, Uint8Array>;
|
|
65
63
|
export declare abstract class State<T> implements IGetToken<T> {
|
|
66
64
|
len: number;
|
|
67
65
|
constructor(header: IAsfObjectHeader);
|
|
68
|
-
abstract get(buf:
|
|
66
|
+
abstract get(buf: Uint8Array, off: number): T;
|
|
69
67
|
protected postProcessTag(tags: ITag[], name: string, valueType: number, data: any): void;
|
|
70
68
|
}
|
|
71
69
|
export declare class IgnoreObjectState extends State<any> {
|
|
72
70
|
constructor(header: IAsfObjectHeader);
|
|
73
|
-
get(buf:
|
|
71
|
+
get(buf: Uint8Array, off: number): null;
|
|
74
72
|
}
|
|
75
73
|
/**
|
|
76
74
|
* Interface for: 3.2: File Properties Object (mandatory, one only)
|
|
@@ -176,7 +174,7 @@ export interface IFilePropertiesObject {
|
|
|
176
174
|
export declare class FilePropertiesObject extends State<IFilePropertiesObject> {
|
|
177
175
|
static guid: GUID;
|
|
178
176
|
constructor(header: IAsfObjectHeader);
|
|
179
|
-
get(buf:
|
|
177
|
+
get(buf: Uint8Array, off: number): IFilePropertiesObject;
|
|
180
178
|
}
|
|
181
179
|
/**
|
|
182
180
|
* Interface for: 3.3 Stream Properties Object (mandatory, one per stream)
|
|
@@ -198,7 +196,7 @@ export interface IStreamPropertiesObject {
|
|
|
198
196
|
export declare class StreamPropertiesObject extends State<IStreamPropertiesObject> {
|
|
199
197
|
static guid: GUID;
|
|
200
198
|
constructor(header: IAsfObjectHeader);
|
|
201
|
-
get(buf:
|
|
199
|
+
get(buf: Uint8Array, off: number): IStreamPropertiesObject;
|
|
202
200
|
}
|
|
203
201
|
export interface IHeaderExtensionObject {
|
|
204
202
|
reserved1: GUID;
|
|
@@ -213,7 +211,7 @@ export declare class HeaderExtensionObject implements IGetToken<IHeaderExtension
|
|
|
213
211
|
static guid: GUID;
|
|
214
212
|
len: number;
|
|
215
213
|
constructor();
|
|
216
|
-
get(buf:
|
|
214
|
+
get(buf: Uint8Array, off: number): IHeaderExtensionObject;
|
|
217
215
|
}
|
|
218
216
|
export interface ICodecEntry {
|
|
219
217
|
type: {
|
|
@@ -222,7 +220,7 @@ export interface ICodecEntry {
|
|
|
222
220
|
};
|
|
223
221
|
codecName: string;
|
|
224
222
|
description: string;
|
|
225
|
-
information:
|
|
223
|
+
information: Uint8Array;
|
|
226
224
|
}
|
|
227
225
|
/**
|
|
228
226
|
* 3.5: Read the Codec-List-Object, which provides user-friendly information about the codecs and formats used to encode the content found in the ASF file.
|
|
@@ -237,7 +235,7 @@ export declare class ContentDescriptionObjectState extends State<ITag[]> {
|
|
|
237
235
|
static guid: GUID;
|
|
238
236
|
private static contentDescTags;
|
|
239
237
|
constructor(header: IAsfObjectHeader);
|
|
240
|
-
get(buf:
|
|
238
|
+
get(buf: Uint8Array, off: number): ITag[];
|
|
241
239
|
}
|
|
242
240
|
/**
|
|
243
241
|
* 3.11 Extended Content Description Object (optional, one only)
|
|
@@ -246,7 +244,7 @@ export declare class ContentDescriptionObjectState extends State<ITag[]> {
|
|
|
246
244
|
export declare class ExtendedContentDescriptionObjectState extends State<ITag[]> {
|
|
247
245
|
static guid: GUID;
|
|
248
246
|
constructor(header: IAsfObjectHeader);
|
|
249
|
-
get(buf:
|
|
247
|
+
get(buf: Uint8Array, off: number): ITag[];
|
|
250
248
|
}
|
|
251
249
|
export interface IStreamName {
|
|
252
250
|
streamLanguageId: number;
|
|
@@ -286,7 +284,7 @@ export interface IExtendedStreamPropertiesObject {
|
|
|
286
284
|
export declare class ExtendedStreamPropertiesObjectState extends State<IExtendedStreamPropertiesObject> {
|
|
287
285
|
static guid: GUID;
|
|
288
286
|
constructor(header: IAsfObjectHeader);
|
|
289
|
-
get(buf:
|
|
287
|
+
get(buf: Uint8Array, off: number): IExtendedStreamPropertiesObject;
|
|
290
288
|
}
|
|
291
289
|
/**
|
|
292
290
|
* 4.7 Metadata Object (optional, 0 or 1)
|
|
@@ -306,7 +304,7 @@ export interface IWmPicture extends IPicture {
|
|
|
306
304
|
format: string;
|
|
307
305
|
description: string;
|
|
308
306
|
size: number;
|
|
309
|
-
data:
|
|
307
|
+
data: Uint8Array;
|
|
310
308
|
}
|
|
311
309
|
/**
|
|
312
310
|
* Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757977(v=vs.85).aspx
|
|
@@ -314,7 +312,7 @@ export interface IWmPicture extends IPicture {
|
|
|
314
312
|
export declare class WmPictureToken implements IGetToken<IWmPicture> {
|
|
315
313
|
len: any;
|
|
316
314
|
static fromBase64(base64str: string): IPicture;
|
|
317
|
-
static fromBuffer(buffer:
|
|
315
|
+
static fromBuffer(buffer: Uint8Array): IWmPicture;
|
|
318
316
|
constructor(len: any);
|
|
319
|
-
get(buffer:
|
|
317
|
+
get(buffer: Uint8Array, offset: number): IWmPicture;
|
|
320
318
|
}
|
package/lib/asf/AsfObject.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// ASF Objects
|
|
2
2
|
import * as Token from 'token-types';
|
|
3
|
-
import { Buffer } from 'node:buffer';
|
|
4
3
|
import * as util from '../common/Util.js';
|
|
5
4
|
import GUID from './GUID.js';
|
|
6
5
|
import { AsfUtil } from './AsfUtil.js';
|
|
7
6
|
import { AttachedPictureType } from '../id3v2/ID3v2Token.js';
|
|
7
|
+
import { base64ToUint8Array } from 'uint8array-extras';
|
|
8
8
|
/**
|
|
9
9
|
* Data Type: Specifies the type of information being stored. The following values are recognized.
|
|
10
10
|
*/
|
|
@@ -43,7 +43,7 @@ export const TopLevelHeaderObjectToken = {
|
|
|
43
43
|
len: 30,
|
|
44
44
|
get: (buf, off) => {
|
|
45
45
|
return {
|
|
46
|
-
objectId: GUID.fromBin(
|
|
46
|
+
objectId: GUID.fromBin(buf, off),
|
|
47
47
|
objectSize: Number(Token.UINT64_LE.get(buf, off + 16)),
|
|
48
48
|
numberOfHeaderObjects: Token.UINT32_LE.get(buf, off + 24)
|
|
49
49
|
// Reserved: 2 bytes
|
|
@@ -58,7 +58,7 @@ export const HeaderObjectToken = {
|
|
|
58
58
|
len: 24,
|
|
59
59
|
get: (buf, off) => {
|
|
60
60
|
return {
|
|
61
|
-
objectId: GUID.fromBin(
|
|
61
|
+
objectId: GUID.fromBin(buf, off),
|
|
62
62
|
objectSize: Number(Token.UINT64_LE.get(buf, off + 16))
|
|
63
63
|
};
|
|
64
64
|
}
|
|
@@ -144,10 +144,11 @@ export class HeaderExtensionObject {
|
|
|
144
144
|
this.len = 22;
|
|
145
145
|
}
|
|
146
146
|
get(buf, off) {
|
|
147
|
+
const view = new DataView(buf.buffer, off);
|
|
147
148
|
return {
|
|
148
149
|
reserved1: GUID.fromBin(buf, off),
|
|
149
|
-
reserved2:
|
|
150
|
-
extensionDataSize:
|
|
150
|
+
reserved2: view.getUint16(16, true),
|
|
151
|
+
extensionDataSize: view.getUint16(18, true)
|
|
151
152
|
};
|
|
152
153
|
}
|
|
153
154
|
}
|
|
@@ -159,14 +160,15 @@ HeaderExtensionObject.guid = GUID.HeaderExtensionObject;
|
|
|
159
160
|
const CodecListObjectHeader = {
|
|
160
161
|
len: 20,
|
|
161
162
|
get: (buf, off) => {
|
|
163
|
+
const view = new DataView(buf.buffer, off);
|
|
162
164
|
return {
|
|
163
|
-
entryCount:
|
|
165
|
+
entryCount: view.getUint16(16, true)
|
|
164
166
|
};
|
|
165
167
|
}
|
|
166
168
|
};
|
|
167
169
|
async function readString(tokenizer) {
|
|
168
170
|
const length = await tokenizer.readNumber(Token.UINT16_LE);
|
|
169
|
-
return (await tokenizer.readToken(new Token.StringType(length * 2, '
|
|
171
|
+
return (await tokenizer.readToken(new Token.StringType(length * 2, 'utf-16le'))).replace('\0', '');
|
|
170
172
|
}
|
|
171
173
|
/**
|
|
172
174
|
* 3.5: Read the Codec-List-Object, which provides user-friendly information about the codecs and formats used to encode the content found in the ASF file.
|
|
@@ -182,7 +184,7 @@ export async function readCodecEntries(tokenizer) {
|
|
|
182
184
|
}
|
|
183
185
|
async function readInformation(tokenizer) {
|
|
184
186
|
const length = await tokenizer.readNumber(Token.UINT16_LE);
|
|
185
|
-
const buf =
|
|
187
|
+
const buf = new Uint8Array(length);
|
|
186
188
|
await tokenizer.readBuffer(buf);
|
|
187
189
|
return buf;
|
|
188
190
|
}
|
|
@@ -212,13 +214,14 @@ export class ContentDescriptionObjectState extends State {
|
|
|
212
214
|
}
|
|
213
215
|
get(buf, off) {
|
|
214
216
|
const tags = [];
|
|
215
|
-
|
|
217
|
+
const view = new DataView(buf.buffer, off);
|
|
218
|
+
let pos = 10;
|
|
216
219
|
for (let i = 0; i < ContentDescriptionObjectState.contentDescTags.length; ++i) {
|
|
217
|
-
const length =
|
|
220
|
+
const length = view.getUint16(i * 2, true);
|
|
218
221
|
if (length > 0) {
|
|
219
222
|
const tagName = ContentDescriptionObjectState.contentDescTags[i];
|
|
220
223
|
const end = pos + length;
|
|
221
|
-
tags.push({ id: tagName, value: AsfUtil.parseUnicodeAttr(buf.slice(pos, end)) });
|
|
224
|
+
tags.push({ id: tagName, value: AsfUtil.parseUnicodeAttr(buf.slice(off + pos, off + end)) });
|
|
222
225
|
pos = end;
|
|
223
226
|
}
|
|
224
227
|
}
|
|
@@ -237,18 +240,19 @@ export class ExtendedContentDescriptionObjectState extends State {
|
|
|
237
240
|
}
|
|
238
241
|
get(buf, off) {
|
|
239
242
|
const tags = [];
|
|
240
|
-
const
|
|
241
|
-
|
|
243
|
+
const view = new DataView(buf.buffer, off);
|
|
244
|
+
const attrCount = view.getUint16(0, true);
|
|
245
|
+
let pos = 2;
|
|
242
246
|
for (let i = 0; i < attrCount; i += 1) {
|
|
243
|
-
const nameLen =
|
|
247
|
+
const nameLen = view.getUint16(pos, true);
|
|
244
248
|
pos += 2;
|
|
245
|
-
const name = AsfUtil.parseUnicodeAttr(buf.slice(pos, pos + nameLen));
|
|
249
|
+
const name = AsfUtil.parseUnicodeAttr(buf.slice(off + pos, off + pos + nameLen));
|
|
246
250
|
pos += nameLen;
|
|
247
|
-
const valueType =
|
|
251
|
+
const valueType = view.getUint16(pos, true);
|
|
248
252
|
pos += 2;
|
|
249
|
-
const valueLen =
|
|
253
|
+
const valueLen = view.getUint16(pos, true);
|
|
250
254
|
pos += 2;
|
|
251
|
-
const value = buf.slice(pos, pos + valueLen);
|
|
255
|
+
const value = buf.slice(off + pos, off + pos + valueLen);
|
|
252
256
|
pos += valueLen;
|
|
253
257
|
this.postProcessTag(tags, name, valueType, value);
|
|
254
258
|
}
|
|
@@ -265,28 +269,29 @@ export class ExtendedStreamPropertiesObjectState extends State {
|
|
|
265
269
|
super(header);
|
|
266
270
|
}
|
|
267
271
|
get(buf, off) {
|
|
272
|
+
const view = new DataView(buf.buffer, off);
|
|
268
273
|
return {
|
|
269
274
|
startTime: Token.UINT64_LE.get(buf, off),
|
|
270
275
|
endTime: Token.UINT64_LE.get(buf, off + 8),
|
|
271
|
-
dataBitrate:
|
|
272
|
-
bufferSize:
|
|
273
|
-
initialBufferFullness:
|
|
274
|
-
alternateDataBitrate:
|
|
275
|
-
alternateBufferSize:
|
|
276
|
-
alternateInitialBufferFullness:
|
|
277
|
-
maximumObjectSize:
|
|
276
|
+
dataBitrate: view.getInt32(12, true),
|
|
277
|
+
bufferSize: view.getInt32(16, true),
|
|
278
|
+
initialBufferFullness: view.getInt32(20, true),
|
|
279
|
+
alternateDataBitrate: view.getInt32(24, true),
|
|
280
|
+
alternateBufferSize: view.getInt32(28, true),
|
|
281
|
+
alternateInitialBufferFullness: view.getInt32(32, true),
|
|
282
|
+
maximumObjectSize: view.getInt32(36, true),
|
|
278
283
|
flags: {
|
|
279
284
|
reliableFlag: util.getBit(buf, off + 40, 0),
|
|
280
285
|
seekableFlag: util.getBit(buf, off + 40, 1),
|
|
281
286
|
resendLiveCleanpointsFlag: util.getBit(buf, off + 40, 2)
|
|
282
287
|
},
|
|
283
288
|
// flagsNumeric: Token.UINT32_LE.get(buf, off + 64),
|
|
284
|
-
streamNumber:
|
|
285
|
-
streamLanguageId:
|
|
286
|
-
averageTimePerFrame:
|
|
287
|
-
streamNameCount:
|
|
288
|
-
payloadExtensionSystems:
|
|
289
|
-
streamNames: [],
|
|
289
|
+
streamNumber: view.getInt16(42, true),
|
|
290
|
+
streamLanguageId: view.getInt16(44, true),
|
|
291
|
+
averageTimePerFrame: view.getInt32(52, true),
|
|
292
|
+
streamNameCount: view.getInt32(54, true),
|
|
293
|
+
payloadExtensionSystems: view.getInt32(56, true),
|
|
294
|
+
streamNames: [], // ToDo
|
|
290
295
|
streamPropertiesObject: null
|
|
291
296
|
};
|
|
292
297
|
}
|
|
@@ -302,20 +307,20 @@ export class MetadataObjectState extends State {
|
|
|
302
307
|
}
|
|
303
308
|
get(uint8Array, off) {
|
|
304
309
|
const tags = [];
|
|
305
|
-
const
|
|
306
|
-
const descriptionRecordsCount =
|
|
307
|
-
let pos =
|
|
310
|
+
const view = new DataView(uint8Array.buffer, off);
|
|
311
|
+
const descriptionRecordsCount = view.getUint16(0, true);
|
|
312
|
+
let pos = 2;
|
|
308
313
|
for (let i = 0; i < descriptionRecordsCount; i += 1) {
|
|
309
314
|
pos += 4;
|
|
310
|
-
const nameLen =
|
|
315
|
+
const nameLen = view.getUint16(pos, true);
|
|
311
316
|
pos += 2;
|
|
312
|
-
const dataType =
|
|
317
|
+
const dataType = view.getUint16(pos, true);
|
|
313
318
|
pos += 2;
|
|
314
|
-
const dataLen =
|
|
319
|
+
const dataLen = view.getUint32(pos, true);
|
|
315
320
|
pos += 4;
|
|
316
|
-
const name = AsfUtil.parseUnicodeAttr(
|
|
321
|
+
const name = AsfUtil.parseUnicodeAttr(uint8Array.slice(off + pos, off + pos + nameLen));
|
|
317
322
|
pos += nameLen;
|
|
318
|
-
const data =
|
|
323
|
+
const data = uint8Array.slice(off + pos, off + pos + dataLen);
|
|
319
324
|
pos += dataLen;
|
|
320
325
|
this.postProcessTag(tags, name, dataType, data);
|
|
321
326
|
}
|
|
@@ -335,7 +340,7 @@ MetadataLibraryObjectState.guid = GUID.MetadataLibraryObject;
|
|
|
335
340
|
*/
|
|
336
341
|
export class WmPictureToken {
|
|
337
342
|
static fromBase64(base64str) {
|
|
338
|
-
return this.fromBuffer(
|
|
343
|
+
return this.fromBuffer(base64ToUint8Array(base64str));
|
|
339
344
|
}
|
|
340
345
|
static fromBuffer(buffer) {
|
|
341
346
|
const pic = new WmPictureToken(buffer.length);
|
|
@@ -345,17 +350,18 @@ export class WmPictureToken {
|
|
|
345
350
|
this.len = len;
|
|
346
351
|
}
|
|
347
352
|
get(buffer, offset) {
|
|
348
|
-
const
|
|
349
|
-
const
|
|
353
|
+
const view = new DataView(buffer.buffer, offset);
|
|
354
|
+
const typeId = view.getUint8(0);
|
|
355
|
+
const size = view.getInt32(1, true);
|
|
350
356
|
let index = 5;
|
|
351
|
-
while (
|
|
357
|
+
while (view.getUint16(index) !== 0) {
|
|
352
358
|
index += 2;
|
|
353
359
|
}
|
|
354
|
-
const format =
|
|
355
|
-
while (
|
|
360
|
+
const format = new Token.StringType(index - 5, 'utf-16le').get(buffer, 5);
|
|
361
|
+
while (view.getUint16(index) !== 0) {
|
|
356
362
|
index += 2;
|
|
357
363
|
}
|
|
358
|
-
const description =
|
|
364
|
+
const description = new Token.StringType(index - 5, 'utf-16le').get(buffer, 5);
|
|
359
365
|
return {
|
|
360
366
|
type: AttachedPictureType[typeId],
|
|
361
367
|
format,
|
package/lib/asf/AsfParser.js
CHANGED
|
@@ -51,11 +51,11 @@ export class AsfParser extends BasicParser {
|
|
|
51
51
|
break;
|
|
52
52
|
case AsfObject.ContentDescriptionObjectState.guid.str: // 3.10
|
|
53
53
|
tags = await this.tokenizer.readToken(new AsfObject.ContentDescriptionObjectState(header));
|
|
54
|
-
this.addTags(tags);
|
|
54
|
+
await this.addTags(tags);
|
|
55
55
|
break;
|
|
56
56
|
case AsfObject.ExtendedContentDescriptionObjectState.guid.str: // 3.11
|
|
57
57
|
tags = await this.tokenizer.readToken(new AsfObject.ExtendedContentDescriptionObjectState(header));
|
|
58
|
-
this.addTags(tags);
|
|
58
|
+
await this.addTags(tags);
|
|
59
59
|
break;
|
|
60
60
|
case GUID.CodecListObject.str:
|
|
61
61
|
const codecs = await AsfObject.readCodecEntries(this.tokenizer);
|
|
@@ -85,10 +85,8 @@ export class AsfParser extends BasicParser {
|
|
|
85
85
|
} while (--numberOfObjectHeaders);
|
|
86
86
|
// done
|
|
87
87
|
}
|
|
88
|
-
addTags(tags) {
|
|
89
|
-
tags.
|
|
90
|
-
this.metadata.addTag(headerType, tag.id, tag.value);
|
|
91
|
-
});
|
|
88
|
+
async addTags(tags) {
|
|
89
|
+
await Promise.all(tags.map(({ id, value }) => this.metadata.addTag(headerType, id, value)));
|
|
92
90
|
}
|
|
93
91
|
async parseExtensionObject(extensionSize) {
|
|
94
92
|
do {
|
|
@@ -103,11 +101,11 @@ export class AsfParser extends BasicParser {
|
|
|
103
101
|
break;
|
|
104
102
|
case AsfObject.MetadataObjectState.guid.str: // 4.7
|
|
105
103
|
const moTags = await this.tokenizer.readToken(new AsfObject.MetadataObjectState(header));
|
|
106
|
-
this.addTags(moTags);
|
|
104
|
+
await this.addTags(moTags);
|
|
107
105
|
break;
|
|
108
106
|
case AsfObject.MetadataLibraryObjectState.guid.str: // 4.8
|
|
109
107
|
const mlTags = await this.tokenizer.readToken(new AsfObject.MetadataLibraryObjectState(header));
|
|
110
|
-
this.addTags(mlTags);
|
|
108
|
+
await this.addTags(mlTags);
|
|
111
109
|
break;
|
|
112
110
|
case GUID.PaddingObject.str:
|
|
113
111
|
// ToDo: register bytes pad
|
package/lib/asf/AsfTagMapper.js
CHANGED
|
@@ -8,7 +8,7 @@ const asfTagMap = {
|
|
|
8
8
|
Author: 'artist',
|
|
9
9
|
'WM/AlbumArtist': 'albumartist',
|
|
10
10
|
'WM/AlbumTitle': 'album',
|
|
11
|
-
'WM/Year': 'date',
|
|
11
|
+
'WM/Year': 'date', // changed to 'year' to 'date' based on Picard mappings; ToDo: check me
|
|
12
12
|
'WM/OriginalReleaseTime': 'originaldate',
|
|
13
13
|
'WM/OriginalReleaseYear': 'originalyear',
|
|
14
14
|
Description: 'comment',
|
package/lib/asf/AsfUtil.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
import { Buffer } from 'node:buffer';
|
|
3
1
|
import { DataType } from './AsfObject.js';
|
|
4
|
-
export type AttributeParser = (buf:
|
|
2
|
+
export type AttributeParser = (buf: Uint8Array) => boolean | string | number | bigint | Uint8Array;
|
|
5
3
|
export declare class AsfUtil {
|
|
6
4
|
static getParserForAttr(i: DataType): AttributeParser;
|
|
7
5
|
static parseUnicodeAttr(uint8Array: Uint8Array): string;
|
package/lib/asf/AsfUtil.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
|
-
import { Buffer } from 'node:buffer';
|
|
3
2
|
import * as util from '../common/Util.js';
|
|
4
3
|
export class AsfUtil {
|
|
5
4
|
static getParserForAttr(i) {
|
|
6
5
|
return AsfUtil.attributeParsers[i];
|
|
7
6
|
}
|
|
8
7
|
static parseUnicodeAttr(uint8Array) {
|
|
9
|
-
return util.stripNulls(util.decodeString(uint8Array, '
|
|
8
|
+
return util.stripNulls(util.decodeString(uint8Array, 'utf-16le'));
|
|
10
9
|
}
|
|
11
10
|
static parseByteArrayAttr(buf) {
|
|
12
|
-
return
|
|
11
|
+
return new Uint8Array(buf);
|
|
13
12
|
}
|
|
14
13
|
static parseBoolAttr(buf, offset = 0) {
|
|
15
14
|
return AsfUtil.parseWordAttr(buf, offset) === 1;
|
|
16
15
|
}
|
|
17
16
|
static parseDWordAttr(buf, offset = 0) {
|
|
18
|
-
return
|
|
17
|
+
return Token.UINT32_LE.get(buf, offset);
|
|
19
18
|
}
|
|
20
19
|
static parseQWordAttr(buf, offset = 0) {
|
|
21
20
|
return Token.UINT64_LE.get(buf, offset);
|
|
22
21
|
}
|
|
23
22
|
static parseWordAttr(buf, offset = 0) {
|
|
24
|
-
return
|
|
23
|
+
return Token.UINT16_LE.get(buf, offset);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
AsfUtil.attributeParsers = [
|
package/lib/asf/GUID.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
1
|
/**
|
|
3
2
|
* Ref:
|
|
4
3
|
* - https://tools.ietf.org/html/draft-fleischman-asf-01, Appendix A: ASF GUIDs
|
|
@@ -58,14 +57,14 @@ export default class GUID {
|
|
|
58
57
|
static FileTransferMedia: GUID;
|
|
59
58
|
static BinaryMedia: GUID;
|
|
60
59
|
static ASF_Index_Placeholder_Object: GUID;
|
|
61
|
-
static fromBin(bin:
|
|
60
|
+
static fromBin(bin: Uint8Array, offset?: number): GUID;
|
|
62
61
|
/**
|
|
63
62
|
* Decode GUID in format like "B503BF5F-2EA9-CF11-8EE3-00C00C205365"
|
|
64
63
|
* @param objectId Binary GUID
|
|
65
64
|
* @param offset Read offset in bytes, default 0
|
|
66
65
|
* @returns GUID as dashed hexadecimal representation
|
|
67
66
|
*/
|
|
68
|
-
static decode(objectId:
|
|
67
|
+
static decode(objectId: Uint8Array, offset?: number): string;
|
|
69
68
|
/**
|
|
70
69
|
* Decode stream type
|
|
71
70
|
* @param mediaType Media type GUID
|
|
@@ -77,8 +76,8 @@ export default class GUID {
|
|
|
77
76
|
* @param guid GUID like: "B503BF5F-2EA9-CF11-8EE3-00C00C205365"
|
|
78
77
|
* @returns Encoded Binary GUID
|
|
79
78
|
*/
|
|
80
|
-
static encode(str: string):
|
|
79
|
+
static encode(str: string): Uint8Array;
|
|
81
80
|
constructor(str: string);
|
|
82
81
|
equals(guid: GUID): boolean;
|
|
83
|
-
toBin():
|
|
82
|
+
toBin(): Uint8Array;
|
|
84
83
|
}
|
package/lib/asf/GUID.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hexToUint8Array, uint8ArrayToHex } from 'uint8array-extras';
|
|
1
2
|
/**
|
|
2
3
|
* Ref:
|
|
3
4
|
* - https://tools.ietf.org/html/draft-fleischman-asf-01, Appendix A: ASF GUIDs
|
|
@@ -23,11 +24,12 @@ class GUID {
|
|
|
23
24
|
* @returns GUID as dashed hexadecimal representation
|
|
24
25
|
*/
|
|
25
26
|
static decode(objectId, offset = 0) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const view = new DataView(objectId.buffer, offset);
|
|
28
|
+
const guid = view.getUint32(0, true).toString(16) + "-" +
|
|
29
|
+
view.getUint16(4, true).toString(16) + "-" +
|
|
30
|
+
view.getUint16(6, true).toString(16) + "-" +
|
|
31
|
+
view.getUint16(8).toString(16) + "-" +
|
|
32
|
+
uint8ArrayToHex(objectId.slice(offset + 10, offset + 16));
|
|
31
33
|
return guid.toUpperCase();
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
@@ -51,12 +53,13 @@ class GUID {
|
|
|
51
53
|
* @returns Encoded Binary GUID
|
|
52
54
|
*/
|
|
53
55
|
static encode(str) {
|
|
54
|
-
const bin =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
const bin = new Uint8Array(16);
|
|
57
|
+
const view = new DataView(bin.buffer);
|
|
58
|
+
view.setUint32(0, parseInt(str.slice(0, 8), 16), true);
|
|
59
|
+
view.setUint16(4, parseInt(str.slice(9, 13), 16), true);
|
|
60
|
+
view.setUint16(6, parseInt(str.slice(14, 18), 16), true);
|
|
61
|
+
bin.set(hexToUint8Array(str.slice(19, 23)), 8);
|
|
62
|
+
bin.set(hexToUint8Array(str.slice(24)), 10);
|
|
60
63
|
return bin;
|
|
61
64
|
}
|
|
62
65
|
constructor(str) {
|
package/lib/common/FourCC.d.ts
CHANGED
package/lib/common/FourCC.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stringToUint8Array, uint8ArrayToString } from 'uint8array-extras';
|
|
1
2
|
import * as util from './Util.js';
|
|
2
3
|
const validFourCC = /^[\x21-\x7e©][\x20-\x7e\x00()]{3}/;
|
|
3
4
|
/**
|
|
@@ -7,17 +8,18 @@ const validFourCC = /^[\x21-\x7e©][\x20-\x7e\x00()]{3}/;
|
|
|
7
8
|
export const FourCcToken = {
|
|
8
9
|
len: 4,
|
|
9
10
|
get: (buf, off) => {
|
|
10
|
-
const id = buf.
|
|
11
|
+
const id = uint8ArrayToString(buf.slice(off, off + FourCcToken.len), 'latin1');
|
|
11
12
|
if (!id.match(validFourCC)) {
|
|
12
13
|
throw new Error(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`);
|
|
13
14
|
}
|
|
14
15
|
return id;
|
|
15
16
|
},
|
|
16
17
|
put: (buffer, offset, id) => {
|
|
17
|
-
const str =
|
|
18
|
+
const str = stringToUint8Array(id);
|
|
18
19
|
if (str.length !== 4)
|
|
19
20
|
throw new Error('Invalid length');
|
|
20
|
-
|
|
21
|
+
buffer.set(str, offset);
|
|
22
|
+
return offset + 4;
|
|
21
23
|
}
|
|
22
24
|
};
|
|
23
25
|
//# sourceMappingURL=FourCC.js.map
|
|
@@ -22,7 +22,7 @@ export interface INativeMetadataCollector extends IWarningCollector {
|
|
|
22
22
|
*/
|
|
23
23
|
hasAny(): boolean;
|
|
24
24
|
setFormat(key: FormatId, value: any): void;
|
|
25
|
-
addTag(tagType: TagType, tagId: string, value: any): void
|
|
25
|
+
addTag(tagType: TagType, tagId: string, value: any): Promise<void>;
|
|
26
26
|
addStreamInfo(streamInfo: ITrackInfo): void;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
@@ -51,9 +51,9 @@ export declare class MetadataCollector implements INativeMetadataCollector {
|
|
|
51
51
|
hasAny(): boolean;
|
|
52
52
|
addStreamInfo(streamInfo: ITrackInfo): void;
|
|
53
53
|
setFormat(key: FormatId, value: any): void;
|
|
54
|
-
addTag(tagType: TagType, tagId: string, value: any): void
|
|
54
|
+
addTag(tagType: TagType, tagId: string, value: any): Promise<void>;
|
|
55
55
|
addWarning(warning: string): void;
|
|
56
|
-
postMap(tagType: TagType | 'artificial', tag: IGenericTag):
|
|
56
|
+
postMap(tagType: TagType | 'artificial', tag: IGenericTag): Promise<void>;
|
|
57
57
|
/**
|
|
58
58
|
* Convert native tags to common tags
|
|
59
59
|
* @returns {IAudioMetadata} Native + common tags
|
|
@@ -60,19 +60,19 @@ export class MetadataCollector {
|
|
|
60
60
|
this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } });
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
addTag(tagType, tagId, value) {
|
|
63
|
+
async addTag(tagType, tagId, value) {
|
|
64
64
|
debug(`tag ${tagType}.${tagId} = ${value}`);
|
|
65
65
|
if (!this.native[tagType]) {
|
|
66
66
|
this.format.tagTypes.push(tagType);
|
|
67
67
|
this.native[tagType] = [];
|
|
68
68
|
}
|
|
69
69
|
this.native[tagType].push({ id: tagId, value });
|
|
70
|
-
this.toCommon(tagType, tagId, value);
|
|
70
|
+
await this.toCommon(tagType, tagId, value);
|
|
71
71
|
}
|
|
72
72
|
addWarning(warning) {
|
|
73
73
|
this.quality.warnings.push({ message: warning });
|
|
74
74
|
}
|
|
75
|
-
postMap(tagType, tag) {
|
|
75
|
+
async postMap(tagType, tag) {
|
|
76
76
|
// Common tag (alias) found
|
|
77
77
|
// check if we need to do something special with common tag
|
|
78
78
|
// if the event has been aliased then we need to clean it before
|
|
@@ -100,13 +100,12 @@ export class MetadataCollector {
|
|
|
100
100
|
}
|
|
101
101
|
break;
|
|
102
102
|
case 'picture':
|
|
103
|
-
this.postFixPicture(tag.value).then(picture => {
|
|
103
|
+
return this.postFixPicture(tag.value).then(picture => {
|
|
104
104
|
if (picture !== null) {
|
|
105
105
|
tag.value = picture;
|
|
106
106
|
this.setGenericTag(tagType, tag);
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
|
-
return;
|
|
110
109
|
case 'totaltracks':
|
|
111
110
|
this.common.track.of = CommonTagMapper.toIntOrNull(tag.value);
|
|
112
111
|
return;
|
|
@@ -194,7 +193,7 @@ export class MetadataCollector {
|
|
|
194
193
|
async postFixPicture(picture) {
|
|
195
194
|
if (picture.data && picture.data.length > 0) {
|
|
196
195
|
if (!picture.format) {
|
|
197
|
-
const fileType = await fileTypeFromBuffer(picture.data);
|
|
196
|
+
const fileType = await fileTypeFromBuffer(Uint8Array.from(picture.data)); // ToDO: remove Buffer
|
|
198
197
|
if (fileType) {
|
|
199
198
|
picture.format = fileType.mime;
|
|
200
199
|
}
|
|
@@ -215,11 +214,11 @@ export class MetadataCollector {
|
|
|
215
214
|
/**
|
|
216
215
|
* Convert native tag to common tags
|
|
217
216
|
*/
|
|
218
|
-
toCommon(tagType, tagId, value) {
|
|
217
|
+
async toCommon(tagType, tagId, value) {
|
|
219
218
|
const tag = { id: tagId, value };
|
|
220
219
|
const genericTag = this.tagMapper.mapTag(tagType, tag, this);
|
|
221
220
|
if (genericTag) {
|
|
222
|
-
this.postMap(tagType, genericTag);
|
|
221
|
+
await this.postMap(tagType, genericTag);
|
|
223
222
|
}
|
|
224
223
|
}
|
|
225
224
|
/**
|
package/lib/common/Util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IRatio } from '../type.js';
|
|
2
|
-
export type StringEncoding = 'ascii' | 'utf8' | '
|
|
2
|
+
export type StringEncoding = 'ascii' | 'utf8' | 'utf-16le' | 'ucs2' | 'base64url' | 'latin1' | 'hex';
|
|
3
3
|
export interface ITextEncoding {
|
|
4
4
|
encoding: StringEncoding;
|
|
5
5
|
bom?: boolean;
|