### Install and Build Project Dependencies with Bun Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Commands to install project dependencies, build the project using tsup, run tests with Vitest, and manage linting and formatting with Biome. ```bash bun install # Install dependencies bun run build # Build the project (tsup) bun run test # Run tests (vitest) bun run lint # Check linting (biome ci) bun run lint:fix # Fix linting issues (biome check --write --unsafe) bun run prettier # Format code (biome format --write) bun run type # Type check (tsc --noEmit) bun run docs # Generate documentation (typedoc) ``` -------------------------------- ### Install DisTube and Dependencies via Package Managers Source: https://github.com/skick1234/distube/wiki/Installation Installs DisTube and its peer dependencies (@discordjs/voice, @discordjs/opus) using various package managers. Ensure Node.js and discord.js are installed prior to running these commands. ```bash # Using bun (recommended) bun add distube @discordjs/voice @discordjs/opus # Using npm npm install distube @discordjs/voice @discordjs/opus # Using yarn yarn add distube @discordjs/voice @discordjs/opus # Using pnpm pnpm add distube @discordjs/voice @discordjs/opus ``` -------------------------------- ### Install Encryption Library for Voice Support Source: https://github.com/skick1234/distube/wiki/Installation Installs the recommended '@noble/ciphers' package using package managers. This is required if the Node.js environment does not natively support 'aes-256-gcm'. ```bash # Using bun bun add @noble/ciphers # Using npm npm install @noble/ciphers ``` -------------------------------- ### Install FFmpeg on Linux (Ubuntu/Debian) Source: https://github.com/skick1234/distube/blob/main/wiki/Installation.md Installs the FFmpeg package on Ubuntu or Debian-based Linux distributions using the apt-get package manager. FFmpeg is crucial for DisTube's audio processing capabilities. ```bash sudo apt-get install ffmpeg ``` -------------------------------- ### Mocking DisTube Components with Vitest (TypeScript) Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Provides an example of mocking DisTube components, specifically `DisTubeVoice`, using Vitest. It demonstrates setting up mocks, clearing mocks between tests, and creating mock voice objects with controllable methods like `stop` and `play`. ```typescript import { beforeEach, describe, expect, it, vi } from "vitest"; import { DisTubeError, Queue } from "@"; vi.mock("@/core/DisTubeVoice"); const createMockVoice = () => ({ id: "123", stop: vi.fn(), play: vi.fn(), on: vi.fn(), channel: { guild: { members: { me: {} } } }, }) as any; describe("Queue", () => { beforeEach(() => { vi.clearAllMocks(); }); it("should do something", () => { expect(result).toBe(expected); }); }); ``` -------------------------------- ### Install DisTube v3 Dependencies (Shell) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Command to install the necessary packages for DisTube v3, including `@discordjs/voice` and `sodium` (or `libsodium-wrappers`). These are required due to DisTube v3's reliance on `@discordjs/voice`. ```sh npm i @discordjs/voice sodium ``` -------------------------------- ### Configure DisTube Queue Defaults (JavaScript) Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Shows how to set default properties for new queues using the `INIT_QUEUE` event. This allows for pre-configuration of settings like autoplay, volume, and repeat mode. ```javascript distube.on(Events.INIT_QUEUE, queue => { queue.autoplay = false; // Disable autoplay queue.setVolume(50); // Set default volume queue.setRepeatMode(0); // Disable repeat }); ``` -------------------------------- ### Install FFmpeg on MacOS Source: https://github.com/skick1234/distube/blob/main/wiki/Installation.md Installs the FFmpeg package on MacOS using the Homebrew package manager. FFmpeg is required for DisTube to handle audio processing and filtering. ```bash brew install ffmpeg ``` -------------------------------- ### Installing DisTube Opus Dependencies Source: https://github.com/skick1234/distube/wiki/Frequently-Asked-Questions Installs the necessary `@discordjs/opus` package for DisTube to handle audio encoding and playback. It also includes commands to remove potentially conflicting packages like `opusscript` or `node-opus`. This is crucial for resolving audio-related errors. ```bash # Using bun bun remove opusscript node-opus bun add @discordjs/opus # Using npm npm uninstall opusscript node-opus npm install @discordjs/opus ``` -------------------------------- ### DisTube v4: Using createCustomPlaylist and play Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Demonstrates the new approach in DisTube v4 for playing custom playlists, using createCustomPlaylist followed by the play method, replacing the removed playCustomPlaylist. ```diff const songs = ["https://www.youtube.com/watch?v=xxx", "https://www.youtube.com/watch?v=yyy"]; - distube.playCustomPlaylist(message, songs, { name: "My playlist name" }); + const playlist = await distube.createCustomPlaylist(songs, { + member: message.member, + properties: { name: "My playlist name" }, + parallel: true + }); + distube.play(message.member.voice.channel, playlist); ``` -------------------------------- ### DisTube Plugin Integration (JavaScript) Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Explains how to integrate official DisTube plugins for additional music sources like YouTube, Spotify, and SoundCloud. This expands the functionality of the music bot. ```javascript import { DisTube } from "distube"; import { YouTubePlugin } from "@distube/youtube"; import { SpotifyPlugin } from "@distube/spotify"; import { SoundCloudPlugin } from "@distube/soundcloud"; const distube = new DisTube(client, { plugins: [ new YouTubePlugin(), new SpotifyPlugin(), new SoundCloudPlugin(), ], }); ``` -------------------------------- ### Running Tests with Bun (Bash) Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Illustrates how to execute tests using the Bun runtime. It covers running all tests, running tests in watch mode for continuous feedback, and running specific test files by providing a pattern. ```bash bun run test bun run test -- --watch bun run test -- Queue ``` -------------------------------- ### Install DisTube and Dependencies Source: https://github.com/skick1234/distube/blob/main/README.md This command installs the DisTube library along with its necessary peer dependencies, @discordjs/voice and @discordjs/opus, which are essential for audio playback in Discord bots. ```bash npm install distube @discordjs/voice @discordjs/opus ``` -------------------------------- ### Check Queue Existence in DisTube (JavaScript) Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Illustrates the best practice of verifying if a music queue exists before attempting any operations on it. This prevents errors when no music is currently playing. ```javascript const queue = distube.getQueue(guildId); if (!queue) { return message.reply("Nothing is playing!"); } ``` -------------------------------- ### Instantiating DisTube v3 with TypeScript Source: https://github.com/skick1234/distube/blob/main/wiki/Major-Upgrade-Guide.md Illustrates the updated way to create a DisTube instance in v3, which is written in TypeScript. It shows two common import patterns for the DisTube class. ```diff const DisTube = require("distube") - const distube = new DisTube(options) + const distube = new DisTube.default(options) // or new DisTube.DisTube(options) ``` ```diff - const DisTube = require("distube") + const { DisTube } = require("distube") const distube = new DisTube(options) ``` -------------------------------- ### Instantiate DisTube Class (JavaScript) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Shows two ways to correctly instantiate the DisTube class in v3, accounting for its TypeScript nature. This addresses changes in how the DisTube client is initialized compared to v2. ```javascript const DisTube = require("distube") // const distube = new DisTube(options) const distube = new DisTube.default(options) // or new DisTube.DisTube(options) ``` ```javascript // const DisTube = require("distube") const { DisTube } = require("distube") const distube = new DisTube(options) ``` -------------------------------- ### Initialize DisTube in Discord.js Bot Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Initializes the DisTube class within a Discord.js client. This setup requires Guilds, GuildVoiceStates, GuildMessages, and MessageContent intents. The DisTube constructor takes the client instance and an options object for playback behavior. ```javascript const { Client, GatewayIntentBits } = require("discord.js"); const { DisTube } = require("distube"); const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, ], }); // Create a new DisTube instance const distube = new DisTube(client, { emitNewSongOnly: true, emitAddSongWhenCreatingQueue: false, emitAddListWhenCreatingQueue: false, }); client.login("YOUR_BOT_TOKEN"); ``` -------------------------------- ### DisTube Resource Cleanup (JavaScript) Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Demonstrates how to automatically leave voice channels when the queue finishes or when the voice channel becomes empty. This is crucial for freeing up resources and improving bot performance. ```javascript // Leave when queue finishes distube.on(Events.FINISH, queue => { queue.voice.leave(); }); // Leave when voice channel is empty import { isVoiceChannelEmpty } from "distube"; client.on("voiceStateUpdate", oldState => { if (!oldState?.channel) return; const voice = distube.voices.get(oldState); if (voice && isVoiceChannelEmpty(oldState)) { voice.leave(); } }); ``` -------------------------------- ### DisTube Shortcut Methods Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md This section details the deprecated shortcut methods for DisTube and their replacements. It is recommended to use the new `distube.getQueue(guild).method()` syntax for managing playback and queue operations. ```APIDOC ## DisTube Shortcut Methods ### Description Use `distube.getQueue(guild).method()` instead of `distube.method(guild)` for managing playback and queue operations. ### Method POST ### Endpoint `/skick1234/distube/shortcut-methods ### Parameters #### Path Parameters - **guild** (string) - Required - The guild ID for which to perform the action. #### Query Parameters None #### Request Body None ### Request Example ```json { "guild": "1234567890" } ``` ### Response #### Success Response (200) - **message** (string) - A confirmation message indicating the operation was successful. #### Response Example ```json { "message": "Operation successful." } ``` ### Deprecated Methods and Replacements | Deprecated Method | Replacement Method | |-------------------|--------------------| | `distube.pause(guild)` | `distube.getQueue(guild).pause()` | | `distube.resume(guild)` | `distube.getQueue(guild).resume()` | | `distube.stop(guild)` | `distube.getQueue(guild).stop()` | | `distube.setVolume(guild, vol)` | `distube.getQueue(guild).setVolume(vol)` | | `distube.skip(guild, opts)` | `distube.getQueue(guild).skip(opts)` | | `distube.previous(guild)` | `distube.getQueue(guild).previous()` | | `distube.shuffle(guild)` | `distube.getQueue(guild).shuffle()` | | `distube.jump(guild, num, opts)` | `distube.getQueue(guild).jump(num, opts)` | | `distube.setRepeatMode(guild, mode)` | `distube.getQueue(guild).setRepeatMode(mode)` | | `distube.toggleAutoplay(guild)` | `distube.getQueue(guild).toggleAutoplay()` | | `distube.addRelatedSong(guild)` | `distube.getQueue(guild).addRelatedSong()` | | `distube.seek(guild, time)` | `distube.getQueue(guild).seek(time)` | ``` -------------------------------- ### DisTube v4: Using Queue Filters Source: https://github.com/skick1234/distube/blob/main/wiki/Major-Upgrade-Guide.md Explains that the `Queue#setFilter` method has been removed in DisTube v4 and replaced by direct manipulation of the `Queue#filters` property. ```diff - Queue#setFilter + Queue#filters ``` -------------------------------- ### DisTube TypeScript Integration Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Shows how to leverage TypeScript with DisTube for enhanced development experience, including type definitions for `Queue` and `Song` objects. This improves code maintainability and reduces runtime errors. ```typescript import { Client, GatewayIntentBits, Message } from "discord.js"; import { DisTube, Events, Queue, Song } from "distube"; const distube = new DisTube(client); distube.on(Events.PLAY_SONG, (queue: Queue, song: Song) => { // Full type support }); ``` -------------------------------- ### Distube Debug Event Handling (TypeScript) Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Demonstrates how to listen for debug events emitted by Distube for troubleshooting. It shows how to attach listeners to `Events.DEBUG` and `Events.FFMPEG_DEBUG` to log detailed information during runtime. ```typescript distube.on(Events.DEBUG, console.log); distube.on(Events.FFMPEG_DEBUG, console.log); ``` -------------------------------- ### Modifying DisTube#playCustomPlaylist Options in v3 Source: https://github.com/skick1234/distube/blob/main/wiki/Major-Upgrade-Guide.md Demonstrates the updated options for the `DisTube#playCustomPlaylist` method in v3. The `skip` parameter is now an object property, and new `parallel` and `unshift` properties are available. ```diff - #playCustomPlaylist(..., true) + #playCustomPlaylist(..., { skip: true }) ``` -------------------------------- ### Apply Multiple Filters with DisTube#setFilter (JavaScript) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Illustrates the enhanced `DisTube#setFilter` method in v3, which now supports applying multiple filters simultaneously using an array. It also shows how to clear filters by passing `false`. ```javascript // No filter applied distube.setFilter(message, "3d"); // Applied filters: 3d distube.setFilter(message, ["3d", "bassboost", "vaporwave"]); // Applied filters: bassboost, vaporwave distube.setFilter(message, ["3d", "bassboost", "vaporwave"], true); // Applied filters: 3d, bassboost, vaporwave distube.setFilter(message, false); // No filter applied ``` -------------------------------- ### Update DisTube PlayCustomPlaylist Options (JavaScript) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Shows the updated syntax for the `DisTube#playCustomPlaylist` method in v3. The `skip` parameter is now part of an options object, and new options like `parallel` and `unshift` are available. ```javascript // #playCustomPlaylist(..., true) #playCustomPlaylist(..., { skip: true }) ``` -------------------------------- ### Basic DisTube Queue Controls (JavaScript) Source: https://github.com/skick1234/distube/wiki/DisTube-Guide Demonstrates how to use queue methods for common playback controls such as stop, skip, pause, resume, volume adjustment, shuffle, repeat mode, displaying the queue, and showing the currently playing song. It emphasizes using queue methods directly over deprecated shortcut methods. ```javascript const queue = distube.getQueue(message.guildId); if (command === "stop") { if (!queue) return message.channel.send("Nothing is playing!"); await queue.stop(); message.channel.send("Stopped the player!"); } if (command === "skip") { if (!queue) return message.channel.send("Nothing is playing!"); await queue.skip(); message.channel.send("Skipped the song!"); } if (command === "pause") { if (!queue) return message.channel.send("Nothing is playing!"); queue.pause(); message.channel.send("Paused the song!"); } if (command === "resume") { if (!queue) return message.channel.send("Nothing is playing!"); queue.resume(); message.channel.send("Resumed the song!"); } if (command === "volume") { if (!queue) return message.channel.send("Nothing is playing!"); const volume = parseInt(args[0]); if (isNaN(volume) || volume < 0 || volume > 100) { return message.channel.send("Please provide a valid volume (0-100)!"); } queue.setVolume(volume); message.channel.send(`Volume set to ${volume}%`); } if (command === "shuffle") { if (!queue) return message.channel.send("Nothing is playing!"); queue.shuffle(); message.channel.send("Shuffled the queue!"); } if (command === "repeat") { if (!queue) return message.channel.send("Nothing is playing!"); const mode = queue.setRepeatMode(); const modeText = ["Off", "Song", "Queue"][mode]; message.channel.send(`Repeat mode: ${modeText}`); } if (command === "queue") { if (!queue) return message.channel.send("Nothing is playing!"); const songs = queue.songs .map((song, i) => `${i === 0 ? "Playing:" : `${i}.`} ${song.name} - `${song.formattedDuration}``) .join("\n"); message.channel.send(songs.slice(0, 1990)); } if (command === "nowplaying" || command === "np") { if (!queue) return message.channel.send("Nothing is playing!"); const song = queue.songs[0]; message.channel.send( `Now playing: ${song.name}\n` + `Duration: ${queue.formattedCurrentTime} / ${song.formattedDuration}` ); } ``` -------------------------------- ### Initialize DisTube with Plugins and Configuration Source: https://context7.com/skick1234/distube/llms.txt Initializes the DisTube class with Discord.js client, specifying intents, plugins (YouTube, Spotify), custom filters, and FFmpeg path. It also accesses and logs DisTube properties like version, registered plugins, and available filters. ```javascript const { Client, GatewayIntentBits } = require("discord.js"); const { DisTube, Events } = require("distube"); const { YouTubePlugin } = require("@distube/youtube"); const { SpotifyPlugin } = require("@distube/spotify"); const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, ], }); // Initialize DisTube with options and plugins const distube = new DisTube(client, { emitNewSongOnly: true, emitAddSongWhenCreatingQueue: false, emitAddListWhenCreatingQueue: false, savePreviousSongs: true, nsfw: false, joinNewVoiceChannel: true, plugins: [ new YouTubePlugin(), new SpotifyPlugin(), ], customFilters: { "clear": "dynaudnorm=f=200", "lowbass": "bass=g=5", }, ffmpeg: { path: "/usr/bin/ffmpeg", // Optional custom path }, }); // Access DisTube properties console.log(`DisTube version: ${distube.version}`); console.log(`Registered plugins: ${distube.plugins.length}`); console.log(`Available filters: ${Object.keys(distube.filters).join(", ")}`); client.login("YOUR_BOT_TOKEN"); ``` -------------------------------- ### Check for Native AES-256-GCM Support Source: https://github.com/skick1234/distube/wiki/Installation Verifies if the Node.js environment has native support for the 'aes-256-gcm' cipher, which is required by discord.js for voice functionality. If this returns false, an external encryption library must be installed. ```javascript require('node:crypto').getCiphers().includes('aes-256-gcm') ``` -------------------------------- ### Conventional Commit Messages for Git Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Defines the structure for Git commit messages following the Conventional Commits specification. It emphasizes using a PascalCase scope and provides examples for different commit types like `feat`, `fix`, `docs`, and `chore`. ```git feat(Queue): add shuffle functionality fix(Voice): handle reconnection failures docs(README): update installation instructions chore(Release): 5.1.2 ``` -------------------------------- ### Extend Music Sources with DisTube Plugins Source: https://context7.com/skick1234/distube/llms.txt This snippet illustrates how to extend DisTube's music source capabilities using its plugin system. It shows the initialization of DisTube with multiple official plugins, including YouTube, Spotify, SoundCloud, Deezer, and yt-dlp. The order of plugins is crucial as the first matching plugin handles a given URL. Official plugins can be found at `@distube/youtube`, `@distube/spotify`, `@distube/soundcloud`, `@distube/deezer`, and `@distube/yt-dlp`. ```javascript const { DisTube } = require("distube"); const { YouTubePlugin } = require("@distube/youtube"); const { SpotifyPlugin } = require("@distube/spotify"); const { SoundCloudPlugin } = require("@distube/soundcloud"); const { DeezerPlugin } = require("@distube/deezer"); const { YtDlpPlugin } = require("@distube/yt-dlp"); // Initialize with multiple plugins const distube = new DisTube(client, { plugins: [ // YouTube with cookies for age-restricted content new YouTubePlugin({ cookies: [ { name: "cookie_name", value: "cookie_value", }, ], }), // Spotify (requires API credentials in env) new SpotifyPlugin({ emitEventsAfterFetching: true, }), // SoundCloud new SoundCloudPlugin(), // Deezer new DeezerPlugin(), // yt-dlp for 700+ sites new YtDlpPlugin({ update: true, // Auto-update yt-dlp }), ], }); // Plugin order matters - first matching plugin handles the URL // Put more specific plugins before general ones (yt-dlp) ``` -------------------------------- ### Handle PlaySong Event with Playlist Check (JavaScript) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Provides an example of how to adapt the `playSong` event handler in DisTube v3 to accommodate songs that are part of a playlist. This replaces the removed `playList` event and consolidates playlist and single song handling. ```javascript distube.on("playSong", (queue, song) => { let msg = `Playing `${song.name}` - `${song.formattedDuration}``; if (song.playlist) msg = `Playlist: ${song.playlist.name}\n${msg}`; queue.textChannel.send(msg); }); ``` -------------------------------- ### Configure DisTube#search Options (JavaScript) Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Demonstrates how to use the `options` parameter in the `DisTube#search` method (v3) to customize search results. This includes setting the limit, type of result (e.g., 'video'), and enabling/disabling safe search. ```javascript distube.search("A query", { limit: 10, type: "video", safeSearch: false, }); ``` -------------------------------- ### DisTube v4: Replacing DisTube#playVoiceChannel Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Notes the removal of the DisTube#playVoiceChannel method in v4, which has been replaced by the unified DisTube#play method. ```diff - distube.playVoiceChannel(...) + distube.play(...) ``` -------------------------------- ### DisTube v4: Replacing youtubeDL with YtDlpPlugin Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Demonstrates how to integrate the new @distube/yt-dlp plugin in DisTube v4, replacing the deprecated built-in youtubeDL option. ```diff - const distube = new DisTube({ youtubeDL: true, updateYouTubeDL: false }) + const { YtDlpPlugin } = require("@distube/yt-dlp") + const distube = new DisTube({ plugins: [new YtDlpPlugin({ update: false })] }) ``` -------------------------------- ### Create Custom Playlist with DisTube.createCustomPlaylist() Source: https://context7.com/skick1234/distube/llms.txt Demonstrates creating custom playlists from arrays of URLs or Song objects. This method is useful for saved playlists or batch operations. It supports fetching songs in parallel for faster processing and allows for custom metadata. ```javascript if (command === "playlist") { const voiceChannel = message.member?.voice.channel; if (!voiceChannel) return message.reply("Join a voice channel!"); const urls = [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://www.youtube.com/watch?v=example2", "https://www.youtube.com/watch?v=example3", ]; try { const playlist = await distube.createCustomPlaylist(urls, { member: message.member, parallel: true, // Fetch songs in parallel (faster) metadata: { createdBy: message.author.id }, name: "My Custom Playlist", source: "custom", thumbnail: "https://example.com/thumbnail.jpg", }); console.log(`Created playlist: ${playlist.name}`); console.log(`Songs: ${playlist.songs.length}`); console.log(`Duration: ${playlist.formattedDuration}`); // Play the custom playlist await distube.play(voiceChannel, playlist, { textChannel: message.channel, member: message.member, }); } catch (error) { message.reply(`Error: ${error.message}`); } } // Create playlist from existing Song objects if (command === "savecurrent") { const queue = distube.getQueue(message.guildId); if (!queue) return message.reply("Nothing is playing!"); // Save current queue as playlist const playlist = await distube.createCustomPlaylist( queue.songs.map(s => s.url).filter(Boolean), { member: message.member, name: `Saved Queue - ${new Date().toLocaleDateString()}`, parallel: true, } ); message.reply(`Saved ${playlist.songs.length} songs to playlist!`); } ``` -------------------------------- ### DisTube v5: YouTube Search with YouTubePlugin Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Demonstrates how to search for YouTube content in DisTube v5 using the YouTubePlugin. This replaces the removed DisTube#search method. ```typescript import { YouTubePlugin } from "@distube/youtube" import { DisTube } from "distube" const ytPlugin = new YouTubePlugin(...); const distube = new DisTube({ plugins: [ytPlugin], ... }) ytPlugin.search(query, { type: "video", limit: 5, safeSearch: true }).then(console.log) ``` -------------------------------- ### Handle Slash Commands with DisTube (JavaScript) Source: https://github.com/skick1234/distube/wiki/Frequently-Asked-Questions This snippet demonstrates how to handle slash commands for DisTube, specifically the 'play' command. It requires the `discord.js` library and assumes a DisTube instance is already initialized. It takes a 'query' option and plays the provided query in the user's voice channel. ```javascript client.on("interactionCreate", async interaction => { if (!interaction.isChatInputCommand()) return; if (interaction.commandName === "play") { const query = interaction.options.getString("query", true); const voiceChannel = interaction.member?.voice?.channel; if (!voiceChannel) { return interaction.reply("You must be in a voice channel!"); } await interaction.deferReply(); try { await distube.play(voiceChannel, query, { textChannel: interaction.channel, member: interaction.member, }); await interaction.editReply(`Searching for: ${query}`); } catch (error) { await interaction.editReply(`Error: ${error.message}`); } } }); ``` -------------------------------- ### DisTube v5: Error Event Signature Change Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Shows the difference in the error event signature between DisTube v4 and v5. The arguments have been updated to include more context about the error. ```diff - distube.on('error', (channel, e) => { - if (channel) channel.send(`An error encountered: ${e}`) - else console.error(e) -}) + distube.on('error', (e, queue, song) => { + queue.textChannel.send(`An error encountered: ${e}`); + }) ``` -------------------------------- ### TypeScript Error Handling Best Practices Source: https://github.com/skick1234/distube/blob/main/CLAUDE.md Demonstrates type-safe error handling in TypeScript using 'catch (e: unknown)' compared to the less safe 'catch (e: any)'. ```typescript // Good - type-safe error handling catch (e: unknown) { const error = e instanceof Error ? e : new Error(String(e)); const message = e instanceof Error ? (e.stack ?? e.message) : String(e); } // Bad - loses type safety catch (e: any) { console.log(e.message); // Unsafe } ``` -------------------------------- ### Display Song Queue and Now Playing Info (JavaScript) Source: https://context7.com/skick1234/distube/llms.txt This code snippet demonstrates how to format and display the current song queue and its details, as well as information about the currently playing song. It includes a progress bar for the current song and details like requester and duration. ```javascript .map((song, i) => `${i + 1}. ${song.name} - `${song.formattedDuration}``) .join("\n"); } queueText += `\n\n**Queue Info:**\n` + `Songs: ${queue.songs.length} | Duration: ${queue.formattedDuration}\n` + `Volume: ${queue.volume}% | Autoplay: ${queue.autoplay ? "On" : "Off"}\n` + `Repeat: ${["Off", "Song", "Queue"][queue.repeatMode]}`; message.reply(queueText.slice(0, 2000)); } // Now playing if (command === "nowplaying" || command === "np") { if (!queue) return message.reply("Nothing is playing!"); const song = queue.songs[0]; // Calculate progress bar const progress = Math.round((queue.currentTime / song.duration) * 20); const progressBar = "▬".repeat(progress) + "🔘" + "▬".repeat(20 - progress); message.reply( `🎵 **${song.name}**\n` + `${progressBar}\n` + ``${queue.formattedCurrentTime} / ${song.formattedDuration}`\n` + `Requested by: ${song.user}` ); } }); ``` -------------------------------- ### DisTube v4: Using options.position instead of options.unshift Source: https://github.com/skick1234/distube/wiki/Major-Upgrade-Guide Explains the replacement of the options.unshift parameter with options.position in DisTube v4's play method for customizing song/playlist order. ```diff - distube.play(..., { unshift: true }) + distube.play(..., { position: 1 }) ```