DisTube

repository·main·Indexed 19 days ago

https://github.com/skick1234/distube

A comprehensive Discord music bot library for Discord.js v14. It simplifies music commands, manages voice connections, and provides an extensible plugin system for playing audio from hundreds of sources, including YouTube, Spotify, and SoundCloud. Features include built-in audio filters (bassboost, echo, karaoke), TypeScript type safety, and a robust Queue system for managing playback, volume, and repeat modes.

Tokens
16.9K
Snippets
53
Records
76
Agent score
65%

What's inside distube

  1. Overview of DisTube features

    main

    DisTube is a music bot library for Discord.js v14 that provides:

    • Voice Management: Handles voice connections and queue management.
    • Audio Filters: Includes built-in filters like bassboost, echo, and karaoke, plus support for custom filters.
    • Plugin System: Supports playback from YouTube, Spotify, SoundCloud, and over 700 other sites via an extensible architecture.
    • Type Safety: Fully written in TypeScript.
  2. Understand DisTube plugin types

    main

    DisTube uses different types of plugins depending on whether the plugin needs to search, extract metadata, or play audio. When choosing a plugin, identify which capability you need:

    1. ExtractorPlugin: Full capability. Can extract info, perform searches, and play songs directly from the source (e.g., YouTube, SoundCloud).
    2. InfoExtractorPlugin: Metadata only. Can extract information from supported links but cannot play songs directly from that source (e.g., Spotify, Deezer).
    3. PlayableExtractorPlugin: Playback only. Can extract and play songs from supported links, but does not support searching within that source (e.g., local files, direct audio links, or yt-dlp for various sites).
  3. Manage playback using the Queue object

    main

    To control playback (skip, pause, stop, etc.), you should first retrieve the Queue object for a specific guild using distube.getQueue(guildId).

    Important: Always use methods directly on the queue instance. Shortcut methods on the distube instance are deprecated and will be removed in v6.0.

    Available queue methods:

    • queue.stop(): Stops the player.
    • queue.skip(): Skips the current song.
    • queue.pause(): Pauses playback.
    • queue.resume(): Resumes playback.
    • queue.setVolume(number): Sets volume (0-100).
    • queue.shuffle(): Shuffles the queue.
    • queue.setRepeatMode(): Sets repeat mode (returns mode index).
    • queue.songs: An array of song objects in the queue.

    Example:

    const queue = distube.getQueue(message.guildId);
    if (!queue) return message.channel.send("Nothing is playing!");
    
    await queue.skip();
    // Get the queue for the guild
    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}`
      );
    }
  4. Check audio playback state correctly

    main

    The queue.playing property indicates if the queue is active (has started playing), not whether audio is currently outputting. It remains true even when paused.

    To check the actual playback state, use the following properties:

    • queue.paused: Returns true if the audio is currently paused.
    • queue.stopped: Returns true if the queue has been stopped.
    // ✅ Check if audio is currently playing
    if (!queue.paused) { ... }
    
    // ✅ Check if paused or stopped
    if (queue.paused) { ... }
    
    // ✅ Check if stopped
    if (queue.stopped) { ... }
  5. Migrate DisTubeOptions#searchSongs from v4 to v5

    main

    In version 5, the searchSongs option has changed from a boolean to a number. This number determines how many results the searchResults event will emit.

    • To search for a specific number of songs, provide that number (e.g., 10).
    • To disable searching or limit it to minimal results, use 0 or 1.
    // v4 style (deprecated/removed)
    new DisTube({ searchSongs: true });
    
    // v5 style
    new DisTube({ searchSongs: 10 });
    
    // To mimic searchSongs: false
    new DisTube({ searchSongs: 0 });
  6. Migrate DisTube#play and DisTube#playVoiceChannel from v3 to v4

    main
    When upgrading from version 3 to version 4, note that the DisTube#play and DisTube#playVoiceChannel methods have undergone changes. Refer to the updated DisTubeOptions and method signatures in the version 4 documentation to ensure compatibility.
  7. Pause and resume the queue based on voice channel occupancy

    main

    To improve user experience, you can automatically pause the music queue when a voice channel becomes empty and resume it when a user joins. Use isVoiceChannelEmpty inside the voiceStateUpdate event to check the channel status and call queue.pause() or queue.resume() accordingly.

    import { isVoiceChannelEmpty } from "distube";
    
    client.on("voiceStateUpdate", oldState => {
      if (!oldState?.channel) return;
      const queue = distube.getQueue(oldState);
      if (!queue) return;
      if (isVoiceChannelEmpty(oldState)) {
        queue.pause();
      } else if (queue.paused) {
        queue.resume();
      }
    });
  8. Get started with DisTube

    main

    DisTube is a music library designed for use with discord.js. To begin building a music bot, follow these steps:

    1. Installation: Check system requirements and install the package via your preferred package manager.
    2. DisTube Guide: Follow the beginner-friendly guide for initial setup and basic usage.
    3. API Reference: For detailed technical specifications of classes and methods, consult the official API Documentation.
    4. Plugins: Explore the [Projects Hub] to extend functionality using community-driven plugins.
    5. Upgrading: If you are moving from an older version, consult the [Major Upgrade Guide] to avoid breaking changes.
    6. Troubleshooting: Check the [Frequently Asked Questions] for common issues.
  9. Clean up voice resources

    main

    To prevent resource leaks, you should explicitly leave voice channels when the queue is finished or when the channel becomes empty.

    1. On Queue Finish: Listen to Events.FINISH and call queue.voice.leave().
    2. On Empty Channel: Use isVoiceChannelEmpty from distube combined with a voiceStateUpdate listener to detect when a channel is empty and leave.

    Example:

    // 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();
      }
    });
  10. Quick Start with DisTube

    main

    To get started with DisTube, install the core library along with the necessary voice dependencies. You must initialize a DisTube instance by passing your discord.js client and an options object.

    Note that when using DisTube, your Discord client must have the following GatewayIntentBits enabled:

    • Guilds
    • GuildVoiceStates
    • GuildMessages
    • MessageContent

    You can listen to events like playSong to interact with the queue and use distube.play() to start music playback in a voice channel.

    const { DisTube } = require('distube');
    const { Client, GatewayIntentBits } = require('discord.js');
    
    const client = new Client({
      intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildVoiceStates,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
      ],
    });
    
    const distube = new DisTube(client, {
      emitNewSongOnly: true,
    });
    
    distube.on('playSong', (queue, song) =>
      queue.textChannel.send(`Playing \`${song.name}\` - \`${song.formatDuration()}\``)
    );
    
    client.on('messageCreate', message => {
      if (message.content.startsWith('!play')) {
        distube.play(message.member.voice.channel, message.content.slice(6), {
          message,
          textChannel: message.channel,
          member: message.member,
        });
      }
    });
    
    client.login('TOKEN');
  11. Leave the voice channel after a period of inactivity

    main

    You can implement an inactivity timer to automatically leave a voice channel after a song finishes. This involves tracking timers in a Map keyed by the queue.id and responding to DisTube events:

    1. Events.FINISH: Start a setTimeout that calls queue.voice.leave() after your desired duration.
    2. Events.PLAY_SONG: Clear the existing timer for that queue to prevent premature leaving when new music starts.
    3. Events.DELETE_QUEUE: Clear the timer to clean up resources when the queue is destroyed.
    import { Events } from "distube";
    
    const inactivityTimers = new Map();
    
    // Start timer when queue finishes
    distube.on(Events.FINISH, queue => {
      const timer = setTimeout(() => {
        queue.voice.leave();
        inactivityTimers.delete(queue.id);
      }, 5 * 60 * 1000); // 5 minutes
    
      inactivityTimers.set(queue.id, timer);
    });
    
    // Clear timer when new song plays
    distube.on(Events.PLAY_SONG, queue => {
      const timer = inactivityTimers.get(queue.id);
      if (timer) {
        clearTimeout(timer);
        inactivityTimers.delete(queue.id);
      }
    });
    
    // Clear timer when queue is deleted
    distube.on(Events.DELETE_QUEUE, queue => {
      const timer = inactivityTimers.get(queue.id);
      if (timer) {
        clearTimeout(timer);
        inactivityTimers.delete(queue.id);
      }
    });