Giter Site home page Giter Site logo

discord-voice / discord-voice Goto Github PK

View Code? Open in Web Editor NEW
37.0 37.0 12.0 560 KB

⏲️ A complete framework to facilitate the tracking of user voice time using discord.js

Home Page: https://discord-voice.js.org

JavaScript 0.34% TypeScript 99.66%
discord discord-api discord-bot discord-giveaways discord-js discord-voice discord-voicechannel discordapp discordbot discordjs hacktoberfest nodejs

discord-voice's Introduction

Discord Voice

What is Discord Voice?

Discord Voice is a powerful Node.js module that allows you to easily track the user's voice time and levels!

Features

  • ✨ Easy to use!
  • 📁 Support for all databases! (default is json)
  • ⚙️ Very customizable! (ignored channels, ignored members, ignored permissions, xp amount to add, voice time to add etc...)
  • 🚀 Super powerful: create, edit and delete!
  • 🕸️ Support for shards!
  • 🔐 Discord.js Collection Based!
  • and much more!

Installation

npm install --save discord-voice

Examples

You can use this example bot on GitHub: VoiceTimeTrackerBot

Launch of the module

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:

Create a guild

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}\``);
        });
    };
});
  • This allow's you create a guild in the database if the guild is not already present in the database. You can pass an options object to customize the guild's data. For a list of them refer to the documentation.

Editing a guild

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}\``);
        });
    }
});
  • This allow's you edit a guild's data. You need to pass an options object to edit the guild's data. For a list of them refer to the documentation.

Delete a guild

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}\``);
        });
    }
});
  • This allow's you delete a guild from the database if the guild is present in the database.

Fetch guilds

// 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>)

Exempt Channels

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

  • You can use this, instead of the guild parameter, inside of the function string to access anything of the giveaway instance.
    For example: this.extraData, or this.client.
  • Strings have to be "stringified" (wrapped in quotation marks) again like you can see in the example.
    Array brackets also have to be stated again.
  • Global variables which contain numbers with more than 16 digits cannot be used.
    => Snoflakes have to be "stringified" correctly to avoid misbehaviour.
  • If you want to make an asynchronous function in this format, refer to this article.
  • Because of those various complications it is therefore highly suggested to use guild.extraData for storing variables.
    But if you really want to do it in this way and need more information/help, please visit the Discord Server.

Exempt Members

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

  • You can use this, instead of the guild parameter, inside of the function string to access anything of the giveaway instance.
    For example: this.extraData, or this.client.
  • Strings have to be "stringified" (wrapped in quotation marks) again like you can see in the example.
    Array brackets also have to be stated again.
  • Global variables which contain numbers with more than 16 digits cannot be used.
    => Snoflakes have to be "stringified" correctly to avoid misbehaviour.
  • If you want to make an asynchronous function in this format, refer to this article.
  • Because of those various complications it is therefore highly suggested to use guild.extraData for storing variables.
    But if you really want to do it in this way and need more information/help, please visit the Discord Server.

Voice Time To Add

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.

Xp Amount To Add

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.

Level Multiplier

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.

Custom Database

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

Icons made by surang from www.flaticon.com

discord-voice's People

Contributors

jjamesiboi avatar lebyy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

discord-voice's Issues

No voice channel detection (voiceStateUpdate)

I'm assuming, due to Discord update, the detection for the voiceStateUpdate is no longer working in the module.
Under discord-voice\src\Manager.js, line 431 for the _checkUsers() function.

The actual if condition is (user.member && user.channel) but client and voiceManager objects changed since so the module don't detect any member nor channel.

In my case, I edited the module as followed:

Fetching the user before:
const user = await u.client.guilds.cache.get(u.guildId).members.cache.get(u.userId);

And checking if there's an user and if the user is in a voice channel.
if (user && user.voice.channel) {

By editing the module like this, you will need to edit the code below aswell.

[⚠️] Maintainer required

Hello! If anybody is interested to maintain this package let me know!
I am busy with my college so I won't be able to push much updates to discord-voice.

Exempt users

It is possible to exempt a specific user from being tracked ? and track all the other ones

Schema name mistake

You are creating schema 'Messages' to store the voice data, but you're using that in your discord-messages package too

add ability graph image to voice-stats

Add graphics, example screen and some code
image

    let embed = new MessageEmbed()
        .setAuthor(message.author.username, message.author.avatarURL({ dynamic: true }))
        .setFooter(`${message.guild.name} root prod.`)
    let day = await tm.getDay(message.guild.id);
    embed.setDescription(`${message.guild.name}** день ${day}** .`);
    embed.setColor("2f3136");

    Stat.aggregate([
        {$project: {Message: 0}},
        { $sort: { AllVoice: -1 } }
    ]).limit(10).exec(async (err, docs) => {
        if (err) return message.reply("произошла ошибка.");
        let users = [], usersToEmbed = [];

        if (docs.length > 0) {
            for (let index = 0; index < docs.length; index++) {
                const doc = docs[index];
                let stat = doc;
                if (!stat) continue;

                if (stat.AllVoice <= 0) continue;

                if (stat.Voice) {
                    let days = Object.keys(stat.Voice);
                    let dataValues = new Array(day).fill(0);
                    days.forEach(_day => {
                        let sum = Object.values(stat.Voice[_day]).reduce((x, y) => x + y, 0);
                        dataValues[_day - 1] = (sum / (1000 * 60));
                    });
                    let user = (await Helper.GetUser(doc.Id));
                    usersToEmbed.push({
                        User: user,
                        Value: dataValues.reduce((x, y) => x + y, 0)
                    });
                    let borderColors = new Array(dataValues.length).fill(getColor(index, "0.8"));
                    let backgroundColors = new Array(dataValues.length).fill(getColor(index, "0.1"))
                    let pointBackgroundColors = new Array(dataValues.length).fill(getColor(index, "1"));
                    let data = {
                        label: `${user.username}`,
                        data: dataValues,
                        backgroundColor: backgroundColors,
                        borderColor: borderColors,
                        pointBackgroundColor: pointBackgroundColors,
                        borderWidth: 1.5,
                    };
                    users.push(data);
                }
            }

            let dataDate = [];
            for (let index = 0; index < day; index++) {
                let date = new Date(Date.now() - (1000 * 60 * 60 * 24 * (day - (index + 1))));
            }

            let buffer = await cm.ImageFromData({
                width: 600,
                height: 290,
                type: 'line',
                data: {
                    labels: [].concat(dataDate),
                    datasets: users
                },
                options: {
                    legend: {
                        labels: {
                            fontColor: '#ffffff',
                            fontSize: 20
                        }
                    }
                }
            });
            embed.addField(`Топ по голосовой активности`, usersToEmbed.map((val, index) => `\`${index + 1}.\` ${val.User}(${val.User.username}): \`${moment.duration(val.Value * (1000 * 60)).format("H [ч., ] m [мин.]")}\``).join("\n"))
            embed.setImage("attachment://Graph.png");
            let attachment = new MessageAttachment(buffer, "Graph.png");

            message.channel.csend({
                embeds: [embed],
                files: [attachment]
            });
        }
        else {
            embed.addField("Нет данных.", "** **");
            return message.csend(embed);
        }
    });
}

const colors = [
    'rgba(240, 255, 0, <f>)',
    'rgba(147, 255, 0, <f>)',
    'rgba(0, 255, 4, <f>)',
    'rgba(0, 255, 182, <f>)',
    'rgba(0, 240, 255, <f>)',
    'rgba(0, 124, 255, <f>)',
    'rgba(81, 0, 255, <f>)',
    'rgba(182, 0, 255, <f>)',
    'rgba(255, 0, 220, <f>)',
    'rgba(255, 0, 85, <f>)',
]
function getColor(index, x) {
    let color = colors[index].replace("<f>", x);
    return color;
}

blacklist channel + minimal count user

Greetings, if not difficult, please add such functions, the ability to add channels where the system will not read online and the ability to specify the minimum number of users in voice channels to get started.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.