update discordeno-audio-plugin and finally switch to yt_download, update discordeno
This commit is contained in:
parent
320d6d1782
commit
891b081791
24
deps.ts
24
deps.ts
|
@ -1,4 +1,4 @@
|
|||
export { ApplicationCommandOptionTypes, createBot, Intents, startBot } from "https://deno.land/x/discordeno@17.0.1/mod.ts";
|
||||
export { ApplicationCommandOptionTypes, createBot, Intents, startBot } from "https://deno.land/x/discordeno@18.0.1/mod.ts";
|
||||
export {
|
||||
createGlobalApplicationCommand,
|
||||
editGlobalApplicationCommand,
|
||||
|
@ -9,15 +9,15 @@ export {
|
|||
sendFollowupMessage,
|
||||
sendMessage,
|
||||
upsertGlobalApplicationCommands
|
||||
} from "https://deno.land/x/discordeno@17.0.1/helpers/mod.ts";
|
||||
export { type BigString, type CreateApplicationCommand, type CreateSlashApplicationCommand, type InteractionCallbackData } from "https://deno.land/x/discordeno@17.0.1/types/mod.ts";
|
||||
export { type CreateMessage } from "https://deno.land/x/discordeno@17.0.1/helpers/messages/mod.ts";
|
||||
export { type InteractionResponse } from "https://deno.land/x/discordeno@17.0.1/types/discordeno.ts";
|
||||
export { editOriginalInteractionResponse, sendInteractionResponse } from "https://deno.land/x/discordeno@17.0.1/helpers/interactions/mod.ts";
|
||||
export { sendPrivateInteractionResponse } from "https://deno.land/x/discordeno@17.0.1/plugins/mod.ts";
|
||||
export { type Channel } from "https://deno.land/x/discordeno@17.0.1/transformers/channel.ts";
|
||||
export { type Bot } from "https://deno.land/x/discordeno@17.0.1/bot.ts";
|
||||
export { type Interaction } from "https://deno.land/x/discordeno@17.0.1/transformers/interaction.ts";
|
||||
export { type ApplicationCommandOption, type ApplicationCommandOptionChoice, type Embed } from "https://deno.land/x/discordeno@17.0.1/transformers/mod.ts";
|
||||
export { leaveVoiceChannel } from "https://deno.land/x/discordeno@17.0.1/helpers/guilds/mod.ts";
|
||||
} from "https://deno.land/x/discordeno@18.0.1/helpers/mod.ts";
|
||||
export { type BigString, type CreateApplicationCommand, type CreateSlashApplicationCommand, type InteractionCallbackData } from "https://deno.land/x/discordeno@18.0.1/types/mod.ts";
|
||||
export { type CreateMessage } from "https://deno.land/x/discordeno@18.0.1/helpers/messages/mod.ts";
|
||||
export { type InteractionResponse } from "https://deno.land/x/discordeno@18.0.1/types/discordeno.ts";
|
||||
export { editOriginalInteractionResponse, sendInteractionResponse } from "https://deno.land/x/discordeno@18.0.1/helpers/interactions/mod.ts";
|
||||
export { sendPrivateInteractionResponse } from "https://deno.land/x/discordeno@18.0.1/plugins/mod.ts";
|
||||
export { type Channel } from "https://deno.land/x/discordeno@18.0.1/transformers/channel.ts";
|
||||
export { type Bot } from "https://deno.land/x/discordeno@18.0.1/bot.ts";
|
||||
export { type Interaction } from "https://deno.land/x/discordeno@18.0.1/transformers/interaction.ts";
|
||||
export { type ApplicationCommandOption, type ApplicationCommandOptionChoice, type Embed } from "https://deno.land/x/discordeno@18.0.1/transformers/mod.ts";
|
||||
export { leaveVoiceChannel } from "https://deno.land/x/discordeno@18.0.1/helpers/guilds/mod.ts";
|
||||
export { getConnectionData } from "./discordeno-audio-plugin/src/connection-data.ts";
|
|
@ -1,8 +1,6 @@
|
|||
export * from "https://deno.land/x/discordeno@17.1.0/mod.ts";
|
||||
export * from "https://deno.land/x/discordeno@17.1.0/plugins/cache/mod.ts";
|
||||
export * from "https://deno.land/x/discordeno@18.0.1/mod.ts";
|
||||
export * from "https://deno.land/x/discordeno@18.0.1/plugins/cache/mod.ts";
|
||||
export * as opus from "https://unpkg.com/@evan/wasm@0.0.95/target/opus/deno.js";
|
||||
export * from "https://unpkg.com/@evan/wasm@0.0.95/target/nacl/deno.js";
|
||||
export { ytDownload } from "https://deno.land/x/yt_download@1.2/mod.ts";
|
||||
export type { VideoFormat } from "https://deno.land/x/ytdl_core@v0.1.2/src/types.ts";
|
||||
export { downloadFromInfo, getInfo, ytdl } from "https://deno.land/x/ytdl_core@v0.1.2/mod.ts";
|
||||
export { ytDownload } from "https://deno.land/x/yt_download@1.3/mod.ts";
|
||||
export { default as YouTube } from "https://deno.land/x/youtube_sr@v4.1.17/mod.ts";
|
|
@ -1,20 +1,8 @@
|
|||
import { YouTube, ytdl } from "../../deps.ts";
|
||||
import { YouTube, ytDownload } from "../../deps.ts";
|
||||
import { bufferIter } from "../../utils/mod.ts";
|
||||
import { demux } from "../demux/mod.ts";
|
||||
import { createAudioSource, empty } from "./audio-source.ts";
|
||||
|
||||
function supportedFormatFilter(format: {
|
||||
codecs: string;
|
||||
container: string;
|
||||
audioSampleRate?: string;
|
||||
}) {
|
||||
return (
|
||||
format.codecs === "opus" &&
|
||||
format.container === "webm" &&
|
||||
format.audioSampleRate === "48000"
|
||||
);
|
||||
}
|
||||
|
||||
export async function getYoutubeSources(added_by?: string, ...queries: string[]) {
|
||||
const sources = queries.map((query) => getYoutubeSource(query, added_by));
|
||||
const awaitedSources = await Promise.all(sources);
|
||||
|
@ -30,11 +18,12 @@ export async function getYoutubeSource(query: string, added_by?: string) {
|
|||
const { id, title } = results[0];
|
||||
return createAudioSource(title!, async () => {
|
||||
try {
|
||||
const stream = await ytdl(id!, {
|
||||
filter: supportedFormatFilter
|
||||
const stream = await ytDownload(id!, {
|
||||
mimeType: `audio/webm; codecs="opus"`,
|
||||
});
|
||||
return bufferIter(demux(stream));
|
||||
} catch {
|
||||
console.error("error");
|
||||
console.log(`Failed to play ${title}\n Returning empty stream`);
|
||||
return empty();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ export type ConnectionData = {
|
|||
speaking: boolean;
|
||||
sequence: number;
|
||||
timestamp: number;
|
||||
missedHeart: number;
|
||||
lastHeart?: number;
|
||||
reconnect: number;
|
||||
};
|
||||
connectInfo: {
|
||||
endpoint?: string;
|
||||
|
@ -106,6 +109,8 @@ export function getConnectionData(botId: bigint, guildId: bigint) {
|
|||
speaking: false,
|
||||
sequence: randomNBit(16),
|
||||
timestamp: randomNBit(32),
|
||||
missedHeart: 0,
|
||||
reconnect: 0,
|
||||
},
|
||||
connectInfo: {},
|
||||
audio: new EventSource<[Uint8Array]>(),
|
||||
|
|
|
@ -76,16 +76,6 @@ export function createOnAudio(
|
|||
}
|
||||
})
|
||||
.filter((data) => data !== undefined)
|
||||
.map((data) => data!)
|
||||
.filter((data) => !silence(...data.decoded));
|
||||
.map((data) => data!);
|
||||
};
|
||||
}
|
||||
|
||||
function silence(...values: number[]) {
|
||||
for (const value of values) {
|
||||
if (value !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,42 +3,23 @@ import { ConnectionData, setUserSSRC } from "../connection-data.ts";
|
|||
import { discoverIP } from "../udp/discover.ts";
|
||||
import { setSpeaking } from "../udp/speaking.ts";
|
||||
import { sendHeart } from "./heartbeat.ts";
|
||||
|
||||
export enum ServerVoiceOpcodes {
|
||||
/** Complete the websocket handshake. */
|
||||
Ready = VoiceOpcodes.Ready,
|
||||
/** Describe the session. */
|
||||
SessionDescription = VoiceOpcodes.SessionDescription,
|
||||
/** Indicate which users are speaking. */
|
||||
Speaking = VoiceOpcodes.Speaking,
|
||||
/** Sent to acknowledge a received client heartbeat. */
|
||||
HeartbeatACK = VoiceOpcodes.HeartbeatACK,
|
||||
/** Time to wait between sending heartbeats in milliseconds. */
|
||||
Hello = VoiceOpcodes.Hello,
|
||||
/** Acknowledge a successful session resume. */
|
||||
Resumed = VoiceOpcodes.Resumed,
|
||||
/** A client has disconnected from the voice channel */
|
||||
ClientDisconnect = VoiceOpcodes.ClientDisconnect,
|
||||
/** Weird OP code containing video and audio codecs */
|
||||
Undocumented = 14,
|
||||
}
|
||||
import { ReceiveVoiceOpcodes } from "./opcodes.ts";
|
||||
|
||||
export const socketHandlers: Record<
|
||||
ServerVoiceOpcodes,
|
||||
ReceiveVoiceOpcodes,
|
||||
(connectionData: ConnectionData, d: any) => void
|
||||
> = {
|
||||
[ServerVoiceOpcodes.Ready]: ready,
|
||||
[ServerVoiceOpcodes.SessionDescription]: sessionDescription,
|
||||
[ServerVoiceOpcodes.Speaking]: speaking,
|
||||
[ServerVoiceOpcodes.HeartbeatACK]: heartbeatACK,
|
||||
[ServerVoiceOpcodes.Hello]: hello,
|
||||
[ServerVoiceOpcodes.Resumed]: resumed,
|
||||
[ServerVoiceOpcodes.ClientDisconnect]: clientDisconnect,
|
||||
[ServerVoiceOpcodes.Undocumented]: undocumented,
|
||||
[ReceiveVoiceOpcodes.Ready]: ready,
|
||||
[ReceiveVoiceOpcodes.SessionDescription]: sessionDescription,
|
||||
[ReceiveVoiceOpcodes.Speaking]: speaking,
|
||||
[ReceiveVoiceOpcodes.HeartbeatACK]: heartbeatACK,
|
||||
[ReceiveVoiceOpcodes.Hello]: hello,
|
||||
[ReceiveVoiceOpcodes.Resumed]: resumed,
|
||||
[ReceiveVoiceOpcodes.ClientDisconnect]: clientDisconnect,
|
||||
};
|
||||
|
||||
function hello(conn: ConnectionData, d: { heartbeat_interval: number }) {
|
||||
conn.stopHeart = sendHeart(conn.ws!, d.heartbeat_interval);
|
||||
conn.stopHeart = sendHeart(conn, d.heartbeat_interval);
|
||||
}
|
||||
|
||||
function ready(conn: ConnectionData, d: any) {
|
||||
|
@ -65,8 +46,9 @@ function ready(conn: ConnectionData, d: any) {
|
|||
}
|
||||
|
||||
function resumed(conn: ConnectionData) {
|
||||
console.log("Resumed success");
|
||||
conn.context.ready = true;
|
||||
conn.context.reconnect = 0;
|
||||
setSpeaking(conn, true);
|
||||
}
|
||||
|
||||
function sessionDescription(conn: ConnectionData, d: any) {
|
||||
|
@ -75,6 +57,7 @@ function sessionDescription(conn: ConnectionData, d: any) {
|
|||
conn.secret = new Uint8Array(secret);
|
||||
conn.mode = mode;
|
||||
conn.context.ready = true;
|
||||
conn.context.reconnect = 0;
|
||||
setSpeaking(conn, true);
|
||||
}
|
||||
|
||||
|
@ -83,8 +66,12 @@ function speaking(conn: ConnectionData, d: any) {
|
|||
const ssrc = Number(d.ssrc);
|
||||
setUserSSRC(conn, user_id, ssrc);
|
||||
}
|
||||
function heartbeatACK() {}
|
||||
|
||||
function heartbeatACK(conn: ConnectionData, d: number) {
|
||||
if (conn.context.lastHeart === d) {
|
||||
conn.context.missedHeart = 0;
|
||||
conn.context.lastHeart = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function clientDisconnect() {}
|
||||
|
||||
function undocumented() {}
|
||||
|
|
|
@ -1,29 +1,37 @@
|
|||
import { VoiceOpcodes } from "../../deps.ts";
|
||||
import { setDriftlessTimeout } from "npm:driftless";
|
||||
import { ConnectionData } from "../mod.ts";
|
||||
|
||||
function createHeartBeat(time: number) {
|
||||
return JSON.stringify({
|
||||
op: VoiceOpcodes.Heartbeat,
|
||||
d: time,
|
||||
});
|
||||
function sendHeartBeat(conn: ConnectionData) {
|
||||
if (conn.context.lastHeart !== undefined) {
|
||||
conn.context.missedHeart++;
|
||||
}
|
||||
conn.context.lastHeart = Date.now();
|
||||
conn.ws?.send(
|
||||
JSON.stringify({
|
||||
op: VoiceOpcodes.Heartbeat,
|
||||
d: conn.context.lastHeart,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function sendHeart(ws: WebSocket, interval: number) {
|
||||
export function sendHeart(conn: ConnectionData, interval: number) {
|
||||
let last = Date.now();
|
||||
let timestamp = 0;
|
||||
const heartbeat = createHeartBeat(timestamp);
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(heartbeat);
|
||||
if (conn.ws?.readyState === WebSocket.OPEN) {
|
||||
sendHeartBeat(conn);
|
||||
}
|
||||
let done = false;
|
||||
const repeatBeat = () => {
|
||||
if (done || ws.readyState !== WebSocket.OPEN) {
|
||||
if (done || conn.ws?.readyState !== WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
if (conn.context.missedHeart >= 3) {
|
||||
console.log("Missed too many heartbeats, attempting reconnect");
|
||||
conn.ws?.close();
|
||||
return;
|
||||
}
|
||||
timestamp += interval;
|
||||
const heartbeat = createHeartBeat(timestamp);
|
||||
last = Date.now();
|
||||
ws.send(heartbeat);
|
||||
sendHeartBeat(conn);
|
||||
setDriftlessTimeout(repeatBeat, interval + (last - Date.now()));
|
||||
};
|
||||
setDriftlessTimeout(repeatBeat, interval + (last - Date.now()));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { VoiceOpcodes } from "../../deps.ts";
|
||||
import { VoiceCloseEventCodes } from "../../deps.ts";
|
||||
import { ConnectionData } from "../connection-data.ts";
|
||||
import { ServerVoiceOpcodes, socketHandlers } from "./handlers.ts";
|
||||
import { socketHandlers } from "./handlers.ts";
|
||||
import { SendVoiceOpcodes } from "./opcodes.ts";
|
||||
|
||||
export function connectWebSocket(
|
||||
conn: ConnectionData,
|
||||
|
@ -19,7 +20,7 @@ export function connectWebSocket(
|
|||
const ws = new WebSocket(`wss://${endpoint}?v=4`);
|
||||
conn.ws = ws;
|
||||
const identifyRequest = JSON.stringify({
|
||||
op: VoiceOpcodes.Identify,
|
||||
op: SendVoiceOpcodes.Identify,
|
||||
d: {
|
||||
server_id: guildId.toString(),
|
||||
user_id: userId.toString(),
|
||||
|
@ -28,7 +29,7 @@ export function connectWebSocket(
|
|||
},
|
||||
});
|
||||
const resumeRequest = JSON.stringify({
|
||||
op: VoiceOpcodes.Resume,
|
||||
op: SendVoiceOpcodes.Resume,
|
||||
d: {
|
||||
server_id: guildId.toString(),
|
||||
session_id: sessionId,
|
||||
|
@ -69,7 +70,7 @@ function handleOpen(
|
|||
|
||||
function handleMessage(conn: ConnectionData, ev: MessageEvent<any>) {
|
||||
const data = JSON.parse(ev.data);
|
||||
socketHandlers[data.op as ServerVoiceOpcodes](conn, data.d);
|
||||
socketHandlers[data.op]?.(conn, data.d);
|
||||
}
|
||||
|
||||
function handleClose(
|
||||
|
@ -80,15 +81,19 @@ function handleClose(
|
|||
) {
|
||||
conn.stopHeart();
|
||||
conn.context.ready = false;
|
||||
if (event.code < 4000) {
|
||||
console.log("The socket lost its connection for some reason");
|
||||
conn.resume = true;
|
||||
connectWebSocket(conn, userId, guildId);
|
||||
} else if (event.code === 4014) {
|
||||
conn.context.speaking = false;
|
||||
} else if (event.code === 4006) {
|
||||
conn.context.speaking = false;
|
||||
conn.context.speaking = false;
|
||||
conn.context.lastHeart = undefined;
|
||||
conn.context.missedHeart = 0;
|
||||
if (VoiceCloseEventCodes.Disconnect === event.code) {
|
||||
console.log("Couldn't reconnect :(");
|
||||
return;
|
||||
}
|
||||
if (conn.context.reconnect >= 3) {
|
||||
return;
|
||||
}
|
||||
conn.context.reconnect++;
|
||||
conn.resume = true;
|
||||
connectWebSocket(conn, userId, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { VoiceOpcodes } from "../../deps.ts";
|
||||
|
||||
export enum ReceiveVoiceOpcodes {
|
||||
/** Complete the websocket handshake. */
|
||||
Ready = VoiceOpcodes.Ready,
|
||||
/** Describe the session. */
|
||||
SessionDescription = VoiceOpcodes.SessionDescription,
|
||||
/** Indicate which users are speaking. */
|
||||
Speaking = VoiceOpcodes.Speaking,
|
||||
/** Sent to acknowledge a received client heartbeat. */
|
||||
HeartbeatACK = VoiceOpcodes.HeartbeatACK,
|
||||
/** Time to wait between sending heartbeats in milliseconds. */
|
||||
Hello = VoiceOpcodes.Hello,
|
||||
/** Acknowledge a successful session resume. */
|
||||
Resumed = VoiceOpcodes.Resumed,
|
||||
/** A client has disconnected from the voice channel */
|
||||
ClientDisconnect = VoiceOpcodes.ClientDisconnect,
|
||||
}
|
||||
|
||||
export enum SendVoiceOpcodes {
|
||||
/** Begin a voice websocket connection. */
|
||||
Identify = VoiceOpcodes.Identify,
|
||||
/** Select the voice protocol. */
|
||||
SelectProtocol = VoiceOpcodes.SelectProtocol,
|
||||
/** Keep the websocket connection alive. */
|
||||
Heartbeat = VoiceOpcodes.Heartbeat,
|
||||
/** Indicate which users are speaking. */
|
||||
Speaking = VoiceOpcodes.Speaking,
|
||||
/** Resume a connection. */
|
||||
Resume = VoiceOpcodes.Resume,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
export async function* streamAsyncIterator<T>(stream: ReadableStream<T>) {
|
||||
export async function* streamAsyncIterator(stream: ReadableStream) {
|
||||
// Get a lock on the stream
|
||||
const reader = stream.getReader();
|
||||
|
||||
|
|
4
utils.ts
4
utils.ts
|
@ -1,6 +1,6 @@
|
|||
import { ytdl } from "https://deno.land/x/ytdl_core@v0.1.1/mod.ts";
|
||||
import { Bot } from "https://deno.land/x/discordeno@17.0.1/bot.ts";
|
||||
import { connectToVoiceChannel } from "https://deno.land/x/discordeno@17.0.1/helpers/guilds/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";
|
||||
|
||||
|
|
Loading…
Reference in New Issue