⏲️ A complete framework to facilitate the tracking of user voice time using discord.js
Discord Voice is a powerful Node.js module that allows you to easily track the user's voice time and levels!
npm install --save discord-voice
You can use this example bot on GitHub: VoiceTimeTrackerBot
Required Discord Intents: Guilds
and GuildVoiceStates
.
const Discord = require('discord.js');
const client = new Discord.Client({
intents: [
Discord.IntentsBitField.Flags.Guilds,
Discord.IntentsBitField.Flags.GuildVoiceStates
]
});
// Requires Manager from discord-voice
const { VoiceTimeManager } = require('discord-voice');
const manager = new VoiceTimeManager(client, {
storage: './guilds.json',
default: {
trackBots: false,
trackAllChannels: true
}
});
// We now have a voiceTimeManager property to access the manager everywhere!
client.voiceTimeManager = manager;
client.on('ready', () => {
console.log('Bot is ready!');
});
client.login(process.env.DISCORD_BOT_TOKEN);
After that, user's who are in the voice channel's that the bot has cached will be checked. You can pass an options object to customize the giveaways. Here is a list of them:
client.on('interactionCreate', (interaction) => {
if (interaction.isChatInputCommand() && interaction.commandName === 'create-guild') {
const guildId = interaction.options.getString('guildId');
const users = interaction.options.getString('users');
const options = interaction.options.getString('options');
client.voiceTimeManager.create(guildId, users, options).then(() => {
interaction.reply('Success! Guild Created!');
}).catch((err) => {
interaction.reply(`An error has occurred, please check and try again.\n\`${err}\``);
});
};
});
client.on('interactionCreate', (interaction) => {
if (interaction.isChatInputCommand() && interaction.commandName === 'edit') {
const guildId = interaction.options.getString('guildId');
client.voiceTimeManager.edit(guildId, {
trackBots: true,
trackAllChannels: false
}).then(() => {
interaction.reply('Success! Guild updated!');
}).catch((err) => {
interaction.reply(`An error has occurred, please check and try again.\n\`${err}\``);
});
}
});
client.on('interactionCreate', (interaction) => {
if (interaction.isChatInputCommand() && interaction.commandName === 'delete') {
const guildId = interaction.options.getString('guildId');
client.voiceTimeManager.delete(guildId).then(() => {
interaction.reply('Success! Guild deleted!');
}).catch((err) => {
interaction.reply(`An error has occurred, please check and try again.\n\`${err}\``);
});
}
});
// A list of all the guilds in the database.
const allGuilds = client.voiceTimeManager.guilds; // Returns a Discord Collection of Guilds (Discord.Collection<guildId, guildData>)
// Returns the guild with Id "1909282092"
const guild = client.voiceTimeManager.guilds.get('1909282092'); // Returns a Guild. (Discord.Collection<guildId, guildData>)
// A list of all guilds with atleast 1 user in the database.
const guildWithUsers = client.voiceTimeManager.guilds.filter((guild) => guild.users.size > 0); // Returns a Discord Collection of Guilds (Discord.Collection<guildId, guildData>)
const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
guild.config.edit({
// The channel will not be tracked if it's name is "private"
exemptChannels: (channel) => channel.name === "private")
});
⚠️ Note (only for proficients) (this applies to all config's which expect a function input): if you want to use values of global variables inside of the function without using guild.extraData
, you can use the Function constructor:
const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
const channelName = "private";
guild.config.edit({
// The channel won't be tracked if it's name is equal to the value which is assigned to "channelName"
exemptChannels: new Function(
"channel",
"guild",
`return channel.name === \'${channelName}\'`)
});
⚠ Note
this
, instead of the guild
parameter, inside of the function string to access anything of the giveaway instance.this.extraData
, or this.client
.guild.extraData
for storing variables.const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
guild.config.edit({
// Only members who have the "Nitro Boost" role are able to be tracked
exemptMembers: (member) => !member.roles.cache.some((r) => r.name === "Nitro Boost")
});
⚠️ Note (only for proficients) (this applies to all config's which expect a function input): if you want to use values of global variables inside of the function without using guild.extraData
, you can use the Function constructor:
const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
const roleName = "Nitro Boost";
guild.config.edit({
// Only members who have the the role which is assigned to "roleName" are able to be tracked
exemptMembers: new Function(
"member",
"guild",
`return !member.roles.cache.some((r) => r.name === \'${roleName}\')`)
});
⚠ Note
this
, instead of the guild
parameter, inside of the function string to access anything of the giveaway instance.this.extraData
, or this.client
.guild.extraData
for storing variables.const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
guild.config.edit({
xpAmountToAdd: (guild) => Math.floor(Math.random() * 10) + 1 // This will add a random amount between 1 and 10 of xp to the user.
});
⚠️ Note: The returned value should be a number or the default value (Math.floor(Math.random() * 10) + 1
) will be used.
const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
guild.config.edit({
voiceTimeToAdd: () => 1000 // This will add 1000 ms of voice time everytime the user is checked.
});
⚠️ Note: The returned value should be a number or the default value (1000
) will be used.
const guildId = '1909282092';
const guild = client.voiceTimeManager.guilds.get(guildId);
guild.config.edit({
levelMultiplier: () => 0.1 // This will set the level multiplier to 0.1 (normally it's 0.1).
});
⚠️ Note: The returned value should be a number or the default value (0.1
) will be used.
You can use your custom database to save guilds, instead of the json files (the "database" by default for discord-voice
). For this, you will need to extend the VoiceTimeManager
class, and replace some methods with your custom ones. There are 4 methods you will need to replace:
getAllGuilds
: this method returns an array of stored guilds.saveGuild
: this method stores a new guild in the database.editGuild
: this method edits a guild already stored in the database.deleteGuild
: this method deletes a guild from the database (permanently).⚠️ All the methods should be asynchronous to return a promise!
SQL examples
NoSQL examples
mongoose
example instead