Download src/systems/drops.js from APRKDEV/wsb-bot: direct link, hf CLI and curl.
- Browser
- Download file 13.1 kB
-
https://huggingface.co/spaces/APRKDEV/wsb-bot/resolve/c8f3880098432483b23491dd763585274d00f8c8/src/systems/drops.js
- Command line
-
hf download hf://spaces/APRKDEV/wsb-bot@c8f3880098432483b23491dd763585274d00f8c8/src/systems/drops.js
-
curl -L -o drops.js https://huggingface.co/spaces/APRKDEV/wsb-bot/resolve/c8f3880098432483b23491dd763585274d00f8c8/src/systems/drops.js
13.1 kB
| const { | |
| ActionRowBuilder, | |
| ButtonBuilder, | |
| ButtonStyle, | |
| StringSelectMenuBuilder, | |
| } = require('discord.js'); | |
| const { createEmbed } = require('../utils/embeds'); | |
| const { Colors } = require('../config'); | |
| const { stmts } = require('../database'); | |
| const OWNER_ID = process.env.OWNER_ID; | |
| // Active drop sessions: Map<userId, session> | |
| const activeSessions = new Map(); | |
| const STEPS = ['title', 'file', 'warnings', 'status', 'about', 'image', 'preview']; | |
| /** | |
| * Check if a user can drop (owner = unlimited, whitelisted = custom limit). | |
| * Returns { allowed: boolean, remaining?: number, resetIn?: string, limit?: number } | |
| */ | |
| function canDrop(userId) { | |
| if (userId === OWNER_ID) return { allowed: true, remaining: Infinity }; | |
| const wl = stmts.getWhitelist.get(userId); | |
| if (!wl) return { allowed: false, reason: 'not_whitelisted' }; | |
| const limit = wl.max_drops; | |
| const { count } = stmts.getDropCount24h.get(userId); | |
| if (count >= limit) { | |
| const last = stmts.getLastDrop.get(userId); | |
| const resetTime = new Date(last.dropped_at + 'Z'); | |
| resetTime.setHours(resetTime.getHours() + 24); | |
| const diff = resetTime - new Date(); | |
| const hours = Math.floor(diff / 3600000); | |
| const mins = Math.floor((diff % 3600000) / 60000); | |
| return { allowed: false, reason: 'rate_limited', resetIn: `${hours}h ${mins}m`, limit }; | |
| } | |
| return { allowed: true, remaining: limit - count, limit }; | |
| } | |
| /** | |
| * Start a new drop session for the owner. | |
| */ | |
| function startDropSession(userId) { | |
| const session = { | |
| step: 'title', | |
| title: null, | |
| file: null, // { url, name, size } | |
| warnings: null, | |
| status: null, // 'checked' or 'unchecked' | |
| about: null, | |
| image: null, // url or null | |
| channelId: null, | |
| }; | |
| activeSessions.set(userId, session); | |
| return session; | |
| } | |
| /** | |
| * Check if a user has an active drop session. | |
| */ | |
| function hasSession(userId) { | |
| return activeSessions.has(userId); | |
| } | |
| /** | |
| * Get the current prompt message for the active step. | |
| */ | |
| function getPrompt(session) { | |
| switch (session.step) { | |
| case 'title': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 1/6', | |
| description: '> **What is the title for this drop?**\n\nType the title below.', | |
| color: Colors.PRIMARY, | |
| footer: 'Type "cancel" at any time to abort', | |
| })], | |
| }; | |
| case 'file': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 2/6', | |
| description: '> **Upload the file for this drop.**\n\nAttach the file to your next message.', | |
| color: Colors.PRIMARY, | |
| footer: `Title: ${session.title}`, | |
| })], | |
| }; | |
| case 'warnings': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 3/6', | |
| description: '> **Any warnings for this drop?**\n\nType warnings below, or type `none` to skip.', | |
| color: Colors.WARNING, | |
| footer: `Title: ${session.title}`, | |
| })], | |
| }; | |
| case 'status': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 4/6', | |
| description: '> **Is this source checked or unchecked?**\n\nClick a button below.', | |
| color: Colors.PRIMARY, | |
| footer: `Title: ${session.title}`, | |
| })], | |
| components: [new ActionRowBuilder().addComponents( | |
| new ButtonBuilder() | |
| .setCustomId('drop_checked') | |
| .setLabel('β Checked') | |
| .setStyle(ButtonStyle.Success), | |
| new ButtonBuilder() | |
| .setCustomId('drop_unchecked') | |
| .setLabel('β οΈ Unchecked') | |
| .setStyle(ButtonStyle.Danger), | |
| )], | |
| }; | |
| case 'about': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 5/6', | |
| description: '> **Describe this source.**\n\nWrite a short description about what this is.', | |
| color: Colors.PRIMARY, | |
| footer: `Title: ${session.title}`, | |
| })], | |
| }; | |
| case 'image': | |
| return { | |
| embeds: [createEmbed({ | |
| title: 'π¦ New Drop β Step 6/6', | |
| description: '> **Reference image?**\n\nUpload an image or type `none` to skip.', | |
| color: Colors.PRIMARY, | |
| footer: `Title: ${session.title}`, | |
| })], | |
| }; | |
| default: | |
| return null; | |
| } | |
| } | |
| /** | |
| * Build the final preview embed for the drop. | |
| */ | |
| function buildDropEmbed(session) { | |
| const statusIcon = session.status === 'checked' ? 'β ' : 'β οΈ'; | |
| const statusText = session.status === 'checked' ? 'Verified / Checked' : 'Unchecked β Use at your own risk'; | |
| const lines = [ | |
| `${statusIcon} **${statusText}**`, | |
| '', | |
| '> **About**', | |
| `> ${session.about}`, | |
| '', | |
| ]; | |
| if (session.warnings && session.warnings.toLowerCase() !== 'none') { | |
| lines.push('β οΈ **Warnings**'); | |
| lines.push(`> ${session.warnings}`); | |
| lines.push(''); | |
| } | |
| lines.push('```'); | |
| lines.push(`π File: ${session.file.name}`); | |
| lines.push(`π Size: ${formatBytes(session.file.size)}`); | |
| lines.push(`π Status: ${statusText}`); | |
| lines.push('```'); | |
| lines.push(''); | |
| lines.push('βββββββββββββββββββββββββββββββββββββ'); | |
| lines.push('*Wyvern Softworks β Educational Use Only*'); | |
| const embedData = { | |
| title: `π¦ ${session.title}`, | |
| description: lines.join('\n'), | |
| color: session.status === 'checked' ? Colors.SUCCESS : Colors.WARNING, | |
| footer: 'Wyvern Softworks β’ ' + new Date().toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }), | |
| }; | |
| if (session.image) { | |
| embedData.image = session.image; | |
| } | |
| return createEmbed(embedData); | |
| } | |
| /** | |
| * Build the download button row for a drop. | |
| */ | |
| function buildDownloadButton(session) { | |
| return new ActionRowBuilder().addComponents( | |
| new ButtonBuilder() | |
| .setLabel('π₯ Download') | |
| .setStyle(ButtonStyle.Link) | |
| .setURL(session.file.url), | |
| ); | |
| } | |
| /** | |
| * Handle a message in an active drop session. | |
| * Returns true if handled, false if not. | |
| */ | |
| async function handleDropMessage(message) { | |
| const userId = message.author.id; | |
| const session = activeSessions.get(userId); | |
| if (!session) return false; | |
| const content = message.content.trim(); | |
| // Cancel | |
| if (content.toLowerCase() === 'cancel') { | |
| activeSessions.delete(userId); | |
| await message.reply({ embeds: [createEmbed({ title: 'β Drop Cancelled', color: Colors.ACCENT })] }); | |
| return true; | |
| } | |
| switch (session.step) { | |
| case 'title': | |
| session.title = content; | |
| session.step = 'file'; | |
| await message.reply(getPrompt(session)); | |
| return true; | |
| case 'file': | |
| if (message.attachments.size === 0) { | |
| await message.reply({ content: 'β Please attach a file.' }); | |
| return true; | |
| } | |
| const att = message.attachments.first(); | |
| session.file = { url: att.url, name: att.name, size: att.size }; | |
| session.step = 'warnings'; | |
| await message.reply(getPrompt(session)); | |
| return true; | |
| case 'warnings': | |
| session.warnings = content.toLowerCase() === 'none' ? null : content; | |
| session.step = 'status'; | |
| await message.reply(getPrompt(session)); | |
| return true; | |
| case 'about': | |
| session.about = content; | |
| session.step = 'image'; | |
| await message.reply(getPrompt(session)); | |
| return true; | |
| case 'image': | |
| if (content.toLowerCase() === 'none') { | |
| session.image = null; | |
| } else if (message.attachments.size > 0) { | |
| session.image = message.attachments.first().url; | |
| } else { | |
| session.image = null; | |
| } | |
| // Show preview | |
| session.step = 'preview'; | |
| const previewEmbed = buildDropEmbed(session); | |
| const row = new ActionRowBuilder().addComponents( | |
| new ButtonBuilder() | |
| .setCustomId('drop_approve') | |
| .setLabel('β Approve & Post') | |
| .setStyle(ButtonStyle.Success), | |
| new ButtonBuilder() | |
| .setCustomId('drop_cancel') | |
| .setLabel('β Cancel') | |
| .setStyle(ButtonStyle.Danger), | |
| ); | |
| await message.reply({ | |
| content: '**π Preview β This is how the drop will look:**', | |
| embeds: [previewEmbed], | |
| components: [buildDownloadButton(session), row], | |
| }); | |
| return true; | |
| case 'channel': | |
| // User provides channel ID to post in | |
| const channelId = content.replace(/[<#>]/g, ''); | |
| session.channelId = channelId; | |
| try { | |
| const guild = message.client.guilds.cache.first(); | |
| const channel = await guild.channels.fetch(channelId); | |
| if (!channel) throw new Error('Channel not found'); | |
| const dropEmbed = buildDropEmbed(session); | |
| const downloadRow = buildDownloadButton(session); | |
| await channel.send({ | |
| embeds: [dropEmbed], | |
| components: [downloadRow], | |
| }); | |
| // Log the drop for rate limiting | |
| stmts.logDrop.run(userId, session.title, channelId); | |
| activeSessions.delete(userId); | |
| await message.reply({ | |
| embeds: [createEmbed({ | |
| title: 'β Drop Posted!', | |
| description: `Successfully posted to <#${channelId}>`, | |
| color: Colors.SUCCESS, | |
| })], | |
| }); | |
| } catch (err) { | |
| await message.reply({ content: `β Failed to post: ${err.message}\nPlease send a valid channel ID.` }); | |
| } | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| /** | |
| * Handle drop button interactions (status select, approve/cancel). | |
| */ | |
| async function handleDropButton(interaction) { | |
| const userId = interaction.user.id; | |
| const session = activeSessions.get(userId); | |
| if (!session) return false; | |
| const { customId } = interaction; | |
| if (customId === 'drop_checked' || customId === 'drop_unchecked') { | |
| session.status = customId === 'drop_checked' ? 'checked' : 'unchecked'; | |
| session.step = 'about'; | |
| await interaction.update({ | |
| embeds: [createEmbed({ | |
| title: `${customId === 'drop_checked' ? 'β ' : 'β οΈ'} Status: ${session.status}`, | |
| color: customId === 'drop_checked' ? Colors.SUCCESS : Colors.WARNING, | |
| })], components: [] | |
| }); | |
| await interaction.followUp(getPrompt(session)); | |
| return true; | |
| } | |
| if (customId === 'drop_approve') { | |
| session.step = 'channel'; | |
| await interaction.update({ | |
| embeds: [interaction.message.embeds[0]], | |
| components: [], | |
| }); | |
| await interaction.followUp({ | |
| embeds: [createEmbed({ | |
| title: 'π€ Where to post?', | |
| description: '> Send the **channel ID** where this drop should be posted.\n\nYou can right-click a channel β Copy Channel ID.', | |
| color: Colors.INFO, | |
| })], | |
| }); | |
| return true; | |
| } | |
| if (customId === 'drop_cancel') { | |
| activeSessions.delete(userId); | |
| await interaction.update({ | |
| embeds: [createEmbed({ title: 'β Drop Cancelled', color: Colors.ACCENT })], | |
| components: [], | |
| }); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Format bytes to human readable string. | |
| */ | |
| function formatBytes(bytes) { | |
| if (bytes === 0) return '0 B'; | |
| const k = 1024; | |
| const sizes = ['B', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
| } | |
| module.exports = { | |
| startDropSession, | |
| hasSession, | |
| getPrompt, | |
| handleDropMessage, | |
| handleDropButton, | |
| buildDropEmbed, | |
| canDrop, | |
| }; | |