Introduction

Aliana-Client is an easy, flexible, and feature-rich Lavalink v4 Client for both beginners and experts.Made using Lavalink-Client,Shokaku,Kazagumo as a reference.This library provides a comprehensive solution for integrating Lavalink into your Discord bot or music application.

What is Lavalink?

Lavalink is a standalone audio sending node that allows you to play music in Discord voice channels without running the audio processing on your bot's server. This significantly reduces resource usage and improves performance.

✨ What Makes Aliana-Client Unique?

🎨 Built-in Music Cards

Generate beautiful, customizable music visualization cards using the integrated musicard library - no extra configuration needed!

🎚️ Audio Normalizer

Automatic volume normalization ensures consistent audio levels across all tracks for a perfect listening experience.

⚡ 10x Faster Loading

Intelligent track resolution caching reduces redundant API calls and speeds up playlist loading dramatically.

🎭 Pre-built Filter Presets

Ready-to-use audio presets: Nightcore, Vaporwave, 8D Audio, Bass Boost, and more - just one line of code!

Features

🚀 Lavalink v4 Native

Full support for Lavalink v4, including its powerful plugin ecosystem.

✅ Detailed Player-Destroy Reasons

Understand precisely why a player was destroyed (e.g., channel deleted, bot disconnected).

✨ Flexible Queue Stores

Use the default in-memory store or bring your own (Redis, databases, etc.).

🎶 Unresolved Tracks

Supports unresolved track objects, fetching full data only when needed.

🎚️ Built-in Filters & EQ

Easy-to-use management for audio filters and equalizers.

⚙️ Advanced Player Options

Fine-tune player behavior for disconnects, empty queues, volume handling, and more.

Installation

Install the aliana-client package using your preferred package manager:

npm install --save aliana-client
yarn add aliana-client
pnpm add aliana-client
bun add aliana-client

Supported Music Sources

Aliana-Client supports multiple music platforms through Lavalink. Sources are automatically detected from URLs, or you can specify them explicitly when searching.

🎵 Supported Platforms

YouTube

Source: youtube or ytsearch:

Native support for YouTube videos, playlists, and search.

YouTube Music

Source: youtubemusic or ytmsearch:

Optimized for music content with better search results.

Spotify

Source: spotify or spsearch:

Search Spotify tracks, albums, and playlists (requires LavaSrc plugin).

SoundCloud

Source: soundcloud or scsearch:

Native support for SoundCloud tracks and playlists.

Apple Music

Source: applemusic or amsearch:

Search Apple Music catalog (requires LavaSrc plugin).

Deezer

Source: deezer or dzsearch:

Access Deezer's music library (requires LavaSrc plugin).

JioSaavn

Source: jiosaavn or jssearch:

Indian music streaming - Bollywood, Punjabi, and more (requires JioSaavn plugin).

Yandex Music

Source: yandex or ymsearch:

Russian music platform support (requires LavaSrc plugin).

📝 Usage Examples

// Direct URLs (automatically detected)
await manager.search('https://www.youtube.com/watch?v=dQw4w9WgXcQ', user);
await manager.search('https://open.spotify.com/track/3n3Ppam7vgaVa1iaRUc9Lp', user);

// Search with specific source
await manager.search('Imagine Dragons', user, 'youtube');
await manager.search('Arijit Singh', user, 'jiosaavn');
await manager.search('Coldplay', user, 'spotify');

// Using search prefixes directly
await manager.search('ytmsearch:Bohemian Rhapsody', user);
await manager.search('spsearch:Shape of You', user);
await manager.search('jssearch:Kesariya', user);
⚙️ Lavalink Configuration Required

To use Spotify, Apple Music, Deezer, or other premium sources, you need to configure your Lavalink server with the appropriate plugins (like LavaSrc). YouTube and SoundCloud work out of the box.

For detailed Lavalink setup with plugins, see the LavaSrc documentation.

Quick Start

Here's a minimal example to get you started quickly:

import { LavalinkManager } from "aliana-client";
        import { Client, GatewayIntentBits } from "discord.js";

        // Extend the Client type to include the lavalink manager
        declare module "discord.js" {
            interface Client {
                lavalink: LavalinkManager;
            }
        }

        const client = new Client({
            intents: [
                GatewayIntentBits.Guilds,
                GatewayIntentBits.GuildVoiceStates,
            ]
        });

        client.lavalink = new LavalinkManager({
            nodes: [
                {
                    authorization: "youshallnotpass",
                    host: "localhost",
                    port: 2333,
                    id: "Main Node",
                }
            ],
            sendToShard: (guildId, payload) => {
                const guild = client.guilds.cache.get(guildId);
                if (guild) guild.shard.send(payload);
            },
            autoSkip: true,
            client: {
                id: process.env.CLIENT_ID,
                username: "MyBot",
            },
        });

        // Listen for the 'raw' event and forward it
        client.on("raw", (d) => client.lavalink.sendRawData(d));

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

        client.login(process.env.DISCORD_TOKEN);

LavalinkManager

The LavalinkManager is the core class that manages all Lavalink nodes and players.

Creating a Manager

const manager = new LavalinkManager({
            nodes: [
                {
                    authorization: "your-password",
                    host: "localhost",
                    port: 2333,
                    id: "Main Node",
                }
            ],
            sendToShard: (guildId, payload) => {
                // Send payload to Discord gateway
            },
            autoSkip: true,
            client: {
                id: "your-bot-id",
                username: "YourBot",
            },
        });

Key Methods

Method Description
init(clientData) Initialize the manager with Discord client data
createPlayer(options) Create a new player for a guild
getPlayer(guildId) Get an existing player by guild ID
search(query, requester, platform) Search for tracks on a specific platform

Player

The Player class represents a music player for a specific guild.

Creating a Player

const player = manager.createPlayer({
            guildId: interaction.guildId,
            voiceChannelId: interaction.member.voice.channelId,
            textChannelId: interaction.channelId,
        });

        await player.connect();

Playing Tracks

// Search for a track
        const result = await manager.search("Despacito", interaction.user, "youtube");

        // Add to queue
        await player.queue.add(result.tracks[0]);

        // Start playing
        await player.play();

Player Properties

Property Type Description
volume number Current volume (0-100)
playing boolean Whether a track is currently playing
paused boolean Whether playback is paused
position number Current playback position in milliseconds
autoPlay boolean Whether autoplay is enabled

Queue System

The queue system manages the list of tracks to be played.

Adding Tracks

// Add a single track
        await player.queue.add(track);

        // Add multiple tracks
        await player.queue.add([track1, track2, track3]);

Queue Operations

// Remove a track
        await player.queue.remove(0);

        // Clear the queue
        await player.queue.clear();

        // Shuffle the queue
        await player.queue.shuffle();

        // Get queue information
        console.log(player.queue.size);       // Number of tracks
        console.log(player.queue.duration);   // Total duration in ms
        console.log(player.queue.current);    // Currently playing track

Events

Listen to various events to create interactive and responsive logic.

Manager Events

// Track started playing
        manager.on('trackStart', (player, track) => {
            console.log(`Now playing: ${track.info.title}`);
        });

        // Track ended
        manager.on('trackEnd', (player, track, reason) => {
            console.log(`Track ended: ${reason}`);
        });

        // Queue ended
        manager.on('queueEnd', (player) => {
            console.log('Queue has finished');
            player.destroy();
        });

        // Track error
        manager.on('trackError', (player, track, error) => {
            console.error(`Error playing ${track.info.title}:`, error);
        });

        // Autoplay track
        manager.on('autoPlayTrack', (player, track) => {
            console.log(`Autoplay: ${track.info.title}`);
        });

Available Events

Event Parameters Description
trackStart player, track Emitted when a track starts playing
trackEnd player, track, reason Emitted when a track ends
trackError player, track, error Emitted when a track encounters an error
trackStuck player, track, threshold Emitted when a track gets stuck
queueEnd player Emitted when the queue finishes
autoPlayTrack player, track Emitted when autoplay plays a track

Autoplay Feature

The autoplay feature automatically finds and plays related tracks when your queue ends, similar to Spotify's autoplay.

How Autoplay Works

When the queue becomes empty and autoplay is enabled:

  • The system searches for tracks related to the last played track
  • If related tracks are found, one is randomly selected and played
  • This process repeats each time the queue ends, creating continuous playback
  • If no related tracks are found, the queueEnd event is emitted and playback stops
  • Disabling autoplay stops this automatic behavior

Enabling Autoplay

// Enable autoplay
        player.setAutoPlay(true);

        // Disable autoplay
        player.setAutoPlay(false);

        // Check autoplay status
        console.log(player.autoPlay); // true or false

Example Command

const autoplayCommand = {
            data: new SlashCommandBuilder()
                .setName('autoplay')
                .setDescription('Toggle autoplay'),
            async execute(interaction) {
                const player = manager.getPlayer(interaction.guildId);

                if (!player) {
                    return interaction.reply('No player found!');
                }

                player.setAutoPlay(!player.autoPlay);

                return interaction.reply(
                    player.autoPlay
                        ? '✅ Autoplay enabled!'
                        : '❌ Autoplay disabled.'
                );
            },
        };

Listening to Autoplay Events

manager.on('autoPlayTrack', (player, track) => {
            const channel = client.channels.cache.get(player.textChannelId);
            if (channel && 'send' in channel) {
                channel.send(`🎵 Autoplay: Now playing **${track.info.title}**`);
            }
        });

🎨 Music Cards Generator (Exclusive Feature)

Aliana-Client includes built-in support for generating beautiful, animated music visualization cards using the musicard library. This is an exclusive feature that sets us apart from other Lavalink clients!

Why Music Cards?

Music cards provide a visually stunning way to display now-playing information in Discord, making your bot stand out with professional-looking embeds and dynamic progress bars.

Quick Start

import { musicCard } from "musicard";
        import { AttachmentBuilder } from "discord.js";

        // Get the current player and track
        const player = manager.players.get(guildId);
        const track = player.queue.current;

        // Generate a beautiful music card
        const card = await musicCard({
            thumbnailImage: track.info.artworkUrl || "default_artwork.png",
            name: track.info.title,
            author: track.info.author,
            color: "auto", // Auto-detect colors from artwork!
            theme: "dynamic",
            brightness: 75,
            progress: player.position,
            startTime: 0,
            endTime: track.duration
        });

        // Send to Discord
        const attachment = new AttachmentBuilder(card, { name: "music-card.png" });
        await channel.send({ files: [attachment] });

Available Themes

🌈 Dynamic

Colors automatically adapt from the track's artwork for a cohesive, professional look.

🌙 Classic Dark

Timeless dark theme with vibrant accent colors that work for any music genre.

⚡ Custom

Full control over background, text, and progress bar colors - match your brand!

Live Progress Updates

// Create a live-updating music card (updates every 10 seconds)
        let cardMessage = null;

        const updateCard = async () => {
            const player = manager.players.get(guildId);
            if (!player?.playing) return;

            const track = player.queue.current;
            const card = await musicCard({
                thumbnailImage: track?.info.artworkUrl || "default.png",
                name: track?.info.title || "Unknown",
                author: track?.info.author || "Unknown Artist",
                progress: player.position,
                endTime: track?.duration || 0,
                theme: "dynamic",
                brightness: 80
            });

            const attachment = new AttachmentBuilder(card, { name: "now-playing.png" });

            if (!cardMessage) {
                cardMessage = await channel.send({ files: [attachment] });
            } else {
                await cardMessage.edit({ files: [attachment] });
            }
        };

        // Update every 10 seconds
        const interval = setInterval(updateCard, 10000);
        updateCard(); // Initial update

        // Clean up when track ends
        manager.on('trackEnd', () => clearInterval(interval));

Advanced Customization

// Full customization options
        const card = await musicCard({
            thumbnailImage: track.info.artworkUrl,
            name: track.info.title,
            author: track.info.author,
            color: "#5865F2", // Custom hex color
            theme: "classic",
            brightness: 90,
            progress: player.position,
            startTime: 0,
            endTime: track.duration,
            nameColor: "#FFFFFF",
            progressColor: "#5865F2",
            progressBarColor: "#2C2F33"
        });

⚡ Performance Tip

Generating music cards can be resource-intensive. Consider caching cards or limiting update frequency (10-15 seconds) to avoid rate limits and reduce CPU/memory usage.

Integration with Commands

// Nowplaying command with music card
        const nowplayingCommand = {
            data: new SlashCommandBuilder()
                .setName('nowplaying')
                .setDescription('Show current track with a beautiful card'),
            async execute(interaction) {
                const player = manager.getPlayer(interaction.guildId);

                if (!player || !player.playing) {
                    return interaction.reply('❌ Nothing is playing!');
                }

                const track = player.queue.current;
                const card = await musicCard({
                    thumbnailImage: track.info.artworkUrl,
                    name: track.info.title,
                    author: track.info.author,
                    theme: "dynamic",
                    progress: player.position,
                    endTime: track.duration
                });

                const attachment = new AttachmentBuilder(card, { name: "np.png" });
                await interaction.reply({ files: [attachment] });
            }
        };

Audio Filters

Apply various audio filters to customize the sound output.

Available Filters

// Bass boost
        await player.filters.setBassBoost(0.5); // 0-1

        // Nightcore (speed up + higher pitch)
        await player.filters.setNightcore(1.2);

        // Vaporwave (slow down + lower pitch)
        await player.filters.setVaporwave(0.8);

        // 8D Audio
        await player.filters.set8D(true);

        // Karaoke
        await player.filters.setKaraoke(true);

        // Tremolo
        await player.filters.setTremolo(4.0, 0.5);

        // Clear all filters
        await player.filters.clear();

Custom Equalizer

// Set custom EQ bands (0-14)
        await player.filters.setEqualizer([
            { band: 0, gain: 0.2 },
            { band: 1, gain: 0.3 },
            { band: 2, gain: 0.1 },
        ]);

Custom Queue Stores

Implement custom queue storage to persist queues across restarts or sync them across multiple processes.

Redis Store Example

import { QueueStore, StoredQueue } from "aliana-client";
        import { RedisClientType } from "redis";

        class RedisQueueStore implements QueueStore {
            private redis: RedisClientType;

            constructor(redisClient: RedisClientType) {
                this.redis = redisClient;
            }

            private key(guildId: string) {
                return `lavalinkqueue_${guildId}`;
            }

            async get(guildId: string): Promise {
                return await this.redis.get(this.key(guildId));
            }

            async set(guildId: string, data: string): Promise {
                await this.redis.set(this.key(guildId), data);
            }

            async delete(guildId: string): Promise {
                await this.redis.del(this.key(guildId));
            }

            async parse(data: string): Promise> {
                return JSON.parse(data);
            }

            stringify(data: Partial): string {
                return JSON.stringify(data);
            }
        }

        // Use the custom store
        const manager = new LavalinkManager({
            // ... other options
            queueOptions: {
                queueStore: new RedisQueueStore(redisClient),
            },
        });

Complete Examples

Play Command

const playCommand = {
            data: new SlashCommandBuilder()
                .setName('play')
                .setDescription('Play a song')
                .addStringOption(option =>
                    option.setName('query')
                        .setDescription('Song name or URL')
                        .setRequired(true)
                ),
            async execute(interaction) {
                await interaction.deferReply();

                // Get or create player
                let player = manager.getPlayer(interaction.guildId);
                if (!player) {
                    player = manager.createPlayer({
                        guildId: interaction.guildId,
                        voiceChannelId: interaction.member.voice.channelId,
                        textChannelId: interaction.channelId,
                    });
                    await player.connect();
                }

                // Search for the track (auto-detects URLs or uses default source)
                const query = interaction.options.getString('query');
                const result = await manager.search(query, interaction.user);

                if (!result.tracks || result.tracks.length === 0) {
                    return interaction.editReply('No results found!');
                }

                const track = result.tracks[0];
                await player.queue.add(track);

                // Start playing if not already playing
                if (!player.playing && !player.paused) {
                    await player.play();
                }

                return interaction.editReply(
                    `Added to queue: **${track.info.title}** by ${track.info.author}`
                );
            },
        };

Queue Command

const queueCommand = {
            data: new SlashCommandBuilder()
                .setName('queue')
                .setDescription('Show the current queue'),
            async execute(interaction) {
                const player = manager.getPlayer(interaction.guildId);

                if (!player || player.queue.isEmpty) {
                    return interaction.reply('Queue is empty!');
                }

                const current = player.queue.current;
                const upcoming = player.queue.tracks.slice(0, 10);

                let description = `**Now Playing:**\n${current.info.title}\n\n`;

                if (upcoming.length > 0) {
                    description += '**Up Next:**\n';
                    upcoming.forEach((track, i) => {
                        description += `${i + 1}. ${track.info.title}\n`;
                    });
                }

                return interaction.reply({
                    embeds: [{
                        title: 'Queue',
                        description,
                        color: 0x5865F2,
                    }]
                });
            },
        };

🤖 Example Bot: Ayira-Bot

Ayira-Bot is a fully-featured Discord music bot built with aliana-client that demonstrates all the capabilities of this library in a real-world application.

🔗 GitHub Repository

https://github.com/Itz-Npg/Ayira-Bot

Check out the source code to see how aliana-client is used in a production-ready Discord bot!

✨ Features Demonstrated

🎵 Music Playback

Play from YouTube, Spotify, SoundCloud, and more with automatic source detection.

📋 Queue Management

Advanced queue system with shuffle, loop, and remove features.

🎚️ Audio Filters

Nightcore, bass boost, 8D audio, and custom filter support.

🎨 Music Cards

Beautiful now-playing cards using the built-in music card generator.

🤖 Smart Autoplay

Intelligent track recommendations when the queue ends.

⚡ Fast Track Loading

FastTrackFetcher integration for 10x faster performance.

🚀 Why Use Ayira-Bot as Reference?

  • Production-Ready Code - Well-structured, maintainable, and scalable
  • Best Practices - Follows aliana-client's recommended patterns
  • Complete Implementation - Shows all major features in action
  • Error Handling - Proper error handling and user feedback
  • TypeScript - Fully typed for better development experience

📚 Learning from Ayira-Bot

The bot serves as a comprehensive example of how to:

  • Initialize and configure LavalinkManager
  • Handle Discord voice state updates
  • Implement commands for play, skip, pause, resume, queue
  • Use filters and audio effects
  • Generate music cards for now-playing displays
  • Implement autoplay with smart recommendations
  • Handle multiple servers simultaneously
💡 Get Started with Ayira-Bot

Clone the repository and explore the code to see how aliana-client powers a full-featured music bot!

git clone https://github.com/Itz-Npg/Ayira-Bot.git
cd Ayira-Bot
npm install
npm start