CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-wavelink

A robust and powerful, fully asynchronous Lavalink wrapper built for discord.py in Python.

Overview
Eval results
Files

player-control.mddocs/

Player Control

Main audio player interface providing playback control, volume management, seeking, and voice channel operations with full discord.py VoiceProtocol integration. The Player class extends discord.VoiceProtocol to seamlessly integrate with Discord's voice system while providing advanced audio playback capabilities.

Capabilities

Player Creation & Connection

The Player class integrates with discord.py's voice system to provide audio playback in Discord voice channels.

class Player(discord.VoiceProtocol):
    def __init__(self, client: discord.Client, channel: discord.VoiceChannel):
        """
        Initialize a new Player instance.
        
        Parameters:
        - client: Discord client instance
        - channel: Voice channel to connect to
        """
    
    # Predefined queue instances
    queue: Queue  # Standard track queue
    auto_queue: Queue  # AutoPlay queue for recommendations
    
    async def connect(
        self,
        channel: discord.VoiceChannel,
        *,
        self_deaf: bool = True,
        **kwargs
    ) -> None:
        """
        Connect to a Discord voice channel.
        
        Parameters:
        - channel: Voice channel to connect to
        - self_deaf: Whether to self-deafen the bot
        - **kwargs: Additional connection parameters
        
        Raises:
        InvalidChannelStateException: If channel is invalid or no permissions
        ChannelTimeoutException: If connection times out
        """
    
    async def move_to(self, channel: discord.VoiceChannel) -> None:
        """
        Move to a different voice channel.
        
        Parameters:
        - channel: New voice channel to move to
        """
    
    async def disconnect(self, **kwargs) -> None:
        """
        Disconnect from the voice channel.
        
        Parameters:
        - **kwargs: Additional disconnection parameters
        """

Playback Control

Core playback functionality including play, pause, seek, skip, and stop operations.

class Player(discord.VoiceProtocol):
    async def play(
        self,
        track: Playable,
        *,
        replace: bool = True,
        start: int = 0,
        end: int | None = None,
        volume: int | None = None,
        paused: bool | None = None,
        add_history: bool = True,
        filters: Filters | None = None,
        populate: bool = False,
        max_populate: int = 5
    ) -> Playable:
        """
        Play a track.
        
        Parameters:
        - track: The track to play
        - replace: Whether to replace the current track
        - start: Start position in milliseconds
        - end: End position in milliseconds (None for full track)
        - volume: Playback volume (0-100)
        - paused: Whether to start paused
        - add_history: Whether to add current track to history
        - filters: Filters to apply when playing
        - populate: Whether to populate AutoPlay queue
        - max_populate: Maximum tracks to populate for AutoPlay
        
        Returns:
        Playable: The track that is now playing
        """
    
    async def pause(self, value: bool) -> None:
        """
        Pause or unpause playback.
        
        Parameters:
        - value: True to pause, False to unpause
        """
    
    async def seek(self, position: int = 0) -> None:
        """
        Seek to a specific position in the current track.
        
        Parameters:
        - position: Position to seek to in milliseconds
        
        Raises:
        ValueError: If track is not seekable
        """
    
    async def stop(self, *, force: bool = True) -> Playable | None:
        """
        Stop the current track.
        
        Parameters:
        - force: Whether to force stop immediately
        
        Returns:
        Playable | None: The stopped track, if any
        """
    
    async def skip(self, *, force: bool = True) -> Playable | None:
        """
        Skip to the next track in the queue.
        
        Parameters:
        - force: Whether to force skip immediately
        
        Returns:
        Playable | None: The skipped track, if any
        """

Player State & Properties

Properties for monitoring and controlling player state, volume, and playback information.

class Player(discord.VoiceProtocol):
    @property
    def inactive_channel_tokens(self) -> int | None:
        """
        Token limit for the amount of tracks to play before firing
        the on_wavelink_inactive_player event when a channel is inactive.
        
        Returns None if the check has been disabled. A channel is 
        considered inactive when no real members are in the voice channel.
        Default value is 3. Setting to <= 0 or None disables the check.
        """
    
    @inactive_channel_tokens.setter
    def inactive_channel_tokens(self, value: int | None) -> None:
        """Set the inactive channel token limit."""
    
    @property
    def inactive_timeout(self) -> int | None:
        """
        Time in seconds to wait before dispatching the 
        on_wavelink_inactive_player event for inactive players.
        
        Returns None if no timeout is set. An inactive player is one
        that has not been playing anything for the specified seconds.
        The countdown starts when a track ends and cancels when a track starts.
        """
    
    @inactive_timeout.setter
    def inactive_timeout(self, value: int | None) -> None:
        """Set the inactive timeout in seconds."""
    
    @property
    def autoplay(self) -> AutoPlayMode:
        """Current AutoPlay mode setting."""
    
    @autoplay.setter
    def autoplay(self, value: AutoPlayMode) -> None:
        """Set the AutoPlay mode."""
    
    @property
    def node(self) -> Node:
        """The Lavalink node this player is connected to."""
    
    @property
    def guild(self) -> discord.Guild | None:
        """The Discord guild this player belongs to."""
    
    @property
    def connected(self) -> bool:
        """Whether the player is connected to a voice channel."""
    
    @property
    def current(self) -> Playable | None:
        """The currently playing track."""
    
    @property
    def volume(self) -> int:
        """Current player volume (0-100)."""
    
    @property
    def filters(self) -> Filters:
        """Currently applied audio filters."""
    
    @property
    def paused(self) -> bool:
        """Whether playback is currently paused."""
    
    @property
    def ping(self) -> int:
        """WebSocket ping to the Lavalink server in milliseconds."""
    
    @property
    def playing(self) -> bool:
        """Whether the player is currently playing a track."""
    
    @property
    def position(self) -> int:
        """Current playback position in milliseconds."""

Volume & Filter Control

Methods for controlling audio volume and applying audio filters to enhance playback.

class Player(discord.VoiceProtocol):
    async def set_volume(self, value: int = 100) -> None:
        """
        Set the player volume.
        
        Parameters:
        - value: Volume level (0-100)
        
        Raises:
        ValueError: If volume is outside valid range
        """
    
    async def set_filters(
        self,
        filters: Filters | None = None,
        *,
        seek: bool = False
    ) -> None:
        """
        Apply audio filters to the player.
        
        Parameters:
        - filters: Filters object to apply (None to reset all filters)
        - seek: Whether to seek to current position after applying filters
        """

Event Handlers

Event handler methods that can be overridden to respond to player events.

class Player(discord.VoiceProtocol):
    async def on_voice_state_update(self, data) -> None:
        """
        Handle voice state updates from Discord.
        
        Parameters:
        - data: Voice state update data
        """
    
    async def on_voice_server_update(self, data) -> None:
        """
        Handle voice server updates from Discord.
        
        Parameters:
        - data: Voice server update data
        """

Usage Examples

Basic Player Setup

import discord
import wavelink
from discord.ext import commands

bot = commands.Bot(command_prefix='!', intents=discord.Intents.all())

@bot.command()
async def join(ctx):
    """Join the user's voice channel."""
    if not ctx.author.voice:
        return await ctx.send("You're not in a voice channel!")
    
    channel = ctx.author.voice.channel
    player = await channel.connect(cls=wavelink.Player)
    await ctx.send(f"Connected to {channel.name}")

@bot.command()
async def leave(ctx):
    """Leave the voice channel."""
    player = ctx.voice_client
    if player:
        await player.disconnect()
        await ctx.send("Disconnected!")

Playback Control

@bot.command()
async def play(ctx, *, query: str):
    """Play a track or add to queue."""
    if not ctx.voice_client:
        player = await ctx.author.voice.channel.connect(cls=wavelink.Player)
    else:
        player = ctx.voice_client
    
    # Search for tracks
    tracks = await wavelink.Pool.fetch_tracks(query)
    if not tracks:
        return await ctx.send("No tracks found!")
    
    track = tracks[0] if isinstance(tracks, list) else tracks.tracks[0]
    
    if player.playing:
        # Add to queue if already playing
        player.queue.put(track)
        await ctx.send(f"Added to queue: {track.title}")
    else:
        # Start playing immediately
        await player.play(track)
        await ctx.send(f"Now playing: {track.title}")

@bot.command()
async def pause(ctx):
    """Pause or unpause playback."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    await player.pause(not player.paused)
    action = "Paused" if player.paused else "Resumed"
    await ctx.send(f"{action} playback!")

@bot.command()
async def skip(ctx):
    """Skip the current track."""
    player = ctx.voice_client
    if not player or not player.playing:
        return await ctx.send("Nothing is playing!")
    
    skipped_track = await player.skip()
    await ctx.send(f"Skipped: {skipped_track.title}")

@bot.command()
async def seek(ctx, seconds: int):
    """Seek to a position in the current track."""
    player = ctx.voice_client
    if not player or not player.current:
        return await ctx.send("Nothing is playing!")
    
    if not player.current.is_seekable:
        return await ctx.send("This track is not seekable!")
    
    position = seconds * 1000  # Convert to milliseconds
    await player.seek(position)
    await ctx.send(f"Seeked to {seconds} seconds")

Volume Control

@bot.command()
async def volume(ctx, level: int = None):
    """Get or set the player volume."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    if level is None:
        await ctx.send(f"Current volume: {player.volume}%")
    else:
        if not 0 <= level <= 100:
            return await ctx.send("Volume must be between 0 and 100!")
        
        await player.set_volume(level)
        await ctx.send(f"Volume set to {level}%")

AutoPlay Configuration

@bot.command()
async def autoplay(ctx, mode: str = None):
    """Configure AutoPlay mode."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    if mode is None:
        current = player.autoplay.name
        await ctx.send(f"AutoPlay mode: {current}")
        return
    
    mode_map = {
        'enabled': wavelink.AutoPlayMode.enabled,
        'partial': wavelink.AutoPlayMode.partial,
        'disabled': wavelink.AutoPlayMode.disabled
    }
    
    if mode.lower() not in mode_map:
        return await ctx.send("Valid modes: enabled, partial, disabled")
    
    player.autoplay = mode_map[mode.lower()]
    await ctx.send(f"AutoPlay mode set to: {mode}")

Player Information

@bot.command()
async def now_playing(ctx):
    """Show information about the current track."""
    player = ctx.voice_client
    if not player or not player.current:
        return await ctx.send("Nothing is playing!")
    
    track = player.current
    embed = discord.Embed(
        title="Now Playing",
        description=f"**{track.title}**\nby {track.author}",
        color=discord.Color.blue()
    )
    
    embed.add_field(
        name="Duration",
        value=f"{track.length // 60000}:{(track.length // 1000) % 60:02d}",
        inline=True
    )
    embed.add_field(
        name="Position",
        value=f"{player.position // 60000}:{(player.position // 1000) % 60:02d}",
        inline=True
    )
    embed.add_field(name="Volume", value=f"{player.volume}%", inline=True)
    embed.add_field(name="Source", value=track.source.name, inline=True)
    embed.add_field(name="Paused", value=player.paused, inline=True)
    embed.add_field(name="Queue Size", value=player.queue.count, inline=True)
    
    if track.artwork:
        embed.set_thumbnail(url=track.artwork)
    
    await ctx.send(embed=embed)

Install with Tessl CLI

npx tessl i tessl/pypi-wavelink

docs

audio-filters.md

events-exceptions.md

index.md

node-management.md

player-control.md

queue-system.md

track-search.md

tile.json