Browse Source

Added more things to the player object to reference in other commands; moved queue logic to be a background task as then it will actually work and won't run too many times like before; added cooldowns to play and stream commands to try and reduce errors when users try and play too many things at once in a short time, this was caused by the speed issues; now cleans playlist when ;stop is issued; nowplaying command now has better output. Also cleaned up the todo list. Still a bit to good before ill let anyone touch this. Probably the most tested part of roxbot.

tags/v1.6.0
Roxie Gibson 6 years ago
parent
commit
33589b95c5
1 changed files with 32 additions and 29 deletions
  1. +32
    -29
      Roxbot/cogs/voice.py

+ 32
- 29
Roxbot/cogs/voice.py View File

import os
import asyncio import asyncio
import discord import discord
import youtube_dl import youtube_dl
super().__init__(source, volume) super().__init__(source, volume)
self.data = data self.data = data
self.title = data.get('title') self.title = data.get('title')
self.uploader = data.get("uploader")
self.url = data.get('url') self.url = data.get('url')
self.webpage_url = data.get('webpage_url')
self.duration = data.get("duration") self.duration = data.get("duration")
self.host = data.get("extractor_key")
self.webpage_url = data.get('webpage_url')
self.thumbnail_url = data.get("thumbnail", "")


@classmethod @classmethod
async def from_url(cls, url, *, loop=None, stream=False): async def from_url(cls, url, *, loop=None, stream=False):
self.skip_votes[guild.id] = [] self.skip_votes[guild.id] = []
self.now_playing[guild.id] = None self.now_playing[guild.id] = None


# TODO: Better documentation
# TODO: Clean up outputs

@commands.command() @commands.command()
async def join(self, ctx, *, channel: discord.VoiceChannel = None): async def join(self, ctx, *, channel: discord.VoiceChannel = None):
"""Joins the voice channel your in.""" """Joins the voice channel your in."""


await channel.connect() await channel.connect()


async def queue_logic(self, ctx):
if ctx.voice_client.source == self.now_playing[ctx.guild.id]:
sleep_for = 0.5
while ctx.voice_client.is_playing():
await asyncio.sleep(sleep_for)
if self.playlist[ctx.guild.id]:
player = self.playlist[ctx.guild.id].pop(0)
if player.get("stream", False) is True:
command = self.stream
else:
command = self.play
await ctx.invoke(command, url=player.get("webpage_url"))

@commands.command(hidden=True) @commands.command(hidden=True)
async def play_local(self, ctx, *, query): async def play_local(self, ctx, *, query):
"""Plays a file from the local filesystem.""" """Plays a file from the local filesystem."""


await ctx.send('Now playing: {}'.format(query)) await ctx.send('Now playing: {}'.format(query))


@commands.cooldown(1, 0.5, commands.BucketType.guild)
@commands.command() @commands.command()
async def play(self, ctx, *, url): async def play(self, ctx, *, url):
"""Plays from a url (almost anything youtube_dl supports)""" """Plays from a url (almost anything youtube_dl supports)"""
if not ctx.voice_client.is_playing() or self.now_playing[ctx.guild.id] is None: if not ctx.voice_client.is_playing() or self.now_playing[ctx.guild.id] is None:
async with ctx.typing(): async with ctx.typing():
player = await YTDLSource.from_url(url, loop=self.bot.loop) player = await YTDLSource.from_url(url, loop=self.bot.loop)

self.now_playing[ctx.guild.id] = player self.now_playing[ctx.guild.id] = player
ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None) ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)
self.bot.loop.create_task(self.queue_logic(ctx))
await ctx.send('Now playing: {}'.format(player.title)) await ctx.send('Now playing: {}'.format(player.title))
else: else:
player = ytdl.extract_info(url, download=False) player = ytdl.extract_info(url, download=False)
self.playlist[ctx.guild.id].append(player) self.playlist[ctx.guild.id].append(player)
await ctx.send("{} added to queue".format(player.get("title"))) await ctx.send("{} added to queue".format(player.get("title")))


@commands.cooldown(1, 0.5, commands.BucketType.guild)
@commands.command() @commands.command()
async def stream(self, ctx, *, url): async def stream(self, ctx, *, url):
"""Streams from a url (same as yt, but doesn't predownload)""" """Streams from a url (same as yt, but doesn't predownload)"""
# TODO: Queuing stuff like with play
if not ctx.voice_client.is_playing(): if not ctx.voice_client.is_playing():
async with ctx.typing(): async with ctx.typing():
player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True) player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True)

self.now_playing[ctx.guild.id] = player self.now_playing[ctx.guild.id] = player
ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None) ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)
self.bot.loop.create_task(self.queue_logic(ctx))
await ctx.send('Now playing: {}'.format(player.title)) await ctx.send('Now playing: {}'.format(player.title))
else: else:
player = ytdl.extract_info(url, download=False) player = ytdl.extract_info(url, download=False)
if ctx.author.voice: if ctx.author.voice:
await ctx.author.voice.channel.connect() await ctx.author.voice.channel.connect()
else: else:
raise commands.CommandError("Author not connected to a voice channel.")

@play.after_invoke
@stream.after_invoke
async def queue_logic(self, ctx):
if ctx.voice_client.source == self.now_playing[ctx.guild.id]:
sleep_for = 0.5
while ctx.voice_client.is_playing():
await asyncio.sleep(sleep_for)
ctx.voice_client.stop()
if self.playlist[ctx.guild.id]:
player = self.playlist[ctx.guild.id].pop(0)
if player.get("stream", False) is True:
command = self.stream
else:
command = self.play
await ctx.invoke(command, url=player.get("webpage_url"))
raise commands.CommandError("Roxbot is not connected to a voice channel and couldn't auto-join a voice channel.")


@volume_perms() @volume_perms()
@commands.command() @commands.command()
if ctx.voice_client is None: if ctx.voice_client is None:
raise commands.CommandError("Roxbot is not in a voice channel.") raise commands.CommandError("Roxbot is not in a voice channel.")
else: else:
self.playlist[ctx.guild.id] = []
self.now_playing[ctx.guild.id] = None self.now_playing[ctx.guild.id] = None
return await ctx.voice_client.disconnect() return await ctx.voice_client.disconnect()


if self.now_playing[ctx.guild.id] is None: if self.now_playing[ctx.guild.id] is None:
return await ctx.send("Nothing is playing.") return await ctx.send("Nothing is playing.")
else: else:
return await ctx.send("Now playing: {}".format(ctx.voice_client.source.title))
np = ctx.voice_client.source
embed = discord.Embed(title="Now playing: '{}' from {}".format(np.title, np.host), colour=0xDEADBF)
embed.description = "Uploaded by: {0.uploader}\nURL: {0.webpage_url}".format(np)
embed.set_image(url=np.thumbnail_url)
return await ctx.send(embed=embed)


@commands.command() @commands.command()
async def skip(self, ctx): async def skip(self, ctx):
# This should be fine as the queue_logic function should handle moving to the next song and all that. # This should be fine as the queue_logic function should handle moving to the next song and all that.
self.now_playing[ctx.guild.id] = None self.now_playing[ctx.guild.id] = None
ctx.voice_client.stop() ctx.voice_client.stop()
print("hello")
else: else:
await ctx.send("I'm not playing anything.") await ctx.send("I'm not playing anything.")


# TODO: Playlist, Queue, Skip Votes commands # TODO: Playlist, Queue, Skip Votes commands
# TODO: Speed Improvements, better cooldown, reduce errors
# TODO: Better documentation
# TODO: Clean up outputs
# TODO: Maybe autoclean the cache


def setup(bot_client): def setup(bot_client):
bot_client.add_cog(Music(bot_client)) bot_client.add_cog(Music(bot_client))

Loading…
Cancel
Save