### Initialize Shoukaku with Seyfert Connector Source: https://github.com/shipgirlproject/shoukaku/blob/master/src/connectors/README.md Provides an example of initializing Shoukaku with the Seyfert connector. This setup involves a Seyfert client instance, server configurations, and any necessary Shoukaku options. ```javascript const { Shoukaku, Connectors } = require('shoukaku'); new Shoukaku(new Connectors.Seyfert(client), servers, options) ``` -------------------------------- ### Install Shoukaku via NPM Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/getting-started.md Install the Shoukaku library directly from the GitHub repository using npm. ```console npm i shipgirlproject/Shoukaku#master ``` -------------------------------- ### Join Voice Channel, Play Track, and Disconnect Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md This example demonstrates the basic workflow of joining a voice channel, searching for a track, playing it, and then disconnecting after a set delay. ```APIDOC ## Join Voice Channel, Play Track, and Disconnect ### Description This example demonstrates the basic workflow of joining a voice channel, searching for a track, playing it, and then disconnecting after a set delay. ### Steps 1. **Join Voice Channel** Tell Shoukaku to join a Discord voice channel. ```ts const player = await shoukaku.joinVoiceChannel({ guildId: "your_guild_id", channelId: "your_channel_id", shardId: 0, }); ``` 2. **Determine Node** Select an appropriate Lavalink node to use for operations. ```ts const node = shoukaku.options.nodeResolver(shoukaku.nodes); ``` 3. **Search for Track** Search for a track using a provider prefix (e.g., `scsearch:` for SoundCloud). ```ts const result = await node.rest.resolve("scsearch:snowhalation"); if (!result?.tracks.length) return; const metadata = result.tracks.shift(); ``` 4. **Play Track** Instruct Lavalink to play the searched track. ```ts await player.playTrack({ track: { encoded: metadata.encoded } }); ``` 5. **Disconnect** After 30 seconds, disconnect from the voice channel. ```ts setTimeout(() => shoukaku.leaveVoiceChannel(player.guildId), 30000).unref(); ``` ``` -------------------------------- ### Join Voice Channel and Get Player Instance Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Joins a specified Discord voice channel using the Shoukaku instance and returns a Player object for controlling audio playback. It also sets up event handlers for various player states like track start, end, and exceptions. ```typescript import { Shoukaku, Player } from "shoukaku"; async function joinChannel( shoukaku: Shoukaku, guildId: string, channelId: string, shardId: number ): Promise { // Join voice channel with options const player = await shoukaku.joinVoiceChannel({ guildId: guildId, channelId: channelId, shardId: shardId, // Use 0 if unsharded deaf: true, // Self-deafen the bot mute: false // Don't self-mute }); // Set up player event handlers player.on("start", (data) => { console.log(`Started playing: ${data.track.info.title}`); }); player.on("end", (data) => { console.log(`Track ended: ${data.reason}`); // Handle queue logic here if (data.reason === "finished") { // Play next track in queue } }); player.on("stuck", (data) => { console.warn(`Track stuck for ${data.thresholdMs}ms`); }); player.on("exception", (data) => { console.error(`Track exception: ${data.exception.message}`); }); player.on("closed", (data) => { console.log(`WebSocket closed: ${data.code} - ${data.reason}`); }); player.on("update", (data) => { // Player state update with position, ping, etc. console.log(`Position: ${data.state.position}ms, Ping: ${data.state.ping}ms`); }); return player; } // Usage const player = await joinChannel(shoukaku, "123456789", "987654321", 0); ``` -------------------------------- ### GET /route-planner/status Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Retrieves the status of the IP route planner, including failing addresses and IP block details. ```APIDOC ## GET /route-planner/status ### Description Manages IP rotation and blacklisting for sources that implement rate limiting. Useful when dealing with IP blocks. ### Method GET ### Endpoint /route-planner/status ### Response #### Success Response (200) - **class** (string) - The type of route planner. - **details** (object) - Detailed information about IP blocks and failing addresses. #### Response Example { "class": "RotatingNanoIpRoutePlanner", "details": { "ipBlock": { "type": "Inet4", "size": "/64" }, "failingAddresses": [] } } ``` -------------------------------- ### GET /loadtracks Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Resolves audio tracks from search queries or direct URLs using the Lavalink REST API. ```APIDOC ## GET /loadtracks ### Description Resolves a search query or URL into a track, playlist, or search result list. ### Method GET ### Endpoint /loadtracks?identifier={query} ### Parameters #### Query Parameters - **identifier** (string) - Required - The search query (e.g., 'ytsearch:song name') or direct URL. ### Request Example GET /loadtracks?identifier=ytsearch:never+gonna+give+you+up ### Response #### Success Response (200) - **loadType** (string) - The type of result (TRACK, PLAYLIST, SEARCH, EMPTY, ERROR). - **data** (object) - The track or playlist information. #### Response Example { "loadType": "TRACK", "data": { "encoded": "QAAAfQIA...", "info": { "title": "Never Gonna Give You Up", "author": "Rick Astley", "length": 212000 } } } ``` -------------------------------- ### Get Shoukaku Node (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md In v4, node resolving is configurable. This snippet shows the new method to get a node using the options.nodeResolver, which replaces the direct getNode() method from v3. ```diff -const node = shoukaku.getNode(); +const node = shoukaku.options.nodeResolver(shoukaku.nodes); ``` -------------------------------- ### Get All Players on a Lavalink Node Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Retrieves a list of all active players managed by a specific Lavalink node. For each player, it displays the guild ID, volume, pause status, and the title of the currently playing track if available. ```typescript import { Shoukaku, Node, NodeOption } from "shoukaku"; // Get all players on a node async function getPlayers(node: Node): Promise { const players = await node.rest.getPlayers(); for (const player of players) { console.log(`Guild: ${player.guildId}`); console.log(`Volume: ${player.volume}`); console.log(`Paused: ${player.paused}`); if (player.track) { console.log(`Track: ${player.track.info.title}`); } } } ``` -------------------------------- ### Get Lavalink Node Information and Statistics Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Provides functions to retrieve detailed information about a Lavalink node. This includes fetching Lavalink server details (version, JVM, plugins), node statistics (players, memory, CPU load), and checking the node's current state and penalties for load balancing. ```typescript import { Shoukaku, Node, NodeOption } from "shoukaku"; // Get node information async function getNodeInfo(node: Node): Promise { // Get Lavalink server info const info = await node.rest.getLavalinkInfo(); if (info) { console.log(`Lavalink Version: ${info.version.semver}`); console.log(`JVM: ${info.jvm}`); console.log(`Lavaplayer: ${info.lavaplayer}`); console.log(`Source Managers: ${info.sourceManagers.join(", ")}`); console.log(`Filters: ${info.filters.join(", ")}`); console.log(`Plugins: ${info.plugins.map(p => `${p.name}@${p.version}`).join(", ")}`); } // Get node statistics const stats = await node.rest.stats(); if (stats) { console.log(`Players: ${stats.players}`); console.log(`Playing: ${stats.playingPlayers}`); console.log(`Uptime: ${stats.uptime}ms`); console.log(`Memory Used: ${stats.memory.used / 1024 / 1024}MB`); console.log(`CPU Cores: ${stats.cpu.cores}`); console.log(`System Load: ${(stats.cpu.systemLoad * 100).toFixed(2)}%`); console.log(`Lavalink Load: ${(stats.cpu.lavalinkLoad * 100).toFixed(2)}%`); } // Access cached stats if (node.stats) { console.log(`Cached players: ${node.stats.players}`); } // Check node state console.log(`State: ${node.state}`); // 0=CONNECTING, 1=CONNECTED, 2=DISCONNECTING, 3=DISCONNECTED console.log(`Penalties: ${node.penalties}`); // Load balancing score console.log(`Session ID: ${node.sessionId}`); } ``` -------------------------------- ### Get Ideal Lavalink Node for Load Balancing Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Determines the most suitable Lavalink node for a new connection or task based on calculated penalties, which represent the node's current load. This function helps in distributing traffic efficiently across available nodes. ```typescript import { Shoukaku, Node, NodeOption } from "shoukaku"; // Get ideal node based on load function getIdealNode(shoukaku: Shoukaku): Node | undefined { const node = shoukaku.getIdealNode(); if (node) { console.log(`Selected node: ${node.name} with ${node.penalties} penalties`); } return node; } ``` -------------------------------- ### Initialize Shoukaku with Discord.JS Connector Source: https://github.com/shipgirlproject/shoukaku/blob/master/src/connectors/README.md Demonstrates initializing the Shoukaku library using the Discord.JS connector. This requires a Discord.JS client instance, server configurations, and optional Shoukaku options. ```javascript const { Shoukaku, Connectors } = require('shoukaku'); new Shoukaku(new Connectors.DiscordJS(client), servers, options); ``` -------------------------------- ### Initialize Shoukaku with Oceanic.JS Connector Source: https://github.com/shipgirlproject/shoukaku/blob/master/src/connectors/README.md Illustrates the initialization of Shoukaku using the Oceanic.JS connector. This integration requires an Oceanic.JS client, server information, and Shoukaku configuration options. ```javascript const { Shoukaku, Connectors } = require('shoukaku'); new Shoukaku(new Connectors.OceanicJS(client), servers, options) ``` -------------------------------- ### Initialize Shoukaku Client Source: https://github.com/shipgirlproject/shoukaku/blob/master/README.md This snippet demonstrates how to instantiate the Shoukaku class by providing a connector, a list of Lavalink nodes, and an optional configuration object. ```javascript new Shoukaku(new Connectors.DiscordJS(client), Nodes, Options); ``` -------------------------------- ### Initializing Shoukaku with Discord.js Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Demonstrates how to initialize Shoukaku with a Discord.js client, configure Lavalink nodes, and set up event handlers for connection status. ```APIDOC ## Initializing Shoukaku with Discord.js ### Description This code snippet shows the main entry point for Shoukaku. It demonstrates how to create a new instance with a Discord library connector, Lavalink node configurations, and optional settings for reconnection, resuming, and load balancing behavior. ### Method Initialization ### Endpoint N/A (Library Initialization) ### Parameters #### Request Body - **client** (Discord.js Client) - Required - The Discord client instance. - **nodes** (Array) - Required - An array of Lavalink node configurations. - **options** (ShoukakuOptions) - Optional - Configuration for Shoukaku's behavior. ### Request Example ```typescript import { Client, GatewayIntentBits } from "discord.js"; import { Shoukaku, Connectors } from "shoukaku"; const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates ] }); const nodes = [ { name: "Main", url: "localhost:2333", auth: "youshallnotpass", secure: false, group: "production" }, { name: "Backup", url: "backup.example.com:2333", auth: "youshallnotpass", secure: true, group: "production" } ]; const shoukaku = new Shoukaku(new Connectors.DiscordJS(client), nodes, { resume: true, resumeTimeout: 30, resumeByLibrary: false, reconnectTries: 3, reconnectInterval: 5, restTimeout: 60, moveOnDisconnect: true, voiceConnectionTimeout: 15, nodeResolver: (nodes, connection) => { return [...nodes.values()] .filter(node => node.state === 1) // State.CONNECTED .sort((a, b) => a.penalties - b.penalties) .shift(); } }); shoukaku.on("error", (name, error) => { console.error(`Node ${name} encountered an error:`, error); }); shoukaku.on("ready", (name, resumed, libraryResumed) => { console.log(`Node ${name} is ready! Resumed: ${resumed}, Library Resumed: ${libraryResumed}`); }); shoukaku.on("close", (name, code, reason) => { console.log(`Node ${name} closed with code ${code}: ${reason}`); }); shoukaku.on("debug", (name, info) => { console.debug(`[${name}] ${info}`); }); client.shoukaku = shoukaku; client.login("YOUR_BOT_TOKEN"); ``` ### Response #### Success Response (200) - **Shoukaku Instance** (Shoukaku) - The initialized Shoukaku instance. #### Response Example N/A (Initialization) ### Error Handling - **error**: Emitted when a Lavalink node encounters an error. - **close**: Emitted when a Lavalink node connection is closed. ``` -------------------------------- ### Initialize Shoukaku with Discord Library Connectors Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/connectors.md Demonstrates how to instantiate the Shoukaku class using specific connectors for Discord.JS, Eris, Oceanic.JS, and Seyfert. This requires the respective client instance and server configuration options. ```typescript import { Shoukaku, Connectors } from 'shoukaku'; new Shoukaku(new Connectors.DiscordJS(client), servers, options); ``` ```typescript import { Shoukaku, Connectors } from 'shoukaku'; new Shoukaku(new Connectors.Eris(client), servers, options); ``` ```typescript import { Shoukaku, Connectors } from 'shoukaku'; new Shoukaku(new Connectors.OceanicJS(client), servers, options); ``` ```typescript import { Shoukaku, Connectors } from 'shoukaku'; new Shoukaku(new Connectors.DiscordJS(client), servers, options); ``` -------------------------------- ### Initialize Shoukaku with Eris Connector Source: https://github.com/shipgirlproject/shoukaku/blob/master/src/connectors/README.md Shows how to initialize Shoukaku with the Eris connector. This method is suitable for projects using the Eris library and requires an Eris client instance, server details, and Shoukaku options. ```javascript const { Shoukaku, Connectors } = require('shoukaku'); new Shoukaku(new Connectors.Eris(client), servers, options) ``` -------------------------------- ### Control Audio Playback on Player Instance Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Explains how to initiate playback with specific options like start/end positions and volume, as well as how to manage the player state through pausing, resuming, seeking, and stopping tracks. ```typescript import { Player, Track } from "shoukaku"; async function playTrack(player: Player, track: Track): Promise { await player.playTrack({ track: { encoded: track.encoded } }); await player.playTrack({ track: { encoded: track.encoded, userData: { requestedBy: "user123" } }, position: 30000, endTime: 180000, volume: 80, paused: false }); await player.playTrack({ track: { encoded: track.encoded } }, true); } async function controlPlayback(player: Player): Promise { await player.setPaused(true); await player.setPaused(false); await player.seekTo(60000); await player.stopTrack(); await player.setGlobalVolume(100); await player.setFilterVolume(1.0); console.log(`Current track: ${player.track}`); console.log(`Position: ${player.position}ms`); console.log(`Volume: ${player.volume}`); console.log(`Paused: ${player.paused}`); console.log(`Ping: ${player.ping}ms`); } ``` -------------------------------- ### Joining Voice Channels Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Explains how to join a voice channel using Shoukaku and obtain a Player instance for controlling audio playback. ```APIDOC ## Joining Voice Channels ### Description This function joins a specified Discord voice channel and returns a Player instance. This Player instance can then be used to control audio playback, manage tracks, and handle playback events. ### Method POST (Implicit via Shoukaku API) ### Endpoint `/voice/join` (Internal Shoukaku endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **guildId** (string) - Required - The ID of the guild to join. - **channelId** (string) - Required - The ID of the voice channel to join. - **shardId** (number) - Required - The ID of the shard the guild belongs to (use 0 if unsharded). - **deaf** (boolean) - Optional - Whether the bot should self-deafen (defaults to true). - **mute** (boolean) - Optional - Whether the bot should self-mute (defaults to false). ### Request Example ```typescript import { Shoukaku, Player } from "shoukaku"; async function joinChannel( shoukaku: Shoukaku, guildId: string, channelId: string, shardId: number ): Promise { const player = await shoukaku.joinVoiceChannel({ guildId: guildId, channelId: channelId, shardId: shardId, deaf: true, mute: false }); player.on("start", (data) => { console.log(`Started playing: ${data.track.info.title}`); }); player.on("end", (data) => { console.log(`Track ended: ${data.reason}`); if (data.reason === "finished") { // Play next track in queue } }); player.on("stuck", (data) => { console.warn(`Track stuck for ${data.thresholdMs}ms`); }); player.on("exception", (data) => { console.error(`Track exception: ${data.exception.message}`); }); player.on("closed", (data) => { console.log(`WebSocket closed: ${data.code} - ${data.reason}`); }); player.on("update", (data) => { console.log(`Position: ${data.state.position}ms, Ping: ${data.state.ping}ms`); }); return player; } // Usage // const player = await joinChannel(shoukaku, "123456789", "987654321", 0); ``` ### Response #### Success Response (200) - **Player Instance** (Player) - An instance of the Player class for controlling the audio playback. #### Response Example ```json { "example": "Player instance object" } ``` ### Error Handling - **start**: Emitted when a track begins playing. - **end**: Emitted when a track finishes or is stopped. - **stuck**: Emitted when a track gets stuck for a specified duration. - **exception**: Emitted when an error occurs during track playback. - **closed**: Emitted when the voice connection WebSocket is closed. - **update**: Emitted periodically with player state updates (position, ping). ``` -------------------------------- ### Apply Audio Filters using Shoukaku Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Demonstrates how to apply various audio filters such as equalizer, timescale, karaoke, tremolo, vibrato, rotation, distortion, channel mixing, and low pass to a Shoukaku player. It also shows how to apply multiple filters simultaneously and clear them. ```typescript import { Player, Band, FilterOptions } from "shoukaku"; async function applyFilters(player: Player): Promise { await player.setEqualizer([ { band: 0, gain: 0.25 }, { band: 1, gain: 0.15 }, { band: 2, gain: 0.1 }, { band: 3, gain: 0.05 }, { band: 4, gain: 0 }, { band: 5, gain: -0.05 }, { band: 6, gain: -0.1 }, { band: 7, gain: 0 }, { band: 8, gain: 0 }, { band: 9, gain: 0 }, { band: 10, gain: 0.1 }, { band: 11, gain: 0.15 }, { band: 12, gain: 0.2 }, { band: 13, gain: 0.25 }, { band: 14, gain: 0.3 } ]); await player.setTimescale({ speed: 1.0, pitch: 1.0, rate: 1.0 }); await player.setKaraoke({ level: 1.0, monoLevel: 1.0, filterBand: 220, filterWidth: 100 }); await player.setTremolo({ frequency: 2.0, depth: 0.5 }); await player.setVibrato({ frequency: 2.0, depth: 0.5 }); await player.setRotation({ rotationHz: 0.2 }); await player.setDistortion({ sinOffset: 0, sinScale: 1, cosOffset: 0, cosScale: 1, tanOffset: 0, tanScale: 1, offset: 0, scale: 1 }); await player.setChannelMix({ leftToLeft: 1.0, leftToRight: 0.0, rightToLeft: 0.0, rightToRight: 1.0 }); await player.setLowPass({ smoothing: 20.0 }); await player.setFilters({ volume: 0.8, equalizer: [{ band: 0, gain: 0.2 }], timescale: { speed: 1.05 }, tremolo: { frequency: 4.0, depth: 0.3 } }); await player.clearFilters(); } ``` -------------------------------- ### Initialize Shoukaku with Discord Library Connectors Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/getting-started.md Configure Lavalink nodes and initialize the Shoukaku instance using specific connectors for Discord.js, Eris, Oceanic.js, or Seyfert. ```typescript import { Client } from "discord.js"; import { Shoukaku, Connectors } from "shoukaku"; const Nodes = [ { name: "Localhost", url: "localhost:6969", auth: "re_aoharu", }, ]; // Discord.js const client = new Client(); const shoukaku = new Shoukaku(new Connectors.DiscordJS(client), Nodes); ``` ```typescript const shoukaku = new Shoukaku(new Connectors.Eris(client), Nodes); ``` ```typescript const shoukaku = new Shoukaku(new Connectors.OceanicJS(client), Nodes); ``` ```typescript const shoukaku = new Shoukaku(new Connectors.Seyfert(client), Nodes); ``` -------------------------------- ### Initialize Shoukaku with Discord.js Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Initializes the Shoukaku library with a Discord.js client, Lavalink node configurations, and optional settings for reconnection and load balancing. It handles setting up the connection to Lavalink servers and listening for various events. ```typescript import { Client, GatewayIntentBits } from "discord.js"; import { Shoukaku, Connectors } from "shoukaku"; const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates ] }); // Configure Lavalink nodes const nodes = [ { name: "Main", url: "localhost:2333", auth: "youshallnotpass", secure: false, group: "production" }, { name: "Backup", url: "backup.example.com:2333", auth: "youshallnotpass", secure: true, group: "production" } ]; // Initialize Shoukaku with options const shoukaku = new Shoukaku(new Connectors.DiscordJS(client), nodes, { resume: true, resumeTimeout: 30, resumeByLibrary: false, reconnectTries: 3, reconnectInterval: 5, restTimeout: 60, moveOnDisconnect: true, voiceConnectionTimeout: 15, nodeResolver: (nodes, connection) => { return [...nodes.values()] .filter(node => node.state === 1) // State.CONNECTED .sort((a, b) => a.penalties - b.penalties) .shift(); } }); // Always handle error events shoukaku.on("error", (name, error) => { console.error(`Node ${name} encountered an error:`, error); }); shoukaku.on("ready", (name, resumed, libraryResumed) => { console.log(`Node ${name} is ready! Resumed: ${resumed}, Library Resumed: ${libraryResumed}`); }); shoukaku.on("close", (name, code, reason) => { console.log(`Node ${name} closed with code ${code}: ${reason}`); }); shoukaku.on("debug", (name, info) => { console.debug(`[${name}] ${info}`); }); // Bind to client for easy access client.shoukaku = shoukaku; client.login("YOUR_BOT_TOKEN"); ``` -------------------------------- ### Play Track and Set Global Volume - TypeScript Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md Demonstrates how to play a previously resolved track and set its global playback volume using the Shoukaku player. This assumes a player object and track metadata are already available. ```typescript await player.playTrack({ track: { encoded: metadata.encoded } }); await player.setGlobalVolume(50); ``` -------------------------------- ### Playback Options Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md This snippet shows how to play a track and modify its playback options, such as volume. ```APIDOC ## Playback Options ### Description This snippet shows how to play a track and modify its playback options, such as volume. ### Play and Set Volume Play a track and set its global volume to 50%. ```ts await player.playTrack({ track: { encoded: metadata.encoded } }); await player.setGlobalVolume(50); ``` ### Update Player Directly Update player options without using helper functions. ```ts await player.update({ ...playerOptions }); ``` ``` -------------------------------- ### Implementing a Custom Connector Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/connectors.md Shows how to extend the base Connector class to create a custom bridge for unsupported Discord libraries. It requires implementing sendPacket, getId, and listen methods to handle gateway communication and event listeners. ```typescript import { Connector } from '../Connector'; import { NodeOption } from '../../Shoukaku'; export class DiscordJS extends Connector { public sendPacket(shardId: number, payload: any, important: boolean): void { return this.client.ws.shards.get(shardId)?.send(payload, important); } public getId(): string { return this.client.user.id; } public listen(nodes: NodeOption[]): void { this.client.once('ready', () => this.ready(nodes)); this.client.on('raw', (packet: any) => this.raw(packet)); } } ``` -------------------------------- ### Search and Resolve Tracks via Lavalink Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Demonstrates how to search for tracks using prefixes like ytsearch or scsearch, resolve direct URLs, and handle various load types such as tracks, playlists, and search results. It also covers decoding encoded track strings into readable track metadata. ```typescript import { Node, LoadType, Track, LavalinkResponse } from "shoukaku"; async function searchTracks(node: Node, query: string): Promise { const ytResult = await node.rest.resolve(`ytsearch:${query}`); const scResult = await node.rest.resolve(`scsearch:${query}`); const urlResult = await node.rest.resolve("https://www.youtube.com/watch?v=dQw4w9WgXcQ"); if (!ytResult) { console.log("No result returned"); return []; } switch (ytResult.loadType) { case LoadType.TRACK: console.log(`Found track: ${ytResult.data.info.title}`); return [ytResult.data]; case LoadType.PLAYLIST: console.log(`Found playlist: ${ytResult.data.info.name}`); console.log(`Tracks: ${ytResult.data.tracks.length}`); return ytResult.data.tracks; case LoadType.SEARCH: console.log(`Found ${ytResult.data.length} search results`); return ytResult.data; case LoadType.EMPTY: console.log("No matches found"); return []; case LoadType.ERROR: console.error(`Error: ${ytResult.data.message}`); console.error(`Severity: ${ytResult.data.severity}`); return []; } } async function decodeTrack(node: Node, encoded: string): Promise { const track = await node.rest.decode(encoded); if (track) { console.log(`Title: ${track.info.title}`); console.log(`Author: ${track.info.author}`); console.log(`Duration: ${track.info.length}ms`); console.log(`Stream: ${track.info.isStream}`); console.log(`URI: ${track.info.uri}`); } } ``` -------------------------------- ### POST /player/play Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Controls audio playback on a specific player instance, allowing for track loading, seeking, and volume adjustments. ```APIDOC ## POST /player/play ### Description Initiates playback of a track on a player instance with optional playback parameters. ### Method POST ### Endpoint /sessions/{sessionId}/players/{guildId} ### Parameters #### Request Body - **encodedTrack** (string) - Required - The base64 encoded track string. - **position** (number) - Optional - Start position in milliseconds. - **endTime** (number) - Optional - End position in milliseconds. - **volume** (number) - Optional - Volume level (0-1000). - **paused** (boolean) - Optional - Whether to start in a paused state. ### Request Example { "encodedTrack": "QAAAfQIA...", "position": 30000, "volume": 80, "paused": false } ### Response #### Success Response (204) - No content returned on successful command execution. ``` -------------------------------- ### Join Voice Channel with Shoukaku (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md Voice channel joining is now handled by the main Shoukaku class in v4, rather than the Node class. This change simplifies the API for managing voice connections. ```diff -const player = await node.joinChannel({ +const player = await shoukaku.joinVoiceChannel({ guildId: "your_guild_id", channelId: "your_channel_id", shardId: 0, // if unsharded it will always be zero (depending on your library implementation) }); ``` -------------------------------- ### Player Methods Returning Promises (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md In Shoukaku v4, player methods like playTrack and stopTrack now return promises, requiring the use of 'await' for proper asynchronous handling. ```typescript await player.playTrack(...data); await player.stopTrack(); ``` -------------------------------- ### Custom Player and REST Structures Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Extend the default Player and Rest classes to add custom functionality like queue management, custom filters, or additional REST endpoints. ```APIDOC ## Customizing Structures ### Description Override default Shoukaku behaviors by extending `Player` and `Rest` classes. This allows for custom queue management, search methods, and specialized playback logic. ### Usage Pass the custom classes into the `structures` option during `Shoukaku` initialization. ### Configuration Example ```typescript const shoukaku = new Shoukaku(connector, nodes, { structures: { player: QueuePlayer, rest: CustomRest } }); ``` ### Custom Player Features - **addToQueue(encoded)**: Adds a track to the internal queue. - **playNext()**: Plays the next track from the queue. - **shuffle()**: Randomizes the internal queue order. ### Custom REST Features - **searchYouTube(query)**: Helper method to resolve YouTube search queries. - **searchSoundCloud(query)**: Helper method to resolve SoundCloud search queries. ``` -------------------------------- ### Update Player Options Directly - TypeScript Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md Shows how to update player options directly without using specific helper functions, allowing for more granular control over playback settings. This requires an existing player object and player options. ```typescript await player.update({ ...playerOptions }); ``` -------------------------------- ### Configure Route Planner Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Functions to monitor and manage IP route planners. This allows developers to inspect IP block status and manually unmark failed addresses to resolve rate-limiting issues. ```typescript import { Node } from "shoukaku"; async function manageRoutePlanner(node: Node): Promise { const status = await node.rest.getRoutePlannerStatus(); if (status && status.class) { console.log(`Route Planner Type: ${status.class}`); if (status.details) { console.log(`IP Block Type: ${status.details.ipBlock.type}`); console.log(`IP Block Size: ${status.details.ipBlock.size}`); console.log(`Current Address: ${status.details.currentAddress}`); for (const addr of status.details.failingAddresses) { console.log(`Failing: ${addr.address} since ${addr.failingTime}`); } } } else { console.log("No route planner configured"); } await node.rest.unmarkFailedAddress("192.168.1.100"); console.log("Address unmarked from failed list"); } ``` -------------------------------- ### Resolve Tracks with Shoukaku Player (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md Tracks can now be resolved using the player.node.rest property after connecting to a voice channel in v4. The old method using the node directly is still supported for backward compatibility. ```diff -const result = await node.rest.resolve("scsearch:snowhalation"); +const result = await player.node.rest.resolve("scsearch:snowhalation"); ``` -------------------------------- ### Create Custom Discord Connectors for Shoukaku Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Implement custom connectors by extending the base Connector class to support additional Discord libraries. This involves overriding methods for sending packets, retrieving the bot's user ID, and listening for Discord events. The custom connector is then passed to the Shoukaku constructor. ```typescript import { Connector, NodeOption } from "shoukaku"; // Example custom connector for a hypothetical library class CustomLibraryConnector extends Connector { // Send voice state update packets to Discord public sendPacket(shardId: number, payload: unknown, important: boolean): void { // Access your client from this.client const shard = this.client.shards.get(shardId); if (shard) { shard.send(payload, important); } } // Return the bot's user ID public getId(): string { return this.client.user.id; } // Attach event listeners for ready and raw events public listen(nodes: NodeOption[]): void { // Listen for ready event (only once) this.client.once("ready", () => { // Call parent ready() to initialize nodes this.ready(nodes); }); // Listen for raw websocket events this.client.on("raw", (packet: { t: string; d: unknown }) => { // Call parent raw() to handle voice events this.raw(packet); }); } } // Usage with custom connector import { Shoukaku } from "shoukaku"; const client = new CustomLibrary.Client(); const shoukaku = new Shoukaku(new CustomLibraryConnector(client), nodes, options); ``` -------------------------------- ### Leave Voice Channel with Shoukaku (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md Similar to joining, leaving voice channels is now managed by the main Shoukaku class in v4. This provides a consistent interface for voice channel management. ```diff -player.connection.disconnect(); +await shoukaku.leaveVoiceChannel(player.guildId); ``` -------------------------------- ### POST /player/move Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Transfers a player from one Lavalink node to another while maintaining playback state. ```APIDOC ## POST /player/move ### Description Transfers a player from one Lavalink node to another while maintaining playback state. Useful for load balancing or when a node becomes unavailable. ### Method POST ### Endpoint /player/move ### Parameters #### Request Body - **targetNodeName** (string) - Optional - The name of the target node to move the player to. If omitted, the nodeResolver is used. ### Request Example { "targetNodeName": "node-2" } ### Response #### Success Response (200) - **moved** (boolean) - Returns true if the player was successfully moved. #### Response Example { "moved": true } ``` -------------------------------- ### Custom Node Resolver Configuration (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md Shoukaku v4 allows for a custom node resolver to be provided via the Shoukaku options. This enables users to define their own logic for selecting an ideal node. ```typescript const ShoukakuOptions = { ...yourShoukakuOptions, nodeResolver: (nodes, connection) => getYourIdealNode(nodes, connection), }; ``` -------------------------------- ### Manage Voice Channels and Cleanup Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Utilities for disconnecting from voice channels, checking connection status, and performing bulk resource cleanup. Essential for preventing memory leaks and managing active voice sessions. ```typescript import { Shoukaku, Player } from "shoukaku"; async function leaveChannel(shoukaku: Shoukaku, guildId: string): Promise { await shoukaku.leaveVoiceChannel(guildId); console.log(`Left voice channel in guild ${guildId}`); } function isConnected(shoukaku: Shoukaku, guildId: string): boolean { return shoukaku.connections.has(guildId); } function getPlayer(shoukaku: Shoukaku, guildId: string): Player | undefined { return shoukaku.players.get(guildId); } async function cleanup(shoukaku: Shoukaku): Promise { for (const [guildId] of shoukaku.connections) { await shoukaku.leaveVoiceChannel(guildId); } for (const [nodeName] of shoukaku.nodes) { shoukaku.removeNode(nodeName, "Shutdown"); } } ``` -------------------------------- ### Migrate and Manage Players Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Functions to transfer players between nodes, resume playback states, and handle automatic migration during node disconnects. These operations ensure high availability and consistent playback for voice sessions. ```typescript import { Player, Shoukaku } from "shoukaku"; async function movePlayer(player: Player, targetNodeName?: string): Promise { try { const moved = await player.move(targetNodeName); if (moved) { console.log(`Player moved to node: ${player.node.name}`); } else { console.log("Player was not moved (same node or unavailable)"); } return moved; } catch (error) { console.error("Failed to move player:", error); return false; } } async function moveToIdealNode(player: Player): Promise { return player.move(); } async function resumePlayer(player: Player): Promise { await player.resume({ position: player.position, paused: player.paused, volume: player.volume }); console.log("Player resumed successfully"); } function setupNodeMigration(shoukaku: Shoukaku): void { shoukaku.on("close", async (nodeName, code, reason) => { console.log(`Node ${nodeName} closed: ${code} - ${reason}`); for (const [guildId, player] of shoukaku.players) { if (player.node.name === nodeName) { try { await player.move(); console.log(`Migrated player for guild ${guildId}`); } catch (error) { console.error(`Failed to migrate player for guild ${guildId}`); } } } }); } ``` -------------------------------- ### Access Shoukaku Players (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md In Shoukaku v4, the management of players has been moved from 'node.players' to the main 'shoukaku.players' property. ```typescript console.log(shoukaku.players); ``` -------------------------------- ### Custom Node Resolver Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md Demonstrates how to implement a custom function to select the ideal Lavalink node based on specific criteria. ```APIDOC ## Custom Node Resolver ### Description Demonstrates how to implement a custom function to select the ideal Lavalink node based on specific criteria. ### Configuration When executing any action, an API endpoint is called on a Lavalink node. This example shows how to configure Shoukaku with a custom `nodeResolver`. ```ts const shoukaku = new Shoukaku( new Connectors.DiscordJS(client), [{ ...yourNodeOptions }], { ...yourShoukakuOptions, nodeResolver: (nodes, connection) => getYourIdealNode(nodes, connection), } ); // Example of joining a voice channel after configuring the custom node resolver const player = await shoukaku.joinVoiceChannel({ guildId: "your_guild_id", channelId: "your_channel_id", shardId: 0, }); ``` ``` -------------------------------- ### Join Voice Channel, Play Track, and Disconnect - TypeScript Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/common.md This snippet shows how to join a Discord voice channel, search for a track using SoundCloud, play it, and then disconnect after a 30-second delay. It requires a Lavalink instance and a Discord API integration. ```typescript const player = await shoukaku.joinVoiceChannel({ guildId: "your_guild_id", channelId: "your_channel_id", shardId: 0, }); ``` ```typescript const node = shoukaku.options.nodeResolver(shoukaku.nodes); ``` ```typescript const result = await node.rest.resolve("scsearch:snowhalation"); if (!result?.tracks.length) return; const metadata = result.tracks.shift(); ``` ```typescript await player.playTrack({ track: { encoded: metadata.encoded } }); ``` ```typescript setTimeout(() => shoukaku.leaveVoiceChannel(player.guildId), 30000).unref(); ``` -------------------------------- ### Set Global Volume (v4) Source: https://github.com/shipgirlproject/shoukaku/blob/master/docsrc/updating-from-v3.md The global volume in Shoukaku v4 can be set using setGlobalVolume, accepting values from 0 to 1000. The current global volume can be accessed via the player.volume property. ```typescript await player.setGlobalVolume(100); console.log(player.volume); ``` -------------------------------- ### Add, Remove, and List Lavalink Nodes Source: https://context7.com/shipgirlproject/shoukaku/llms.txt Demonstrates dynamic management of Lavalink nodes. Includes functions to add new nodes with specified options, remove existing nodes by name, and iterate through all connected nodes to display their status and penalties. ```typescript import { Shoukaku, Node, NodeOption } from "shoukaku"; // Add a new node dynamically function addNode(shoukaku: Shoukaku, options: NodeOption): void { shoukaku.addNode({ name: "NewNode", url: "newnode.example.com:2333", auth: "password123", secure: true, group: "us-east" }); } // Remove a node function removeNode(shoukaku: Shoukaku, nodeName: string): void { try { shoukaku.removeNode(nodeName, "Maintenance mode"); } catch (error) { console.error("Node not found:", error); } } // Iterate over all nodes function listNodes(shoukaku: Shoukaku): void { for (const [name, node] of shoukaku.nodes) { console.log(`${name}: State=${node.state}, Penalties=${node.penalties}`); } } ```