I have been having issues with my queue feature as it would either delete two elements from the playlist dictionary at once when I skip a song using a command or it comes up with bugs when I let the songs finish- whenever I try to come up with a fix which would resolve both issues.
This is the relevant code -
def queueCheck(self, ctx, id, vc):
text = ""
if queues[id] != []: # if server player queue not empty
stream = queues[id].pop(0)
if self.skipping == True:
current[id] = tracks[id].pop(0)
if len(tracks[id]) != 0:
text = "Now playing **" tracks[ctx.message.guild.id][0] "**"
self.skipping = False
vc.play(stream, after=lambda e: self.queueCheck(ctx, id, vc))
else:
text = "Queue has finished playing!"
coro = ctx.send(text)
fut = asyncio.run_coroutine_threadsafe(coro, self.client.loop)
try:
fut.result()
except:
pass
async def playSong(self, ctx, url):
with youtube_dl.YoutubeDL(self.YDL_OPTIONS) as ydl:
info = ydl.extract_info(url, download=False)
if 'entries' in info: # if no url is input
url2 = info['entries'][0]['formats'][0]['url']
if ctx.message.guild.id not in tracks.keys():
tracks[ctx.message.guild.id] = [info['entries'][0]['title']]
else:
tracks[ctx.message.guild.id].append(info['entries'][0]['title'])
elif 'formats' in info: # if url is passed
url2 = info['formats'][0]['url']
if ctx.message.guild.id not in tracks.keys():
tracks[ctx.message.guild.id] = [info['title']]
else:
tracks[ctx.message.guild.id].append(info['title'])
#print(*(x for x in tracks[ctx.message.guild.id]), sep='\n')
stream = await discord.FFmpegOpusAudio.from_probe(url2, **self.FFMPEG_OPTIONS)
return stream
async def queue(self, ctx, url):
stream = await self.playSong(ctx, url)
guild = ctx.message.guild
if guild.id in queues:
queues[guild.id].append(stream)
await ctx.send('Added track ' '**' str(tracks[guild.id][len(tracks[guild.id]) - 1]) '**')
@commands.command(name='play', help="Plays any song", aliases=['pl'])
async def play(self, ctx, *, url):
if ctx.author.voice is None:
return await ctx.send('You are not in a voice channel!')
if ctx.voice_client is None:
await ctx.author.voice.channel.connect()
vc = ctx.guild.voice_client
guild = ctx.message.guild
if not vc.is_playing() and not self.isPaused:# and not self.skipping:
stream = await self.playSong(ctx, url)
queues[guild.id] = [stream]
vc.play(stream, after=lambda e: self.queueCheck(ctx, guild.id, vc))
await ctx.send('Playing ' '**' str(tracks[ctx.message.guild.id][0]) '**')
else:
await self.queue(ctx, url)
@commands.command(name='queue', help="Shows the current queue", aliases=['q','Q'])
async def showQueue(self, ctx):
if len(tracks[ctx.message.guild.id]) == 1:
queueEmbed = discord.Embed(title="Queue", description = "Your queue seems to be a tad bit empty :(", color=discord.Colour.random())
queueEmbed.add_field(name=':drum: Currently playing \n' tracks[ctx.message.guild.id][0], value='\u200b', inline=False)
await ctx.send(embed=queueEmbed)
elif len(tracks[ctx.message.guild.id]) > 0 or current[ctx.message.guild.id] is not None:
queueEmbed = discord.Embed(title="Queue", color=discord.Colour.random())
queuee = ""
if len(tracks[ctx.message.guild.id]) != 0:
for i in range(1, len(tracks[ctx.message.guild.id])):
queuee = ":white_small_square:" str(i) ". " tracks[ctx.message.guild.id][i] "\n"
else:
queuee = "No songs here"
queueEmbed.add_field(name='Coming up next', value='**' queuee '**', inline=False)
queueEmbed.add_field(name=':drum: Currently playing \n' tracks[ctx.message.guild.id][0], value='\u200b', inline=False)
await ctx.send(embed=queueEmbed)
else:
await ctx.send('No music in queue')
@commands.command(name='skip', help="Skips the current song")
async def skip(self, ctx):
if ctx.author.voice is None:
return await ctx.send('You are not in a voice channel!')
self.skipping = True
ctx.voice_client.stop()
self.isPaused = False
Cannot post the pic of the queue showing the wrong output but here is the output embed-
Queue
-Coming up next-
1. Song 2 # should be shown below
2. Song 3
-:drum: Currently playing-
Song 1 # has finished already
Basically, if I keep skipping my way through all the songs before they end, the queue will update, otherwise if I wait for them to finish, the queue never updates. I am aware that this has to do with the conditional check for self.skipping
which only lets me update the queue if I am skipping songs, but how can I pop off elements from track the moment the song ends at the same time?
CodePudding user response:
I'm not sure where you are getting the songs from as you haven't shown that section of your code, however I am going to assume you are using YoutubeDL. In the case of YoutubeDL, what you can do is extract the duration of the video in seconds, and then have a while loop counting up from 0 every second, once the counter reaches the same value as the duration of the video, just remove the track from the queue and carry on. For example:
def player():
with YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(queues[id][0], download=False)
vduration = info['duration']
link = info['url']
voice.play(FFmpegPCMAudio(link, **ffmpeg_opts))
voice.is_playing()
@commands.command()
asnyc def play(ctx, url)
queues[id].append(url)
#do everything you do here
while True:
if 0 <= 0 < len(queues[id]):
player()
counter = 0
while not counter >= vduration:
await asyncio.sleep(1)
counter = 1
queues[id].pop(0)
This is just an extremely simple example because as I said before it's hard to answer if you do not show all the relevant code, however it should apply regardless. Essentially all you need is to extract the duration of the video into a variable and then just count up 1 every second for as long as the video is playing, and then when variables match, move on to the next video.