Code Monkey home page Code Monkey logo

riffy's Introduction

About

Riffy is a lavalink client for node.js. It is designed to be simple and easy to use, with a focus on stablity and more features.

Installation

npm install riffy

Features

  • Supports v3 and v4 of the lavalink protocols.
  • Autoplay support for youtube, soundcloud & spotify.
  • Works with all discord libraries (discord.js, eris, etc..)
  • All working filters (bassboost, nightcore, etc..)

Example Project

Documentation

1. Lavalink Node

First thing first, you need to have a lavalink node running. You can download the latest version of lavalink from here, or you can use this for free.

2. Creating a Project

We are using discord.js for this example, but you can use any discord library you want.

Import the Riffy from the package.

const { Riffy } = require("riffy");

Below is the example for basic discord music bot, using discord.js (used lavalink v4)

// [index.js]

const { Client, GatewayDispatchEvents } = require("discord.js");
const { Riffy } = require("riffy");

const client = new Client({
    intents: [
        "Guilds",
        "GuildMessages",
        "GuildVoiceStates",
        "GuildMessageReactions",
        "MessageContent",
        "DirectMessages"
    ]
});

const nodes = [
    {
        host: "localhost",
        password: "youshallnotpass",
        port: 2333,
        secure: false
    },
];

client.riffy = new Riffy(client, nodes, {
    send: (payload) => {
        const guild = client.guilds.cache.get(payload.d.guild_id);
        if (guild) guild.shard.send(payload);
    },
    defaultSearchPlatform: "ytmsearch",
    restVersion: "v4" // or v3 based on your lavalink version
});

client.on("ready", () => {
    client.riffy.init(client.user.id);
    console.log(`Logged in as ${client.user.tag}`);
});

client.on("messageCreate", async (message) => {
    if (!message.content.startsWith('!') || message.author.bot) return;

    const args = message.content.slice(1).trim().split(" ");
    const command = args.shift().toLowerCase();

    if (command === "play") {
        const query = args.join(" ");

		// Create a player.
        const player = client.riffy.createConnection({
            guildId: message.guild.id,
            voiceChannel: message.member.voice.channel.id,
            textChannel: message.channel.id,
            deaf: true
        });

        const resolve = await client.riffy.resolve({ query: query, requester: message.author });
        const { loadType, tracks, playlistInfo } = resolve;

		/**
		 * Important: If you are using Lavalink V3, here are the changes you need to make:
		 * 
		 * 1. Replace "playlist" with "PLAYLIST_LOADED"
		 * 2. Replace "search" with "SEARCH_RESULT"
		 * 3. Replace "track" with "TRACK_LOADED" 
		 */

        if (loadType === 'playlist') {
            for (const track of resolve.tracks) {
                track.info.requester = message.author;
                player.queue.add(track);
            }

            message.channel.send(`Added: \`${tracks.length} tracks\` from \`${playlistInfo.name}\``,);
            if (!player.playing && !player.paused) return player.play();

        } else if (loadType === 'search' || loadType === 'track') {
            const track = tracks.shift();
            track.info.requester = message.author;

            player.queue.add(track);
            message.channel.send(`Added: \`${track.info.title}\``);
            if (!player.playing && !player.paused) return player.play();
        } else {
            return message.channel.send('There are no results found.');
        }
    }
})

// This will send log when the lavalink node is connected.
client.riffy.on("nodeConnect", node => {
    console.log(`Node "${node.name}" connected.`)
})

// This will send log when the lavalink node faced an error.
client.riffy.on("nodeError", (node, error) => {
    console.log(`Node "${node.name}" encountered an error: ${error.message}.`)
})

// This is the event handler for track start.
client.riffy.on("trackStart", async (player, track) => {
    const channel = client.channels.cache.get(player.textChannel);

    channel.send(`Now playing: \`${track.info.title}\` by \`${track.info.author}\`.`);
});

// This is the event handler for queue end.
client.riffy.on("queueEnd", async (player) => {
    const channel = client.channels.cache.get(player.textChannel);
    
	// Set this to true if you want to enable autoplay.
	const autoplay = false;

    if (autoplay) {
        player.autoplay(player)
    } else {
        player.destroy();
        channel.send("Queue has ended.");
    }
})

// This will update the voice state of the player.
client.on("raw", (d) => {
    if (![GatewayDispatchEvents.VoiceStateUpdate, GatewayDispatchEvents.VoiceServerUpdate,].includes(d.t)) return;
    client.riffy.updateVoiceState(d);
});

client.login("Discord-Bot-Token-Here");

3. Running our Discord bot

Now that we have created our project, we can run our bot by typing node index.js in the terminal.

When the bot is running, you can use the !play song_name command to play music.

Conclusion

That's it! You have successfully created a discord music bot using riffy. If you have any questions, feel free to join our discord server.

We have set this example by keeping in mind that you know the basics of discord.js or any other discord library you are using.

Our Team

๐ŸŸช Elitex

๐ŸŸฅ FlameFace

๐ŸŸฆ UnschooledGamer

License

This project is licensed under the MIT License

riffy's People

Contributors

dependabot[bot] avatar elitex07 avatar flameface avatar gabcaua avatar unschooledgamer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

riffy's Issues

Node Voice Region Choosing Different Node then Choosed Node

๐Ÿšฅ Status

Open - If you have any better ideas for this do tell me here or mention and tell me on discord, do tell me if you're interested in resolving it

Issue description

Explanation: After creating a player with createConnection along with the region option/parameter set, Creates an Player on the Node matching that "region", If you try searching with resolve method it will search on other Node and plays on the other Node(previously selected Region Node) That's The main Issue here. It's caused By leastUsedNodes sorting method in Riffy.

My Solution: To add a node parameter riffy resolve method that way the user can parse the player's node while searching.
Another Solution is to modify the leastUsedNodes But it's not that much reliable compared to 1st solution.
Better Solution I have is to have resolve method in the Player Class itself & Have node parameter in Riffy resolve method too.

Steps to Reproduce:

  1. Create a Player with createConnection
  2. Provide the region parameter
  3. Search something with riffy Resolve method
  4. You'll see in the logs it searches on one Node and plays on other Node(It's supposed to search this Node only, As that's the Node filtered by Region and created on it)
  5. Make sure to have regions defined in the NodeOptions.

Code sample

No response

Versions

  • riffy riffy-team/riffy#fix/user-bugs-feats

Issue priority

Medium (should be fixed soon)

[v3] Tracks not playing in v3 Lavalink. Issue caused by a commit.

Issue description

A commit cause the v3 Lavalink to not playing the tracks(not sending play requests to Lavalink).

That happened while making the updatePlayer method to convert data inputted(taking a single data and convert those) to v3 or v4 depending on the version of Lavalink.

And Yeah Ofc by me while doing this changes.

Code sample

No response

Versions

  • riffy v1.0.5

Issue priority

High (immediate attention needed)

Type definition file uses Wrappers instead of Primitive types for strings, booleans, numbers etc

Issue description

Try to use this library with typescript, in the code example below, the arguement passed into the "get" method will be flagged as its defined as a type String instead of string.

Code sample

this.lavalink = new Riffy(this, lavaNode, {
            send: (payload) => {
                const guild = this.guilds.cache.get(payload.d.guild_id);
                if (guild) guild.shard.send(payload);
            },

        })

Versions

[email protected]

Issue priority

Medium (should be fixed soon)

Not playing audio. [Fixed]

Issue description

My lavalink is working fine, my code is fine but the bot is not playing audio dont know why..
Screenshot 2024-02-21 224646

Code sample

const { Client, EmbedBuilder, PermissionFlagsBits } = require("discord.js");

module.exports = {
  name: "play",
  category: "Music",
  aliases: ["p"],
  clientPermissions: [PermissionFlagsBits.Connect, PermissionFlagsBits.Speak],
  description: "Play songs",
  inVoice: true,

  execute: async (message, args, client) => {
    /**
     *
     * @param {Client} client
     * @param {CommandInteraction} interaction
     * @param {String} args
     * @returns
     */

    const query = args.join(' ');
    
    //This will not load the third-party link
    if (query.includes(`bit.ly`)) {
      return message.channel.send({
        embeds: [
          new EmbedBuilder()
            .setColor(client.embedColor)
            .setDescription(`**We Don't Support This Link**`),
        ],
      });
    }

    let player = client.riffy.players.get(message.guildId);

    if (!player)
      player = await client.riffy.createConnection({
        guildId: message.guild.id,
        voiceChannel: message.member.voice.channel.id,
        textChannel: message.channel.id,
        deaf: true,
      });

    const resolve = await client.riffy.resolve({
      query: query,
      requester: message.author,
    });
    const { loadType, tracks, playlistInfo } = resolve;

    if (loadType === "PLAYLIST_LOADED") {
      for (const track of resolve.tracks) {
        track.info.requester = message.author;
        player.queue.add(track);
      }

      await message.reply(
        `Added ${tracks.length} songs from ${playlistInfo.name} playlist.`
      );

      if (!player.playing && !player.paused) return player.play();
    } else if (loadType === "SEARCH_RESULT" || loadType === "TRACK_LOADED") {
      const track = tracks.shift();
      track.info.requester = message.author;

      player.queue.add(track);

      await message.reply(`Added **${track.info.title}** to the queue.`);

      if (!player.playing && !player.paused) return player.play();
    } else {
      return message.reply(`There were no results found for your query.`);
    }
  },
};

Versions

"discord.js": "14.11",
"fs": "^0.0.1-security",
"musicard": "^2.0.3",
"riffy": "^1.0.3",
"riffy-spotify": "^1.0.2"

Issue priority

High (immediate attention needed)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.