diff --git a/README.md b/README.md index ac9050c..5180e0a 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,129 @@ -Icon -
- -# Project for PvR: Discord MusicBot in Rust -- Author: Pavel Mikula (MIK0486) -- Took approximately 40 hours - -## Project Theme -This project is a Discord bot developed in Rust, designed to play music in Discord voice channels. It uses libraries like `serenity` and `poise` for handling the Discord API, `songbird` for managing audio playback, `yt-dlp` for YouTube track streaming, and integrates with the Spotify Web API for Spotify URLs. The bot supports a full music queue, a local audio library, timed reminders, and several utility commands. - -## Project Requirements -- Rust: The primary programming language for bot logic -- Serenity + Poise: Discord API wrapper and command framework for Rust -- Songbird: Voice and audio playback library for Discord -- yt-dlp: For downloading and streaming audio from YouTube -- SQLite (via sqlx): Persistent storage for guild settings and reminders -- Spotify Web API: For resolving Spotify track / playlist URLs - -## Installation -### Prerequisites -- Installed rust from [rust-lang.org](https://www.rust-lang.org/tools/install) -- Installed yt-dlp from [github.com/yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) - - `yt-dlp` should be in the system PATH -- Installed `ffmpeg` (in the system PATH) — used by yt-dlp for post-processing **and** by the bot's loudness analyzer to measure each track's integrated LUFS for cross-track volume normalization -- YouTube Data API token from [Google Cloud Console](https://developers.google.com/youtube/registering_an_application) -- Discord bot token from [Discord Developer Portal](https://discord.com/developers/applications) -- (Optional) Spotify Client ID & Secret from [Spotify Developer Dashboard](https://developer.spotify.com/dashboard) — required for Spotify URL support -- Installed CMAKE. Required for the [audiopus_sys](https://github.com/Lakelezz/audiopus_sys) library - -### Installation -1. Clone this repository - ```bash - git clone https://github.com/Firestone82/RustyTunes.git - cd RustyTunes - ``` -2. Create a `.env` file in the root directory - ```bash - cp .env.example .env - - # Edit the .env file with your Discord bot token, YouTube API key, - # and (optionally) Spotify client id and secret. - ``` -3. Setup database - ```bash - cargo install sqlx-cli - sqlx database create - sqlx migrate run - ``` -4. Install dependencies - ```bash - # yt-dlp - sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp - sudo chmod a+rx /usr/local/bin/yt-dlp - - # ffmpeg (required by yt-dlp and by the loudness normalizer) - sudo apt-get install ffmpeg - - # CMAKE - sudo apt-get install cmake - ``` -5. Build and run the bot - ```bash - cargo build --release - cargo run - ``` - -## Usage -All commands are available as both **prefix commands** (default prefix `!`) and **slash commands** (`/`). Use `!help` or `/help` in Discord to list every command, or `!help ` for details on a specific one. +Icon + +# RustyTunes + +> **VŠB-TUO** — School project · Programming in Rust (PvR) + +![Rust](https://img.shields.io/badge/Rust-2021-orange) ![Discord](https://img.shields.io/badge/Discord-Bot-5865F2) + +A feature-rich Discord music bot written in Rust. Supports YouTube, Spotify, local audio files, and direct URLs. Includes a persistent queue, per-guild volume memory, loudness normalization, timed reminders, and various utility commands. ## Features ### Audio Sources -- Play tracks and playlists from **YouTube** (direct URL or text search) -- Play tracks and playlists from **Spotify** (URL — resolved to YouTube for playback) -- Play files from a **local audio library** stored on the bot host -- Stream user-uploaded **Discord attachments** (audio files) -- Stream audio from **arbitrary direct URLs** +- YouTube (direct URL or text search) +- Spotify (URL — resolved to YouTube for playback) +- Local audio library stored on the bot host +- Discord attachment uploads (audio files) +- Arbitrary direct URLs ### Playback Controls -- `play ` — play a track or playlist from YouTube or Spotify (appends to queue) -- `playtop ` — same as `play` but inserts at the front of the queue -- `pause` / `resume` — pause and resume the current track -- `skip [amount]` — skip the current track (or multiple at once) -- `stop` — stop playback and clear the active track -- `playing` — show the currently playing track -- `volume [1-100]` — set the playback volume; append `!` (e.g. `volume 200!`) to opt into the extended 1–500 overdrive range -- `normalize [on|off]` — toggle session-only cross-track loudness normalization (off by default, applies to every source once enabled, resets on restart) -- `silent [on|off]` — suppress NowPlaying announcements for the session -- `join` / `leave` — manually summon or dismiss the bot from your voice channel +| Command | Description | +|---------|-------------| +| `play ` | Play a track or playlist, append to queue | +| `playtop ` | Same, but insert at front of queue | +| `pause` / `resume` | Pause and resume the current track | +| `skip [amount]` | Skip current track (or N tracks) | +| `stop` | Stop playback and clear the active track | +| `playing` | Show the currently playing track | +| `volume [1-100]` | Set volume; append `!` for overdrive (1–500) | +| `normalize [on\|off]` | Toggle cross-track loudness normalization (EBU R128) | +| `silent [on\|off]` | Suppress Now Playing announcements | +| `join` / `leave` | Summon or dismiss from voice channel | ### Queue Management -- `queue` — paginated queue listing (10 tracks per page) with navigation buttons -- `clear` — remove every track from the queue -- `remove ` — remove a specific track from the queue by its 1-based index -- `shuffle` — shuffle the current queue -- `history` — show the last 10 played tracks with buttons to instantly replay any of them +| Command | Description | +|---------|-------------| +| `queue` | Paginated queue (10 tracks/page) with navigation | +| `clear` | Remove all tracks from the queue | +| `remove ` | Remove a specific track by 1-based index | +| `shuffle` | Shuffle the current queue | +| `history` | Last 10 played tracks with replay buttons | ### Local Audio Library -The `local` command groups subcommands for managing audio files saved on the bot host: -- `local download [name]` — download an audio file from a URL into the library -- `local upload [name]` — save an uploaded Discord attachment into the library -- `local list` — list all saved local tracks -- `local play [name]` — play a saved track by name (with autocomplete and an interactive picker) -- `local rename ` — rename a saved track -- `local remove ` — delete a saved track from the library - -### Reminders / Notifications -The `notify` command (alias `remind`) lets users schedule timed reminders persisted to the database: -- `notify me ` — schedule a reminder for yourself -- `notify you ` — schedule a reminder for another user -- `notify list` — list your pending reminders -- `notify remove ` — cancel a pending reminder - -### Utility Commands -- `wakeup [count]` — drags a user briefly between voice channels to grab their attention (also available as a right-click **WakeUp!** user context menu action) -- `rename [new name]` — set another member's nickname (respects role hierarchy) -- `uwu ` — uwuify the given text -- `uwu_me ` — uwuify text and post it impersonating the author via webhook -- `help [command]` — built-in help listing and per-command detail - -### Quality-of-Life Behaviour -- **Auto-leave**: bot automatically leaves the voice channel when it's left alone -- **Auto-cleanup**: when the bot is kicked, dragged out, or otherwise loses its voice connection, playback state and the queue are cleaned up automatically -- **Per-guild volume persistence**: the last-set volume is remembered between sessions in SQLite -- **Cross-track loudness normalization**: opt-in via `!normalize`. When enabled, each cached track's integrated loudness is measured once (EBU R128 via ffmpeg) and a static gain is applied so songs sit at roughly the same perceived loudness without crushing in-song dynamics. Off by default, takes effect immediately on the current track, resets on restart. The target loudness (`NORMALIZE_TARGET_LUFS`, default -10) and gain clamps (`NORMALIZE_MIN_GAIN_DB`, `NORMALIZE_MAX_GAIN_DB`) are tunable via env vars — higher target = louder output -- **Per-source cache layout**: downloaded audio is filed under `cache/youtube/` or `cache/spotify/` (legacy flat-cached files still play) -- **Slash + prefix parity**: every command works both ways -- **Graceful shutdown**: handles SIGINT/SIGTERM (and Ctrl+C on Windows) to disconnect cleanly -- **Structured logging**: powered by `tracing` with environment-controlled filtering +| Command | Description | +|---------|-------------| +| `local download [name]` | Download audio from URL into library | +| `local upload [name]` | Save a Discord attachment into library | +| `local list` | List all saved tracks | +| `local play [name]` | Play a saved track (with autocomplete) | +| `local rename ` | Rename a saved track | +| `local remove ` | Delete a saved track | + +### Reminders +| Command | Description | +|---------|-------------| +| `notify me ` | Schedule a reminder for yourself | +| `notify you ` | Schedule a reminder for another user | +| `notify list` | List your pending reminders | +| `notify remove ` | Cancel a pending reminder | + +### Utilities +| Command | Description | +|---------|-------------| +| `wakeup [count]` | Drag a user between voice channels to get attention | +| `rename [name]` | Set a member's nickname | +| `uwu ` | Uwuify text | +| `help [command]` | Show command list or per-command help | + +All commands are available as both prefix commands (default `!`) and slash commands (`/`). + +### Quality-of-Life +- Auto-leave when alone in channel +- Per-guild volume persistence (SQLite) +- Cross-track loudness normalization (opt-in, EBU R128 via ffmpeg) +- Slash + prefix parity +- Graceful SIGINT/SIGTERM shutdown +- Structured logging via `tracing` + +## Requirements + +- Rust stable toolchain — [rustup.rs](https://rustup.rs/) +- [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) in system PATH +- [`ffmpeg`](https://ffmpeg.org/) in system PATH +- CMake (required by `audiopus_sys`) +- Discord bot token — [discord.com/developers](https://discord.com/developers/applications) +- YouTube Data API v3 key — [Google Cloud Console](https://console.cloud.google.com/) +- *(Optional)* Spotify Client ID & Secret — [Spotify Developer Dashboard](https://developer.spotify.com/dashboard) + +## Setup + +1. Install system dependencies: + ```bash + # Debian/Ubuntu + sudo apt-get install ffmpeg cmake + sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp \ + -o /usr/local/bin/yt-dlp && sudo chmod a+rx /usr/local/bin/yt-dlp + ``` + +2. Clone the repository: + ```bash + git clone https://github.com/Firestone82/RustyTunes.git + cd RustyTunes + ``` + +3. Copy `.env.example` to `.env` and fill in your Discord token, YouTube API key, and optional Spotify credentials. + +4. Set up the database: + ```bash + cargo install sqlx-cli + sqlx database create + sqlx migrate run + ``` + +5. Build and run: + ```bash + cargo build --release + cargo run --release + ``` + +### Discord bot setup + +1. Create an application at [discord.com/developers/applications](https://discord.com/developers/applications). +2. Under **Bot**, enable **Message Content Intent** and **Server Members Intent**. +3. Copy the bot token into `.env` as `DISCORD_TOKEN`. +4. Invite the bot via the OAuth2 URL generator with `bot` + `applications.commands` scopes and `Connect`, `Speak`, and `Send Messages` permissions. + +## License + +This project was created as a school assignment at VŠB-TUO.