mirror of
https://github.com/YuzuZensai/play-dl-test.git
synced 2026-01-31 14:58:05 +00:00
prettier code
This commit is contained in:
@@ -1,217 +1,224 @@
|
||||
import { WebmElements, WebmHeader } from 'play-audio'
|
||||
import { Duplex, DuplexOptions } from 'stream'
|
||||
import { WebmElements, WebmHeader } from 'play-audio';
|
||||
import { Duplex, DuplexOptions } from 'stream';
|
||||
|
||||
enum DataType { master, string, uint, binary, float }
|
||||
enum DataType {
|
||||
master,
|
||||
string,
|
||||
uint,
|
||||
binary,
|
||||
float
|
||||
}
|
||||
|
||||
export enum WebmSeekerState{
|
||||
export enum WebmSeekerState {
|
||||
READING_HEAD = 'READING_HEAD',
|
||||
READING_DATA = 'READING_DATA',
|
||||
READING_DATA = 'READING_DATA'
|
||||
}
|
||||
|
||||
interface WebmSeekerOptions extends DuplexOptions{
|
||||
mode? : "precise" | "granular"
|
||||
interface WebmSeekerOptions extends DuplexOptions {
|
||||
mode?: 'precise' | 'granular';
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
constructor(options : WebmSeekerOptions){
|
||||
super(options)
|
||||
this.state = WebmSeekerState.READING_HEAD
|
||||
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
|
||||
constructor(options: WebmSeekerOptions) {
|
||||
super(options);
|
||||
this.state = WebmSeekerState.READING_HEAD;
|
||||
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;
|
||||
}
|
||||
|
||||
private get vint_length(): number{
|
||||
private get vint_length(): number {
|
||||
let i = 0;
|
||||
for (; i < 8; i++){
|
||||
if ((1 << (7 - i)) & this.chunk![this.cursor])
|
||||
break;
|
||||
}
|
||||
return ++i;
|
||||
for (; i < 8; i++) {
|
||||
if ((1 << (7 - i)) & this.chunk![this.cursor]) break;
|
||||
}
|
||||
return ++i;
|
||||
}
|
||||
|
||||
private get vint_value(): boolean {
|
||||
if (!this.chunk) return false
|
||||
const length = this.vint_length
|
||||
if(this.chunk.length < this.cursor + length) return false
|
||||
let value = this.chunk[this.cursor] & ((1 << (8 - length)) - 1)
|
||||
if (!this.chunk) return false;
|
||||
const length = this.vint_length;
|
||||
if (this.chunk.length < this.cursor + length) return false;
|
||||
let value = this.chunk[this.cursor] & ((1 << (8 - length)) - 1);
|
||||
for (let i = this.cursor + 1; i < this.cursor + length; i++) value = (value << 8) + this.chunk[i];
|
||||
this.data_size = length
|
||||
this.data_length = value
|
||||
return true
|
||||
this.data_size = length;
|
||||
this.data_length = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
cleanup(){
|
||||
this.cursor = 0
|
||||
this.chunk = undefined
|
||||
this.remaining = undefined
|
||||
cleanup() {
|
||||
this.cursor = 0;
|
||||
this.chunk = undefined;
|
||||
this.remaining = undefined;
|
||||
}
|
||||
|
||||
_read() {}
|
||||
|
||||
seek(sec : number): Error | number{
|
||||
let position = 0
|
||||
let time = (Math.floor(sec / 10) * 10)
|
||||
this.time_left = (sec - time) * 1000 || 0
|
||||
if (!this.header.segment.cues) return new Error("Failed to Parse Cues")
|
||||
seek(sec: number): Error | number {
|
||||
let position = 0;
|
||||
let time = Math.floor(sec / 10) * 10;
|
||||
this.time_left = (sec - time) * 1000 || 0;
|
||||
if (!this.header.segment.cues) return new Error('Failed to Parse Cues');
|
||||
|
||||
for(const data of this.header.segment.cues){
|
||||
if(Math.floor(data.time as number / 1000) === time) {
|
||||
position = data.position as number
|
||||
for (const data of this.header.segment.cues) {
|
||||
if (Math.floor((data.time as number) / 1000) === time) {
|
||||
position = data.position as number;
|
||||
break;
|
||||
}
|
||||
else continue;
|
||||
} else continue;
|
||||
}
|
||||
if(position === 0) return Error("Failed to find Cluster Position")
|
||||
else return position
|
||||
if (position === 0) return Error('Failed to find Cluster Position');
|
||||
else return position;
|
||||
}
|
||||
|
||||
_write(chunk: Buffer, _: BufferEncoding, callback: (error?: Error | null) => void): void {
|
||||
if (this.remaining) {
|
||||
this.chunk = Buffer.concat([this.remaining, chunk])
|
||||
this.remaining = undefined
|
||||
}
|
||||
else this.chunk = chunk
|
||||
this.chunk = Buffer.concat([this.remaining, chunk]);
|
||||
this.remaining = undefined;
|
||||
} else this.chunk = chunk;
|
||||
|
||||
let err : Error | undefined;
|
||||
let err: Error | undefined;
|
||||
|
||||
if(this.state === WebmSeekerState.READING_HEAD) err = this.readHead()
|
||||
else if(!this.seekfound) err = this.getClosetCluster()
|
||||
else err = this.readTag()
|
||||
if (this.state === WebmSeekerState.READING_HEAD) err = this.readHead();
|
||||
else if (!this.seekfound) err = this.getClosetCluster();
|
||||
else err = this.readTag();
|
||||
|
||||
if(err) callback(err)
|
||||
else callback()
|
||||
if (err) callback(err);
|
||||
else callback();
|
||||
}
|
||||
|
||||
private readHead(): Error | undefined{
|
||||
if (!this.chunk) return new Error("Chunk is missing")
|
||||
|
||||
while(this.chunk.length > this.cursor ){
|
||||
const oldCursor = this.cursor
|
||||
const id = this.vint_length
|
||||
if(this.chunk.length < this.cursor + id) break;
|
||||
private readHead(): Error | undefined {
|
||||
if (!this.chunk) return new Error('Chunk is missing');
|
||||
|
||||
const ebmlID = this.parseEbmlID(this.chunk.slice(this.cursor, this.cursor + id).toString('hex'))
|
||||
this.cursor += id
|
||||
const vint = this.vint_value
|
||||
while (this.chunk.length > this.cursor) {
|
||||
const oldCursor = this.cursor;
|
||||
const id = this.vint_length;
|
||||
if (this.chunk.length < this.cursor + id) break;
|
||||
|
||||
if(!vint) {
|
||||
this.cursor = oldCursor
|
||||
break;
|
||||
}
|
||||
if(!ebmlID){
|
||||
this.cursor += this.data_size + this.data_length
|
||||
continue;
|
||||
}
|
||||
const ebmlID = this.parseEbmlID(this.chunk.slice(this.cursor, this.cursor + id).toString('hex'));
|
||||
this.cursor += id;
|
||||
const vint = this.vint_value;
|
||||
|
||||
if(!this.headfound){
|
||||
if(ebmlID.name === "ebml") this.headfound = true
|
||||
else return new Error("Failed to find EBML ID at start of stream.")
|
||||
}
|
||||
const data = this.chunk.slice(this.cursor + this.data_size, this.cursor + this.data_size + this.data_length)
|
||||
const parse = this.header.parse(ebmlID, data)
|
||||
if(parse instanceof Error) return parse
|
||||
|
||||
if(ebmlID.type === DataType.master) {
|
||||
this.cursor += this.data_size
|
||||
continue;
|
||||
}
|
||||
|
||||
if(this.chunk.length < this.cursor + this.data_size + this.data_length) {
|
||||
if (!vint) {
|
||||
this.cursor = oldCursor;
|
||||
break;
|
||||
}
|
||||
else this.cursor += this.data_size + this.data_length
|
||||
if (!ebmlID) {
|
||||
this.cursor += this.data_size + this.data_length;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.headfound) {
|
||||
if (ebmlID.name === 'ebml') this.headfound = true;
|
||||
else return new Error('Failed to find EBML ID at start of stream.');
|
||||
}
|
||||
const data = this.chunk.slice(
|
||||
this.cursor + this.data_size,
|
||||
this.cursor + this.data_size + this.data_length
|
||||
);
|
||||
const parse = this.header.parse(ebmlID, data);
|
||||
if (parse instanceof Error) return parse;
|
||||
|
||||
if (ebmlID.type === DataType.master) {
|
||||
this.cursor += this.data_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.chunk.length < this.cursor + this.data_size + this.data_length) {
|
||||
this.cursor = oldCursor;
|
||||
break;
|
||||
} else this.cursor += this.data_size + this.data_length;
|
||||
}
|
||||
this.remaining = this.chunk.slice(this.cursor)
|
||||
this.cursor = 0
|
||||
this.remaining = this.chunk.slice(this.cursor);
|
||||
this.cursor = 0;
|
||||
}
|
||||
|
||||
private readTag(): Error | undefined{
|
||||
if (!this.chunk) return new Error("Chunk is missing")
|
||||
|
||||
while(this.chunk.length > this.cursor ){
|
||||
const oldCursor = this.cursor
|
||||
const id = this.vint_length
|
||||
if(this.chunk.length < this.cursor + id) break;
|
||||
private readTag(): Error | undefined {
|
||||
if (!this.chunk) return new Error('Chunk is missing');
|
||||
|
||||
const ebmlID = this.parseEbmlID(this.chunk.slice(this.cursor, this.cursor + id).toString('hex'))
|
||||
this.cursor += id
|
||||
const vint = this.vint_value
|
||||
while (this.chunk.length > this.cursor) {
|
||||
const oldCursor = this.cursor;
|
||||
const id = this.vint_length;
|
||||
if (this.chunk.length < this.cursor + id) break;
|
||||
|
||||
if(!vint) {
|
||||
this.cursor = oldCursor
|
||||
break;
|
||||
}
|
||||
if(!ebmlID){
|
||||
this.cursor += this.data_size + this.data_length
|
||||
continue;
|
||||
}
|
||||
const ebmlID = this.parseEbmlID(this.chunk.slice(this.cursor, this.cursor + id).toString('hex'));
|
||||
this.cursor += id;
|
||||
const vint = this.vint_value;
|
||||
|
||||
const data = this.chunk.slice(this.cursor + this.data_size, this.cursor + this.data_size + this.data_length)
|
||||
const parse = this.header.parse(ebmlID, data)
|
||||
if(parse instanceof Error) return parse
|
||||
|
||||
if(ebmlID.type === DataType.master) {
|
||||
this.cursor += this.data_size
|
||||
continue;
|
||||
}
|
||||
|
||||
if(this.chunk.length < this.cursor + this.data_size + this.data_length) {
|
||||
if (!vint) {
|
||||
this.cursor = oldCursor;
|
||||
break;
|
||||
}
|
||||
else this.cursor += this.data_size + this.data_length
|
||||
if (!ebmlID) {
|
||||
this.cursor += this.data_size + this.data_length;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ebmlID.name === 'simpleBlock'){
|
||||
if(this.time_left !== 0 && this.mode === "precise"){
|
||||
if(data.readUInt16BE(1) === this.time_left) this.time_left = 0
|
||||
const data = this.chunk.slice(
|
||||
this.cursor + this.data_size,
|
||||
this.cursor + this.data_size + this.data_length
|
||||
);
|
||||
const parse = this.header.parse(ebmlID, data);
|
||||
if (parse instanceof Error) return parse;
|
||||
|
||||
if (ebmlID.type === DataType.master) {
|
||||
this.cursor += this.data_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.chunk.length < this.cursor + this.data_size + this.data_length) {
|
||||
this.cursor = oldCursor;
|
||||
break;
|
||||
} 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))
|
||||
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));
|
||||
}
|
||||
}
|
||||
this.remaining = this.chunk.slice(this.cursor)
|
||||
this.cursor = 0
|
||||
this.remaining = this.chunk.slice(this.cursor);
|
||||
this.cursor = 0;
|
||||
}
|
||||
|
||||
private getClosetCluster(): 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.seekfound = true
|
||||
return this.readTag()
|
||||
private getClosetCluster(): 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.seekfound = true;
|
||||
return this.readTag();
|
||||
}
|
||||
|
||||
private parseEbmlID(ebmlID : string){
|
||||
if(Object.keys(WebmElements).includes(ebmlID)) return WebmElements[ebmlID]
|
||||
else return false
|
||||
private parseEbmlID(ebmlID: string) {
|
||||
if (Object.keys(WebmElements).includes(ebmlID)) return WebmElements[ebmlID];
|
||||
else return false;
|
||||
}
|
||||
|
||||
_destroy(error : Error | null, callback : (error : Error | null) => void) : void {
|
||||
this.cleanup()
|
||||
_destroy(error: Error | null, callback: (error: Error | null) => void): void {
|
||||
this.cleanup();
|
||||
callback(error);
|
||||
}
|
||||
|
||||
@@ -219,4 +226,4 @@ export class WebmSeeker extends Duplex{
|
||||
this.cleanup();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user