Esempio n. 1
0
    async def subreddit(self, ctx, subreddit):
        """
        Grabs an image or video (jpg, png, gif, gifv, webm, mp4) from the subreddit inputted.
        Example:
        {command_prefix}subreddit pics
        """
        subreddit = subreddit.lower()
        if isinstance(ctx.channel, discord.DMChannel):
            cache_id = ctx.author.id
            nsfw_allowed = True
        else:  # Is text channel in guild
            cache_id = ctx.guild.id
            nsfw_allowed = ctx.channel.is_nsfw()

        self.scrapper.cache_refresh(cache_id)
        posts = await self.scrapper.sub_request(subreddit)

        if not posts:
            raise roxbot.UserError(self.SUB_NOT_FOUND)

        choice = await self.scrapper.random(posts["children"], cache_id,
                                            nsfw_allowed)

        if not choice:
            raise commands.CommandError(self.NO_IMAGES)
        elif choice.get("success", True) is False:
            raise roxbot.UserError(self.NSFW_FAIL)

        title = "**{}** \nby /u/{} from /r/{}\n".format(
            unescape(choice["title"]), unescape(choice["author"]), subreddit)
        url = str(choice["url"])

        if url.split("/")[-2] == "a":
            text = "This is an album, click on the link to see more.\n"
        else:
            text = ""

        # Not using a embed here because we can't use video in rich embeds but they work in embeds now :/
        output = await ctx.send(title + text + url)
        await self.bot.delete_option(output,
                                     self.bot.get_emoji(444410658101002261))

        if ctx.invoked_with == "subreddit" and isinstance(
                ctx.channel, discord.TextChannel):
            # Only log the command when it is this command being used. Not the inbuilt commands.
            await self.bot.log(ctx.guild,
                               "subreddit",
                               User=ctx.author,
                               Subreddit=subreddit,
                               Returned="<{}>".format(url),
                               Channel=ctx.channel,
                               Channel_Mention=ctx.channel.mention,
                               Time=roxbot.datetime.format(
                                   ctx.message.created_at))
Esempio n. 2
0
    async def join(self, ctx, *, channel: discord.VoiceChannel = None):
        """Summon Roxbot to a voice channel, usually the one you are currently in.

        This is done automatically when you execute the `;play` or `;stream` commands.

        Options:

            - `Voice Channel` - OPTIONAL. The name of a Voice Channel

        Example:
            # Join a voice channle called General
            ;join General
        """
        # Get channel
        if channel is None:
            try:
                channel = ctx.author.voice.channel
            except AttributeError:
                raise roxbot.UserError(
                    "Failed to join voice channel. Please specify a channel or join one for Roxbot to join."
                )

        # Join VoiceChannel
        if ctx.voice_client is not None:
            await ctx.voice_client.move_to(channel)
        else:
            await channel.connect()
        return await ctx.send("Joined {0.name} :ok_hand:".format(channel))
Esempio n. 3
0
 async def ensure_voice(self, ctx):
     """Ensures the bot is in a voice channel before continuing and if it cannot auto join, raise an error."""
     if ctx.voice_client is None:
         if ctx.author.voice:
             await ctx.author.voice.channel.connect()
         else:
             raise roxbot.UserError(
                 "Roxbot is not connected to a voice channel and couldn't auto-join a voice channel."
             )
Esempio n. 4
0
    async def remove(self, ctx, index):
        """Removes a item from the queue with the given index.

        Options:
            - `index/all` - A number representing an index in the queue to remove one video, or "all" to clear all videos.

        Examples:
            # Remove 2nd video
            ;remove 2
            # Clear the queue
            ;remove all
        """
        # Try and convert index into an into. If not possible, just move forward
        try:
            index = int(index)
        except ValueError:
            pass

        # If not str "all" or an int, raise error.
        if index != "all" and not isinstance(index, int):
            raise roxbot.UserError("No valid option given.")
        elif index == "all":
            # Remove all queued items
            length = len(self.playlist[ctx.guild.id])
            self.playlist[ctx.guild.id] = []
            return await ctx.send(
                "Removed all queued videos. ({})".format(length))
        else:
            try:
                # Try and remove item using index.
                removed = self.playlist[ctx.guild.id].pop(
                    index -
                    1)  # -1 because queue index shown starts from 1, not 0
                return await ctx.send("Removed '{}' from the queue.".format(
                    removed.get("title", index)))
            except IndexError:
                raise roxbot.UserError("Valid Index not given.")
Esempio n. 5
0
    async def edit(self, ctx, command, *edit):
        """Edits an existing custom command.

        Example:
            # edit a command called test to output "new output"
            ;cc edit test "new output"

        For more examples of how to setup a custom command, look at the help for the ;custom add command.
        You cannot change the type of a command. If you want to change the type, remove the command and re-add it.
        """
        if ctx.message.mentions or ctx.message.mention_everyone or ctx.message.role_mentions:
            raise roxbot.UserError(self.ERROR_AT_MENTION)

        if not edit:
            raise commands.BadArgument("Missing required argument: edit")

        with db_session:
            query = CCCommands.get(name=command.lower(), guild_id=ctx.guild.id)
            if query:
                if query.type == 2:
                    if len(edit) < 2:
                        raise roxbot.UserError(self.ERROR_EMBED_VALUE)
                    try:
                        edit = self._embed_parse_options(edit)
                        query.output = edit
                        return await ctx.send(
                            self.OUTPUT_EDIT.format(command, edit))
                    except ValueError:
                        raise roxbot.UserError(self.ERROR_OUTPUT_TOO_LONG)
                else:
                    query.output = edit
                    return await ctx.send(
                        self.OUTPUT_EDIT.format(
                            command, edit if len(edit) > 1 else edit[0]))
            else:
                raise roxbot.UserError(self.ERROR_COMMAND_NULL)
Esempio n. 6
0
    async def remove(self, ctx, command):
        """Removes a custom command.

        Example:
            # Remove custom command called "test"
            ;cc remove test
        """

        command = command.lower()

        with db_session:
            c = CCCommands.get(name=command, guild_id=ctx.guild.id)
            if c:
                c.delete()
                return await ctx.send(self.OUTPUT_REMOVE.format(command))
            else:
                raise roxbot.UserError(self.ERROR_COMMAND_NULL)
Esempio n. 7
0
    async def volume(self, ctx, volume: int):
        """
        Sets the volume percentage for Roxbot's audio.

        The current volume of Roxbot is displayed by her nowplaying rich embeds that are displayed when she begins to play a video or when the `;nowplaying` command is used.

        Options:

            - `percent` - A positive integer between 0-100 representing a percentage.

        Example:
            # Set volume to 20%
            ;volume 20
        """
        if 0 <= volume <= 100:
            ctx.voice_client.source.volume = volume / 100  # Volume needs to be a float between 0 and 1... kinda
            self._volume[
                ctx.guild.
                id] = volume / 100  # Volume needs to be a float between 0 and 1... kinda
        else:
            raise roxbot.UserError("Volume needs to be between 0-100%")
        return await ctx.send("Changed volume to {}%".format(volume))
Esempio n. 8
0
    async def add(self, ctx, command_type, command, *output):
        """Adds a custom command to the list of custom commands.

        Options:
            - `type` - There are three types of custom commands.
                - `no_prefix`/`0` - These are custom commands that will trigger without a prefix. Example: a command named `test` will trigger when a user says `test` in chat.
                - `prefix`/`1` - These are custom commands that will trigger with a prefix. Example: a command named `test` will trigger when a user says `;test` in chat.
                - `embed`/`2` - These are prefix commands that will output a rich embed. [You can find out more about rich embeds from Discord's API documentation.](https://discordapp.com/developers/docs/resources/channel#embed-object) Embed types currently support these fields: `title, description, colour, color, url, footer, image, thumbnail`
            - `name` - The name of the command. No commands can have the same name.
            - `output` - The output of the command. The way you input this is determined by the type.

            `no_prefix` and `prefix` types support single outputs and also listing multiple outputs. When the latter is chosen, the output will be a random choice of the multiple outputs.

        Examples:
            # Add a no_prefix command called "test" with a URL output.
            ;cc add no_prefix test "https://www.youtube.com/watch?v=vJZp6awlL58"
            # Add a prefix command called test2 with a randomised output between "the person above me is annoying" and "the person above me is cool :sunglasses:"
            ;cc add prefix test2 "the person above me is annoying" "the person above me is cool :sunglasses:
            # Add an embed command called test3 with a title of "Title" and a description that is a markdown hyperlink to a youtube video, and the colour #deadbf
            ;cc add embed test3 title "Title" description "[Click here for a rad video](https://www.youtube.com/watch?v=dQw4w9WgXcQ)" colour #deadbf

        Note: With custom commands, it is important to remember that "" is used to pass any text with spaces as one argument. If the output you want requires the use of these characters, surround your output with three speech quotes at either side instead.
        """
        command = command.lower()

        if command_type in ("0", "no_prefix", "no prefix"):
            command_type = 0
        elif command_type in ("1", "prefix"):
            command_type = 1
        elif command_type in ("2", "embed"):
            command_type = 2
            if len(output) < 2:
                raise roxbot.UserError(self.ERROR_EMBED_VALUE)
            try:
                output = self._embed_parse_options(output)
            except ValueError:
                raise roxbot.UserError(self.ERROR_OUTPUT_TOO_LONG)
        else:
            raise roxbot.UserError(self.ERROR_INCORRECT_TYPE)

        with db_session:

            if ctx.message.mentions or ctx.message.mention_everyone or ctx.message.role_mentions:
                raise roxbot.UserError(self.ERROR_AT_MENTION)
            elif len(output) > 1800:
                raise roxbot.UserError(self.ERROR_OUTPUT_TOO_LONG)
            elif command in self.bot.all_commands.keys() and command_type == 1:
                raise roxbot.UserError(self.ERROR_COMMAND_EXISTS_INTERNAL)
            elif select(c for c in CCCommands if c.name == command
                        and c.guild_id == ctx.guild.id).exists():
                raise roxbot.UserError(self.ERROR_COMMAND_EXISTS)
            elif len(command.split(" ")) > 1 and command_type == "1":
                raise roxbot.UserError(self.ERROR_PREFIX_SPACE)

            CCCommands(name=command,
                       guild_id=ctx.guild.id,
                       output=output,
                       type=command_type)

        return await ctx.send(
            self.OUTPUT_ADD.format(
                command, output
                if len(output) > 1 or isinstance(output, dict) else output[0]))
Esempio n. 9
0
 async def check_playing(self, ctx):
     try:
         if not ctx.voice_client.is_playing():
             raise roxbot.UserError("I'm not playing anything.")
     except AttributeError:
         raise roxbot.UserError("I'm not playing anything.")
Esempio n. 10
0
 async def check_in_voice(self, ctx):
     if ctx.voice_client is None:
         raise roxbot.UserError("Roxbot is not in a voice channel.")
Esempio n. 11
0
    async def play(self,
                   ctx,
                   *,
                   url,
                   stream=False,
                   from_queue=False,
                   queued_by=None):
        """Plays a video over voice chat using the given URL. This URL has to be one that YoutubeDL can download from. [A list can be found here.](https://rg3.github.io/youtube-dl/supportedsites.html)

        If the bot is already playing something, this will be queued up to be played later. If you want to play a livestream, use the `;stream` command.

        The user needs to be in a voice channel for this command to work. This is ignored if the user has the `manage_channels` permission. There is also a duration limit that can be placed on videos. This is also ignored if the user has the `manage_channels` permission.


        Options:

            - `url` -  A url to a video or playlist or a search term. If a playlist, it will play the first video and queue up all other videos in the playlist. If just text, Roxbot will play the first Youtube search result.

        Examples:
            # Play the quality youtube video
            ;play https://www.youtube.com/watch?v=3uOPGkEJ56Q
        """
        guild = ctx.guild
        with db_session:
            max_duration = VoiceSingle.get(guild_id=guild.id).max_length

        # Checks if invoker is in voice with the bot. Skips admins and mods and owner and if the song was queued previously.
        if not (roxbot.utils.has_permissions_or_owner(
                ctx, manage_channels=True) or from_queue):
            if not ctx.author.voice:
                raise roxbot.UserError(
                    "You're not in the same voice channel as Roxbot.")
            if ctx.author.voice.channel != ctx.voice_client.channel:
                raise roxbot.UserError(
                    "You're not in the same voice channel as Roxbot.")

        # For internal speed. This should make the playlist management quicker when play is being invoked internally.
        if isinstance(url, dict):
            video = url
            url = video.get("webpage_url")
        else:
            video = ytdl.extract_info(url, download=False)

        # Playlist and search handling.
        if 'entries' in video and video.get(
                "extractor_key") != "YoutubeSearch":
            await ctx.send(
                "Looks like you have given me a playlist. I will queue up all {} videos in the playlist."
                .format(len(video.get("entries"))))
            data = dict(video)
            video = data["entries"].pop(0)
            for entry in data["entries"]:
                self._queue_song(ctx, entry, stream)

        elif 'entries' in video and video.get(
                "extractor_key") == "YoutubeSearch":
            video = video["entries"][0]

        # Duration limiter handling
        if video.get(
                "duration", 1
        ) > max_duration and not roxbot.utils.has_permissions_or_owner(
                ctx, manage_channels=True):
            raise roxbot.UserError(
                "Cannot play video, duration is bigger than the max duration allowed."
            )

        # Actual playing stuff section.
        # If not playing and not queuing, and not paused, play the song. Otherwise queue it.
        if (not ctx.voice_client.is_playing() and self.am_queuing[guild.id] is
                False) and not ctx.voice_client.is_paused():
            self.am_queuing[guild.id] = True
            async with ctx.typing():
                await self._play(ctx, url, stream, queued_by)
            self.am_queuing[ctx.guild.id] = False

            embed = NowPlayingEmbed.make(self.now_playing[ctx.guild.id],
                                         "Now Playing")
            await ctx.send(embed=embed)
        else:
            # Queue the song as there is already a song playing or paused.
            self._queue_song(ctx, video, stream)

            # Sleep because if not, queued up things will send first and probably freak out users or something
            while self.am_queuing[guild.id] is True:
                await asyncio.sleep(self.refresh_rate)
            embed = discord.Embed(description='Added "{}" to queue'.format(
                video.get("title")),
                                  colour=roxbot.EmbedColours.pink)
            await ctx.send(embed=embed)