music-metadata 11.5.0 → 11.6.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.
@@ -4,7 +4,7 @@ import * as util from '../common/Util.js';
4
4
  import { VorbisPictureToken } from '../ogg/vorbis/Vorbis.js';
5
5
  import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
6
6
  import { FourCcToken } from '../common/FourCC.js';
7
- import { VorbisParser } from '../ogg/vorbis/VorbisParser.js';
7
+ import { VorbisStream } from '../ogg/vorbis/VorbisStream.js';
8
8
  import { VorbisDecoder } from '../ogg/vorbis/VorbisDecoder.js';
9
9
  import { makeUnexpectedFileContentError } from '../ParseError.js';
10
10
  const debug = initDebug('music-metadata:parser:FLAC');
@@ -26,7 +26,7 @@ const BlockType = {
26
26
  export class FlacParser extends AbstractID3Parser {
27
27
  constructor() {
28
28
  super(...arguments);
29
- this.vorbisParser = new VorbisParser(this.metadata, this.options);
29
+ this.vorbisParser = new VorbisStream(this.metadata, this.options);
30
30
  this.padding = 0;
31
31
  }
32
32
  async postId3v2Parse() {
@@ -1,6 +1,4 @@
1
- import { type IGetToken } from 'strtok3';
2
1
  import { BasicParser } from '../common/BasicParser.js';
3
- import type * as Ogg from './Ogg.js';
4
2
  declare const OggContentError_base: {
5
3
  new (message: string): {
6
4
  readonly fileType: string;
@@ -15,20 +13,11 @@ declare const OggContentError_base: {
15
13
  };
16
14
  export declare class OggContentError extends OggContentError_base {
17
15
  }
18
- export declare class SegmentTable implements IGetToken<Ogg.ISegmentTable> {
19
- private static sum;
20
- len: number;
21
- constructor(header: Ogg.IPageHeader);
22
- get(buf: Uint8Array, off: number): Ogg.ISegmentTable;
23
- }
24
16
  /**
25
17
  * Parser for Ogg logical bitstream framing
26
18
  */
27
19
  export declare class OggParser extends BasicParser {
28
- private static Header;
29
- private header;
30
- private pageNumber;
31
- private pageConsumer;
20
+ private streams;
32
21
  /**
33
22
  * Parse page
34
23
  * @returns {Promise<void>}
@@ -1,33 +1,70 @@
1
1
  import * as Token from 'token-types';
2
2
  import { EndOfStreamError } from 'strtok3';
3
3
  import initDebug from 'debug';
4
- import * as util from '../common/Util.js';
5
- import { FourCcToken } from '../common/FourCC.js';
6
4
  import { BasicParser } from '../common/BasicParser.js';
7
- import { VorbisParser } from './vorbis/VorbisParser.js';
8
- import { OpusParser } from './opus/OpusParser.js';
9
- import { SpeexParser } from './speex/SpeexParser.js';
10
- import { TheoraParser } from './theora/TheoraParser.js';
5
+ import { VorbisStream } from './vorbis/VorbisStream.js';
6
+ import { OpusStream } from './opus/OpusStream.js';
7
+ import { SpeexStream } from './speex/SpeexStream.js';
8
+ import { TheoraStream } from './theora/TheoraStream.js';
11
9
  import { makeUnexpectedFileContentError } from '../ParseError.js';
10
+ import { PageHeader, SegmentTable } from './OggToken.js';
12
11
  export class OggContentError extends makeUnexpectedFileContentError('Ogg') {
13
12
  }
14
13
  const debug = initDebug('music-metadata:parser:ogg');
15
- export class SegmentTable {
16
- static sum(buf, off, len) {
17
- const dv = new DataView(buf.buffer, 0);
18
- let s = 0;
19
- for (let i = off; i < off + len; ++i) {
20
- s += dv.getUint8(i);
21
- }
22
- return s;
23
- }
24
- constructor(header) {
25
- this.len = header.page_segments;
14
+ class OggStream {
15
+ constructor(metadata, streamSerial, options) {
16
+ this.pageNumber = 0;
17
+ this.closed = false;
18
+ this.metadata = metadata;
19
+ this.streamSerial = streamSerial;
20
+ this.options = options;
26
21
  }
27
- get(buf, off) {
28
- return {
29
- totalPageSize: SegmentTable.sum(buf, off, this.len)
30
- };
22
+ async parsePage(tokenizer, header) {
23
+ this.pageNumber = header.pageSequenceNo;
24
+ debug('serial=%s page#=%s, Ogg.id=%s', header.streamSerialNumber, header.pageSequenceNo, header.capturePattern);
25
+ const segmentTable = await tokenizer.readToken(new SegmentTable(header));
26
+ debug('totalPageSize=%s', segmentTable.totalPageSize);
27
+ const pageData = await tokenizer.readToken(new Token.Uint8ArrayType(segmentTable.totalPageSize));
28
+ debug('firstPage=%s, lastPage=%s, continued=%s', header.headerType.firstPage, header.headerType.lastPage, header.headerType.continued);
29
+ if (header.headerType.firstPage) {
30
+ const idData = pageData.slice(0, 7); // Copy this portion
31
+ switch (idData[0]) {
32
+ case 0x01:
33
+ case 0x80:
34
+ idData[0] = 0x5F; // underscore
35
+ break;
36
+ }
37
+ const id = new TextDecoder('latin1').decode(idData);
38
+ switch (id) {
39
+ case '_vorbis': // Ogg/Vorbis
40
+ debug(`Set Ogg stream serial ${header.streamSerialNumber}, codec=Vorbis`);
41
+ this.pageConsumer = new VorbisStream(this.metadata, this.options);
42
+ break;
43
+ case 'OpusHea': // Ogg/Opus
44
+ debug('Set page consumer to Ogg/Opus');
45
+ this.pageConsumer = new OpusStream(this.metadata, this.options, tokenizer);
46
+ break;
47
+ case 'Speex ': // Ogg/Speex
48
+ debug('Set page consumer to Ogg/Speex');
49
+ this.pageConsumer = new SpeexStream(this.metadata, this.options, tokenizer);
50
+ break;
51
+ case 'fishead':
52
+ case '_theora': // Ogg/Theora
53
+ debug('Set page consumer to Ogg/Theora');
54
+ this.pageConsumer = new TheoraStream(this.metadata, this.options, tokenizer);
55
+ break;
56
+ default:
57
+ throw new OggContentError(`Ogg codec not recognized (id=${id})`);
58
+ }
59
+ }
60
+ if (header.headerType.lastPage) {
61
+ this.closed = true;
62
+ }
63
+ if (this.pageConsumer) {
64
+ await this.pageConsumer.parsePage(header, pageData);
65
+ }
66
+ else
67
+ throw new Error('pageConsumer should be initialized');
31
68
  }
32
69
  }
33
70
  /**
@@ -36,98 +73,47 @@ export class SegmentTable {
36
73
  export class OggParser extends BasicParser {
37
74
  constructor() {
38
75
  super(...arguments);
39
- this.header = null;
40
- this.pageNumber = 0;
41
- this.pageConsumer = null;
76
+ this.streams = new Map();
42
77
  }
43
78
  /**
44
79
  * Parse page
45
80
  * @returns {Promise<void>}
46
81
  */
47
82
  async parse() {
83
+ this.streams = new Map();
48
84
  debug('pos=%s, parsePage()', this.tokenizer.position);
85
+ let header;
49
86
  try {
50
- let header;
51
87
  do {
52
- header = await this.tokenizer.readToken(OggParser.Header);
88
+ header = await this.tokenizer.readToken(PageHeader);
53
89
  if (header.capturePattern !== 'OggS')
54
90
  throw new OggContentError('Invalid Ogg capture pattern');
55
91
  this.metadata.setFormat('container', 'Ogg');
56
- this.header = header;
57
- this.pageNumber = header.pageSequenceNo;
58
- debug('page#=%s, Ogg.id=%s', header.pageSequenceNo, header.capturePattern);
59
- const segmentTable = await this.tokenizer.readToken(new SegmentTable(header));
60
- debug('totalPageSize=%s', segmentTable.totalPageSize);
61
- const pageData = await this.tokenizer.readToken(new Token.Uint8ArrayType(segmentTable.totalPageSize));
62
- debug('firstPage=%s, lastPage=%s, continued=%s', header.headerType.firstPage, header.headerType.lastPage, header.headerType.continued);
63
- if (header.headerType.firstPage) {
64
- const id = new TextDecoder('ascii').decode(pageData.subarray(0, 7));
65
- switch (id) {
66
- case '\x01vorbis': // Ogg/Vorbis
67
- debug('Set page consumer to Ogg/Vorbis');
68
- this.pageConsumer = new VorbisParser(this.metadata, this.options);
69
- break;
70
- case 'OpusHea': // Ogg/Opus
71
- debug('Set page consumer to Ogg/Opus');
72
- this.pageConsumer = new OpusParser(this.metadata, this.options, this.tokenizer);
73
- break;
74
- case 'Speex ': // Ogg/Speex
75
- debug('Set page consumer to Ogg/Speex');
76
- this.pageConsumer = new SpeexParser(this.metadata, this.options, this.tokenizer);
77
- break;
78
- case 'fishead':
79
- case '\x00theora': // Ogg/Theora
80
- debug('Set page consumer to Ogg/Theora');
81
- this.pageConsumer = new TheoraParser(this.metadata, this.options, this.tokenizer);
82
- break;
83
- default:
84
- throw new OggContentError(`gg audio-codec not recognized (id=${id})`);
85
- }
92
+ let stream = this.streams.get(header.streamSerialNumber);
93
+ if (!stream) {
94
+ stream = new OggStream(this.metadata, header.streamSerialNumber, this.options);
95
+ this.streams.set(header.streamSerialNumber, stream);
86
96
  }
87
- await this.pageConsumer.parsePage(header, pageData);
88
- } while (!header.headerType.lastPage);
97
+ await stream.parsePage(this.tokenizer, header);
98
+ } while (![...this.streams.values()].every(item => item.closed));
89
99
  }
90
100
  catch (err) {
91
- if (err instanceof Error) {
92
- if (err instanceof EndOfStreamError) {
93
- this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
94
- debug("End-of-stream");
95
- this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
96
- if (this.header) {
97
- this.pageConsumer.calculateDuration(this.header);
98
- }
99
- }
100
- else if (err.message.startsWith('FourCC')) {
101
- if (this.pageNumber > 0) {
102
- // ignore this error: work-around if last OGG-page is not marked with last-page flag
103
- this.metadata.addWarning('Invalid FourCC ID, maybe last OGG-page is not marked with last-page flag');
104
- await this.pageConsumer.flush();
105
- }
106
- }
101
+ if (err instanceof EndOfStreamError) {
102
+ debug("Reached end-of-stream");
103
+ }
104
+ else if (err instanceof OggContentError) {
105
+ this.metadata.addWarning(`Corrupt Ogg content at ${this.tokenizer.position}`);
107
106
  }
108
107
  else
109
108
  throw err;
110
109
  }
110
+ for (const stream of this.streams.values()) {
111
+ if (!stream.closed) {
112
+ this.metadata.addWarning(`End-of-stream reached before reaching last page in Ogg stream serial=${stream.streamSerial}`);
113
+ await stream.pageConsumer?.flush();
114
+ }
115
+ stream.pageConsumer?.calculateDuration();
116
+ }
111
117
  }
112
118
  }
113
- OggParser.Header = {
114
- len: 27,
115
- get: (buf, off) => {
116
- return {
117
- capturePattern: FourCcToken.get(buf, off),
118
- version: Token.UINT8.get(buf, off + 4),
119
- headerType: {
120
- continued: util.getBit(buf, off + 5, 0),
121
- firstPage: util.getBit(buf, off + 5, 1),
122
- lastPage: util.getBit(buf, off + 5, 2)
123
- },
124
- // packet_flag: Token.UINT8.get(buf, off + 5),
125
- absoluteGranulePosition: Number(Token.UINT64_LE.get(buf, off + 6)),
126
- streamSerialNumber: Token.UINT32_LE.get(buf, off + 14),
127
- pageSequenceNo: Token.UINT32_LE.get(buf, off + 18),
128
- pageChecksum: Token.UINT32_LE.get(buf, off + 22),
129
- page_segments: Token.UINT8.get(buf, off + 26)
130
- };
131
- }
132
- };
133
119
  //# sourceMappingURL=OggParser.js.map
@@ -1,3 +1,4 @@
1
+ import type { IGetToken } from 'strtok3';
1
2
  /**
2
3
  * Page header
3
4
  * Ref: https://www.xiph.org/ogg/doc/framing.html#page_header
@@ -50,21 +51,27 @@ export interface IPageHeader {
50
51
  */
51
52
  page_segments: number;
52
53
  }
54
+ export declare const PageHeader: IGetToken<IPageHeader>;
53
55
  export interface ISegmentTable {
54
56
  totalPageSize: number;
55
57
  }
58
+ export declare class SegmentTable implements IGetToken<ISegmentTable> {
59
+ private static sum;
60
+ len: number;
61
+ constructor(header: IPageHeader);
62
+ get(buf: Uint8Array, off: number): ISegmentTable;
63
+ }
56
64
  export interface IPageConsumer {
57
65
  /**
58
66
  * Parse Ogg page
59
- * @param {IPageHeader} header Ogg page header
60
- * @param {Buffer} pageData Ogg page data
67
+ * @param header Ogg page header
68
+ * @param pageData Ogg page data
61
69
  */
62
70
  parsePage(header: IPageHeader, pageData: Uint8Array): Promise<void>;
63
71
  /**
64
72
  * Calculate duration of provided header
65
- * @param header Ogg header
66
73
  */
67
- calculateDuration(header: IPageHeader): void;
74
+ calculateDuration(): void;
68
75
  /**
69
76
  * Force to parse pending segments
70
77
  */
@@ -0,0 +1,42 @@
1
+ import * as Token from 'token-types';
2
+ import * as util from '../common/Util.js';
3
+ import { StringType } from 'token-types';
4
+ export const PageHeader = {
5
+ len: 27,
6
+ get: (buf, off) => {
7
+ return {
8
+ capturePattern: new StringType(4, 'latin1').get(buf, off),
9
+ version: Token.UINT8.get(buf, off + 4),
10
+ headerType: {
11
+ continued: util.getBit(buf, off + 5, 0),
12
+ firstPage: util.getBit(buf, off + 5, 1),
13
+ lastPage: util.getBit(buf, off + 5, 2)
14
+ },
15
+ // packet_flag: Token.UINT8.get(buf, off + 5),
16
+ absoluteGranulePosition: Number(Token.UINT64_LE.get(buf, off + 6)),
17
+ streamSerialNumber: Token.UINT32_LE.get(buf, off + 14),
18
+ pageSequenceNo: Token.UINT32_LE.get(buf, off + 18),
19
+ pageChecksum: Token.UINT32_LE.get(buf, off + 22),
20
+ page_segments: Token.UINT8.get(buf, off + 26)
21
+ };
22
+ }
23
+ };
24
+ export class SegmentTable {
25
+ static sum(buf, off, len) {
26
+ const dv = new DataView(buf.buffer, 0);
27
+ let s = 0;
28
+ for (let i = off; i < off + len; ++i) {
29
+ s += dv.getUint8(i);
30
+ }
31
+ return s;
32
+ }
33
+ constructor(header) {
34
+ this.len = header.page_segments;
35
+ }
36
+ get(buf, off) {
37
+ return {
38
+ totalPageSize: SegmentTable.sum(buf, off, this.len)
39
+ };
40
+ }
41
+ }
42
+ //# sourceMappingURL=OggToken.js.map
@@ -1,14 +1,14 @@
1
1
  import type { ITokenizer } from 'strtok3';
2
- import type { IPageHeader } from '../Ogg.js';
3
- import { VorbisParser } from '../vorbis/VorbisParser.js';
2
+ import type { IPageHeader } from '../OggToken.js';
3
+ import { VorbisStream } from '../vorbis/VorbisStream.js';
4
4
  import type { IOptions } from '../../type.js';
5
5
  import type { INativeMetadataCollector } from '../../common/MetadataCollector.js';
6
6
  /**
7
7
  * Opus parser
8
8
  * Internet Engineering Task Force (IETF) - RFC 6716
9
- * Used by OggParser
9
+ * Used by OggStream
10
10
  */
11
- export declare class OpusParser extends VorbisParser {
11
+ export declare class OpusStream extends VorbisStream {
12
12
  private idHeader;
13
13
  private lastPos;
14
14
  private tokenizer;
@@ -20,5 +20,5 @@ export declare class OpusParser extends VorbisParser {
20
20
  */
21
21
  protected parseFirstPage(_header: IPageHeader, pageData: Uint8Array): void;
22
22
  protected parseFullPage(pageData: Uint8Array): Promise<void>;
23
- calculateDuration(header: IPageHeader): void;
23
+ calculateDuration(): void;
24
24
  }
@@ -1,13 +1,13 @@
1
1
  import * as Token from 'token-types';
2
- import { VorbisParser } from '../vorbis/VorbisParser.js';
2
+ import { VorbisStream } from '../vorbis/VorbisStream.js';
3
3
  import * as Opus from './Opus.js';
4
4
  import { OpusContentError } from './Opus.js';
5
5
  /**
6
6
  * Opus parser
7
7
  * Internet Engineering Task Force (IETF) - RFC 6716
8
- * Used by OggParser
8
+ * Used by OggStream
9
9
  */
10
- export class OpusParser extends VorbisParser {
10
+ export class OpusStream extends VorbisStream {
11
11
  constructor(metadata, options, tokenizer) {
12
12
  super(metadata, options);
13
13
  this.idHeader = null;
@@ -40,10 +40,10 @@ export class OpusParser extends VorbisParser {
40
40
  break;
41
41
  }
42
42
  }
43
- calculateDuration(header) {
44
- if (this.metadata.format.sampleRate && header.absoluteGranulePosition >= 0) {
43
+ calculateDuration() {
44
+ if (this.lastPageHeader && this.metadata.format.sampleRate && this.lastPageHeader.absoluteGranulePosition >= 0) {
45
45
  // Calculate duration
46
- const pos_48bit = header.absoluteGranulePosition - this.idHeader.preSkip;
46
+ const pos_48bit = this.lastPageHeader.absoluteGranulePosition - this.idHeader.preSkip;
47
47
  this.metadata.setFormat('numberOfSamples', pos_48bit);
48
48
  this.metadata.setFormat('duration', pos_48bit / 48000);
49
49
  if (this.lastPos !== -1 && this.tokenizer.fileInfo.size && this.metadata.format.duration) {
@@ -53,4 +53,4 @@ export class OpusParser extends VorbisParser {
53
53
  }
54
54
  }
55
55
  }
56
- //# sourceMappingURL=OpusParser.js.map
56
+ //# sourceMappingURL=OpusStream.js.map
@@ -1,6 +1,6 @@
1
1
  import type { ITokenizer } from 'strtok3';
2
- import type { IPageHeader } from '../Ogg.js';
3
- import { VorbisParser } from '../vorbis/VorbisParser.js';
2
+ import type { IPageHeader } from '../OggToken.js';
3
+ import { VorbisStream } from '../vorbis/VorbisStream.js';
4
4
  import type { IOptions } from '../../type.js';
5
5
  import type { INativeMetadataCollector } from '../../common/MetadataCollector.js';
6
6
  /**
@@ -9,7 +9,7 @@ import type { INativeMetadataCollector } from '../../common/MetadataCollector.js
9
9
  * - https://www.speex.org/docs/manual/speex-manual/
10
10
  * - https://tools.ietf.org/html/rfc5574
11
11
  */
12
- export declare class SpeexParser extends VorbisParser {
12
+ export declare class SpeexStream extends VorbisStream {
13
13
  private tokenizer;
14
14
  constructor(metadata: INativeMetadataCollector, options: IOptions, tokenizer: ITokenizer);
15
15
  /**
@@ -1,5 +1,5 @@
1
1
  import initDebug from 'debug';
2
- import { VorbisParser } from '../vorbis/VorbisParser.js';
2
+ import { VorbisStream } from '../vorbis/VorbisStream.js';
3
3
  import * as Speex from './Speex.js';
4
4
  const debug = initDebug('music-metadata:parser:ogg:speex');
5
5
  /**
@@ -8,7 +8,7 @@ const debug = initDebug('music-metadata:parser:ogg:speex');
8
8
  * - https://www.speex.org/docs/manual/speex-manual/
9
9
  * - https://tools.ietf.org/html/rfc5574
10
10
  */
11
- export class SpeexParser extends VorbisParser {
11
+ export class SpeexStream extends VorbisStream {
12
12
  constructor(metadata, options, tokenizer) {
13
13
  super(metadata, options);
14
14
  this.tokenizer = tokenizer;
@@ -30,4 +30,4 @@ export class SpeexParser extends VorbisParser {
30
30
  this.metadata.setAudioOnly();
31
31
  }
32
32
  }
33
- //# sourceMappingURL=SpeexParser.js.map
33
+ //# sourceMappingURL=SpeexStream.js.map
@@ -1,12 +1,12 @@
1
1
  import type { ITokenizer } from 'strtok3';
2
- import type * as Ogg from '../Ogg.js';
2
+ import type * as Ogg from '../OggToken.js';
3
3
  import type { IOptions } from '../../type.js';
4
4
  import type { INativeMetadataCollector } from '../../common/MetadataCollector.js';
5
5
  /**
6
6
  * Ref:
7
7
  * - https://theora.org/doc/Theora.pdf
8
8
  */
9
- export declare class TheoraParser implements Ogg.IPageConsumer {
9
+ export declare class TheoraStream implements Ogg.IPageConsumer {
10
10
  private metadata;
11
11
  private tokenizer;
12
12
  constructor(metadata: INativeMetadataCollector, _options: IOptions, tokenizer: ITokenizer);
@@ -16,10 +16,10 @@ export declare class TheoraParser implements Ogg.IPageConsumer {
16
16
  * @param pageData Page data
17
17
  */
18
18
  parsePage(header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
19
- flush(): Promise<void>;
20
- calculateDuration(_header: Ogg.IPageHeader): void;
19
+ calculateDuration(): void;
21
20
  /**
22
21
  * Parse first Theora Ogg page. the initial identification header packet
23
22
  */
24
23
  protected parseFirstPage(_header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
24
+ flush(): Promise<void>;
25
25
  }
@@ -5,7 +5,7 @@ const debug = initDebug('music-metadata:parser:ogg:theora');
5
5
  * Ref:
6
6
  * - https://theora.org/doc/Theora.pdf
7
7
  */
8
- export class TheoraParser {
8
+ export class TheoraStream {
9
9
  constructor(metadata, _options, tokenizer) {
10
10
  this.metadata = metadata;
11
11
  this.tokenizer = tokenizer;
@@ -20,10 +20,7 @@ export class TheoraParser {
20
20
  await this.parseFirstPage(header, pageData);
21
21
  }
22
22
  }
23
- async flush() {
24
- debug('flush');
25
- }
26
- calculateDuration(_header) {
23
+ calculateDuration() {
27
24
  debug('duration calculation not implemented');
28
25
  }
29
26
  /**
@@ -34,7 +31,10 @@ export class TheoraParser {
34
31
  this.metadata.setFormat('codec', 'Theora');
35
32
  const idHeader = IdentificationHeader.get(pageData, 0);
36
33
  this.metadata.setFormat('bitrate', idHeader.nombr);
37
- this.metadata.setAudioOnly();
34
+ this.metadata.setFormat('hasVideo', true);
35
+ }
36
+ flush() {
37
+ return Promise.resolve();
38
38
  }
39
39
  }
40
- //# sourceMappingURL=TheoraParser.js.map
40
+ //# sourceMappingURL=TheoraStream.js.map
@@ -1,5 +1,5 @@
1
1
  import { type IVorbisPicture } from './Vorbis.js';
2
- import type { IPageConsumer, IPageHeader } from '../Ogg.js';
2
+ import type { IPageConsumer, IPageHeader } from '../OggToken.js';
3
3
  import type { IOptions } from '../../type.js';
4
4
  import type { INativeMetadataCollector } from '../../common/MetadataCollector.js';
5
5
  declare const VorbisContentError_base: {
@@ -18,12 +18,13 @@ export declare class VorbisContentError extends VorbisContentError_base {
18
18
  }
19
19
  /**
20
20
  * Vorbis 1 Parser.
21
- * Used by OggParser
21
+ * Used by OggStream
22
22
  */
23
- export declare class VorbisParser implements IPageConsumer {
23
+ export declare class VorbisStream implements IPageConsumer {
24
24
  private pageSegments;
25
25
  protected metadata: INativeMetadataCollector;
26
26
  protected options: IOptions;
27
+ protected lastPageHeader?: IPageHeader;
27
28
  constructor(metadata: INativeMetadataCollector, options: IOptions);
28
29
  /**
29
30
  * Vorbis 1 parser
@@ -35,7 +36,7 @@ export declare class VorbisParser implements IPageConsumer {
35
36
  flush(): Promise<void>;
36
37
  parseUserComment(pageData: Uint8Array, offset: number): Promise<number>;
37
38
  addTag(id: string, value: string | IVorbisPicture): Promise<void>;
38
- calculateDuration(header: IPageHeader): void;
39
+ calculateDuration(): void;
39
40
  /**
40
41
  * Parse first Ogg/Vorbis page
41
42
  * @param header
@@ -8,9 +8,9 @@ export class VorbisContentError extends makeUnexpectedFileContentError('Vorbis')
8
8
  }
9
9
  /**
10
10
  * Vorbis 1 Parser.
11
- * Used by OggParser
11
+ * Used by OggStream
12
12
  */
13
- export class VorbisParser {
13
+ export class VorbisStream {
14
14
  constructor(metadata, options) {
15
15
  this.pageSegments = [];
16
16
  this.metadata = metadata;
@@ -22,6 +22,7 @@ export class VorbisParser {
22
22
  * @param pageData Page data
23
23
  */
24
24
  async parsePage(header, pageData) {
25
+ this.lastPageHeader = header;
25
26
  if (header.headerType.firstPage) {
26
27
  this.parseFirstPage(header, pageData);
27
28
  }
@@ -35,16 +36,13 @@ export class VorbisParser {
35
36
  if (header.headerType.lastPage || !header.headerType.continued) {
36
37
  // Flush page segments
37
38
  if (this.pageSegments.length > 0) {
38
- const fullPage = VorbisParser.mergeUint8Arrays(this.pageSegments);
39
+ const fullPage = VorbisStream.mergeUint8Arrays(this.pageSegments);
39
40
  await this.parseFullPage(fullPage);
40
41
  }
41
42
  // Reset page segments
42
43
  this.pageSegments = header.headerType.lastPage ? [] : [pageData];
43
44
  }
44
45
  }
45
- if (header.headerType.lastPage) {
46
- this.calculateDuration(header);
47
- }
48
46
  }
49
47
  static mergeUint8Arrays(arrays) {
50
48
  const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
@@ -56,7 +54,7 @@ export class VorbisParser {
56
54
  return merged;
57
55
  }
58
56
  async flush() {
59
- await this.parseFullPage(VorbisParser.mergeUint8Arrays(this.pageSegments));
57
+ await this.parseFullPage(VorbisStream.mergeUint8Arrays(this.pageSegments));
60
58
  }
61
59
  async parseUserComment(pageData, offset) {
62
60
  const decoder = new VorbisDecoder(pageData, offset);
@@ -78,11 +76,11 @@ export class VorbisParser {
78
76
  }
79
77
  await this.metadata.addTag('vorbis', id, value);
80
78
  }
81
- calculateDuration(header) {
82
- if (this.metadata.format.sampleRate && header.absoluteGranulePosition >= 0) {
79
+ calculateDuration() {
80
+ if (this.lastPageHeader && this.metadata.format.sampleRate && this.lastPageHeader.absoluteGranulePosition >= 0) {
83
81
  // Calculate duration
84
- this.metadata.setFormat('numberOfSamples', header.absoluteGranulePosition);
85
- this.metadata.setFormat('duration', header.absoluteGranulePosition / this.metadata.format.sampleRate);
82
+ this.metadata.setFormat('numberOfSamples', this.lastPageHeader.absoluteGranulePosition);
83
+ this.metadata.setFormat('duration', this.lastPageHeader.absoluteGranulePosition / this.metadata.format.sampleRate);
86
84
  }
87
85
  }
88
86
  /**
@@ -92,7 +90,7 @@ export class VorbisParser {
92
90
  */
93
91
  parseFirstPage(_header, pageData) {
94
92
  this.metadata.setFormat('codec', 'Vorbis I');
95
- this.metadata.setAudioOnly();
93
+ this.metadata.setFormat('hasAudio', true);
96
94
  debug('Parse first page');
97
95
  // Parse Vorbis common header
98
96
  const commonHeader = CommonHeader.get(pageData, 0);
@@ -135,4 +133,4 @@ export class VorbisParser {
135
133
  }
136
134
  }
137
135
  }
138
- //# sourceMappingURL=VorbisParser.js.map
136
+ //# sourceMappingURL=VorbisStream.js.map