🐛 fix: Skip error

This commit is contained in:
2024-08-17 20:10:50 +07:00
parent cbde524e19
commit dad6510fd4
4 changed files with 43 additions and 28 deletions

View File

@@ -21,12 +21,10 @@ const main = async () => {
player.startCurrentStream(); player.startCurrentStream();
}); });
const info = await player.enqueue( await player.enqueue(`https://www.youtube.com/watch?v=${videoId}`);
`https://www.youtube.com/watch?v=${videoId}`,
);
console.log(info);
await player.enqueue(`https://www.youtube.com/watch?v=${videoId2}`); await player.enqueue(`https://www.youtube.com/watch?v=${videoId2}`);
console.log(player.getQueue());
}; };
let lastFFmpeg: ffmpeg.FfmpegCommand | null = null; let lastFFmpeg: ffmpeg.FfmpegCommand | null = null;
@@ -68,6 +66,7 @@ const playSpeaker = async (player: Player) => {
// .on("end", async () => { // .on("end", async () => {
// await closeSpeaker(); // await closeSpeaker();
// }) // })
// @ts-expect-error - ffmpeg typings are incorrect
.on("error", (err) => { .on("error", (err) => {
console.error("[FFmpeg] > Error:", err.message); console.error("[FFmpeg] > Error:", err.message);
}); });

View File

@@ -12,6 +12,7 @@ export class Player {
private currentAudioInformation: AudioInformation | null = null; private currentAudioInformation: AudioInformation | null = null;
public _stream: SeekableStream | null = null; public _stream: SeekableStream | null = null;
private _skipFlag: boolean = false;
constructor(providers: Provider[]) { constructor(providers: Provider[]) {
this.providers = providers; this.providers = providers;
@@ -25,26 +26,17 @@ export class Player {
information: AudioInformation, information: AudioInformation,
url: string, url: string,
seekTime: number, seekTime: number,
noDestroy: boolean = false,
) { ) {
// If already playing, destroy the current stream // If already playing, destroy the current stream
if (this._stream) { if (this._stream && !noDestroy) {
this._stream.destroy(); this._stream.destroy();
} }
this._stream = new SeekableStream(information, url, seekTime); this._stream = new SeekableStream(information, url, seekTime);
this.currentAudioInformation = information; this.currentAudioInformation = information;
this._stream.on("destroy", () => { this._stream.on("destroy", () => {
console.log("Stream destroyed, total song", this.queue.length); console.debug("Stream destroyed");
if (this.queue.length > 0) {
const next = this.queue.shift();
console.log("Playing next in queue");
if (next) {
this._createStream(next, next.url, 0);
}
} else {
this._stream = null;
this.currentAudioInformation = null;
}
}); });
this.playerEvent.emit("play", information); this.playerEvent.emit("play", information);
@@ -56,10 +48,30 @@ export class Player {
} }
} }
public endCurrentStream() { public endCurrentStream(skip: boolean = false) {
if (this._skipFlag) {
return;
}
if (skip) {
this._skipFlag = true;
}
if (this._stream) { if (this._stream) {
this._stream.destroy(); this._stream.destroy();
} }
if (this.queue.length > 0) {
const next = this.queue.shift();
if (next) {
this._createStream(next, next.url, 0);
}
} else {
this._stream = null;
this.currentAudioInformation = null;
}
this._skipFlag = false;
} }
public on(event: string, listener: (...args: any[]) => void) { public on(event: string, listener: (...args: any[]) => void) {
@@ -79,12 +91,17 @@ export class Player {
this.currentProvider = providers[0]; this.currentProvider = providers[0];
} }
console.debug(
"Using provider",
this.currentProvider.constructor.name,
url,
);
return await this.currentProvider.getInformation(url); return await this.currentProvider.getInformation(url);
} }
public async play(url: string, seekTime: number = 0) { public async play(url: string, seekTime: number = 0) {
const information = await this.getInformation(url); const information = await this.getInformation(url);
//console.log(information);
if (information.livestream) if (information.livestream)
// TODO: Implement livestreams // TODO: Implement livestreams
@@ -124,14 +141,8 @@ export class Player {
} }
public async skip() { public async skip() {
if (this.queue.length === 0) { this.endCurrentStream(true);
throw new Error("No song in queue"); console.debug("Skipping");
}
const next = this.queue.shift();
if (next) {
this._createStream(next, next.url, 0);
}
} }
public getCurrentSampleRate() { public getCurrentSampleRate() {

View File

@@ -65,7 +65,7 @@ export async function getYouTubeFormats(id: string) {
waitUntil: "networkidle2", waitUntil: "networkidle2",
}); });
const body = await page.evaluate(() => document.body.innerHTML); const body = await page.evaluate(() => document.body.innerHTML);
await page.close(); page.close();
const match = body.match( const match = body.match(
/var ytInitialPlayerResponse = (.*?)(?=;\s*<\/script>)/, /var ytInitialPlayerResponse = (.*?)(?=;\s*<\/script>)/,
@@ -91,6 +91,7 @@ export async function getYouTubeFormats(id: string) {
return formats; return formats;
} catch (err) { } catch (err) {
console.error(err);
throw new Error("Failed to parse YouTube formats"); throw new Error("Failed to parse YouTube formats");
} }
} }

View File

@@ -366,6 +366,10 @@ export class SeekableStream {
this.event.on(event, listener); this.event.on(event, listener);
} }
public removeAllListeners(event: string) {
this.event.removeAllListeners(event);
}
public destroy() { public destroy() {
if (this.destroyed) return; if (this.destroyed) return;