UNPKG

givify

Version:

A Advance Discord Giveaway System

267 lines (251 loc) 15.7 kB
const Discord = require('discord.js'); exports.DEFAULT_CHECK_INTERVAL = 15_000; exports.DELETE_DROP_DATA_AFTER = 6.048e8; // 1 week /** * The Giveaway messages that are used to display the giveaway content. * @typedef GiveawayMessages * * @property {string} [giveaway='🎉🎉 **GIVEAWAY** 🎉🎉'] Displayed above the giveaway embed when the giveaway is running. * @property {string} [giveawayEnded='🎉🎉 **GIVEAWAY ENDED** 🎉🎉'] Displayed above the giveaway embed when the giveaway has ended. * @property {string} [title='{this.prize}'] The title of the giveaway embed.<br>Will default to the prize of the giveaway if the value is not a string. * @property {string} [inviteToParticipate='React with 🎉 to participate!'] Displayed in the giveaway embed. Invite people to react to the giveaway. * @property {string|MessageObject} [winMessage='Congratulations, {winners}! You won **{this.prize}**!\n{this.messageURL}'] Sent in the channel when the giveaway is ended. "{winners}" will be replaced automatically with the mentions of the giveaway winners. * @property {string} [drawing='Drawing: {timestamp}'] Displayed below "inviteToParticipate" in the giveaway embed. "{timestamp}" will be replaced automatically with the time remaining. * @property {string} [dropMessage='Be the first to react with 🎉'] Displayed in the giveaway embed for drop giveaways. * @property {string|EmbedFooterObject} [embedFooter='{this.winnerCount} winner(s)'] The footer of the giveaway embed. An empty string can be used for "deactivation". * @property {string} [noWinner='Giveaway cancelled, no valid participations.'] Displayed in the giveaway embed when there is no valid winner for the giveaway. * @property {string} [winners='Winner(s):'] Displayed in the giveaway embed before the winners. * @property {string} [endedAt='Ended at'] Displayed as the embed footer, next to the giveaway end date, when the giveaway has ended. * @property {string} [hostedBy='Hosted by: {this.hostedBy}'] Below the "inviteToParticipate" message, in the description of the embed. */ exports.GiveawayMessages = { giveaway: '🎉🎉 **GIVEAWAY** 🎉🎉', giveawayEnded: '🎉🎉 **GIVEAWAY ENDED** 🎉🎉', title: '{this.prize}', inviteToParticipate: 'React with 🎉 to participate!', winMessage: 'Congratulations, {winners}! You won **{this.prize}**!\n{this.messageURL}', drawing: 'Drawing: {timestamp}', dropMessage: 'Be the first to react with 🎉 !', embedFooter: '{this.winnerCount} winner(s)', noWinner: `Giveaway cancelled, no valid participation's.`, winners: 'Winner(s):', endedAt: 'Ended at', hostedBy: 'Hosted by: {this.hostedBy}' }; /** * Embed Footer object. * @typedef EmbedFooterObject * * @property {string} [text] The text of the footer. * @property {string} [iconURL] The icon URL of the footer of ALL giveaway embeds.<br>"text" is required to be defined, when the icon is to be shown in the main embed. */ /** * Message object. * @typedef MessageObject * * @property {string} [content] The raw message * @property {Discord.JSONEncodable<Discord.APIEmbed>|Discord.APIEmbed} [embed] The embed * @property {Array<Discord.JSONEncodable<Discord.APIActionRowComponent<Discord.APIActionRowComponentTypes>>|Discord.APIActionRowComponent<Discord.APIActionRowComponentTypes>>} [components] The components.<br>"content" or "embed" is required to be defined. * @property {boolean} [replyToGiveaway] If the sent message should reply to the giveaway embed. */ /** * @typedef {Object} ButtonsObject * * @property {Discord.JSONEncodable<Discord.APIButtonComponent>|Discord.APIButtonComponent} join The button to join the giveaway. * @property {Discord.JSONEncodable<Discord.APIButtonComponent>|Discord.APIButtonComponent} [leave] The button to leave the giveaway. * @property {?(string|MessageObject)} [joinReply] Sent in the channel as the ephemeral interaction reply to the join-button. * @property {?(string|MessageObject)} [leaveReply] Sent in the channel as the ephemeral interaction reply to the leave-button. */ /** * @typedef {Function} ExemptMembersFunction * * @param {Discord.GuildMember} member * @param {Giveaway} giveaway * @returns {Promise<boolean>|boolean} */ /** * The start options for new giveaways. * @typedef GiveawayStartOptions * * @property {number} duration The giveaway duration (milliseconds). * @property {number} winnerCount The number of winners for the giveaway. * @property {string} prize The giveaway prize. * @property {Discord.User} [hostedBy] The user who hosts the giveaway. * @property {boolean} [botsCanWin] If bots can win the giveaway. * @property {Discord.PermissionResolvable[]} [exemptPermissions] Members with any of these permissions will not be able to win a giveaway. * @property {ExemptMembersFunction} [exemptMembers] Function to filter members.<br>If true is returned, the member will not be able to win the giveaway. * @property {BonusEntry[]} [bonusEntries] An array of BonusEntry objects. * @property {Discord.ColorResolvable} [embedColor] The color of the giveaway embed when it is running. * @property {Discord.ColorResolvable} [embedColorEnd] The color of the giveaway embed when it has ended. * @property {Discord.EmojiIdentifierResolvable} [reaction] The reaction to participate in the giveaway. * @property {ButtonsObject} [buttons] The buttons for the giveaway. * @property {GiveawayMessages} [messages] The giveaway messages. * @property {string} [thumbnail] The URL appearing as the thumbnail on the giveaway embed. * @property {string} [image] The URL appearing as the image on the giveaway embed. * @property {any} [extraData] The extra data for this giveaway. * @property {LastChanceOptions} [lastChance] The options for the last chance system. * @property {PauseOptions} [pauseOptions] The options for the pause system. * @property {boolean} [isDrop] If the giveaway is a drop, or not. <br>Drop means that if the amount of valid entrants to the giveaway is the same as "winnerCount" then it immediately ends. * @property {Discord.MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the giveaway messages content. */ exports.GiveawayStartOptions = {}; /** * @typedef {Function} BonusFunction * * @param {Discord.GuildMember} member * @param {Giveaway} giveaway * @returns {Promise<number>|number} */ /** * Bonus entry object. * @typedef BonusEntry * * @property {BonusFunction} bonus The filter function that takes one parameter, a member and returns the amount of entries. * @property {boolean} [cumulative] If the amount of entries from the function can get summed with other amounts of entries. */ exports.BonusEntry = {}; /** * The last chance options. * @typedef LastChanceOptions * * @property {boolean} [enabled=false] If the last chance system is enabled. * @property {string} [content='⚠️ **LAST CHANCE TO ENTER !** ⚠️'] The text of the embed when the last chance system is enabled. * @property {number} [threshold=5000] The number of milliseconds before the giveaway ends when the last chance system will be enabled. * @property {Discord.ColorResolvable} [embedColor='#FF0000'] The color of the embed when last chance is enabled. */ exports.LastChanceOptions = { enabled: false, content: '⚠️ **LAST CHANCE TO ENTER !** ⚠️', threshold: 10_000, embedColor: '#FF0000' }; /** * The pause options. * @typedef PauseOptions * * @property {boolean} [isPaused=false] If the giveaway is paused. * @property {string} [content='⚠️ **THIS GIVEAWAY IS PAUSED !** ⚠️'] The text of the embed when the giveaway is paused. * @property {?number} [unpauseAfter=null] The number of milliseconds, or a timestamp in milliseconds, after which the giveaway will automatically unpause. * @property {Discord.ColorResolvable} [embedColor='#FFFF00'] The color of the embed when the giveaway is paused. * @private @property {?number} [durationAfterPause=null|giveaway.remainingTime] The remaining duration after the giveaway is unpaused.<br>⚠ This property gets set by the manager so that the pause system works properly. It is not recommended to set it manually! * @property {string} [infiniteDurationText='`NEVER`'] The text that gets displayed next to "GiveawayMessages#drawing" in the paused embed, when there is no "unpauseAfter". */ exports.PauseOptions = { isPaused: false, content: '⚠️ **THIS GIVEAWAY IS PAUSED !** ⚠️', unpauseAfter: null, embedColor: '#FFFF00', durationAfterPause: null, infiniteDurationText: '`NEVER`' }; /** * The giveaways manager options. * @typedef GiveawaysManagerOptions * * @property {string} [storage='./giveaways.json'] The storage path for the giveaways. * @property {?number} [forceUpdateEvery=null] Force the giveaway messages to be updated at a specific interval. * @property {?number} [endedGiveawaysLifetime=null] The number of milliseconds after which ended giveaways should get deleted from the DB.<br>⚠ Giveaways deleted from the DB cannot get rerolled anymore! * @property {Object} [default] The default options for new giveaways. * @property {boolean} [default.botsCanWin=false] If bots can win giveaways. * @property {Discord.PermissionResolvable[]} [default.exemptPermissions=[]] Members with any of these permissions won't be able to win a giveaway. * @property {ExemptMembersFunction} [default.exemptMembers] Function to filter members.<br>If true is returned, the member won't be able to win a giveaway. * @property {Discord.ColorResolvable} [default.embedColor='#FF0000'] The color of the giveaway embeds when they are running. * @property {Discord.ColorResolvable} [default.embedColorEnd='#000000'] The color of the giveaway embeds when they have ended. * @property {?Discord.EmojiIdentifierResolvable} [default.reaction='🎉'] The reaction to participate in giveaways. * @property {LastChanceOptions} [default.lastChance] The options for the last chance system. * @property {?ButtonsObject} [default.buttons] The buttons for the giveaways. * @property {?(string|MessageObject)} [default.buttons.joinReply='✅ joined'] Sent in the channel as the ephemeral interaction reply to the join-button. * @property {?(string|MessageObject)} [default.buttons.leaveReply='✅ left'] Sent in the channel as the ephemeral interaction reply to the leave-button. */ exports.GiveawaysManagerOptions = { storage: './giveaways.json', forceUpdateEvery: null, endedGiveawaysLifetime: null, default: { botsCanWin: false, exemptPermissions: [], exemptMembers: () => false, embedColor: '#FF0000', embedColorEnd: '#000000', reaction: '🎉', buttons: { joinReply: '✅ joined', leaveReply: '✅ left' }, lastChance: { enabled: false, content: '⚠️ **LAST CHANCE TO ENTER !** ⚠️', threshold: 5000, embedColor: '#FF0000' } } }; /** * The reroll method options. * @typedef GiveawayRerollOptions * * @property {number} [winnerCount=giveaway.winnerCount] The number of winners to pick. * @property {Object} [messages] The messages used in this method. * @property {string|MessageObject} [messages.congrat=':tada: New winner(s): {winners}! Congratulations, you won **{this.prize}**!\n{this.messageURL}'] The message used if there are new winners. * @property {string|MessageObject} [messages.error=`No valid participation's, no new winner(s) can be chosen!`] The message used if no new winner(s) could be chosen. * @property {boolean} [messages.replyWhenNoWinner=true] Whether or not to send the "error" message when there is no winner. */ exports.GiveawayRerollOptions = { winnerCount: null, messages: { congrat: ':tada: New winner(s): {winners}! Congratulations, you won **{this.prize}**!\n{this.messageURL}', error: `No valid participation's, no new winner(s) can be chosen!`, replyWhenNoWinner: true } }; /** * The edit method options. * @typedef GiveawayEditOptions * * @property {number} [newWinnerCount] The new number of winners. * @property {string} [newPrize] The new giveaway prize. * @property {number} [addTime] Number of milliseconds to add to the giveaway duration. * @property {number} [setEndTimestamp] The timestamp of the new end date. * @property {GiveawayMessages} [newMessages] The new giveaway messages.<br>Will get merged with the existing object, if there. * @property {string} [newThumbnail] The new thumbnail URL. * @property {string} [newImage] The new image URL. * @property {any} [newExtraData] The new extra data for this giveaway. * @property {BonusEntry[]} [newBonusEntries] The new BonusEntry objects. * @property {ExemptMembersFunction} [newExemptMembers] The new filter function to exempt members from winning the giveaway. * @property {LastChanceOptions} [newLastChance] The new options for the last chance system.<br>Will get merged with the existing object, if there. * @property {ButtonsObject} [newButtons] The new buttons for the giveaway. */ exports.GiveawayEditOptions = {}; /** * Raw giveaway object (used to store giveaways in the database). * @typedef GiveawayData * * @property {number} startAt The start date of the giveaway. * @property {number} endAt The end date of the giveaway. * @property {number} winnerCount The number of winners for the giveaway. * @property {boolean} ended If the giveaway has ended. * @property {GiveawayMessages} messages The giveaway messages. * @property {string} prize The giveaway prize. * @property {string} [thumbnail] The URL appearing as the thumbnail on the giveaway embed. * @property {string} [image] The URL appearing as the image on the giveaway embed. * @property {Discord.Snowflake} channelId The Id of the channel. * @property {Discord.Snowflake} guildId The Id of the guild. * @property {Discord.Snowflake[]} [winnerIds] The winner Ids of the giveaway after it ended. * @property {Discord.Snowflake} messageId The Id of the message. * @property {Discord.EmojiIdentifierResolvable} [reaction] The reaction to participate in the giveaway. * @property {ButtonsObject} [buttons] The buttons for the giveaway. * @property {boolean} [botsCanWin] If bots can win the giveaway. * @property {Discord.PermissionResolvable[]} [exemptPermissions] Members with any of these permissions will not be able to win the giveaway. * @property {string} [exemptMembers] Filter function to exempt members from winning the giveaway. * @property {string} [bonusEntries] The array of BonusEntry objects for the giveaway. * @property {Discord.ColorResolvable} [embedColor] The color of the giveaway embed when it is running. * @property {Discord.ColorResolvable} [embedColorEnd] The color of the giveaway embed when it has ended. * @property {string} [hostedBy] The mention of the user who hosts the giveaway. * @property {any} [extraData] The extra data for this giveaway. * @property {LastChanceOptions} [lastChance] The options for the last chance system. * @property {PauseOptions} [pauseOptions] The options for the pause system. * @property {boolean} [isDrop] If the giveaway is a drop, or not.<br>Drop means that if the amount of valid entrants to the giveaway is the same as "winnerCount" then it immediately ends. * @property {Discord.MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the giveaway messages content. * @property {Snowflake[]} [entrantIds] The entrant ids for this giveaway, if buttons are used. */ exports.GiveawayData = {};