Snax Bot

Documentation

Everything you need to set up, configure, and extend SNAX. Version 1.1.0.

Add to Server

Overview

Snax is a highly modular, multi-purpose Discord bot built with discord.js v14. It combines a full-featured music player powered by Lavalink, a rich role-based permission system, server moderation tools, voice management utilities, and smart anti-spam protection — all in one lightweight, easy-to-extend package.

Invite Link: Add to Discord

Default Prefix: $ — customizable per-server with $setprefix, or reset with $remprefix. You can trigger commands by @mentioning the bot, using the prefix, or via slash (/) commands for all music features.

Project Structure

Snax-Bot/
├── index.js                  — Entry point. Creates Discord client, loads
│                               handlers, Lavalink music player, and logs in.
├── config/
│   ├── config.json           — Main runtime configuration (prefix, volume, etc.)
│   ├── config.js             — Loader that merges .env with config.json
│   └── slashOptionsMap.js    — Slash command options config for music commands
├── commands/                 — All non-music prefix commands (39 files)
├── lavalink_music/           — Lavalink music integration using Kazagumo/Shoukaku
│   ├── player.js             — Initialises Kazagumo player, registers Lavalink
│   │                           events, and loads music commands into the client.
│   ├── interaction.js        — Controller button component interaction handler
│   ├── embeds.js             — Embed builders for Now Playing / Queue UI
│   ├── commands/             — 13 music-specific commands (play, loop, loopQ, etc.)
│   └── events/               — Player lifecycle events (playerStart, playerEmpty, etc.)
├── events/                   — Discord client events (messageCreate, ready, etc.)
├── handlers/
│   ├── commandHandler.js     — Dynamically loads all files from commands/
│   └── eventHandler.js       — Dynamically loads all files from events/
├── utils/
│   ├── permissions.js        — RBAC engine (groups, DB read/write, checks, bot owner)
│   ├── antiSpam.js           — Rolling-window spam detection & auto-timeout
│   ├── serverLogger.js       — Creates/writes to the private snax-log channel
│   ├── logger.js             — Terminal logger (success/warn/error)
│   ├── voiceCheck.js         — Voice-channel presence validation helper
│   └── slashDeploy.js        — Deploys slash commands to Discord globally
├── data/
│   └── permissions.json      — Auto-generated guild permission database (JSON)
├── install.bat               — One-click Windows installer
├── setup_mac.sh              — macOS setup script
├── package.json
└── .env                      — Secret tokens (never commit this file!)

Setup & Installation

Prerequisites

  • Node.js v18 or highernodejs.org
  • Discord Bot Application & tokenDiscord Developer Portal
  • Lavalink Server Node — either self-hosted, or a public host (like the default one configured).

Windows

  1. Double-click install.bat. This runs npm install, creates your .env, and configures default settings automatically.
  2. Open .env in any text editor and fill in your credentials (see Configuration section).
  3. Run the bot: node index.js

macOS / Linux

  1. Run the setup script: bash setup_mac.sh
  2. Fill in .env (see Configuration section).
  3. Run the bot: node index.js

Successful Startup Output

[SUCCESS] Loaded 13 Lavalink music commands successfully!
[SUCCESS] Registered 2 Kazagumo player events successfully!
[SUCCESS] Loaded 39 commands successfully!
[SUCCESS] Registered 4 client events successfully!
🤖 Success! Logged in as Snax#XXXX
👑 Successfully fetched application owner: DeveloperName
[SUCCESS] Lavalink Node "HeavenCloud-Node" connected successfully!

Configuration

.env File (Secrets — Never Share)

Bot_Token=YOUR_DISCORD_BOT_TOKEN
OWNER_ID=YOUR_DISCORD_USER_ID
LAVALINK_HOST=lava-v4.ajieblogs.eu.org
LAVALINK_PORT=443
LAVALINK_PASSWORD=https://dsc.gg/ajidevserver
LAVALINK_SECURE=true
  • Bot_Token — Your Discord bot token from the Developer Portal.
  • OWNER_ID — (Optional) Your Discord user ID to hardcode yourself as Bot Owner. If left blank, the bot will dynamically fetch your ID from Discord on boot.
  • LAVALINK_HOST — The IP/domain of your Lavalink node server.
  • LAVALINK_PORT — The port of your Lavalink node server.
  • LAVALINK_PASSWORD — The access password for your Lavalink node server.
  • LAVALINK_SECURE — Set to true if the node uses SSL/WSS, otherwise false.

config/config.json (Runtime Settings)

{
  "prefix": "$",                   // Default command prefix for all servers.
  "defaultVolume": 100,            // Starting playback volume (0–100).
  "leaveOnEmpty": true,            // Leave voice channel when it becomes empty.
  "leaveOnEmptyCooldown": 30000,   // Milliseconds to wait before leaving (30 s).
  "leaveOnEnd": false,             // Stay in VC after the queue finishes.
  "autoJoin": false,               // Auto-join on message (not implemented yet).
  "selfDeaf": true,                // Bot deafens itself while in VC.
  "embed": {
    "color": "#5865F2",            // Hex colour for all bot embeds.
    "showThumbnail": true,         // Show song thumbnail in Queue/Now Playing.
    "showRequester": true          // Show who requested the song.
  },
  "maxQueueDisplay": 10,           // Max songs shown per queue page.
  "permissions": {
    "sameVoiceRequired": true,     // Users must be in same VC to control music.
    "djRole": "",                  // Dedicated DJ role check (unused).
    "adminBypass": true            // Admins bypass all voice checks.
  }
}

Per-server prefix overrides are stored automatically in data/permissions.json and take precedence over the global prefix in config.json.

Permission System (RBAC)

Snax uses a custom Role-Based Access Control (RBAC) system stored in data/permissions.json. Permissions are evaluated per-server (guild).

Priority Order

  1. Bot Owner — unrestricted access to everything (all servers).
  2. Server Owner — unrestricted access to everything in their server.
  3. AdminExe — bypasses all permission checks.
  4. Assigned permission group matching the command.
  5. @everyone (if Default group is set to @everyone).
  6. Denied — command blocked.

Bot Owner Privileges

The Bot Owner gets absolute privilege override automatically. The bot queries the Discord API on boot to fetch your client owner ID. You can also override it explicitly in your .env file with the OWNER_ID variable. Bot Owners bypass all command permission checks and all anti-spam warning/timeout filters.

Permission Groups

GroupCommands Unlocked
Defaultplay, skip, queue, ping, help, hello, nowplaying, volume, pause, resume, prev, remove, clear, shuffle, loop, loopQ, autoplay, stop, join, leave
VoiceExemute, unmute, deafen, undeafen, dragreq, addme
setNickExesetnick, remnick
ChatExepurge, timeout
ManagerExeban, unban, kick (ManagerExe users can also assign: VoiceExe, remVoiceExe, setNickExe, remNickExe, assign_default, default_remove)
AdminExeAll of the above PLUS all admin/assignment commands: VoiceExe, remVoiceExe, setNickExe, remNickExe, assign_default, default_remove, AdminExe, remAdminExe, ChatExe, remChatExe, ManagerExe, remManagerExe, BypassExe, remBypassExe, SupBypass, remSupBypass, setprefix, remprefix, fetch
BypassExeAnti-spam extended limit (15 warns / 20 timeout, vs 4/7 default)
SupBypassTotal anti-spam immunity (no warnings or timeouts ever applied)
OwnerOnlyCommands not in any group — only Server/Bot Owners can use them.

AdminExe 10-Minute Cooldown

When AdminExe is granted with $AdminExe @target, the target is placed in a pendingAdminExe queue with a 10-minute delay before becoming a full AdminExe. This prevents accidental instant privilege escalation. If $remAdminExe is called before the 10 minutes elapse, the pending entry is removed immediately.

Data Storage Format

{
  "<guild_id>": {
    "Default": ["@everyone"],
    "VoiceExe": ["<role_or_user_id>", ...],
    "setNickExe": [...],
    "ChatExe": [...],
    "ManagerExe": [...],
    "AdminExe": [...],
    "pendingAdminExe": { "<id>": <unix_timestamp_ms> },
    "BypassExe": [...],
    "SupBypass": [...],
    "customPrefix": "<prefix>"   // optional — only present when set
  }
}

New guilds are initialised with Default: ["@everyone"] so music commands work for everyone out of the box.

Anti-Spam System

The bot monitors message frequency using an in-memory rolling-window counter. Each user's message timestamps are tracked over a 10-second window.

TierLimit (10s window)Action
Normal user4 messagesWarning sent (auto-deleted after 5s)
Normal user7 messages2-minute Discord timeout applied
BypassExe15 messagesWarning sent
BypassExe20 messages2-minute timeout applied
SupBypassNo limitFully immune — no warnings or timeouts
AdminExeNo limitImmune
ManagerExeNo limitImmune
Server OwnerNo limitImmune
Bot OwnerNo limitImmune

Only bot commands (prefix / @mention) are checked — regular chat messages are not affected by this filter.

Music System (Lavalink)

The music system is isolated in the lavalink_music/ directory and utilizes Lavalink (via Kazagumo & **Shoukaku** wrappers) for low-overhead audio streaming.

Audio Playback Pipeline

  1. User types $play <query>
  2. The bot checks that the user is in a voice channel.
  3. The bot ensures it has an active Player instance for the server (guild) or creates one using player.createPlayer().
  4. Kazagumo queries the Lavalink server using player.search(query, { requester }). Lavalink handles the backend URL resolution and metadata extraction.
  5. The resolved tracks are loaded:
    • If a playlist is found, all tracks are added to the player's queue.
    • If a single track is found, the top result is added to the queue.
    • YouTube Shorts URLs are automatically converted.
  6. Lavalink streams the audio directly to Discord's voice servers, ensuring latency-free, high-quality audio that doesn't burden the host machine.

Interactive Embed Controller

When a song starts playing, Snax sends an interactive Now Playing/Queue embed. It includes:

  • Song title (hyperlinked to original source), duration, and status indicators.
  • Thumbnail (when enabled in config).
  • List of up next tracks (collapsible queue list).
  • Integrated media control buttons:
    • ⏯️ (Play/Pause) — Toggles track pausing.
    • ⏭️ (Skip) — Skips the current track.
    • ⏹️ (Stop) — Clears queue, stops player, and disconnects.
    • 🔼 / 🔽 (More/Less) — Expands/collapses queue details (default up to 10 vs 3).

Supported Audio Sources

SourceSupport Level
YouTube (URL/Search)Full — handled by Lavalink node
SoundCloudFull — handled by Lavalink node
SpotifyFull — metadata matching → streams YouTube audio
Apple MusicFull — metadata matching → streams YouTube audio

Event Reference

Discord Client Events (events/)

EventDescription
messageCreateMain command dispatcher. Handles prefix/mention triggers, anti-spam checks, permission validation, and command execution.
interactionCreateHandles slash (/) commands (for music) and component interactions (buttons, dropdowns, modals). Routes to the appropriate handlers based on customId.
guildCreateCreates the private snax-log channel upon joining a server.
readyRuns on login. Fetches client application owner info.

Kazagumo Player Events (lavalink_music/events/)

EventDescription
playerStartFires when a new track begins playback. Sends the main queue controller embed and action buttons.
playerEmptyFires when the queue ends; handles empty queue channel alerts.
errorLogs Lavalink player and connection errors.

Utility Modules

utils/permissions.js

Function / PropertyDescription
hasPermission(message, commandName)Checks if the user is allowed to run a command.
hasGroup(message, groupName)Checks if user holds a specific permission group.
isBotOwner(message)Bypasses checks if author is the Bot Owner.
addTarget / removeTargetAdds or removes a user/role from a group. For AdminExe, handles 10-minute pending delay.
checkManagerHierarchyEnforces Manager hierarchy roles.
getGuildPrefix / setGuildPrefixManages custom guild prefix overrides.

utils/antiSpam.js

Monitors user message frequency with auto-warning and 2-minute timeouts.

utils/serverLogger.js

Creates and writes server logs to the private `#snax-log` channel.

utils/logger.js

Custom terminal logger with color codes (success/warn/error).

utils/voiceCheck.js

Checks if user and bot are in voice channels together before music playback.

utils/slashDeploy.js

deploySlashCommands(client): Dynamically registers the 13 music commands as slash commands globally.

Adding New Commands

Snax uses a dynamic command loader — adding a command requires only creating a new file. No manual registration is needed.

  1. Create a new .js file in the commands/ directory (or lavalink_music/commands/ for music commands).
  2. Export an object with at minimum:
    module.exports = {
      name: 'mycommand',             // REQUIRED — command trigger name (lowercase)
      aliases: ['mc', 'mycmd'],      // OPTIONAL — alternative trigger names
      description: 'Does a thing',   // OPTIONAL — shown in help
      async execute(message, args, client, player, config) {
        // Your command logic here
        message.reply('Hello!');
      }
    };
  3. Restart the bot. The commandHandler will automatically detect and load the file.
  4. To make the command require a permission group, add the command name to the appropriate group in the COMMAND_GROUPS object inside utils/permissions.js. If not listed in any group, it will default to OwnerOnly.

Dependencies

PackageVersionPurpose
discord.js^14.26.4Core Discord API wrapper
dotenv^17.4.2Loads .env variables
kazagumo^3.4.3Lavalink node manager & queue wrapper
shoukaku^4.3.0Lavalink node connector library

Known Notes & Limitations

Pending AdminExe

AdminExe grants have a mandatory 10-minute delay before taking effect. This is intentional and cannot be bypassed (except by Server/Bot Owners).

Purge Age Limit

Discord's API does not allow bulk-deleting messages older than 14 days.

Bot Privileged Intents

Ensure Message Content, Server Members, and Voice State intents are enabled in the Discord Developer Portal under bot settings.

Local Data Storage

Guild permissions are stored in data/permissions.json on the local host.

Recent Updates (Version 1.1.0)

The following features, optimizations, and bug fixes were introduced in Version 1.1.0:

  • New Command: $remnick — Added to the nickname group (setNickExe). Resets the nickname of the bot or the mentioned user back to their default username.
  • New Command: $fetch — Added to the admin group (AdminExe). Queries the bot permissions assigned directly to a user/role or inherited via roles. Returns ! Dev ! if the query target is the owner defined in the .env file.
  • Robust Exe Assignments — Refactored all 16 permission management commands to support both user/role mentions and raw IDs, resolving members dynamically from the Discord API.
  • Proactive Role Hierarchy Warnings — Added startup and server-join checks that post a warning in #snax-log if the bot's role is below other roles in the server hierarchy, prompting administrators to drag it to the top.
  • Non-Music Bug Fixes:
    • Moved anti-spam checks to only monitor command executions rather than general messages in the server.
    • Capped the purge command message fetch limit to prevent RangeErrors when fetching exactly 100 messages.
    • Added hierarchy validation checks to the timeout command.
    • Fixed requester VC validation upon target acceptance in dragreq.
    • Fixed setnick role check when targeting the bot itself.