리눅스 빌드 환경에서 대소문자 잔존 파일과 충돌(TS1261)을 막기 위해 파일명을 PascalCase 로 통일하고 import 경로도 동일하게 수정.
93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
import { Connectors, LoadType, Shoukaku, Track } from "shoukaku";
|
|
import { Client } from "discord.js";
|
|
import { GuildPlayer } from "./GuildPlayer";
|
|
import { Config } from "../utils/Config";
|
|
import { Logger } from "../utils/Logger";
|
|
import { parseLink } from "../utils/music/Url";
|
|
import { shuffle } from "../utils/Shuffle";
|
|
import { Spotify } from "../utils/api/Spotify";
|
|
import { YoutubeMusic } from "../utils/api/YoutubeMusic";
|
|
|
|
export class LavalinkManager {
|
|
public shoukaku: Shoukaku;
|
|
private players: Map<string, GuildPlayer> = new Map();
|
|
|
|
constructor(readonly client: Client) {
|
|
this.shoukaku = new Shoukaku(new Connectors.DiscordJS(client), [{
|
|
name: "tkrmagid-Lavalink-Server",
|
|
url: `${Config.lavalink.host}:${Config.lavalink.port}`,
|
|
auth: Config.lavalink.pw,
|
|
secure: false,
|
|
}], {
|
|
moveOnDisconnect: true,
|
|
reconnectTries: 3,
|
|
});
|
|
|
|
this.shoukaku.on("ready", (name) => {
|
|
Logger.ready(`[LavalinkManager] 노드 [${name}] 연결 완료!`);
|
|
});
|
|
this.shoukaku.on("error", (name, err) => {
|
|
Logger.error(`[LavalinkManager] 노드 [${name}] 에러: ${String(err)}`);
|
|
});
|
|
}
|
|
|
|
getPlayer(guildId: string) {
|
|
return this.players.get(guildId);
|
|
}
|
|
addPlayer(guildId: string, player: GuildPlayer) {
|
|
this.players.set(guildId, player);
|
|
}
|
|
delPlayer(guildId: string) {
|
|
this.players.delete(guildId);
|
|
}
|
|
|
|
async search(guildId: string, query: string, userId: string, player?: GuildPlayer) {
|
|
const node = this.shoukaku.options.nodeResolver(this.shoukaku.nodes);
|
|
if (!node) {
|
|
this.delPlayer(guildId);
|
|
throw new ReferenceError(`[LavalinkManager] lavalink node is missing`);
|
|
}
|
|
player = player ?? this.getPlayer(guildId);
|
|
if (!player) return;
|
|
const { isUrl, text, flags } = parseLink(query.trim());
|
|
let searchText = isUrl ? text : (await Spotify.getSearchUrl(text)) ?? (await YoutubeMusic.getSearchUrl(text)) ?? `ytsearch:${text}`;
|
|
if (flags.has('y')) searchText = (await YoutubeMusic.getSearchUrl(text)) ?? `ytsearch:${text}`;
|
|
if (searchText.startsWith("ytsearch") && !flags.has('o')) searchText += " Topic";
|
|
const result = await node.rest.resolve(searchText);
|
|
if (!result || result.loadType === LoadType.EMPTY || result.loadType === LoadType.ERROR) {
|
|
if (result?.loadType === LoadType.ERROR) Logger.error(`[LavalinkManager] loadtype ERROR: ${result.data.message}`);
|
|
// 노래 못찾았을때
|
|
player.errMsg(`노래를 찾을수 없습니다.`);
|
|
return;
|
|
}
|
|
if (result.loadType === LoadType.PLAYLIST) {
|
|
player.addTracks(
|
|
flags?.has("s") ? shuffle(result.data.tracks) : result.data.tracks,
|
|
userId
|
|
);
|
|
return;
|
|
}
|
|
if (result.loadType === LoadType.TRACK) {
|
|
player.addTrack(result.data, userId);
|
|
return;
|
|
}
|
|
if (result.loadType === LoadType.SEARCH) {
|
|
if (result.data.length === 0) {
|
|
player.errMsg(`노래를 찾을수 없습니다.`);
|
|
return;
|
|
}
|
|
player.addTrack(result.data[0], userId);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public async youtubeSearch(query: string): Promise<Track[]> {
|
|
const node = this.shoukaku.options.nodeResolver(this.shoukaku.nodes);
|
|
if (!node) throw new ReferenceError(`[LavalinkManager] lavalink node is missing`);
|
|
const result = await node.rest.resolve(`ytsearch:${query.trim()}`);
|
|
// if (!result || result.loadType === LoadType.EMPTY || result.loadType === LoadType.ERROR) return [];
|
|
if (result?.loadType === LoadType.TRACK) return [ result.data ];
|
|
if (result?.loadType === LoadType.SEARCH) return result.data;
|
|
return [];
|
|
}
|
|
} |