diff --git a/play-dl/YouTube/classes/SeekStream.ts b/play-dl/YouTube/classes/SeekStream.ts index 423d8af..9114ea2 100644 --- a/play-dl/YouTube/classes/SeekStream.ts +++ b/play-dl/YouTube/classes/SeekStream.ts @@ -65,7 +65,6 @@ export class SeekStream { this.stream = new WebmSeeker({ highWaterMark: 5 * 1000 * 1000, readableObjectMode: true, - mode: options.seekMode }); this.url = url; this.quality = options.quality as number; diff --git a/play-dl/YouTube/classes/WebmSeeker.ts b/play-dl/YouTube/classes/WebmSeeker.ts index 121c975..a7876a9 100644 --- a/play-dl/YouTube/classes/WebmSeeker.ts +++ b/play-dl/YouTube/classes/WebmSeeker.ts @@ -23,13 +23,11 @@ const WEB_ELEMENT_KEYS = Object.keys(WebmElements); export class WebmSeeker extends Duplex { remaining?: Buffer; state: WebmSeekerState; - mode: 'precise' | 'granular'; chunk?: Buffer; cursor: number; header: WebmHeader; headfound: boolean; headerparsed: boolean; - time_left: number; seekfound: boolean; private data_size: number; private data_length: number; @@ -40,11 +38,9 @@ export class WebmSeeker extends Duplex { this.cursor = 0; this.header = new WebmHeader(); this.headfound = false; - this.time_left = 0; this.headerparsed = false; this.seekfound = false; this.data_length = 0; - this.mode = options.mode || 'granular'; this.data_size = 0; } @@ -75,21 +71,22 @@ export class WebmSeeker extends Duplex { _read() {} - seek(sec: number): Error | number { - let position = 0; + seek(sec : number): Error | number{ + let clusterlength = 0, position = 0; const time = Math.floor(sec / 10) * 10; - this.time_left = (sec - time) * 1000 || 0; - this.time_left = Math.round(this.time_left / 20) * 20; + let time_left = (sec - time) * 1000 || 0; + time_left = Math.round(time_left / 20) * 20; if (!this.header.segment.cues) return new Error('Failed to Parse Cues'); - for (const data of this.header.segment.cues) { + for (let i = 0; i < this.header.segment.cues.length; i++) { + const data = this.header.segment.cues[i] if (Math.floor((data.time as number) / 1000) === time) { position = data.position as number; + clusterlength = this.header.segment.cues[i + 1].position! - position - 1 break; } else continue; } - if (position === 0) return new Error('Failed to find Cluster Position'); - else return position; + return Math.round(position + (time_left / 20) * (clusterlength / 500)); } _write(chunk: Buffer, _: BufferEncoding, callback: (error?: Error | null) => void): void { @@ -101,7 +98,7 @@ export class WebmSeeker extends Duplex { let err: Error | undefined; if (this.state === WebmSeekerState.READING_HEAD) err = this.readHead(); - else if (!this.seekfound) err = this.getClosestCluster(); + else if (!this.seekfound) err = this.getClosestBlock(); else err = this.readTag(); if (err) callback(err); @@ -196,10 +193,6 @@ export class WebmSeeker extends Duplex { } else this.cursor += this.data_size + this.data_length; if (ebmlID.name === 'simpleBlock') { - if (this.time_left !== 0 && this.mode === 'precise') { - if (data.readUInt16BE(1) === this.time_left) this.time_left = 0; - else continue; - } const track = this.header.segment.tracks![this.header.audioTrack]; if (!track || track.trackType !== 2) return new Error('No audio Track in this webm file.'); if ((data[0] & 0xf) === track.trackNumber) this.push(data.slice(4)); @@ -209,11 +202,28 @@ export class WebmSeeker extends Duplex { this.cursor = 0; } - private getClosestCluster(): Error | undefined { + private getClosestBlock(): Error | undefined { if (!this.chunk) return new Error('Chunk is missing'); - const count = this.chunk.indexOf('1f43b675', 0, 'hex'); - if (count === -1) throw new Error('Failed to find nearest Cluster.'); - else this.chunk = this.chunk.slice(count); + this.cursor = 0 + let positionFound = false; + while(!positionFound){ + this.cursor = this.chunk.indexOf('a3', this.cursor, 'hex'); + if (this.cursor === -1) return new Error('Failed to find nearest Block.'); + this.cursor ++; + if(!this.vint_value()) return new Error("Failed to find correct simpleBlock in first chunk") + const data = this.chunk.slice( + this.cursor + this.data_size, + this.cursor + this.data_size + this.data_length + ); + const track = this.header.segment.tracks![this.header.audioTrack]; + if (!track || track.trackType !== 2) return new Error('No audio Track in this webm file.'); + if ((data[0] & 0xf) === track.trackNumber) { + this.cursor += this.data_size + this.data_length; + this.push(data.slice(4)) + positionFound = true; + } + else continue; + } this.seekfound = true; return this.readTag(); } diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 2d5e0fb..9d19cf9 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -14,7 +14,6 @@ export enum StreamType { } export interface StreamOptions { - seekMode?: 'precise' | 'granular'; seek?: number; quality?: number; language?: string; diff --git a/play-dl/index.ts b/play-dl/index.ts index f631c9b..8c3f16f 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -77,7 +77,7 @@ import { EventEmitter } from 'stream'; async function stream( url: string, - options: { seek?: number; seekMode?: 'precise' | 'granular' } & StreamOptions + options: { seek?: number } & StreamOptions ): Promise; async function stream(url: string, options?: StreamOptions): Promise; /** @@ -89,13 +89,8 @@ async function stream(url: string, options?: StreamOptions): Promise