Need help with discord-giveaways?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

Androz2091
212 Stars 105 Forks MIT License 537 Commits 12 Opened issues

Description

🎉 Complete framework to facilitate the creation of giveaways using discord.js

Services available

!
?

Need anything else?

Contributors list

# 25,400
Discord
js
Bootstr...
embeds
312 commits
# 157,566
Discord
discord...
HTML
js
2 commits
# 445,317
embeds
Discord
discord...
CSS
1 commit
# 607,095
Dart
Discord
discord...
JavaScr...
1 commit
# 89,030
Discord
TypeScr...
React
Node.js
1 commit

Discord Giveaways

discordBadge downloadsBadge versionBadge documentationBadge

Discord Giveaways is a powerful Node.js module that allows you to easily create giveaways!

Features

  • ⏱️ Easy to use!
  • 🔄 Automatic restart after bot crash!
  • 🇫🇷 Support for translations: adapt the strings for your own language!
  • 📁 Support for all databases! (default is json)
  • ⚙️ Very customizable! (prize, duration, winners, ignored permissions, bonus entries, etc...)
  • 🚀 Super powerful: start, edit, reroll, end, delete and pause giveaways!
  • 💥 Events: giveawayEnded, giveawayRerolled, giveawayDeleted, giveawayReactionAdded, giveawayReactionRemoved, endedGiveawayReactionAdded
  • 🕸️ Support for shards!
  • and much more!

Installation

npm install --save discord-giveaways

Examples

You can read this example bot on GitHub: discord-giveaways-bot

Launch of the module

Required Discord Intents:

GUILDS
and
GUILD_MESSAGE_REACTIONS
.
Optional Discord Privileged Intent for better performance:
GUILD_MEMBERS
.
const Discord = require('discord.js'),
    client = new Discord.Client({
        intents: [
            Discord.Intents.FLAGS.GUILDS,
            Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
            Discord.Intents.FLAGS.GUILD_MEMBERS // Optional, for better performance
        ]
    }),
    settings = {
        prefix: 'g!',
        token: 'Your Discord Bot Token'
    };

// Requires Manager from discord-giveaways const { GiveawaysManager } = require('discord-giveaways'); // Starts updating currents giveaways const manager = new GiveawaysManager(client, { storage: './giveaways.json', default: { botsCanWin: false, embedColor: '#FF0000', embedColorEnd: '#000000', reaction: '🎉' } }); // We now have a giveawaysManager property to access the manager everywhere! client.giveawaysManager = manager;

client.on('ready', () => { console.log('I'm ready!'); });

client.login(settings.token);

After that, giveaways that are not yet completed will start to be updated again and new giveaways can be started. You can pass an options object to customize the giveaways. Here is a list of them:

Start a giveaway

client.on('interactionCreate', (interaction) => {

const ms = require('ms');

if (interaction.isCommand() && interaction.commandName === 'start') {
    // /start 2d 1 Awesome prize!
    // Will create a giveaway with a duration of two days, with one winner and the prize will be "Awesome prize!"

    const duration = interaction.options.getString('duration');
    const winnerCount = interaction.options.getInteger('winners');
    const prize = interaction.options.getString('prize');

    client.giveawaysManager.start(interaction.channel, {
        duration: ms(duration),
        winnerCount,
        prize
    }).then((gData) => {
        console.log(gData); // {...} (messageId, end date and more)
    });
    // And the giveaway has started!
}

});

This allows you to start a new giveaway. Once the

start()
function is called, the giveaway starts, and you only have to observe the result, the package does the rest!

⚠ ATTENTION!

The command examples below (reroll, edit delete, end) can be executed on any server your bot is a member of if a person has the

prize
or the
messageId
of a giveaway. To prevent abuse we recommend to check if the
prize
or the
messageId
that was provided by the command user is for a giveaway on the same server, if it is not, then cancel the command execution.
const giveaway = 
// Search with giveaway prize
client.giveawaysManager.giveaways.find((g) => g.guildId === interaction.guildId && g.prize === interaction.options.getString('query')) ||
// Search with messageId
client.giveawaysManager.giveaways.find((g) => g.guildId === interaction.guildId && g.messageId === interaction.options.getString('query'));

// If no giveaway was found if (!giveaway) return interaction.channel.send('Unable to find a giveaway for '+ args.join(' ') +'.');

Reroll a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'reroll') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.reroll(messageId).then(() => {
        interaction.channel.send('Success! Giveaway rerolled!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

  • options.winnerCount: the number of winners to pick.
  • options.messages: an object with the "congrat" and the "error" message. Usage example.

Edit a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'edit') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.edit(messageId, {
        addTime: 5000,
        newWinnerCount: 3,
        newPrize: 'New Prize!'
    }).then(() => {
        interaction.channel.send('Success! Giveaway updated!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

  • options.newWinnerCount: the new number of winners.
  • options.newPrize: the new prize. You can access giveaway properties.
  • options.addTime: the number of milliseconds to add to the giveaway duration.
  • options.setEndTimestamp: the timestamp of the new end date (for example, for the giveaway to be ended in 1 hour, set it to
    Date.now() + 60000
    ).
  • options.newMessages: the new giveaway messages. Will get merged with the existing object, if there.
    ^^^ You can access giveaway properties.
  • options.newExtraData: the new extra data value for the giveaway.
  • options.newBonusEntries: the new BonusEntry objects (for example, to change the amount of entries).
  • options.newLastChance: the new options for the last chance system. Will get merged with the existing object, if there.

Note: to reduce giveaway duration, define

addTime
with a negative number! For example
addTime: -5000
will reduce giveaway duration by 5 seconds!

Delete a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'delete') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.delete(messageId).then(() => {
        interaction.channel.send('Success! Giveaway deleted!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

  • doNotDeleteMessage: whether the giveaway message shouldn't be deleted.

⚠️ Note: when you use the delete function, the giveaway data and the message of the giveaway are deleted (by default). You cannot restore a giveaway once you have deleted it!

End a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'end') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.end(messageId).then(() => {
        interaction.channel.send('Success! Giveaway ended!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

Pause a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'pause') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.pause(messageId).then(() => {
        interaction.channel.send('Success! Giveaway paused!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

  • options.content: the text of the embed when the giveaway is paused. You can access giveaway properties.
  • options.unPauseAfter: the number of milliseconds after which the giveaway will automatically unpause.
  • options.embedColor: the color of the embed when the giveaway is paused.

⚠️ Note: the pause function overwrites/edits the pauseOptions object property of a giveaway!

Unpause a giveaway

client.on('interactionCreate', (interaction) => {

if (interaction.isCommand() && interaction.commandName === 'unpause') {
    const messageId = interaction.options.getString('message_id');
    client.giveawaysManager.unpause(messageId).then(() => {
        interaction.channel.send('Success! Giveaway unpaused!');
    }).catch((err) => {
        interaction.channel.send(`An error has occurred, please check and try again.\n\`${err}\``);
    });
}

});

Fetch giveaways

// A list of all the giveaways
const allGiveaways = client.giveawaysManager.giveaways; // [ {Giveaway}, {Giveaway} ]

// A list of all the giveaways on the server with Id "1909282092" const onServer = client.giveawaysManager.giveaways.filter((g) => g.guildId === '1909282092');

// A list of the current active giveaways (not ended) const notEnded = client.giveawaysManager.giveaways.filter((g) => !g.ended);

Exempt Members

Function to filter members. If true is returned, the member will not be able to win the giveaway.

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Free Steam Key',
    // Only members who have the "Nitro Boost" role are able to win
    exemptMembers: (member) => !member.roles.cache.some((r) => r.name === 'Nitro Boost')
});

Note: if the function should be customizable:

const roleName = 'Nitro Boost';

client.giveawaysManager.start(interaction.channel, { duration: 60000, winnerCount: 1, prize: 'Free Steam Key', // Only members who have the the role which is assigned to "roleName" are able to win exemptMembers: new Function('member', return !member.roles.cache.some((r) => r.name === \'${roleName}\')), });

Note: because of the special

new Function()
format, you can use
this
inside of the function string to access anything from the giveaway instance. For example:
this.extraData
, or
this.client
.

Last Chance

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Discord Nitro!',
    lastChance: {
        enabled: true,
        content: '⚠️ **LAST CHANCE TO ENTER !** ⚠️',
        threshold: 5000,
        embedColor: '#FF0000'
    }
});
  • lastChance.enabled: if the last chance system is enabled.
  • lastChance.content: the text of the embed when the last chance system is enabled.
    ^^^ You can access giveaway properties.
  • lastChance.threshold: the number of milliseconds before the giveaway ends when the last chance system will be enabled.
  • lastChance.embedColor: the color of the embed when last chance is enabled.

Pause Options

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Discord Nitro!',
    pauseOptions: {
        isPaused: true,
        content: '⚠️ **THIS GIVEAWAY IS PAUSED !** ⚠️',
        unPauseAfter: null,
        embedColor: '#FFFF00'
    }
});
  • pauseOptions.isPaused: if the giveaway is paused.
  • pauseOptions.content: the text of the embed when the giveaway is paused.
    ^^^ You can access giveaway properties.
  • pauseOptions.unPauseAfter: the number of milliseconds after which the giveaway will automatically unpause.
  • pauseOptions.embedColor: the color of the embed when the giveaway is paused.

Bonus Entries

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Free Steam Key',
    bonusEntries: [  
        {
            // Members who have the "Nitro Boost" role get 2 bonus entries
            bonus: (member) => member.roles.cache.some((r) => r.name === 'Nitro Boost') ? 2 : null,
            cumulative: false
        }
    ]
});
  • bonusEntries[].bonus: the filter function that takes one parameter, a member and returns the amount of entries.
  • bonusEntries[].cumulative: if the amount of entries from the function can get summed with other amounts of entries.

Note: if the

bonus
function should be customizable:
const roleName = 'Nitro Boost';
const roleBonusEntries = 2;

client.giveawaysManager.start(interaction.channel, { duration: 60000, winnerCount: 1, prize: 'Free Steam Key', bonusEntries: [ {
// Members who have the role which is assigned to "roleName" get the amount of bonus entries which is assigned to "roleBonusEntries" bonus: new Function('member', return member.roles.cache.some((r) => r.name === \'${roleName}\') ? ${roleBonusEntries} : null), cumulative: false } ] });

Note: because of the special

new Function()
format, you can use
this
inside of the function string to access anything from the giveaway instance. For example:
this.extraData
, or
this.client
.

Send embed as message

You can send an embed instead of, or with the normal message for the following messages:

giveaway.messages.winMessage
,
GiveawayRerollOptions.messages.congrat
,
GiveawayRerollOptions.messages.error
and
client.giveawaysManager.end(messageId, noWinnerMessage)
.

The format looks like this:

js
message: { content: '', embed: new Discord.MessageEmbed() }

You can access giveaway properties in all embed properties that are a string.

Access giveaway properties in messages

You can access any giveaway property inside of giveaway messages with the format:

{this.}
.
For example:
messages: { winMessage: 'Congratulations, {winners}! You won **{this.prize}**!\n{this.messageURL}' }

Also, you can write JavaScript code inside of the

{}
.
For example:
messages: { winMessage: 'Congratulations, {winners}! You won **{this.prize.toUpperCase()}**!\n{this.messageURL}' }

If you want to fill in strings that are not messages of a giveaway, or just custom embeds, then you can use

giveaway.fillInString(string)
for strings and
giveaway.fillInEmbed(embed)
for embeds.

🇫🇷 Translation

You can also pass a

messages
parameter for
start()
function, if you want to translate the bot text:
  • options.messages.giveaway: the message that will be displayed above the embeds.
  • options.messages.giveawayEnded: the message that will be displayed above the embeds when the giveaway is ended.
  • options.messages.drawing: the message that displays the drawing timestamp.
  • options.messages.dropMessage: the message that will be displayed for drop giveaways.
  • options.messages.inviteToParticipate: the message that invites users to participate.
  • options.messages.winMessage: the message that will be displayed to congratulate the winner(s) when the giveaway is ended.
    ^^^ You can send an embed instead of, or with the normal message.
  • options.messages.embedFooter: the message displayed at the bottom of the embeds.
    ^^^ Can be deactivated and iconURL can be set.
  • options.messages.noWinner: the message that is displayed if no winner can be drawn.
  • options.messages.hostedBy: the message to display the host of the giveaway.
  • options.messages.winners: simply the expression "Winner(s):" in your language.
  • options.messages.endedAt: simply the words "Ended at" in your language.

For example:

const duration = interaction.options.getString('duration');
const winnerCount = interaction.options.getInteger('winners');
const prize = interaction.options.getString('prize');

client.giveawaysManager.start(interaction.channel, { duration: ms(duration), winnerCount, prize, messages: { giveaway: '🎉🎉 GIVEAWAY 🎉🎉', giveawayEnded: '🎉🎉 GIVEAWAY ENDED 🎉🎉', drawing: 'Drawing: {timestamp}', dropMessage: 'Be the first to react with 🎉 !', inviteToParticipate: 'React with 🎉 to participate!', winMessage: 'Congratulations, {winners}! You won {this.prize}!\n{this.messageURL}', embedFooter: '{this.winnerCount} winner(s)', noWinner: 'Giveaway cancelled, no valid participations.', hostedBy: 'Hosted by: {this.hostedBy}', winners: 'Winner(s):', endedAt: 'Ended at', } });

You can access giveaway properties in all these messages.

And for the

reroll()
function:
client.giveawaysManager.reroll(messageId, {
        messages: {
            congrat: ':tada: New winner(s): {winners}! Congratulations, you won **{this.prize}**!\n{this.messageURL}',
            error: 'No valid participations, no new winner(s) can be chosen!'
        }
    });
  • options.messages.congrat: the congratulatory message.
  • options.messages.error: the error message if there is no valid participant.

You can access giveaway properties in these messages.
You can send embeds instead of, or with the normal messages.

Custom Database

You can use your custom database to save giveaways, instead of the json files (the "database" by default for

discord-giveaways
). For this, you will need to extend the
GiveawaysManager
class, and replace some methods with your custom ones. There are 4 methods you will need to replace:
  • getAllGiveaways
    : this method returns an array of stored giveaways.
  • saveGiveaway
    : this method stores a new giveaway in the database.
  • editGiveaway
    : this method edits a giveaway already stored in the database.
  • deleteGiveaway
    : this method deletes a giveaway from the database (permanently).

⚠️ All the methods should be asynchronous to return a promise!

SQL examples

NoSQL examples

Support shards

To make

discord-giveaways
working with shards, you will need to extend the
GiveawaysManager
class and update the
refreshStorage()
method. This method should call the
getAllGiveaways()
method for every shard, so all
GiveawaysManager
synchronize their cache with the updated database.

⚠️ Note: If you are using a custom database then you must call (= add to code)

this.refreshStorage()
at the end of your extended
saveGiveaway
,
editGiveaway
and
deleteGiveaway
methods.
const Discord = require('discord.js'),
    client = new Discord.Client({
        intents: [
            Discord.Intents.FLAGS.GUILDS,
            Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
            Discord.Intents.FLAGS.GUILD_MEMBERS // Not required, but recommended
        ]
    }),
    settings = {
        prefix: 'g!',
        token: 'Your Discord Bot Token'
    };

// Extends the GiveawaysManager class and update the refreshStorage method const { GiveawaysManager } = require('discord-giveaways'); const GiveawayManagerWithShardSupport = class extends GiveawaysManager { // Refresh storage method is called when the database is updated on one of the shards async refreshStorage() { // This should make all shard refreshing their cache with the updated database return client.shard.broadcastEval(() => this.giveawaysManager.getAllGiveaways()); } };

// Create a new instance of your new class const manager = new GiveawayManagerWithShardSupport(client, { storage: './giveaways.json', default: { botsCanWin: false, embedColor: '#FF0000', embedColorEnd: '#000000', reaction: '🎉' } }); // We now have a giveawaysManager property to access the manager everywhere! client.giveawaysManager = manager;

client.on('ready', () => { console.log('I'm ready!'); });

client.login(settings.token);

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.