Playback Control
Control audio playback with play, pause, skip, volume, and seeking functions.Basic Playback Controls
Play/Pause
await player.play()
await player.pause(False)
await player.pause(True)
await player.resume()
is_paused = player.paused
if is_paused:
await player.resume()
else:
await player.pause()
Stop & Skip
await player.stop()
await player.skip()
Volume Control
await player.setVolume(50)
await player.setVolume(100)
await player.setVolume(150)
print(f'Current volume: {player.volume}')
Seeking
await player.seek(60000)
await player.seek(120000)
async def seek_to_percentage(player, percentage: float):
track = player.currentTrackObj
if track and hasattr(track, 'duration'):
position = int((track.duration * percentage) / 100)
await player.seek(position)
print(f'Seeked to {percentage}%')
await seek_to_percentage(player, 50)
Queue Management
Queue Operations
player.queue.add(track)
for track in tracks:
player.queue.add(track)
player.addToQueue(track)
player.queue.remove(2)
player.queue.clear()
player.queue.shuffle()
print(f'Queue size: {len(player.queue)}')
print(f'Current track: {player.queue.current.title if player.queue.current else None}')
Loop Modes
from salada.enums import LoopMode
player.queue.setLoop(None)
player.queue.setLoop(LoopMode.TRACK)
player.queue.setLoop(LoopMode.QUEUE)
print(f'Loop mode: {player.queue.loop}')
Player State
Check Player Status
print(f'Playing: {player.playing}')
print(f'Paused: {player.paused}')
print(f'Connected: {player.connected}')
print(f'Destroyed: {player.destroyed}')
print(f'Position: {player.position}ms')
print(f'Volume: {player.volume}%')
Current Track Information
if player.currentTrackObj:
track = player.currentTrackObj
print(f'Title: {track.title}')
print(f'Author: {track.author}')
print(f'Duration: {track.duration}ms')
print(f'Position: {player.position}ms')
if hasattr(track, 'uri'):
print(f'URL: {track.uri}')
Complete Playback Example
from discord import app_commands
import discord
@bot.tree.command(name='play')
@app_commands.describe(query='Song name or URL')
async def play_command(interaction: discord.Interaction, query: str):
await interaction.response.defer()
if not interaction.user.voice:
await interaction.followup.send('❌ Join a voice channel first!')
return
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
player = await bot.salad.createConnection({
'guildId': interaction.guild.id,
'voiceChannel': interaction.user.voice.channel.id,
'textChannel': interaction.channel.id
})
await interaction.user.voice.channel.connect()
result = await bot.salad.resolve(query, requester=interaction.user)
tracks = result.get('tracks', [])
if not tracks:
await interaction.followup.send('❌ No tracks found!')
return
track = tracks[0]
player.addToQueue(track)
if not player.playing:
await player.play()
await interaction.followup.send(f'▶️ Now playing: **{track.title}**')
else:
await interaction.followup.send(f'➕ Added to queue: **{track.title}**')
@bot.tree.command(name='pause')
async def pause_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
if player.paused:
await player.resume()
await interaction.followup.send('▶️ Resumed!')
else:
await player.pause()
await interaction.followup.send('⏸️ Paused!')
@bot.tree.command(name='skip')
async def skip_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
await player.skip()
await interaction.followup.send('⏭️ Skipped!')
@bot.tree.command(name='stop')
async def stop_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
await player.stop()
await interaction.followup.send('⏹️ Stopped and cleared queue!')
@bot.tree.command(name='volume')
@app_commands.describe(level='Volume level (0-1000)')
async def volume_command(interaction: discord.Interaction, level: int):
await interaction.response.defer()
if level < 0 or level > 1000:
await interaction.followup.send('❌ Volume must be between 0 and 1000!')
return
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
await player.setVolume(level)
await interaction.followup.send(f'🔊 Volume set to {level}%')
@bot.tree.command(name='seek')
@app_commands.describe(position='Position in seconds')
async def seek_command(interaction: discord.Interaction, position: int):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player or not player.playing:
await interaction.followup.send('❌ Nothing is playing!')
return
position_ms = position * 1000
await player.seek(position_ms)
await interaction.followup.send(f'⏩ Seeked to {position} seconds!')
Queue Commands
@bot.tree.command(name='queue')
async def queue_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
if len(player.queue) == 0:
await interaction.followup.send('📭 Queue is empty!')
return
queue_list = []
for i, track in enumerate(player.queue.getAll()[:10]):
queue_list.append(f'{i+1}. {track.title}')
embed = discord.Embed(
title='📃 Queue',
description='\n'.join(queue_list),
color=discord.Color.blue()
)
if len(player.queue) > 10:
embed.set_footer(text=f'And {len(player.queue) - 10} more...')
await interaction.followup.send(embed=embed)
@bot.tree.command(name='nowplaying')
async def nowplaying_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player or not player.currentTrackObj:
await interaction.followup.send('❌ Nothing is playing!')
return
track = player.currentTrackObj
duration = track.duration if hasattr(track, 'duration') else 0
position = player.position
duration_str = f'{duration // 60000}:{(duration // 1000) % 60:02d}'
position_str = f'{position // 60000}:{(position // 1000) % 60:02d}'
embed = discord.Embed(
title='🎵 Now Playing',
description=f'**{track.title}**\nBy {track.author}',
color=discord.Color.green()
)
embed.add_field(name='Progress', value=f'{position_str} / {duration_str}')
embed.add_field(name='Volume', value=f'{player.volume}%')
if player.paused:
embed.add_field(name='Status', value='⏸️ Paused')
await interaction.followup.send(embed=embed)
@bot.tree.command(name='loop')
@app_commands.describe(mode='Loop mode: none, track, or queue')
async def loop_command(interaction: discord.Interaction, mode: str):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
from salada.enums import LoopMode
if mode.lower() == 'none':
player.queue.setLoop(None)
await interaction.followup.send('🔁 Loop disabled')
elif mode.lower() == 'track':
player.queue.setLoop(LoopMode.TRACK)
await interaction.followup.send('🔂 Looping current track')
elif mode.lower() == 'queue':
player.queue.setLoop(LoopMode.QUEUE)
await interaction.followup.send('🔁 Looping queue')
else:
await interaction.followup.send('❌ Invalid mode! Use: none, track, or queue')
@bot.tree.command(name='shuffle')
async def shuffle_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
if len(player.queue) == 0:
await interaction.followup.send('❌ Queue is empty!')
return
player.queue.shuffle()
await interaction.followup.send('🔀 Queue shuffled!')
@bot.tree.command(name='clear')
async def clear_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player:
await interaction.followup.send('❌ No player found!')
return
player.queue.clear()
await interaction.followup.send('🗑️ Queue cleared!')
Advanced Usage
Auto-disconnect on Queue End
@bot.salad.on('queueEnd')
async def on_queue_end(player):
channel = bot.get_channel(player.textChannel)
if channel:
await channel.send('📭 Queue ended. Disconnecting in 5 minutes...')
await asyncio.sleep(300)
if len(player.queue) == 0 and not player.playing:
await player.destroy()
guild = bot.get_guild(player.guildId)
if guild and guild.voice_client:
await guild.voice_client.disconnect()
Progress Bar
def create_progress_bar(position: int, duration: int, length: int = 20) -> str:
if duration == 0:
return '─' * length
filled = int((position / duration) * length)
bar = '━' * filled + '○' + '─' * (length - filled - 1)
return bar
@bot.tree.command(name='progress')
async def progress_command(interaction: discord.Interaction):
await interaction.response.defer()
player = bot.salad.getPlayer(interaction.guild.id)
if not player or not player.currentTrackObj:
await interaction.followup.send('❌ Nothing is playing!')
return
track = player.currentTrackObj
duration = track.duration if hasattr(track, 'duration') else 0
position = player.position
bar = create_progress_bar(position, duration)
duration_str = f'{duration // 60000}:{(duration // 1000) % 60:02d}'
position_str = f'{position // 60000}:{(position // 1000) % 60:02d}'
await interaction.followup.send(f'`{position_str}` {bar} `{duration_str}`')
All playback control methods are asynchronous and should be awaited. The player automatically handles queue management and track progression.
Always check if a player exists before attempting to control it. Use
bot.salad.getPlayer(guild_id) to retrieve the player instance.