How can I create a listener for @discordjs/voice states?

Title kinda explains itself lol, but how can I convert things like
const { VoiceConnectionStatus, AudioPlayerStatus } = require('@discordjs/voice');

connection.on(VoiceConnectionStatus.Ready, (oldState, newState) => {
console.log('Connection is in the Ready state!');
});

player.on(AudioPlayerStatus.Playing, (oldState, newState) => {
console.log('Audio player is in the Playing state!');
});
const { VoiceConnectionStatus, AudioPlayerStatus } = require('@discordjs/voice');

connection.on(VoiceConnectionStatus.Ready, (oldState, newState) => {
console.log('Connection is in the Ready state!');
});

player.on(AudioPlayerStatus.Playing, (oldState, newState) => {
console.log('Audio player is in the Playing state!');
});
into Sapphire Listeners to put in my listeners folder? I've already got some Listeners set up for default discordjs events but I'm just unsure of how to do it for the voice status events.
Solution:
Nevermind I found my answer somewhere else
Jump to solution
18 Replies
Solution
edenn! \ (•◡•) /
Nevermind I found my answer somewhere else
edenn! \ (•◡•) /
Sapphire Framework
Listening to events emitted by other emitters | Sapphire
By default, Sapphire's event emitter is your client. However, for advanced use cases, you can specify a different
Farleena (Dani)
Farleena (Dani)11mo ago
Hey dylann! Sorry for the ping and replying to this old topc, but could you please share with me how you did this? I also would like to add voice related listeners.
edenn! \ (•◡•) /
I don't really remember anymore pepeCry apologies
Farleena (Dani)
Farleena (Dani)11mo ago
bummer, i was hoping you have a working project that used it, thanks anyway 🙂
Favna
Favna11mo ago
export class MyListener extends Listener {
public constructor(context: Listener.LoaderContext, options: Listener.Options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}
export class MyListener extends Listener {
public constructor(context: Listener.LoaderContext, options: Listener.Options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}
Assuming similar code as Dylann's original post
Farleena (Dani)
Farleena (Dani)11mo ago
Thanks! Yes, I would like to listen to the state of the bot's voiceconnection and an audioplayer. I have an ogg stream coming from a web api and I don't know why the stream keeps stopping after every song..might be stream related not discord, but I want to check. I was just not sure it's that easy, I thought as these listeners are not attached to the client, there must be some more difficult magic behind to do it 😄 So it's just the same for the other? player as emitter and Audioplayerstate.Playing as the event? Damn Sapphire sure is convenient 😄
Favna
Favna11mo ago
yes it is. You can make it "attached to the client" though after which you can use emitter: 'connection' (i.e. you dont have to import it). You do this by extending the client class and adding properties to it, similar-ish to https://www.sapphirejs.dev/docs/Guide/CLI/getting-started (though what you're really doing is basic JavaScript class extension, it's not sapphire specific at all)
Farleena (Dani)
Farleena (Dani)11mo ago
I see. I'm still not so versed in JS, but trying to research stuff, sorry if I asked something lame! blobpeek
Favna
Favna11mo ago
you didnt, no worries
Farleena (Dani)
Farleena (Dani)11mo ago
just one more please: how would I access the oldState and newState parameters? input them in the run() function?
Favna
Favna11mo ago
yes, the parameter order matches 1:1 with what is emitted. Bother. Normally I would link docs to show an example of that but the @discordjs/voice docs dont document events on the class. Well you can find what goes where I think.
Farleena (Dani)
Farleena (Dani)11mo ago
Oh wait, this is TS actually? bummer I only know JS blobpeek
Favna
Favna11mo ago
TS is JS, just with additional types.
class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}

module.exports = MyListener;
class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}

module.exports = MyListener;
it's basically the same code heck when it's ESM (basically modern JS) then it's even closer:
export class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}
export class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: connection
event: VoiceConnectionStatus.Ready
});

}
}
TS is a superset of JS. All valid JS is also valid TS.
Farleena (Dani)
Farleena (Dani)11mo ago
Yup, I think that much I knew, but not much more.. okay, I really start to feel dumb, but.. how do I get the connection? I need to export it in the command file I create it and import it in the listener?
Favna
Favna11mo ago
Correct-ish. You're better off doing something like this:
// src/lib/audio/connection.js

let connection;

function getConnection() {
return connection;
}

function setConnection(newConnection) {
connection = newConnection;
}

module.exports = { getConnection, setConnection }
// We use functions here because it's an anti-pattern to set an imported value
// --------------------
// src/commands/audio/play.js
const { getConnection, setConnection } = require('../../lib/audio/connection');
// (lots of code irrelevant to this example here)

const currentConnection = getConnection();

if (!currentConnection) {
const theConnection = whateverGoesHere;
setConnection(theConnection);
}
// --------------------
// src/listeners/audio/your-event.js
const { getConnection } = require('../../lib/audio/connection');
const { Listener } = require('@sapphire/framework');

class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: getConnection(),
event: VoiceConnectionStatus.Ready
});

}
}

module.exports = MyListener;
// src/lib/audio/connection.js

let connection;

function getConnection() {
return connection;
}

function setConnection(newConnection) {
connection = newConnection;
}

module.exports = { getConnection, setConnection }
// We use functions here because it's an anti-pattern to set an imported value
// --------------------
// src/commands/audio/play.js
const { getConnection, setConnection } = require('../../lib/audio/connection');
// (lots of code irrelevant to this example here)

const currentConnection = getConnection();

if (!currentConnection) {
const theConnection = whateverGoesHere;
setConnection(theConnection);
}
// --------------------
// src/listeners/audio/your-event.js
const { getConnection } = require('../../lib/audio/connection');
const { Listener } = require('@sapphire/framework');

class MyListener extends Listener {
constructor(context, options) {
super(context, {
...options,
emitter: getConnection(),
event: VoiceConnectionStatus.Ready
});

}
}

module.exports = MyListener;
Farleena (Dani)
Farleena (Dani)11mo ago
Kokonoted I think i messed something up.. the event fires right when i start the client 😄 Favna, where can I have a quick voice related question that's not closely related to this topic? Should I open a new topic for it?
Favna
Favna11mo ago
New topic yes
Want results from more Discord servers?
Add your server