discord-giveaway-easy
Version:
A module allowing the simple creation of a discord giveaway with your bot supported by Discord.js^14.0.0
548 lines (399 loc) • 21.2 kB
JavaScript
/* A giveaway system for discord.js. */
const Discord = require("discord.js");
const {customID} = require("discord-giveaway-easy/src/Giveaway-Discord/system/customId")
module.exports = class Giveaway {
constructor() {
this.language = null,
this.interaction = null,
this.embedColor = null,
this.Title = null,
this.footer = null,
this.winnerNumber = null,
this.buttonType = null,
this.buttonEmoji = null,
this.time = null,
this.bot = null,
this.status = null
this.customID = customID()
}
/**
* @param {Discord.Message} value
*/
setInteraction(value) {
this.interaction = value
return this;
}
/**
* @param {String} value
*/
setLanguage(value) {
this.language = value
return this;
}
/**
* @param {Number} value
*/
setWinnerNumber(value) {
this.winnerNumber = value
return this;
}
/**
* @param {String} value
*/
setEmbedColor(value) {
this.embedColor = value
return this;
}
/**
* @param {String} value
*/
setTitle(value) {
this.Title = value
return this;
}
/**
* @param {String} value
*/
setFooter(value) {
this.footer = value
return this;
}
/**
* @param {Discord.ButtonStyle} value
*/
setButtonType(value) {
this.buttonType = value
return this;
}
/**
* @param {String} value
*/
setButtonEmoji(value) {
this.buttonEmoji = value
return this;
}
/**
* @param {String} value
*/
setTime(value) {
this.time = value
return this;
}
/**
* @param {Discord.Client} value
*/
setBot(value) {
this.bot = value
return this;
}
CreateGiveaway() {
this.status = "In progress"
//Discord-giveaway-easy cannot support languages other than 'fr' and 'en'
let language1 = "fren"
// globad error
if (this.language === null || !this.language) this.language = "en"
if (this.footer === null || typeof this.footer !== "string") this.footer = "Discord-Giveaway-Easy"
if (this.embedColor === null || typeof this.embedColor !== "string") this.embedColor = "#ffffff"
if (this.disableShareButton === null || typeof this.disableShareButton !== "boolean") this.disableShareButton = false
if (this.winnerNumber === null || typeof this.winnerNumber !== "number") throw new Error("setWinnerNumber must be a number.");
if (this.interaction === null || !this.interaction.channel || this.interaction.channel === null) throw new Error("setInteraction must be a Discord Interaction.");
if (this.buttonType === null) this.buttonType = Discord.ButtonStyle.Primary
if (this.buttonEmoji === null || typeof this.buttonEmoji !== "string") this.buttonEmoji = "🎉"
if (this.Title === null || typeof this.Title !== "string") throw new Error("setTitle must be a string.");
if (this.time === null || typeof this.time !== "string") throw new Error("setTime must be a string.");
if (this.bot === null || !this.bot.token || this.bot.token === null) throw new Error("setBot must be a Discord Client and must have a token.");
if (!language1.includes(this.language)) throw new Error("You can enter 2 languages: 'fr' and 'en'. No other languages translated.");
// time system
if (this.language === "en") {
//initialisation of setWinner's and setButtonType's error
let keyButtonType = [ '1', '2', '3', '4', '5' ];
// button type error
if (!keyButtonType.includes(String(this.buttonType))) throw new Error("Pls, enter 'Primary', 'Secondary', 'Success', 'Danger' or 'Link' on setButtonType argument.")
if (typeof this.winnerNumber !== "number") throw new Error("Pls, enter a number in setWninnerNumber.")
//initialisation of time error
let timeString = "mhj"
//time error for type of time
if (!timeString.includes(this.time.slice(this.time.length - 1))) throw new Error("Pls, include in setTime argument 'm', 'h' or 'j' after you number.")
//time error for check if there is a number before the type of time.
let numebrTime = this.time.replace(this.time.slice(this.time.length - 1), "")
if (numebrTime === "") numebrTime = null
if (numebrTime === null) throw new Error("Pls, enter a number before your type of time in setTime argument.")
if (Number(numebrTime) < 1 && Number(numebrTime) > 0) throw new Error("Pls, enter a whole number before your type of time in setTime argument.")
if (!Number.isInteger(Number(numebrTime))) throw new Error("Pls, enter a whole number before your type of time in setTime argument.")
//time system for filter type of time and number for initialised it in a let variable
if (this.time?.includes("m")) {
let m = this.time
var time = parseInt(Number(m?.replace("m", "")) * 60)
}
if (this.time?.includes("h")) {
let m = this.time
var time = parseInt(Number(m?.replace("h", "")) * 3600)
}
if (this.time?.includes("d")) {
let m = this.time
var time = parseInt(Number(m?.replace("d", "")) * 86400)
}
let secondes = Math.floor((Date.now() / 1000) + (time))
if (typeof time !== "number") throw new Error("Pls, enter Number for setTime argument.")
//convert a time in second to millisecond
let ms = time * 1000
if (ms > 2147483647) throw new Error("You cannot enter a value with milliseconds greater than 2,147,483,647. Or, you cannot enter a value superior to 3 weeks and 5 days.")
//interaction button
/**
* @param {Discord.Interaction} interaction
*/
let giveawayRamdom = []
//system global bot command
let messageId;
this.bot?.on("interactionCreate", async (interaction) => {
if (interaction.type = Discord.InteractionType.MessageComponent) {
if (interaction.customId === this.customID) {
messageId = interaction.message.id
if (giveawayRamdom.includes(`${interaction.user.id}`)) {
return interaction?.reply({content: 'You are already in the list for this giveaway!', ephemeral: true})
} else {
await interaction?.reply({content: 'You have been queued for this giveaway. Good luck!', ephemeral: true})
giveawayRamdom.push(interaction.user.id)
let Embed = new Discord.EmbedBuilder()
.setTitle(this.Title)
.setDescription(`Please click on the button ${this.buttonEmoji} to participate in the giveaway.\nEnd of the giveaway: <t:${secondes}:R>\nPosted by: **<@${this.interaction?.user?.id}>**\nNumber of winners: **${this.winnerNumber}**`)
.setColor(this.embedColor)
.setFooter({text: `Attendees: ${giveawayRamdom.length} | ${this.footer}`})
.setTimestamp()
return this.interaction.channel.messages.fetch(messageId).then(mess => mess.edit({embeds: [Embed], components: [this.getButton()]}));
}
}
}
})
//save data in local database
let guild;
let timeArray;
let winnernumber;
if (this.time && this.winnerNumber) {
timeArray = time
winnernumber = this.winnerNumber
} else {
guild = undefined
timeArray = undefined
winnernumber = undefined
}
// start timeOut of the time corresponding at the time of the giveaway for choice a winners after it.
let WinnerTimeOut = setTimeout(() => {
if (messageId === null || !messageId || giveawayRamdom.length < 1) return this.interaction.channel.send("Error ❌ : this giveaway can't be finished.")
function randomWinner(number) {
// const toDeleteDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) == index)
const toFindDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) !== index)
let arryDuplicate = toFindDuplicates(giveawayRamdom)
let tirage = []
if (number === giveawayRamdom.length || number > giveawayRamdom.length) {
tirage.push(`<@${giveawayRamdom.join(">, <@")}>`)
return tirage
}
for(let i = 0; i < (number + arryDuplicate); i++) {
tirage.push(`<@${giveawayRamdom[Math.floor(Math.random() * giveawayRamdom.length)]}>`)
}
return tirage.join(", ")
}
let EmbedsEnding = new Discord.EmbedBuilder()
.setTitle(`${this.Title}`)
.setDescription(`The winner is ${randomWinner(winnernumber)}!\nThe giveaway **${this.Title}** has been closed.`)
.setFooter({text : `Attendees: ${giveawayRamdom.length} | winners: ${this.winnerNumber}`})
.setColor(this.embedColor)
.setTimestamp()
this.interaction.channel.messages.fetch(messageId).then(mess => mess.edit({content: "🎉🎉 **GIVEAWAY ENDED** 🎉🎉", embeds: [EmbedsEnding], components: []}))
giveawayRamdom = [];
this.status = "To end"
// clear that timeOut
clearTimeout(WinnerTimeOut);
}, ms)
}
//========================
//========================
//========================
//========================
//========================
//========================
if (this.language === "fr") {
//initialisation of setWinner's and setButtonType's error
let keyButtonType = [ '1', '2', '3', '4', '5' ];
// button type error
if (!keyButtonType.includes(String(this.buttonType))) throw new Error("Svp, entrer 'Primary', 'Secondary', 'Success', 'Danger' ou 'Link' dans l'argument setButtonType.")
if (typeof this.winnerNumber !== "number") throw new Error("Svp, entrer un nombre dans setWninnerNumber.")
//initialisation of time error
let timeString = "mhj"
//time error for type of time
if (!timeString.includes(this.time.slice(this.time.length - 1))) throw new Error("Svp, veuillez inclure dans l'argument setTime 'm', 'h' or 'j' après votre nombre.")
//time error for check if there is a number before the type of time.
let numebrTime = this.time.replace(this.time.slice(this.time.length - 1), "")
if (numebrTime === "") numebrTime = null
if (numebrTime === null) throw new Error("Svp, entrer un numbre avant votre type de temps dans l'argument setTime.")
if (Number(numebrTime) < 1 && Number(numebrTime) > 0) throw new Error("Svp, entrer un nombre entier avant votre type de temps dans l'argument setTime.")
if (!Number.isInteger(Number(numebrTime))) throw new Error("Svp, entrer un nombre entier avant votre type de temps dans l'argument setTime.")
//time system for filter type of time and number for initialised it in a let variable
if (this.time?.includes("m")) {
let m = this.time
var time = parseInt(Number(m?.replace("m", "")) * 60)
}
if (this.time?.includes("h")) {
let m = this.time
var time = parseInt(Number(m?.replace("h", "")) * 3600)
}
if (this.time?.includes("j")) {
let m = this.time
var time = parseInt(Number(m?.replace("j", "")) * 86400)
}
let secondes = Math.floor((Date.now() / 1000) + (time))
if (typeof time !== "number") throw new Error("Svp, entrer un nombre pour l'argument setTime.")
//convert a time in second to millisecond
let ms = time * 1000
if (ms > 2147483647) throw new Error("Vous ne pouvez pas entrer une valeur avec des millisecondes supérieures à 2 147 483 647. Ou, vous ne pouvez pas entrer une valeur supérieure à 3 semaines et 5 jours.")
//interaction button
/**
* @param {Discord.Interaction} interaction
*/
let giveawayRamdom = []
//system global bot command
let messageId;
this.bot?.on("interactionCreate", async (interaction) => {
if (interaction.type = Discord.InteractionType.MessageComponent) {
if (interaction.customId === this.customID) {
messageId = interaction.message.id
if (giveawayRamdom.includes(`${interaction.user.id}`)) {
interaction?.reply({content: 'Vous êtes déjà dans la liste pour ce giveaway!', ephemeral: true})
} else {
await interaction?.reply({content: "Vous avez été mis en file d'attente pour ce giveaway. Bonne chance!", ephemeral: true})
giveawayRamdom.push(interaction.user.id)
let Embed = new Discord.EmbedBuilder()
.setTitle(this.Title)
.setDescription(`Cliquer sur le button ${this.buttonEmoji} pour participer au giveaway.\nFin du giveaway : <t:${secondes}:R>\nPosté par : **<@${this.interaction?.user?.id}>**\nNombre de gagnant.e.s : **${this.winnerNumber}**`)
.setColor(this.embedColor)
.setFooter({text: `Participants : ${giveawayRamdom.length} | ${this.footer}`})
.setTimestamp()
return this.interaction.channel.messages.fetch(messageId).then(mess => mess.edit({embeds: [Embed], components: [this.getButton()]}));
}
}
}
})
//save data in local database
let guild;
let timeArray;
let winnernumber;
if (this.time && this.winnerNumber) {
timeArray = time
winnernumber = this.winnerNumber
} else {
guild = undefined
timeArray = undefined
winnernumber = undefined
messageId = undefined
}
// start timeOut of the time corresponding at the time of the giveaway for choice a winners after it.
let WinnerTimeOut = setTimeout(() => {
if (messageId === null || !messageId || giveawayRamdom.length < 1) return this.interaction.channel.send("Erreur ❌ : ce giveaway ne peut pas être terminé.")
function randomWinner(number) {
// const toDeleteDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) == index)
const toFindDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) !== index)
let arryDuplicate = toFindDuplicates(giveawayRamdom)
let tirage = []
if (number === giveawayRamdom.length || number > giveawayRamdom.length) {
tirage.push(`<@${giveawayRamdom.join(">, <@")}>`)
return tirage
}
for(let i = 0; i < (number + arryDuplicate); i++) {
tirage.push(`<@${giveawayRamdom[Math.floor(Math.random() * giveawayRamdom.length)]}>`)
}
return tirage.join(", ")
}
let EmbedsEnding = new Discord.EmbedBuilder()
.setTitle(`${this.Title}`)
.setDescription(`Le gagnant est ${randomWinner(winnernumber)}!\nLe giveaway **${this.Title}** a été fermer.`)
.setFooter({text : `Participants : ${giveawayRamdom.length} | gagnants : ${this.winnerNumber}`})
.setColor(this.embedColor)
.setTimestamp()
this.interaction.channel.messages.fetch(messageId).then(mess => mess.edit({content: "🎉🎉 **GIVEAWAY TERMINE** 🎉🎉", embeds: [EmbedsEnding], components: []}))
giveawayRamdom = [];
this.status = "To end"
// clear that timeOut
clearTimeout(WinnerTimeOut);
}, ms)
}
return this;
}
getEmbed() {
if (!this.Title) throw new Error("setTitle must be a string.")
if (!this.buttonEmoji) throw new Error("setButtonEmoji must be a string.")
if (!this.interaction) throw new Error("setInteraction must be a Discord Interaction.")
if (!this.embedColor) throw new Error("setEmbedColor must be a String.")
if (!this.footer) throw new Error("setFooter must be a String.")
if (this.language === "en") {
if (this.time?.includes("m")) {
let m = this.time
var time = parseInt(Number(m?.replace("m", "")) * 60)
}
if (this.time?.includes("h")) {
let m = this.time
var time = parseInt(Number(m?.replace("h", "")) * 3600)
}
if (this.time?.includes("d")) {
let m = this.time
var time = parseInt(Number(m?.replace("d", "")) * 86400)
}
let secondes = Math.floor((Date.now() / 1000) + (time))
let Embed = new Discord.EmbedBuilder()
.setTitle(this.Title)
.setDescription(`Please click on the button ${this.buttonEmoji} to participate in the giveaway.\nEnd of the giveaway: <t:${secondes}:R>\nPosted by: **<@${this.interaction?.user?.id}>**\nNumber of winners: **${this.winnerNumber}**`)
.setColor(this.embedColor)
.setFooter({text: `Attendees: 0 | ${this.footer}`})
.setTimestamp()
return Embed;
}
if (this.language === "fr") {
if (this.time?.includes("m")) {
let m = this.time
var time = parseInt(Number(m?.replace("m", "")) * 60)
}
if (this.time?.includes("h")) {
let m = this.time
var time = parseInt(Number(m?.replace("h", "")) * 3600)
}
if (this.time?.includes("j")) {
let m = this.time
var time = parseInt(Number(m?.replace("j", "")) * 86400)
}
let secondes = Math.floor((Date.now() / 1000) + (time))
let Embed = new Discord.EmbedBuilder()
.setTitle(this.Title)
.setDescription(`Cliquer sur le button ${this.buttonEmoji} pour participer au giveaway.\nFin du giveaway : <t:${secondes}:R>\nPosté par : **<@${this.interaction?.user?.id}>**\nNombre de gagnant.e.s : **${this.winnerNumber}**`)
.setColor(this.embedColor)
.setFooter({text: `Participants : 0 | ${this.footer}`})
.setTimestamp()
return Embed;
}
}
getButton() {
if (!this.buttonEmoji) throw new Error("setButtonEmoji must be a string.")
if (!this.buttonType) throw new Error("setButtonType must be a string.")
if (this.language === "en") {
const button = new Discord.ActionRowBuilder()
.addComponents(
new Discord.ButtonBuilder()
.setCustomId(this.customID)
.setLabel('Participate')
.setEmoji(this.buttonEmoji)
.setStyle(this.buttonType)
)
return button;
}
if (this.language === "fr") {
const button = new Discord.ActionRowBuilder()
.addComponents(
new Discord.ButtonBuilder()
.setCustomId(this.customID)
.setLabel('Participer')
.setEmoji(this.buttonEmoji)
.setStyle(this.buttonType)
)
return button;
}
}
}