discord-lottery-private
v1.1.4
Published
A complete framework to facilitate the creation of lotteries using discord.js
Downloads
326
Maintainers
Readme
🎰 Discord Lottery Private
A powerful and feature-rich Node.js module for creating and managing lotteries in Discord using discord.js v14+.
🎯 Features
- 🎰 Easy-to-use lottery system for Discord bots
- 🎨 Customizable embeds and messages
- ⏰ Automatic lottery management
- 🏆 Winner selection with reaction-based entries
- 💾 Persistent storage (JSON-based)
- 🎨 Custom database support
- 🌍 Multi-language support
- 📊 Event-driven architecture
- ⚠️ Last Chance announcements - Automatic @everyone pings before lottery ends
- 🧹 Memory management - Proper cleanup with destroy() method
- ✅ Input validation - Comprehensive parameter validation
- 🔒 Production ready - 45 tests, 100% passing
- ⚙️ Highly Customizable - Configure prizes, duration, winners, and more
- 🚀 Powerful Features - Start, edit, reroll, end, delete, and pause lotteries
- 💥 Event System - Listen to lottery events (ended, rerolled, deleted, etc.)
- ⚠️ Last Chance Alerts - Automatic warnings before lottery ends
- 🕸️ Shard Support - Works seamlessly with sharded bots
- 🎨 Custom Embeds - Full embed customization
- 🧪 Well Tested - Comprehensive unit test coverage
📦 Installation
npm install discord-lottery-privateRequirements:
- Node.js >= 16.9.0
- discord.js >= 14.0.0
🚀 Quick Start
Basic Setup
const { Client, GatewayIntentBits } = require('discord.js');
const { LotteriesManager } = require('discord-lottery-private');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildMembers // Optional, for better performance
]
});
// Initialize the lottery manager
const lotteryManager = new LotteriesManager(client, {
storage: './lotteries.json',
default: {
embedColor: '#FF0000',
embedColorEnd: '#000000',
reaction: '🎰'
}
});
// Make it accessible everywhere
client.lotteryManager = lotteryManager;
client.on('ready', () => {
console.log(`${client.user.tag} is ready!`);
});
client.login('YOUR_BOT_TOKEN');Start a Lottery
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'lottery') {
const duration = interaction.options.getInteger('duration'); // in hours
const prize = interaction.options.getString('prize');
await client.lotteryManager.start(interaction.channel, {
duration: duration * 60 * 60 * 1000, // Convert hours to ms
winnerCount: 1,
prize: prize,
hostedBy: interaction.user,
lastChance: {
enabled: true,
content: '⚠️ **LAST CHANCE TO ENTER!** ⚠️',
threshold: 60 * 60 * 1000, // 1 hour before end
embedColor: '#FFA500'
}
});
await interaction.reply('🎰 Lottery started!');
}
});📖 Documentation
Manager Options
new LotteriesManager(client, {
storage: './lotteries.json', // or false for no storage
forceUpdateEvery: 15000, // Update interval in ms
endedLotteriesLifetime: 30000, // How long to keep ended lotteries
default: {
embedColor: '#FF0000',
embedColorEnd: '#000000',
reaction: '🎰',
botsCanWin: false
}
});Start a Lottery
lotteryManager.start(channel, {
duration: 86400000, // 24 hours in ms
winnerCount: 1,
prize: '10,000 coins',
hostedBy: user,
// Optional: Last chance warning
lastChance: {
enabled: true,
content: '⚠️ **LAST CHANCE TO ENTER!** ⚠️',
threshold: 3600000, // 1 hour before end
embedColor: '#FFA500'
},
// Optional: Custom messages
messages: {
lottery: '🎰🎰 **LOTTERY** 🎰🎰',
lotteryEnded: '🎰🎰 **LOTTERY ENDED** 🎰🎰',
inviteToParticipate: 'React with 🎰 to enter!',
winMessage: 'Congratulations {winners}! You won **{this.prize}**!',
embedFooter: '{this.winnerCount} winner(s)',
noWinner: 'Lottery cancelled, no valid participants.',
winners: 'Winner(s):',
endedAt: 'Ended at'
}
});Edit a Lottery
lotteryManager.edit(messageId, {
newWinnerCount: 3,
newPrize: 'New Prize!',
addTime: 3600000 // Add 1 hour
// or setEndTimestamp: Date.now() + 7200000 // End in 2 hours
});End a Lottery
lotteryManager.end(messageId);Reroll a Lottery
lotteryManager.reroll(messageId, {
winnerCount: 2,
messages: {
congrat: '🎉 New winner(s): {winners}!',
error: 'No valid participants!'
}
});Delete a Lottery
lotteryManager.delete(messageId, {
doNotDeleteMessage: false // Set to true to keep the message
});Pause/Unpause a Lottery
// Pause
lotteryManager.pause(messageId, {
content: '⚠️ **LOTTERY PAUSED** ⚠️',
unpauseAfter: 3600000, // Auto-unpause after 1 hour
embedColor: '#FFFF00'
});
// Unpause
lotteryManager.unpause(messageId);🎯 Events
Listen to lottery events:
// Lottery ended
lotteryManager.on('lotteryEnded', (lottery, winners) => {
console.log(`Lottery ${lottery.messageId} ended!`);
console.log(`Winners:`, winners);
});
// Last chance triggered (NEW!)
lotteryManager.on('lotteryLastChance', (lottery) => {
console.log(`⚠️ Last chance for lottery ${lottery.messageId}!`);
// Send a public announcement
const channel = lottery.message?.channel;
if (channel) {
channel.send(`@everyone 🎰 **LAST CHANCE!** The lottery ends in ${lottery.lastChance.threshold / 60000} minutes! React now to enter!`);
}
});
// Lottery rerolled
lotteryManager.on('lotteryRerolled', (lottery, winners) => {
console.log(`Lottery ${lottery.messageId} rerolled!`);
});
// Lottery deleted
lotteryManager.on('lotteryDeleted', (lottery) => {
console.log(`Lottery ${lottery.messageId} deleted!`);
});
// Reaction added
lotteryManager.on('lotteryReactionAdded', (lottery, user) => {
console.log(`${user.tag} entered lottery ${lottery.messageId}`);
});
// Reaction removed
lotteryManager.on('lotteryReactionRemoved', (lottery, user) => {
console.log(`${user.tag} left lottery ${lottery.messageId}`);
});Available Events
| Event | Parameters | Description |
| ------------------------ | -------------------- | -------------------------------- |
| lotteryEnded | (lottery, winners) | Lottery has ended |
| lotteryLastChance | (lottery) | Last chance period triggered |
| lotteryRerolled | (lottery, winners) | Lottery was rerolled |
| lotteryDeleted | (lottery) | Lottery was deleted |
| lotteryReactionAdded | (lottery, user) | User entered lottery |
| lotteryReactionRemoved | (lottery, user) | User left lottery |
⚠️ Last Chance Feature
The "Last Chance" feature automatically updates the lottery embed with a warning message when approaching the end time and emits an event for custom announcements:
lotteryManager.start(channel, {
duration: 86400000, // 24 hours
prize: 'Amazing Prize',
lastChance: {
enabled: true,
content: '⚠️ **LAST CHANCE TO ENTER!** ⚠️',
threshold: 3600000, // Show warning 1 hour before end
embedColor: '#FFA500' // Orange color for urgency
}
});
// Listen for last chance event to send custom announcements
lotteryManager.on('lotteryLastChance', async (lottery) => {
const channel = lottery.message?.channel;
if (channel) {
// Send a public announcement
await channel.send({
content: '@everyone',
embeds: [
{
title: '⚠️ LAST CHANCE! ⚠️',
description: `The **${lottery.prize}** lottery ends soon!\nReact to the message above to enter!`,
color: 0xffa500,
footer: { text: 'Hurry up!' }
}
]
});
}
});How it works:
- When
remainingTime <= threshold, the embed automatically updates - Shows the custom warning message
- Changes embed color to grab attention
- Emits
lotteryLastChanceevent for custom announcements - Increases participation in the final hours!
Use Cases:
- Send @everyone ping when last chance triggers
- Post announcement in a separate channel
- Log to your database
- Send DMs to participants
- Update external systems
🎨 Custom Database
Use your own database instead of JSON files:
class CustomLotteriesManager extends LotteriesManager {
// Get all lotteries from database
async getAllLotteries() {
return await db.lotteries.findMany();
}
// Save a new lottery
async saveLottery(messageId, lotteryData) {
await db.lotteries.create({
data: { messageId, ...lotteryData }
});
}
// Edit a lottery
async editLottery(messageId, lotteryData) {
await db.lotteries.update({
where: { messageId },
data: lotteryData
});
}
// Delete a lottery
async deleteLottery(messageId) {
await db.lotteries.delete({
where: { messageId }
});
}
}🌍 Translations
Customize all messages:
lotteryManager.start(channel, {
duration: 86400000,
prize: 'Prize',
messages: {
lottery: '🎰 **LOTERIE** 🎰',
lotteryEnded: '🎰 **LOTERIE TERMINÉE** 🎰',
inviteToParticipate: 'Réagissez avec 🎰 pour participer!',
winMessage: 'Félicitations {winners}! Vous avez gagné **{this.prize}**!',
embedFooter: '{this.winnerCount} gagnant(s)',
noWinner: 'Loterie annulée, aucun participant valide.',
winners: 'Gagnant(s):',
endedAt: 'Terminé à',
hostedBy: 'Organisé par: {this.hostedBy}'
}
});🧪 Testing
Run the test suite:
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverage🛠️ Development
# Clone the repository
git clone https://gitlab.com/bbnetnl/m4t3/npm-packages/discord-lottery.git
cd discord-lottery
# Install dependencies
npm install
# Run linter
npm run lint
# Fix linting issues
npm run lint:fix
# Run tests
npm test📝 Changelog
See CHANGELOG.md for version history.
🤝 Contributing
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
Commit Format:
feat: add new feature # Minor version bump
fix: bug fix # Patch version bump
feat!: breaking change # Major version bump📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
- npm: https://www.npmjs.com/package/discord-lottery-private
- GitLab: https://gitlab.com/bbnetnl/m4t3/npm-packages/discord-lottery
- Issues: https://gitlab.com/bbnetnl/m4t3/npm-packages/discord-lottery/issues
- discord.js: https://discord.js.org
💡 Examples
Complete Bot Example
const { Client, GatewayIntentBits } = require('discord.js');
const { LotteriesManager } = require('discord-lottery-private');
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.GuildMembers]
});
client.lotteryManager = new LotteriesManager(client, {
storage: './lotteries.json',
default: {
embedColor: '#FF0000',
embedColorEnd: '#000000',
reaction: '🎰'
}
});
// Start lottery command
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'start-lottery') {
await client.lotteryManager.start(interaction.channel, {
duration: 24 * 60 * 60 * 1000, // 24 hours
winnerCount: 1,
prize: '10,000 Coins',
hostedBy: interaction.user,
lastChance: {
enabled: true,
content: '⚠️ **LAST CHANCE!** ⚠️',
threshold: 60 * 60 * 1000,
embedColor: '#FFA500'
}
});
await interaction.reply('🎰 Lottery started!');
}
if (interaction.commandName === 'end-lottery') {
const messageId = interaction.options.getString('message_id');
await client.lotteryManager.end(messageId);
await interaction.reply('🎰 Lottery ended!');
}
if (interaction.commandName === 'reroll-lottery') {
const messageId = interaction.options.getString('message_id');
await client.lotteryManager.reroll(messageId);
await interaction.reply('🎰 Lottery rerolled!');
}
});
// Listen to events
client.lotteryManager.on('lotteryEnded', (lottery, winners) => {
console.log(`Lottery ended: ${lottery.prize}`);
console.log(`Winners:`, winners.map((w) => w.tag).join(', '));
});
client.login('YOUR_BOT_TOKEN');🎉 Credits
Created and maintained by universenl
Based on the original discord-giveaways package with lottery-specific enhancements.
Made with ❤️ for the Discord community
