Add an import command for playlists; handle new downloading method of songs
This commit is contained in:
parent
56ca4dabf2
commit
0be369fb79
120
cogs/music.py
120
cogs/music.py
|
@ -92,12 +92,8 @@ class VoiceState:
|
|||
if self.playing or not self.voice:
|
||||
return
|
||||
if self.current:
|
||||
source = FFmpegPCMAudio(
|
||||
self.current.filename,
|
||||
before_options='-nostdin',
|
||||
options='-vn -b:a 128k'
|
||||
)
|
||||
source = PCMVolumeTransformer(source, volume=self.volume)
|
||||
# Transform our source into a volume source
|
||||
source = PCMVolumeTransformer(self.current, volume=self.volume)
|
||||
self.voice.play(source, after=self.after)
|
||||
self.current.start_time = time.time()
|
||||
# We handle users who join a user queue without songs (either at all, or ready) elsewhere
|
||||
|
@ -110,13 +106,7 @@ class VoiceState:
|
|||
|
||||
async def next_song(self):
|
||||
if not self.user_queue:
|
||||
_result = await self.songs.get_next_entry()
|
||||
if _result:
|
||||
fut, self.current = _result
|
||||
if fut.exception():
|
||||
raise ExtractionError(fut.exception())
|
||||
else:
|
||||
self.current = None
|
||||
self.current = await self.songs.next_entry()
|
||||
else:
|
||||
try:
|
||||
dj = self.djs.popleft()
|
||||
|
@ -124,13 +114,7 @@ class VoiceState:
|
|||
self.dj = None
|
||||
self.current = None
|
||||
else:
|
||||
_result = await dj.get_next_entry()
|
||||
if _result:
|
||||
fut, song = _result
|
||||
else:
|
||||
return await self.next_song()
|
||||
if fut.exception():
|
||||
raise ExtractionError(fut.exception())
|
||||
song = await dj.next_entry()
|
||||
# Add an extra check here in case in the very short period of time possible, someone has queued a
|
||||
# song while we are downloading the next...which caused 2 play calls to be done
|
||||
# The 2nd may be called while the first has already started playing...this check is for that 2nd one
|
||||
|
@ -161,6 +145,15 @@ class Music:
|
|||
self.downloader = down
|
||||
self.bot.downloader = down
|
||||
|
||||
def __unload(self):
|
||||
for state in self.voice_states.values():
|
||||
try:
|
||||
if state.voice:
|
||||
state.voice.stop()
|
||||
self.bot.loop.create_task(state.voice.disconnect())
|
||||
except:
|
||||
pass
|
||||
|
||||
async def queue_embed_task(self, state, channel, author):
|
||||
index = 0
|
||||
message = None
|
||||
|
@ -197,7 +190,7 @@ class Music:
|
|||
dj = entry
|
||||
entry = entry.peek()
|
||||
# Get the entry's embed
|
||||
embed = entry.to_embed()
|
||||
embed = entry.embed
|
||||
|
||||
# Set the embed's title to indicate the amount of things in the queue
|
||||
count = len(queue)
|
||||
|
@ -326,12 +319,44 @@ class Music:
|
|||
|
||||
async def add_entry(self, song, ctx):
|
||||
state = self.voice_states[ctx.message.guild.id]
|
||||
entry, _ = await state.songs.add_entry(song)
|
||||
entry = await state.songs.add_entry(song)
|
||||
if not state.playing:
|
||||
await state.play_next_song()
|
||||
self.bot.loop.create_task(state.play_next_song())
|
||||
entry.requester = ctx.message.author
|
||||
return entry
|
||||
|
||||
async def import_playlist(self, url, ctx):
|
||||
state = self.voice_states[ctx.message.guild.id]
|
||||
try:
|
||||
msg = await ctx.send("Looking up {}\nThis may take a while...".format(url))
|
||||
except:
|
||||
msg = None
|
||||
|
||||
num_songs = None
|
||||
successful = 0
|
||||
failed = 0
|
||||
fmt = "Downloading {} songs\n{} successful\n{} failed"
|
||||
if msg:
|
||||
# Go through each song in the playlist
|
||||
async for success in state.songs.import_from(url, ctx.message.author):
|
||||
# If this hasn't been set yet, the first yield is the number of songs
|
||||
# Otherwise just add one based on successful or not
|
||||
if not num_songs:
|
||||
num_songs = success
|
||||
elif success:
|
||||
# If we're not playing yet and this is the first successful one we found
|
||||
if not state.playing and successful == 0:
|
||||
await state.play_next_song()
|
||||
successful += 1
|
||||
else:
|
||||
failed += 1
|
||||
try:
|
||||
await msg.edit(content=fmt.format(num_songs, successful, failed))
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
await state.songs.import_from(url)
|
||||
|
||||
async def join_channel(self, channel, text_channel):
|
||||
state = self.voice_states.get(channel.guild.id)
|
||||
log.info("Joining channel {} in guild {}".format(channel.id, channel.guild.id))
|
||||
|
@ -436,6 +461,37 @@ class Music:
|
|||
|
||||
return await self.join_channel(channel, ctx.channel)
|
||||
|
||||
@commands.command(name='import')
|
||||
@commands.guild_only()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
@utils.check_restricted()
|
||||
async def _import(self, ctx, *, song: str):
|
||||
"""Imports a song into the current voice queue"""
|
||||
# If we don't have a voice state yet, create one
|
||||
if not self.bot.db.load('server_settings', key=ctx.message.guild.id, pluck='playlists_allowed'):
|
||||
await ctx.send("You cannot import playlists at this time; the {}allowplaylists command can be used to change this setting".format(ctx.prefix))
|
||||
return
|
||||
if ctx.message.guild.id not in self.voice_states:
|
||||
if not await ctx.invoke(self.join):
|
||||
return
|
||||
state = self.voice_states.get(ctx.message.guild.id)
|
||||
# If this is a user queue, this is the wrong command
|
||||
if state.user_queue:
|
||||
await ctx.send("The current queue type is the DJ queue. "
|
||||
"Use the command {}dj to join this queue".format(ctx.prefix))
|
||||
return
|
||||
# Ensure the user is in the voice channel
|
||||
try:
|
||||
if ctx.message.author.voice.channel != ctx.message.guild.me.voice.channel:
|
||||
await ctx.send("You need to be in the channel to use this command!")
|
||||
return
|
||||
except AttributeError:
|
||||
await ctx.send("You need to be in the channel to use this command!")
|
||||
return
|
||||
|
||||
song = re.sub('[<>\[\]]', '', song)
|
||||
await self.import_playlist(song, ctx)
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
|
@ -462,8 +518,10 @@ class Music:
|
|||
try:
|
||||
if ctx.message.author.voice.channel != ctx.message.guild.me.voice.channel:
|
||||
await ctx.send("You need to be in the channel to use this command!")
|
||||
return
|
||||
except AttributeError:
|
||||
await ctx.send("You need to be in the channel to use this command!")
|
||||
return
|
||||
|
||||
song = re.sub('[<>\[\]]', '', song)
|
||||
if len(song) == 11:
|
||||
|
@ -472,12 +530,17 @@ class Music:
|
|||
# Youtube will still succeed if this *is* an ID provided, if there's a . after
|
||||
song += "."
|
||||
|
||||
try:
|
||||
msg = await ctx.send("Looking up {}...".format(song))
|
||||
except:
|
||||
msg = None
|
||||
|
||||
try:
|
||||
entry = await self.add_entry(song, ctx)
|
||||
except LiveStreamError as e:
|
||||
await ctx.send(str(e))
|
||||
except WrongEntryTypeError:
|
||||
await ctx.send("Cannot enqueue playlists at this time.")
|
||||
await ctx.send("Please use the {}import command to import a playlist.".format(ctx.prefix))
|
||||
except ExtractionError as e:
|
||||
error = e.message.split('\n')
|
||||
if len(error) >= 3:
|
||||
|
@ -496,9 +559,12 @@ class Music:
|
|||
if entry is None:
|
||||
await ctx.send("Sorry but I couldn't download/find {}".format(song))
|
||||
else:
|
||||
embed = entry.to_embed()
|
||||
embed = entry.embed
|
||||
embed.title = "Enqueued song!"
|
||||
await ctx.send(embed=embed)
|
||||
try:
|
||||
await msg.edit(content=None, embed=embed)
|
||||
except:
|
||||
await ctx.send(embed=embed)
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
|
@ -727,7 +793,7 @@ class Music:
|
|||
fmt = "{0[0]}m {0[1]}s/{1[0]}m {1[1]}s".format(progress, length)
|
||||
embed.add_field(name='Progress', value=fmt, inline=False)
|
||||
# And send the embed
|
||||
await ctx.send(embed=embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
|
|
Loading…
Reference in a new issue