music-metadata 11.2.3 → 11.4.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.
@@ -71,7 +71,7 @@ export class ParserFactory {
71
71
  // Parser could not be determined on MIME-type or extension
72
72
  debug('Guess parser on content...');
73
73
  await tokenizer.peekBuffer(buf, { mayBeLess: true });
74
- const guessedType = await fileTypeFromBuffer(buf);
74
+ const guessedType = await fileTypeFromBuffer(buf, { mpegOffsetTolerance: 10 });
75
75
  if (!guessedType || !guessedType.mime) {
76
76
  throw new CouldNotDetermineFileTypeError('Failed to determine audio format');
77
77
  }
@@ -108,7 +108,7 @@ export class ParserFactory {
108
108
  try {
109
109
  mime = parseHttpContentType(httpContentType);
110
110
  }
111
- catch (err) {
111
+ catch (_err) {
112
112
  debug(`Invalid HTTP Content-Type header value: ${httpContentType}`);
113
113
  return;
114
114
  }
@@ -18,8 +18,8 @@ declare const ApeContentError_base: {
18
18
  };
19
19
  export declare class ApeContentError extends ApeContentError_base {
20
20
  }
21
+ export declare function tryParseApeHeader(metadata: INativeMetadataCollector, tokenizer: strtok3.ITokenizer, options: IOptions): Promise<void>;
21
22
  export declare class APEv2Parser extends BasicParser {
22
- static tryParseApeHeader(metadata: INativeMetadataCollector, tokenizer: strtok3.ITokenizer, options: IOptions): Promise<void>;
23
23
  /**
24
24
  * Calculate the media file duration
25
25
  * @param ah ApeHeader
@@ -11,15 +11,15 @@ const tagFormat = 'APEv2';
11
11
  const preamble = 'APETAGEX';
12
12
  export class ApeContentError extends makeUnexpectedFileContentError('APEv2') {
13
13
  }
14
+ export function tryParseApeHeader(metadata, tokenizer, options) {
15
+ const apeParser = new APEv2Parser(metadata, tokenizer, options);
16
+ return apeParser.tryParseApeHeader();
17
+ }
14
18
  export class APEv2Parser extends BasicParser {
15
19
  constructor() {
16
20
  super(...arguments);
17
21
  this.ape = {};
18
22
  }
19
- static tryParseApeHeader(metadata, tokenizer, options) {
20
- const apeParser = new APEv2Parser(metadata, tokenizer, options);
21
- return apeParser.tryParseApeHeader();
22
- }
23
23
  /**
24
24
  * Calculate the media file duration
25
25
  * @param ah ApeHeader
@@ -82,7 +82,7 @@ export declare abstract class State<T> implements IGetToken<T> {
82
82
  protected postProcessTag(tags: ITag[], name: string, valueType: number, data: AnyTagValue): void;
83
83
  }
84
84
  export declare class IgnoreObjectState extends State<unknown> {
85
- get(buf: Uint8Array, off: number): null;
85
+ get(_buf: Uint8Array, _off: number): null;
86
86
  }
87
87
  /**
88
88
  * Interface for: 3.2: File Properties Object (mandatory, one only)
@@ -83,7 +83,7 @@ export class State {
83
83
  }
84
84
  // ToDo: use ignore type
85
85
  export class IgnoreObjectState extends State {
86
- get(buf, off) {
86
+ get(_buf, _off) {
87
87
  return null;
88
88
  }
89
89
  }
@@ -47,5 +47,5 @@ export declare class CommonTagMapper implements IGenericTagMapper {
47
47
  * @param tag Tag e.g. {"©alb", "Buena Vista Social Club")
48
48
  * @param warnings Used to register warnings
49
49
  */
50
- protected postMap(tag: ITag, warnings: IWarningCollector): void;
50
+ protected postMap(_tag: ITag, _warnings: IWarningCollector): void;
51
51
  }
@@ -44,7 +44,7 @@ export class CommonTagMapper {
44
44
  * @param tag Tag e.g. {"©alb", "Buena Vista Social Club")
45
45
  * @param warnings Used to register warnings
46
46
  */
47
- postMap(tag, warnings) {
47
+ postMap(_tag, _warnings) {
48
48
  return;
49
49
  }
50
50
  }
package/lib/core.d.ts CHANGED
@@ -63,12 +63,12 @@ export declare function scanAppendingHeaders(tokenizer: IRandomAccessTokenizer,
63
63
  * Implementation only available when loaded as Node.js
64
64
  * This method will throw an Error, always.
65
65
  */
66
- export declare function parseFile(filePath: string, options?: IOptions): Promise<IAudioMetadata>;
66
+ export declare function parseFile(_filePath: string, _options?: IOptions): Promise<IAudioMetadata>;
67
67
  /**
68
68
  * Implementation only available when loaded as Node.js
69
69
  * This method will throw an Error, always.
70
70
  */
71
- export declare function parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
71
+ export declare function parseStream(_stream: Readable, _fileInfo?: IFileInfo | string, _options?: IOptions): Promise<IAudioMetadata>;
72
72
  /**
73
73
  * Return a list of supported mime-types
74
74
  */
package/lib/core.js CHANGED
@@ -109,14 +109,14 @@ export async function scanAppendingHeaders(tokenizer, options = {}) {
109
109
  * Implementation only available when loaded as Node.js
110
110
  * This method will throw an Error, always.
111
111
  */
112
- export async function parseFile(filePath, options = {}) {
112
+ export async function parseFile(_filePath, _options = {}) {
113
113
  throw new Error('This function require a Node engine. To load Web API File objects use parseBlob instead.');
114
114
  }
115
115
  /**
116
116
  * Implementation only available when loaded as Node.js
117
117
  * This method will throw an Error, always.
118
118
  */
119
- export async function parseStream(stream, fileInfo, options = {}) {
119
+ export async function parseStream(_stream, _fileInfo, _options = {}) {
120
120
  throw new Error('This function require a Node engine.');
121
121
  }
122
122
  /**
@@ -194,7 +194,7 @@ function readUIntBeAsBigInt(buf, len) {
194
194
  normalizedNumber.set(cleanNumber, 8 - len);
195
195
  return Token.UINT64_BE.get(normalizedNumber, 0);
196
196
  }
197
- catch (error) {
197
+ catch (_error) {
198
198
  return BigInt(-1);
199
199
  }
200
200
  }
@@ -7,16 +7,25 @@ import { LyricsContentType, TimestampFormat } from '../type.js';
7
7
  export function parseLrc(lrcString) {
8
8
  const lines = lrcString.split('\n');
9
9
  const syncText = [];
10
- // Regular expression to match LRC timestamps (e.g., [00:45.52])
11
- const timestampRegex = /\[(\d{2}):(\d{2})\.(\d{2})\]/;
10
+ // Regular expression to match LRC timestamps (e.g., [00:45.52] or [00:45.520])
11
+ const timestampRegex = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/;
12
12
  for (const line of lines) {
13
13
  const match = line.match(timestampRegex);
14
14
  if (match) {
15
15
  const minutes = Number.parseInt(match[1], 10);
16
16
  const seconds = Number.parseInt(match[2], 10);
17
- const hundredths = Number.parseInt(match[3], 10);
17
+ const millisecondsStr = match[3];
18
+ let milliseconds;
19
+ if (millisecondsStr.length === 3) {
20
+ // (e.g., .521 = 521 millseconds)
21
+ milliseconds = Number.parseInt(millisecondsStr, 10);
22
+ }
23
+ else {
24
+ // (e.g., .52 = 520 millseconds)
25
+ milliseconds = Number.parseInt(millisecondsStr, 10) * 10;
26
+ }
18
27
  // Convert the timestamp to milliseconds, as per TimestampFormat.milliseconds
19
- const timestamp = (minutes * 60 + seconds) * 1000 + hundredths * 10;
28
+ const timestamp = (minutes * 60 + seconds) * 1000 + milliseconds;
20
29
  // Get the text portion of the line (e.g., "あの蝶は自由になれたかな")
21
30
  const text = line.replace(timestampRegex, '').trim();
22
31
  syncText.push({ timestamp, text });
package/lib/mp4/Atom.js CHANGED
@@ -50,6 +50,7 @@ export class Atom {
50
50
  case '<id>':
51
51
  case 'ilst':
52
52
  case 'tref':
53
+ case 'moof':
53
54
  return this.readAtoms(tokenizer, dataHandler, this.getPayloadLength(remaining));
54
55
  case 'meta': { // Metadata Atom, ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW8
55
56
  // meta has 4 bytes of padding, ignore
@@ -402,4 +402,64 @@ export declare class ChapterText implements IGetToken<string> {
402
402
  constructor(len: number);
403
403
  get(buf: Uint8Array, off: number): string;
404
404
  }
405
+ interface ITrackFragmentHeaderBoxFlags {
406
+ baseDataOffsetPresent: boolean;
407
+ sampleDescriptionIndexPresent: boolean;
408
+ defaultSampleDurationPresent: boolean;
409
+ defaultSampleSizePresent: boolean;
410
+ defaultSampleFlagsPresent: boolean;
411
+ defaultDurationIsEmpty: boolean;
412
+ defaultBaseIsMoof: boolean;
413
+ }
414
+ export interface ITrackFragmentHeaderBox {
415
+ version: number;
416
+ flags: ITrackFragmentHeaderBoxFlags;
417
+ trackId: number;
418
+ baseDataOffset?: bigint;
419
+ sampleDescriptionIndex?: number;
420
+ defaultSampleDuration?: number;
421
+ defaultSampleSize?: number;
422
+ defaultSampleFlags?: number;
423
+ }
424
+ /**
425
+ * Sample-size ('tfhd') TrackFragmentHeaderBox
426
+ */
427
+ export declare class TrackFragmentHeaderBox implements IGetToken<ITrackFragmentHeaderBox> {
428
+ len: number;
429
+ constructor(len: number);
430
+ get(buf: Uint8Array, off: number): ITrackFragmentHeaderBox;
431
+ }
432
+ interface ITrackRunBoxFlags {
433
+ dataOffsetPresent: boolean;
434
+ firstSampleFlagsPresent: boolean;
435
+ sampleDurationPresent: boolean;
436
+ sampleSizePresent: boolean;
437
+ sampleFlagsPresent: boolean;
438
+ sampleCompositionTimeOffsetsPresent: boolean;
439
+ }
440
+ /**
441
+ * trun atom
442
+ */
443
+ export interface ITrackRunBox {
444
+ version: number;
445
+ flags: ITrackRunBoxFlags;
446
+ samples: ITrackRunBoxSample[];
447
+ sampleCount: number;
448
+ dataOffset?: number;
449
+ firstSampleFlags?: number;
450
+ }
451
+ interface ITrackRunBoxSample {
452
+ sampleDuration?: number;
453
+ sampleSize?: number;
454
+ sampleFlags?: number;
455
+ sampleCompositionTimeOffset?: number;
456
+ }
457
+ /**
458
+ * Sample-size ('trun') TrackRunBox
459
+ */
460
+ export declare class TrackRunBox implements IGetToken<ITrackRunBox> {
461
+ len: number;
462
+ constructor(len: number);
463
+ get(buf: Uint8Array, off: number): ITrackRunBox;
464
+ }
405
465
  export {};
@@ -2,6 +2,7 @@ import * as Token from 'token-types';
2
2
  import initDebug from 'debug';
3
3
  import { FourCcToken } from '../common/FourCC.js';
4
4
  import { makeUnexpectedFileContentError } from '../ParseError.js';
5
+ import * as util from '../common/Util.js';
5
6
  const debug = initDebug('music-metadata:parser:MP4:atom');
6
7
  export class Mp4ContentError extends makeUnexpectedFileContentError('MP4') {
7
8
  }
@@ -390,4 +391,107 @@ function readTokenTable(buf, token, off, remainingLen, numberOfEntries) {
390
391
  }
391
392
  return entries;
392
393
  }
394
+ /**
395
+ * Sample-size ('tfhd') TrackFragmentHeaderBox
396
+ */
397
+ export class TrackFragmentHeaderBox {
398
+ constructor(len) {
399
+ this.len = len;
400
+ }
401
+ get(buf, off) {
402
+ const flagOffset = off + 1;
403
+ const header = {
404
+ version: Token.INT8.get(buf, off),
405
+ flags: {
406
+ baseDataOffsetPresent: util.getBit(buf, flagOffset + 2, 0),
407
+ sampleDescriptionIndexPresent: util.getBit(buf, flagOffset + 2, 1),
408
+ defaultSampleDurationPresent: util.getBit(buf, flagOffset + 2, 3),
409
+ defaultSampleSizePresent: util.getBit(buf, flagOffset + 2, 4),
410
+ defaultSampleFlagsPresent: util.getBit(buf, flagOffset + 2, 5),
411
+ defaultDurationIsEmpty: util.getBit(buf, flagOffset, 0),
412
+ defaultBaseIsMoof: util.getBit(buf, flagOffset, 1)
413
+ },
414
+ trackId: Token.UINT32_BE.get(buf, 4)
415
+ };
416
+ let dynOffset = 8;
417
+ if (header.flags.baseDataOffsetPresent) {
418
+ header.baseDataOffset = Token.UINT64_BE.get(buf, dynOffset);
419
+ dynOffset += 8;
420
+ }
421
+ if (header.flags.sampleDescriptionIndexPresent) {
422
+ header.sampleDescriptionIndex = Token.UINT32_BE.get(buf, dynOffset);
423
+ dynOffset += 4;
424
+ }
425
+ if (header.flags.defaultSampleDurationPresent) {
426
+ header.defaultSampleDuration = Token.UINT32_BE.get(buf, dynOffset);
427
+ dynOffset += 4;
428
+ }
429
+ if (header.flags.defaultSampleSizePresent) {
430
+ header.defaultSampleSize = Token.UINT32_BE.get(buf, dynOffset);
431
+ dynOffset += 4;
432
+ }
433
+ if (header.flags.defaultSampleFlagsPresent) {
434
+ header.defaultSampleFlags = Token.UINT32_BE.get(buf, dynOffset);
435
+ }
436
+ return header;
437
+ }
438
+ }
439
+ /**
440
+ * Sample-size ('trun') TrackRunBox
441
+ */
442
+ export class TrackRunBox {
443
+ constructor(len) {
444
+ this.len = len;
445
+ }
446
+ get(buf, off) {
447
+ const flagOffset = off + 1;
448
+ const trun = {
449
+ version: Token.INT8.get(buf, off),
450
+ flags: {
451
+ dataOffsetPresent: util.getBit(buf, flagOffset + 2, 0),
452
+ firstSampleFlagsPresent: util.getBit(buf, flagOffset + 2, 2),
453
+ sampleDurationPresent: util.getBit(buf, flagOffset + 1, 0),
454
+ sampleSizePresent: util.getBit(buf, flagOffset + 1, 1),
455
+ sampleFlagsPresent: util.getBit(buf, flagOffset + 1, 2),
456
+ sampleCompositionTimeOffsetsPresent: util.getBit(buf, flagOffset + 1, 3)
457
+ },
458
+ sampleCount: Token.UINT32_BE.get(buf, off + 4),
459
+ samples: []
460
+ };
461
+ let dynOffset = off + 8;
462
+ if (trun.flags.dataOffsetPresent) {
463
+ trun.dataOffset = Token.UINT32_BE.get(buf, dynOffset);
464
+ dynOffset += 4;
465
+ }
466
+ if (trun.flags.firstSampleFlagsPresent) {
467
+ trun.firstSampleFlags = Token.UINT32_BE.get(buf, dynOffset);
468
+ dynOffset += 4;
469
+ }
470
+ for (let n = 0; n < trun.sampleCount; ++n) {
471
+ if (dynOffset >= this.len) {
472
+ debug("TrackRunBox size mismatch");
473
+ break;
474
+ }
475
+ const sample = {};
476
+ if (trun.flags.sampleDurationPresent) {
477
+ sample.sampleDuration = Token.UINT32_BE.get(buf, dynOffset);
478
+ dynOffset += 4;
479
+ }
480
+ if (trun.flags.sampleSizePresent) {
481
+ sample.sampleSize = Token.UINT32_BE.get(buf, dynOffset);
482
+ dynOffset += 4;
483
+ }
484
+ if (trun.flags.sampleFlagsPresent) {
485
+ sample.sampleFlags = Token.UINT32_BE.get(buf, dynOffset);
486
+ dynOffset += 4;
487
+ }
488
+ if (trun.flags.sampleCompositionTimeOffsetsPresent) {
489
+ sample.sampleCompositionTimeOffset = Token.UINT32_BE.get(buf, dynOffset);
490
+ dynOffset += 4;
491
+ }
492
+ trun.samples.push(sample);
493
+ }
494
+ return trun;
495
+ }
496
+ }
393
497
  //# sourceMappingURL=AtomToken.js.map
@@ -4,6 +4,7 @@ export declare class MP4Parser extends BasicParser {
4
4
  private static read_BE_Integer;
5
5
  private audioLengthInBytes;
6
6
  private tracks;
7
+ private getTrackById;
7
8
  parse(): Promise<void>;
8
9
  handleAtom(atom: Atom, remaining: number): Promise<void>;
9
10
  private getTrackDescription;
@@ -17,6 +18,7 @@ export declare class MP4Parser extends BasicParser {
17
18
  */
18
19
  private parseMetadataItemData;
19
20
  private parseValueAtom;
21
+ private parseTrackFragmentBox;
20
22
  private atomParsers;
21
23
  /**
22
24
  * @param sampleDescription
@@ -127,6 +127,7 @@ export class MP4Parser extends BasicParser {
127
127
  },
128
128
  tkhd: async (len) => {
129
129
  const track = (await this.tokenizer.readToken(new AtomToken.TrackHeaderAtom(len)));
130
+ track.fragments = [];
130
131
  this.tracks.push(track);
131
132
  },
132
133
  /**
@@ -214,6 +215,9 @@ export class MP4Parser extends BasicParser {
214
215
  }
215
216
  return Number(token.get(array, 0));
216
217
  }
218
+ getTrackById(trackId) {
219
+ return this.tracks.find(track => track.trackId === trackId);
220
+ }
217
221
  async parse() {
218
222
  this.tracks = [];
219
223
  let remainingFileSize = this.tokenizer.fileInfo.size || 0;
@@ -280,8 +284,26 @@ export class MP4Parser extends BasicParser {
280
284
  if (audioTracks.length >= 1) {
281
285
  const audioTrack = audioTracks[0];
282
286
  if (audioTrack.timeScale > 0) {
283
- const duration = audioTrack.duration / audioTrack.timeScale; // calculate duration in seconds
284
- this.metadata.setFormat('duration', duration);
287
+ if (audioTrack.duration > 0) {
288
+ debug('Using duration defined on audio track');
289
+ const duration = audioTrack.duration / audioTrack.timeScale; // calculate duration in seconds
290
+ this.metadata.setFormat('duration', duration);
291
+ }
292
+ else if (audioTrack.fragments.length > 0) {
293
+ debug('Calculate duration defined in track fragments');
294
+ let totalTimeUnits = 0;
295
+ for (const fragment of audioTrack.fragments) {
296
+ const defaultDuration = fragment.header.defaultSampleDuration;
297
+ for (const sample of fragment.trackRun.samples) {
298
+ const dur = sample.sampleDuration ?? defaultDuration;
299
+ if (dur == null) {
300
+ throw new Error("Missing sampleDuration and no default_sample_duration in tfhd");
301
+ }
302
+ totalTimeUnits += dur;
303
+ }
304
+ }
305
+ this.metadata.setFormat('duration', totalTimeUnits / audioTrack.timeScale);
306
+ }
285
307
  }
286
308
  const ssd = audioTrack.soundSampleDescription[0];
287
309
  if (ssd.description) {
@@ -309,6 +331,11 @@ export class MP4Parser extends BasicParser {
309
331
  case 'ilst':
310
332
  case '<id>':
311
333
  return this.parseMetadataItemData(atom);
334
+ case 'moof':
335
+ switch (atom.header.name) {
336
+ case 'traf':
337
+ return this.parseTrackFragmentBox(atom);
338
+ }
312
339
  }
313
340
  }
314
341
  // const payloadLength = atom.getPayloadLength(remaining);
@@ -432,6 +459,35 @@ export class MP4Parser extends BasicParser {
432
459
  this.addWarning(`atom key=${tagKey}, has unknown well-known-type (data-type): ${dataAtom.type.type}`);
433
460
  }
434
461
  }
462
+ parseTrackFragmentBox(trafBox) {
463
+ let tfhd;
464
+ return trafBox.readAtoms(this.tokenizer, async (child, remaining) => {
465
+ const payLoadLength = child.getPayloadLength(remaining);
466
+ switch (child.header.name) {
467
+ case 'tfhd': { // TrackFragmentHeaderBox
468
+ const fragmentHeaderBox = new AtomToken.TrackFragmentHeaderBox(child.getPayloadLength(remaining));
469
+ tfhd = await this.tokenizer.readToken(fragmentHeaderBox);
470
+ break;
471
+ }
472
+ case 'tfdt': // TrackFragmentBaseMediaDecodeTimeBo
473
+ await this.tokenizer.ignore(payLoadLength);
474
+ break;
475
+ case 'trun': { // TrackRunBox
476
+ const trackRunBox = new AtomToken.TrackRunBox(payLoadLength);
477
+ const trun = await this.tokenizer.readToken(trackRunBox);
478
+ if (tfhd) {
479
+ const track = this.getTrackById(tfhd.trackId);
480
+ track?.fragments.push({ header: tfhd, trackRun: trun });
481
+ }
482
+ break;
483
+ }
484
+ default: {
485
+ debug(`Unexpected box: ${child.header.name}`);
486
+ await this.tokenizer.ignore(payLoadLength);
487
+ }
488
+ }
489
+ }, trafBox.getPayloadLength(0));
490
+ }
435
491
  /**
436
492
  * @param sampleDescription
437
493
  * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-128916
@@ -487,11 +543,6 @@ export class MP4Parser extends BasicParser {
487
543
  await this.tokenizer.ignore(len);
488
544
  }
489
545
  findSampleOffset(track, chapterOffset) {
490
- let totalDuration = 0;
491
- track.timeToSampleTable.forEach(e => {
492
- totalDuration += e.count * e.duration;
493
- });
494
- debug(`Total duration=${totalDuration}`);
495
546
  let chunkIndex = 0;
496
547
  while (chunkIndex < track.chunkOffsetTable.length && track.chunkOffsetTable[chunkIndex] < chapterOffset) {
497
548
  ++chunkIndex;
@@ -4,5 +4,5 @@ import type { INativeMetadataCollector } from "../common/MetadataCollector.js";
4
4
  export declare const tagType = "iTunes";
5
5
  export declare class MP4TagMapper extends CaseInsensitiveTagMap {
6
6
  constructor();
7
- protected postMap(tag: ITag, warnings: INativeMetadataCollector): void;
7
+ protected postMap(tag: ITag, _warnings: INativeMetadataCollector): void;
8
8
  }
@@ -110,7 +110,7 @@ export class MP4TagMapper extends CaseInsensitiveTagMap {
110
110
  constructor() {
111
111
  super([tagType], mp4TagMap);
112
112
  }
113
- postMap(tag, warnings) {
113
+ postMap(tag, _warnings) {
114
114
  switch (tag.id) {
115
115
  case 'rate':
116
116
  tag.value = {
@@ -1,6 +1,6 @@
1
1
  import initDebug from 'debug';
2
2
  import { BasicParser } from '../../common/BasicParser.js';
3
- import { APEv2Parser } from '../../apev2/APEv2Parser.js';
3
+ import { tryParseApeHeader } from '../../apev2/APEv2Parser.js';
4
4
  import { BitReader } from './BitReader.js';
5
5
  import * as SV7 from './StreamVersion7.js';
6
6
  import { MusepackContentError } from '../MusepackConentError.js';
@@ -29,7 +29,7 @@ export class MpcSv7Parser extends BasicParser {
29
29
  this.metadata.setFormat('codec', (version / 100).toFixed(2));
30
30
  await this.skipAudioData(header.frameCount);
31
31
  debug(`End of audio stream, switching to APEv2, offset=${this.tokenizer.position}`);
32
- return APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options);
32
+ return tryParseApeHeader(this.metadata, this.tokenizer, this.options);
33
33
  }
34
34
  async skipAudioData(frameCount) {
35
35
  while (frameCount-- > 0) {
@@ -1,6 +1,6 @@
1
1
  import initDebug from 'debug';
2
2
  import { BasicParser } from '../../common/BasicParser.js';
3
- import { APEv2Parser } from '../../apev2/APEv2Parser.js';
3
+ import { tryParseApeHeader } from '../../apev2/APEv2Parser.js';
4
4
  import { FourCcToken } from '../../common/FourCC.js';
5
5
  import * as SV8 from './StreamVersion8.js';
6
6
  import { MusepackContentError } from '../MusepackConentError.js';
@@ -46,7 +46,7 @@ export class MpcSv8Parser extends BasicParser {
46
46
  if (this.metadata.format.duration) {
47
47
  this.metadata.setFormat('bitrate', this.audioLength * 8 / this.metadata.format.duration);
48
48
  }
49
- return APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options);
49
+ return tryParseApeHeader(this.metadata, this.tokenizer, this.options);
50
50
  default:
51
51
  throw new MusepackContentError(`Unexpected header: ${header.key}`);
52
52
  }
@@ -18,7 +18,7 @@ export declare class OpusParser extends VorbisParser {
18
18
  * @param {IPageHeader} header
19
19
  * @param {Uint8Array} pageData
20
20
  */
21
- protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
21
+ protected parseFirstPage(_header: IPageHeader, pageData: Uint8Array): void;
22
22
  protected parseFullPage(pageData: Uint8Array): Promise<void>;
23
23
  calculateDuration(header: IPageHeader): void;
24
24
  }
@@ -19,7 +19,7 @@ export class OpusParser extends VorbisParser {
19
19
  * @param {IPageHeader} header
20
20
  * @param {Uint8Array} pageData
21
21
  */
22
- parseFirstPage(header, pageData) {
22
+ parseFirstPage(_header, pageData) {
23
23
  this.metadata.setFormat('codec', 'Opus');
24
24
  // Parse Opus ID Header
25
25
  this.idHeader = new Opus.IdHeader(pageData.length).get(pageData, 0);
@@ -17,5 +17,5 @@ export declare class SpeexParser extends VorbisParser {
17
17
  * @param {IPageHeader} header
18
18
  * @param {Uint8Array} pageData
19
19
  */
20
- protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
20
+ protected parseFirstPage(_header: IPageHeader, pageData: Uint8Array): void;
21
21
  }
@@ -18,7 +18,7 @@ export class SpeexParser extends VorbisParser {
18
18
  * @param {IPageHeader} header
19
19
  * @param {Uint8Array} pageData
20
20
  */
21
- parseFirstPage(header, pageData) {
21
+ parseFirstPage(_header, pageData) {
22
22
  debug('First Ogg/Speex page');
23
23
  const speexHeader = Speex.Header.get(pageData, 0);
24
24
  this.metadata.setFormat('codec', `Speex ${speexHeader.version}`);
@@ -9,7 +9,7 @@ import type { INativeMetadataCollector } from '../../common/MetadataCollector.js
9
9
  export declare class TheoraParser implements Ogg.IPageConsumer {
10
10
  private metadata;
11
11
  private tokenizer;
12
- constructor(metadata: INativeMetadataCollector, options: IOptions, tokenizer: ITokenizer);
12
+ constructor(metadata: INativeMetadataCollector, _options: IOptions, tokenizer: ITokenizer);
13
13
  /**
14
14
  * Vorbis 1 parser
15
15
  * @param header Ogg Page Header
@@ -17,11 +17,9 @@ export declare class TheoraParser implements Ogg.IPageConsumer {
17
17
  */
18
18
  parsePage(header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
19
19
  flush(): Promise<void>;
20
- calculateDuration(header: Ogg.IPageHeader): void;
20
+ calculateDuration(_header: Ogg.IPageHeader): void;
21
21
  /**
22
22
  * Parse first Theora Ogg page. the initial identification header packet
23
- * @param {IPageHeader} header
24
- * @param {Buffer} pageData
25
23
  */
26
- protected parseFirstPage(header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
24
+ protected parseFirstPage(_header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
27
25
  }
@@ -6,7 +6,7 @@ const debug = initDebug('music-metadata:parser:ogg:theora');
6
6
  * - https://theora.org/doc/Theora.pdf
7
7
  */
8
8
  export class TheoraParser {
9
- constructor(metadata, options, tokenizer) {
9
+ constructor(metadata, _options, tokenizer) {
10
10
  this.metadata = metadata;
11
11
  this.tokenizer = tokenizer;
12
12
  }
@@ -23,15 +23,13 @@ export class TheoraParser {
23
23
  async flush() {
24
24
  debug('flush');
25
25
  }
26
- calculateDuration(header) {
26
+ calculateDuration(_header) {
27
27
  debug('duration calculation not implemented');
28
28
  }
29
29
  /**
30
30
  * Parse first Theora Ogg page. the initial identification header packet
31
- * @param {IPageHeader} header
32
- * @param {Buffer} pageData
33
31
  */
34
- async parseFirstPage(header, pageData) {
32
+ async parseFirstPage(_header, pageData) {
35
33
  debug('First Ogg/Theora page');
36
34
  this.metadata.setFormat('codec', 'Theora');
37
35
  const idHeader = IdentificationHeader.get(pageData, 0);
@@ -41,7 +41,7 @@ export declare class VorbisParser implements IPageConsumer {
41
41
  * @param header
42
42
  * @param pageData
43
43
  */
44
- protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
44
+ protected parseFirstPage(_header: IPageHeader, pageData: Uint8Array): void;
45
45
  protected parseFullPage(pageData: Uint8Array): Promise<void>;
46
46
  /**
47
47
  * Ref: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-840005.2
@@ -90,7 +90,7 @@ export class VorbisParser {
90
90
  * @param header
91
91
  * @param pageData
92
92
  */
93
- parseFirstPage(header, pageData) {
93
+ parseFirstPage(_header, pageData) {
94
94
  this.metadata.setFormat('codec', 'Vorbis I');
95
95
  debug('Parse first page');
96
96
  // Parse Vorbis common header
@@ -1,5 +1,5 @@
1
1
  import * as Token from 'token-types';
2
- import { APEv2Parser } from '../apev2/APEv2Parser.js';
2
+ import { tryParseApeHeader } from '../apev2/APEv2Parser.js';
3
3
  import { FourCcToken } from '../common/FourCC.js';
4
4
  import { BasicParser } from '../common/BasicParser.js';
5
5
  import { BlockHeaderToken, MetadataIdToken } from './WavPackToken.js';
@@ -22,7 +22,7 @@ export class WavPackParser extends BasicParser {
22
22
  // First parse all WavPack blocks
23
23
  await this.parseWavPackBlocks();
24
24
  // try to parse APEv2 header
25
- return APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options);
25
+ return tryParseApeHeader(this.metadata, this.tokenizer, this.options);
26
26
  }
27
27
  async parseWavPackBlocks() {
28
28
  do {