diff --git a/commands/np.ts b/commands/np.ts index 18a0c4f..d34185d 100644 --- a/commands/np.ts +++ b/commands/np.ts @@ -54,7 +54,7 @@ function nowPlayingResponse(bot: Bot, interaction: Interaction) { } } -function nowPlayingMessage(bot: Bot, guildId: number) { +function nowPlayingMessage(bot: Bot, guildId: BigInt) { const player = bot.helpers.getPlayer(guildId); return { embeds: [{ diff --git a/commands/play.ts b/commands/play.ts index e3756e0..c033e88 100644 --- a/commands/play.ts +++ b/commands/play.ts @@ -60,13 +60,14 @@ export async function play(bot: Bot, interaction: Interaction, _args?) { } let href; + // remove the timestamp from the query if(parsed_url.href.indexOf("?t=") !== -1) { href = parsed_url.href.substring(0, parsed_url.href.indexOf("?")) } else { href = parsed_url.href; } - const result = await player.pushQuery(interaction.user.username, href); + const result = await player.pushQuery(interaction.guildId, interaction.user.username, href); if(result && result[0] && parsed_url.href.indexOf("youtube.com") !== -1 || parsed_url.href.indexOf("youtu.be") !== -1 && result[0].title) { await editOriginalInteractionResponse(bot, interaction.token, addedToQueueResponse(interaction, result[0].title)); } @@ -84,72 +85,3 @@ export async function play(bot: Bot, interaction: Interaction, _args?) { } } } - -/*import { exists } from "https://deno.land/std@0.161.0/fs/mod.ts"; - -import { configs } from "../configs.ts"; -import { Bot } from "../deps.ts"; -import { download, ensureVoiceConnection } from "../utils.ts"; -import { type Command } from "../types.ts"; - -export async function play(bot: Bot, command: Command) { - await ensureVoiceConnection(bot, command.guildId); - const player = bot.helpers.getPlayer(command.guildId); - await player.pushQuery(command.params); - await player.play(); -}*/ - -/*const parsed_url = new URL(url); -let video_id = ""; - -if(parsed_url.href.indexOf("youtube.com") !== -1) { - video_id = parsed_url.search.substring(3); -} else if(parsed_url.href.indexOf("youtu.be") === -1) { - video_id = parsed_url.pathname.substring(1); -} else { - return { - status: false, - message: "This URL is invalid" - }; -} - -if (!(await exists(`${configs.project_root}/music/`))) { - await download(video_id); -}*/ - - -// single video -/* -URL { - href: "https://www.youtube.com/watch?v=DhobsmmyGFs", - origin: "https://www.youtube.com", - protocol: "https:", - username: "", - password: "", - host: "www.youtube.com", - hostname: "www.youtube.com", - port: "", - pathname: "/watch", - hash: "", - search: "?v=DhobsmmyGFs" -} -{ - endpoint: "stockholm3048.discord.media:443", - sessionId: "74d4d31a8f5c507f9852278867d42c05", - token: "08b9f3bc65a233d5" -}*/ - -// playlist -/*URL { - href: "https://www.youtube.com/playlist?list=PLvNazUnle2rTZO7OVYhhRdzFb9W4xSpNk", - origin: "https://www.youtube.com", - protocol: "https:", - username: "", - password: "", - host: "www.youtube.com", - hostname: "www.youtube.com", - port: "", - pathname: "/playlist", - hash: "", - search: "?list=PLvNazUnle2rTZO7OVYhhRdzFb9W4xSpNk" -}*/ \ No newline at end of file diff --git a/discordeno-audio-plugin/src/audio-source/audio-source.ts b/discordeno-audio-plugin/src/audio-source/audio-source.ts index bab8c79..1012f67 100644 --- a/discordeno-audio-plugin/src/audio-source/audio-source.ts +++ b/discordeno-audio-plugin/src/audio-source/audio-source.ts @@ -6,6 +6,7 @@ export type AudioSource = { data: () => | Promise> | AsyncIterableIterator; + guildId: bigint; added_by?: string; }; @@ -16,6 +17,7 @@ export function createAudioSource( data: () => | Promise> | AsyncIterableIterator, + guildId: bigint, added_by?: string ): AudioSource { lastId++; @@ -31,6 +33,7 @@ export function createAudioSource( return empty(); } }, + guildId, added_by }; } diff --git a/discordeno-audio-plugin/src/audio-source/universal.ts b/discordeno-audio-plugin/src/audio-source/universal.ts index 46aaade..1567d65 100644 --- a/discordeno-audio-plugin/src/audio-source/universal.ts +++ b/discordeno-audio-plugin/src/audio-source/universal.ts @@ -2,6 +2,6 @@ import { getYoutubeSources } from "./youtube.ts"; export type LoadSource = typeof loadLocalOrYoutube; -export function loadLocalOrYoutube(query: string, added_by?: string) { - return getYoutubeSources(query, String(added_by)); +export function loadLocalOrYoutube(query: string, guildId: bigint, added_by?: string) { + return getYoutubeSources(guildId, String(added_by), query); } diff --git a/discordeno-audio-plugin/src/audio-source/youtube.ts b/discordeno-audio-plugin/src/audio-source/youtube.ts index a87345b..d16e733 100644 --- a/discordeno-audio-plugin/src/audio-source/youtube.ts +++ b/discordeno-audio-plugin/src/audio-source/youtube.ts @@ -3,31 +3,35 @@ import { bufferIter } from "../../utils/mod.ts"; import { demux } from "../demux/mod.ts"; import { createAudioSource, empty } from "./audio-source.ts"; -export async function getYoutubeSources(added_by?: string, ...queries: string[]) { - const sources = queries.map((query) => getYoutubeSource(query, added_by)); +import { errorMessageCallback, parseYoutubeId } from "../../../utils.ts"; + +export async function getYoutubeSources(guildId: bigint, added_by?: string, ...queries: string[]) { + const sources = queries.map((query) => getYoutubeSource(query, guildId, added_by)); const awaitedSources = await Promise.all(sources); return awaitedSources .filter((source) => source !== undefined) .map((source) => source!); } -export async function getYoutubeSource(query: string, added_by?: string) { +export async function getYoutubeSource(query: string, guildId: bigint, added_by?: string) { try { + query = parseYoutubeId(query); const results = await YouTube.search(query, { limit: 1, type: "video" }); if (results.length > 0) { const { id, title } = results[0]; return createAudioSource(title!, async () => { try { - const stream = await ytDownload(id!, { + const stream = await ytDownload(query, { mimeType: `audio/webm; codecs="opus"`, }); return bufferIter(demux(stream)); } catch { - console.error("error"); + errorMessageCallback(guildId, `There was an error trying to play **${title}**:\n + something broke in getYoutubeSource`); console.log(`Failed to play ${title}\n Returning empty stream`); return empty(); } - }, added_by); + }, guildId, added_by); } } catch(err) { console.error(err); diff --git a/discordeno-audio-plugin/src/connection-data.ts b/discordeno-audio-plugin/src/connection-data.ts index ddad6e9..808a930 100644 --- a/discordeno-audio-plugin/src/connection-data.ts +++ b/discordeno-audio-plugin/src/connection-data.ts @@ -9,7 +9,7 @@ export type BotData = { guildData: Map; udpSource: EventSource<[UdpArgs]>; bufferSize: number; - loadSource: (query: string, added_by?: string) => AudioSource[] | Promise; + loadSource: (query: string, guild_id: bigint, added_by?: string) => AudioSource[] | Promise; }; export type ConnectionData = { diff --git a/discordeno-audio-plugin/src/player/queue-player.ts b/discordeno-audio-plugin/src/player/queue-player.ts index c424e58..4fc4d7e 100644 --- a/discordeno-audio-plugin/src/player/queue-player.ts +++ b/discordeno-audio-plugin/src/player/queue-player.ts @@ -79,24 +79,24 @@ export class QueuePlayer extends Queue implements Player { * Interrupts the current song, resumes when finished * @param query Loads a universal song (local file or youtube search) */ - async interruptQuery(query: string) { - const sources = await this.#loadSource(query as string); + async interruptQuery(guildId: bigint, query: string) { + const sources = await this.#loadSource(query as string, guildId); this.#rawPlayer.interrupt(await sources[0].data()); } - async pushQuery(added_by?: string, ...queries: string[]) { + async pushQuery(guildId: bigint, added_by?: string, ...queries: string[]) { const sources = []; for (const query of queries) { - sources.push(...(await this.#loadSource(String(added_by), query as string))); + sources.push(...(await this.#loadSource(query as string, guildId, String(added_by)))); this.push(...sources); } return sources; } - async unshiftQuery(...queries: string[]) { + async unshiftQuery(guildId: bigint, ...queries: string[]) { const sources = []; for (const query of queries) { - sources.push(...(await this.#loadSource(query as string))); + sources.push(...(await this.#loadSource(query as string, guildId))); this.unshift(...sources); } return sources; diff --git a/main.ts b/main.ts index 9d82b18..ed14fc4 100644 --- a/main.ts +++ b/main.ts @@ -30,7 +30,7 @@ export const bot = enableAudioPlugin(baseBot); bot.events.ready = async function (bot, payload) { //await registerCommands(bot); - console.log(`${cyan("permanent waves")} is ready to go with session id ${yellow(payload.sessionId)}`); + console.log(`${cyan("permanent waves")} is ready to go`); sessionId = payload.sessionId; } diff --git a/utils.ts b/utils.ts index b3aceee..861a278 100644 --- a/utils.ts +++ b/utils.ts @@ -1,9 +1,19 @@ -import { ytdl } from "https://deno.land/x/ytdl_core@v0.1.1/mod.ts"; import { Bot } from "https://deno.land/x/discordeno@18.0.1/bot.ts"; -import { connectToVoiceChannel } from "https://deno.land/x/discordeno@18.0.1/helpers/guilds/mod.ts"; import { configs } from "./configs.ts"; -import { getChannel, getChannels, getGuild, type BigString, type Embed, type InteractionCallbackData, type InteractionResponse } from "./deps.ts"; +import { + getChannel, + getChannels, + getGuild, + sendMessage, + type BigString, + type CreateMessage, + type Embed, + type InteractionCallbackData, + type InteractionResponse +} from "./deps.ts"; +import { bot } from "./main.ts"; +import { ConnectionData } from "./discordeno-audio-plugin/mod.ts"; export function channelIsAllowed(guild: string, channel: string) { if(`${guild}:${channel}` in configs.allowed_text_channels) { @@ -13,30 +23,6 @@ export function channelIsAllowed(guild: string, channel: string) { return false; } -export async function download(url: string) { - try { - const stream = await ytdl(url, { filter: "audio" }); - - const chunks: Uint8Array[] = []; - - for await (const chunk of stream) { - chunks.push(chunk); - } - - const videoDetails = stream.videoInfo.videoDetails; - const blob = new Blob(chunks); - const result = await Deno.writeFile(`${configs.project_root}/music/${videoDetails.videoId}.mp3`, new Uint8Array(await blob.arrayBuffer())); - return { - result: true, - message: `Now playing **${videoDetails.title}**` - }; - } catch(err) { - console.error(err); - } - - return false; -} - export async function ensureVoiceConnection(bot: Bot, guildId: BigString) { const channels = await getChannels(bot, guildId); const guild = await getGuild(bot, guildId); @@ -47,9 +33,9 @@ export async function ensureVoiceConnection(bot: Bot, guildId: BigString) { } } - const channel = await getChannel(bot, channelId); + await getChannel(bot, channelId); try { - const connection = await bot.helpers.connectToVoiceChannel(guildId, channelId); + await bot.helpers.connectToVoiceChannel(guildId, channelId); } catch(err) { console.error(err); } @@ -93,4 +79,23 @@ export const waitingForResponse = { data: { content: "waiting for response..." } -}; \ No newline at end of file +}; + +function errorMessage(bot: Bot, guildId: bigint, message: string) { + const player = bot.helpers.getPlayer(guildId); + return { + embeds: [{ + color: configs.embed_color, + description: message + }] + } +} + +export async function errorMessageCallback(guildId: bigint, message: string) { + const channel = await getAllowedTextChannel(bot, guildId); + await sendMessage(bot, channel.id, errorMessage(bot, guildId, message)); +} + +export function parseYoutubeId(url: string) { + return url.substring(url.indexOf("?")+3); +} \ No newline at end of file