npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lithora

v1.0.0

Published

The most advanced Lavalink v4 wrapper with Discord.js cluster/shard compatibility

Readme

Lithora Advanced - The Ultimate Lavalink v4 Wrapper

NPM Version License Node.js Discord.js

Lithora Advanced is the most sophisticated and production-ready Lavalink v4 wrapper built in pure JavaScript, specifically designed to integrate seamlessly with Discord.js's native cluster and shard management systems.

🌟 Why Lithora Advanced?

⚡ Built for Scale

  • Discord.js Native Integration - Works perfectly with Discord.js cluster and shard managers
  • No Internal Conflicts - External cluster/shard management for maximum flexibility
  • Advanced Load Balancing - Intelligent node selection with penalty-based algorithms
  • Automatic Failover - Seamless player migration during node failures

🎵 Feature-Rich Audio Experience

  • Comprehensive Queue System - Shuffle, repeat modes, history, statistics
  • Advanced Audio Filters - 15+ built-in filters with custom filter creation
  • Real-time Player Management - Position tracking, volume control, seeking
  • Multi-Platform Search - YouTube, Spotify, SoundCloud, and more

🛡️ Production Ready

  • Robust Error Handling - Comprehensive error recovery and retry mechanisms
  • Performance Monitoring - Real-time statistics and health checks
  • Memory Efficient - Optimized for long-running applications
  • TypeScript Ready - Full type definitions included

📊 Cluster/Shard Management Comparison

| Feature | Built-in Management | Discord.js Native | Lithora Advanced Approach | |---------|-------------------|------------------|-------------------------| | Shard Routing | Internal implementation | Discord.js handles | External (Discord.js) | | Cluster Management | Built-in cluster manager | discord.js ClusterManager | Compatible with both | | Integration Complexity | Low (self-contained) | Moderate | Low (designed for it) | | Flexibility | Limited to wrapper design | High | Maximum flexibility | | Conflict Resolution | Potential conflicts | No conflicts | Zero conflicts | | Scaling Control | Wrapper-dependent | Full Discord.js control | Best of both worlds | | Memory Usage | Higher (duplicate logic) | Optimized | Optimized | | Update Compatibility | Wrapper-dependent | Always compatible | Always compatible |

✅ Why External Management is Superior

  1. No Conflicts - Lithora doesn't interfere with Discord.js's proven cluster/shard logic
  2. Better Performance - No duplicate shard management code
  3. Easier Scaling - Use Discord.js's battle-tested scaling solutions
  4. Simpler Debugging - One less layer of complexity
  5. Future Proof - Always compatible with Discord.js updates

🚀 Installation

npm install lithora ws node-fetch eventemitter3 discord.js

🎯 Quick Start

Basic Setup

const { Client, GatewayIntentBits } = require('discord.js');
const { Lithora, DiscordJSConnector } = require('lithora');

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

const lithora = new Lithora(new DiscordJSConnector(client), {
    nodes: [
        {
            name: 'main',
            host: 'localhost',
            port: 2333,
            password: 'youshallnotpass'
        }
    ],
    resume: true,
    autoResume: true,
    moveOnDisconnect: true
});

lithora.on('ready', (nodes) => {
    console.log(`🎵 Lithora ready! Connected to ${nodes.length} node(s)`);
});

client.once('ready', async () => {
    console.log(`🤖 Logged in as ${client.user.tag}`);
    await lithora.connect();
});

client.login(process.env.DISCORD_TOKEN);

Discord.js Cluster Integration

// cluster-manager.js
const { ClusterManager } = require('discord.js');
const path = require('path');

const manager = new ClusterManager(path.join(__dirname, 'bot.js'), {
    totalShards: 'auto',
    totalClusters: 'auto',
    mode: 'process',
    token: process.env.DISCORD_TOKEN
});

manager.on('clusterCreate', cluster => {
    console.log(`🚀 Cluster ${cluster.id} launched`);
});

manager.spawn();

// bot.js
const { Client } = require('discord.js');
const { Lithora, DiscordJSConnector } = require('lithora');

const client = new Client({ /* your intents */ });

// Multiple nodes for high availability
const lithora = new Lithora(new DiscordJSConnector(client), {
    nodes: [
        {
            name: 'node1',
            host: 'lavalink1.example.com',
            port: 2333,
            password: 'password1'
        },
        {
            name: 'node2', 
            host: 'lavalink2.example.com',
            port: 2333,
            password: 'password2'
        }
    ],
    moveOnDisconnect: true // Auto-migrate players on node failure
});

client.once('ready', async () => {
    await lithora.connect();
    console.log(`Cluster ${process.env.CLUSTER} ready with ${client.ws.totalShards} shards`);
});

client.login(process.env.DISCORD_TOKEN);

🎮 Player Management

Creating and Using Players

// Create a player
const player = await lithora.createPlayer({
    guildId: message.guild.id,
    channelId: voiceChannel.id,
    autoPlay: true,
    autoLeave: true,
    autoLeaveDelay: 30000
});

// Search and play
const result = await lithora.search('Never Gonna Give You Up', 'ytsearch');
if (result.loadType === 'search' && result.data.length > 0) {
    const track = result.data[0];
    player.queue.add(track);

    if (!player.playing) {
        await player.play();
    }
}

Advanced Queue Operations

// Queue management
player.queue.add([track1, track2, track3]); // Add multiple tracks
player.queue.shuffle(); // Shuffle queue
player.queue.setRepeatMode('QUEUE'); // Repeat entire queue
player.queue.move(0, 5); // Move track from position 0 to 5

// Queue information
console.log(`Queue: ${player.queue.size} tracks, ${player.queue.duration}ms total`);
console.log(`Current: ${player.queue.current?.info.title}`);
console.log(`Repeat: ${player.queue.repeatMode}, Shuffled: ${player.queue.shuffled}`);

// Queue events
player.queue.on('trackAdd', (tracks) => {
    console.log(`Added ${tracks.length} track(s) to queue`);
});

player.queue.on('trackChange', (track) => {
    console.log(`Now playing: ${track.info.title}`);
});

🎛️ Audio Filters

Built-in Filter Presets

const { Utilities } = require('lithora');

// Apply preset filters
await player.setFilters(Utilities.createBassBoost(0.5));
await player.setFilters(Utilities.createNightcore(1.2, 1.2));
await player.setFilters(Utilities.create8D(0.2));
await player.setFilters(Utilities.createKaraoke());

// Get all presets
const presets = Utilities.getFilterPresets();
await player.setFilters(presets.BASS_BOOST);

Custom Filter Creation

// Custom equalizer
const customEQ = Utilities.createEqualizer([
    0.25, 0.5, 0.75, 0.5, 0.25, // Low frequencies
    0, 0, 0, 0, 0,               // Mid frequencies  
    -0.25, -0.5, -0.25, 0, 0    // High frequencies
]);

// Combine multiple filters
const combined = Utilities.combineFilters(
    Utilities.createBassBoost(0.3),
    Utilities.createTremolo(2.0, 0.5),
    Utilities.createLowPass(15.0)
);

await player.setFilters(combined);

Available Filters

  • Equalizer - 15-band frequency adjustment
  • Bass Boost - Enhanced low frequencies
  • Nightcore - Speed and pitch increase
  • Vaporwave - Speed and pitch decrease
  • 8D Audio - Rotation effect
  • Karaoke - Vocal isolation/removal
  • Tremolo - Volume oscillation
  • Vibrato - Pitch oscillation
  • Distortion - Audio distortion effects
  • Low Pass - High frequency filtering

📊 Monitoring & Statistics

Node Statistics

// Get node statistics
const nodeStats = lithora.nodes.getStats();
console.log(`Nodes: ${nodeStats.connected}/${nodeStats.total} connected`);
console.log(`Average ping: ${nodeStats.averagePing}ms`);

// Monitor node health
lithora.on('nodeStats', (node, stats) => {
    console.log(`Node ${node.options.name}: ${stats.players} players, ${stats.cpu.systemLoad}% CPU`);
});

Player Statistics

// Get player statistics
const playerStats = lithora.players.getStats();
console.log(`Players: ${playerStats.total} total, ${playerStats.playing} playing`);

// Queue statistics
const queueStats = player.queue.getStats();
console.log(`Queue: ${queueStats.size} tracks, ${queueStats.duration}ms duration`);

🔧 Advanced Configuration

Node Configuration

const lithora = new Lithora(connector, {
    nodes: [
        {
            name: 'primary',
            host: 'lavalink.example.com',
            port: 2333,
            password: 'secure_password',
            secure: true, // Use WSS/HTTPS
            resume: true,
            resumeTimeout: 60,
            reconnectTries: 3,
            reconnectInterval: 5000,
            timeout: 30000
        }
    ],
    moveOnDisconnect: true,
    autoResume: true,
    defaultSearchPlatform: 'ytsearch'
});

Player Options

const player = await lithora.createPlayer({
    guildId: '123456789',
    channelId: '987654321',
    deaf: true,
    mute: false,
    autoPlay: true,        // Auto-play next track
    autoLeave: true,       // Auto-leave when queue is empty
    autoLeaveDelay: 30000  // Delay before leaving (ms)
});

🔍 Event Handling

Core Events

// Lithora events
lithora.on('ready', (nodes) => {});
lithora.on('nodeConnect', (node) => {});
lithora.on('nodeDisconnect', (node) => {});
lithora.on('playerCreate', (player) => {});
lithora.on('error', (error) => {});

// Player events
player.on('trackStart', (player, track) => {});
player.on('trackEnd', (player, track, reason) => {});
player.on('trackException', (player, track, exception) => {});
player.on('playerUpdate', (player, state) => {});

// Queue events
player.queue.on('trackAdd', (tracks) => {});
player.queue.on('trackChange', (track) => {});
player.queue.on('queueShuffle', (enabled) => {});

🌐 Multi-Platform Search

Supported Platforms

const { SearchSources } = require('lithora');

// Search different platforms
await lithora.search('song name', SearchSources.YOUTUBE);
await lithora.search('artist name', SearchSources.YOUTUBE_MUSIC);
await lithora.search('playlist', SearchSources.SOUNDCLOUD);
await lithora.search('album', SearchSources.SPOTIFY);

// Direct URLs (auto-detected)
await lithora.search('https://youtube.com/watch?v=...');
await lithora.search('https://soundcloud.com/...');

📈 Performance Optimization

Load Balancing

// Automatic load balancing
const idealNode = lithora.nodes.getLeastUsed();
console.log(`Best node: ${idealNode.options.name} (${idealNode.penalties} penalties)`);

// Manual load rebalancing
const results = await lithora.nodes.rebalanceLoad();
console.log(`Rebalanced ${results.length} players`);

Memory Management

// Cleanup disconnected players
const cleaned = lithora.players.cleanup();
console.log(`Cleaned up ${cleaned} disconnected players`);

// Get memory usage
const { Utilities } = require('lithora');
const memory = Utilities.getMemoryUsage();
console.log(`Memory usage: ${memory.heapUsed} / ${memory.heapTotal}`);

🚀 Production Deployment

Docker Compose Example

version: '3.8'
services:
  lavalink:
    image: ghcr.io/lavalink-devs/lavalink:4-alpine
    ports:
      - "2333:2333"
    volumes:
      - ./application.yml:/opt/Lavalink/application.yml
    restart: unless-stopped

  bot:
    build: .
    environment:
      - DISCORD_TOKEN=${DISCORD_TOKEN}
      - LAVALINK_HOST=lavalink
      - LAVALINK_PASSWORD=${LAVALINK_PASSWORD}
    depends_on:
      - lavalink
    restart: unless-stopped

PM2 Cluster Configuration

// ecosystem.config.js
module.exports = {
    apps: [{
        name: 'music-bot',
        script: 'cluster-manager.js',
        instances: 1,
        autorestart: true,
        watch: false,
        max_memory_restart: '1G',
        env: {
            NODE_ENV: 'production'
        }
    }]
};

🔧 Troubleshooting

Common Issues

Connection Timeouts

// Increase timeout values
const lithora = new Lithora(connector, {
    nodes: [{ 
        // ... other options
        timeout: 60000,
        reconnectInterval: 10000
    }]
});

Memory Leaks

// Proper cleanup
process.on('SIGINT', async () => {
    await lithora.destroy();
    process.exit(0);
});

Node Failures

// Enable automatic failover
const lithora = new Lithora(connector, {
    moveOnDisconnect: true,
    autoResume: true
});

📚 API Reference

Classes

  • Lithora - Main wrapper class
  • LithoraNode - Individual Lavalink node
  • LithoraPlayer - Audio player instance
  • LithoraQueue - Advanced queue system
  • NodeManager - Node management and load balancing
  • PlayerManager - Player lifecycle management
  • DiscordJSConnector - Discord.js integration

Utilities

  • LithoraUtil - Utility functions and filter creation
  • LithoraError - Enhanced error handling
  • Constants - All constants and enums

🤝 Contributing

We welcome contributions! Please read our Contributing Guide for details.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🔗 Links

⭐ Acknowledgments

  • Lavalink - The amazing audio server
  • Discord.js - The Discord library we integrate with
  • All contributors and users who make this project possible

Made with ❤️ for the Discord bot community