yaejunyang/packages/bot/music.ts

83 lines
2.2 KiB
TypeScript

import {
AudioPlayerStatus,
AudioResource,
createAudioPlayer,
createAudioResource,
VoiceConnection,
} from "@discordjs/voice";
import { Guild } from "discord.js";
import { getOrCreateVoiceConnection } from "./util";
import { OutputHandler } from "../utils/outputHandler";
import play from "play-dl";
namespace InitPlayDl {
let initialized = false;
export async function init() {
if (initialized) return;
await play.getFreeClientID();
initialized = true;
}
}
class MusicQueue {
private connection: VoiceConnection;
private list: AudioResource[];
constructor(connection: VoiceConnection) {
this.connection = connection;
this.list = [];
}
public static fromConnection(connection: VoiceConnection): MusicQueue {
return ((connection as any).queue ??= new MusicQueue(connection));
}
private play() {
if (!this.list[0]) return;
const player = createAudioPlayer();
this.connection.subscribe(player);
player.once(AudioPlayerStatus.Idle, this.next.bind(this));
player.play(this.list[0]);
}
public enqueue(resource: AudioResource) {
this.list.push(resource);
if (this.list.length == 1) {
this.play();
return;
}
}
public next() {
this.list.shift();
this.play();
}
}
// TODO: 토큰 설정하고 플레이돼게 만들기
export async function playMusic(guild: Guild, url: string) {
try {
const connection = await getOrCreateVoiceConnection(guild);
if (!connection) throw new Error("Yaeju is not joined VoiceChat");
await InitPlayDl.init();
const validation = play.yt_validate(url);
if (validation !== "video" && validation !== "playlist")
throw new Error("Invalid YouTube URL: " + validation);
const stream = await play.stream(url);
MusicQueue.fromConnection(connection).enqueue(
createAudioResource(stream.stream, {
inputType: stream.type,
}),
);
} catch (err) {
OutputHandler.errorLog("[PlayMusic Error]", err);
throw err;
}
}
export async function skipMusic(guild: Guild) {
const connection = await getOrCreateVoiceConnection(guild);
if (!connection) throw new Error("Yaeju is not joined VoiceChat");
MusicQueue.fromConnection(connection).next();
}