Esempio n. 1
0
    async def setup(self, ctx: utils.TypedGuildContext,
                    channel: Optional[discord.TextChannel]):
        "Setup the bot to read messages from `<channel>`"
        if channel is None:
            select_view = utils.CommandView[discord.TextChannel](ctx)
            for channels in discord.utils.as_chunks(
                (channel for channel in ctx.guild.text_channels
                 if (channel.permissions_for(ctx.guild.me).read_messages
                     and channel.permissions_for(ctx.author).read_messages)),
                    25):
                try:
                    select_view.add_item(utils.ChannelSelector(ctx, channels))
                except ValueError:
                    return await ctx.send_error(
                        error=
                        "we cannot show a menu as this server has too many channels",
                        fix=
                        f"use the slash command or do `{ctx.prefix}setup #channel`"
                    )

            await ctx.reply("Select a channel!", view=select_view)
            channel = await select_view.wait()

        embed = discord.Embed(title="TTS Bot has been setup!",
                              description=cleandoc(f"""
                TTS Bot will now accept commands and read from {channel.mention}.
                Just do `{ctx.prefix}join` and start talking!
            """))
        embed.set_footer(text=pick_random(utils.FOOTER_MSGS))
        embed.set_thumbnail(url=self.bot.user.display_avatar.url)
        embed.set_author(name=ctx.author.display_name,
                         icon_url=ctx.author.display_avatar.url)

        await self.bot.settings.set(ctx.guild.id, {"channel": channel.id})
        await ctx.send(embed=embed)
    async def join(self, ctx: utils.TypedGuildContext):
        "Joins the voice channel you're in!"
        if not ctx.author.voice:
            return await ctx.send(
                "Error: You need to be in a voice channel to make me join your voice channel!"
            )

        voice_client = ctx.guild.voice_client
        voice_channel = ctx.author.voice.channel
        permissions = voice_channel.permissions_for(ctx.guild.me)

        if not permissions.view_channel:
            return await ctx.send(
                "Error: Missing Permission to view your voice channel!")

        if not permissions.speak:
            return await ctx.send("Error: I do not have permssion to speak!")

        if voice_client:
            if voice_client == voice_channel:
                await ctx.send("Error: I am already in your voice channel!")
            else:
                await ctx.send(
                    f"Error: I am in {voice_client.channel.mention}!")
            return

        join_embed = discord.Embed(
            title="Joined your voice channel!",
            description="Just type normally and TTS Bot will say your messages!"
        )
        join_embed.set_thumbnail(url=self.bot.user.avatar.url)
        join_embed.set_author(name=ctx.author.display_name,
                              icon_url=ctx.author.avatar.url)
        join_embed.set_footer(text=pick_random(utils.FOOTER_MSGS))

        try:
            await voice_channel.connect(cls=TTSVoicePlayer)  # type: ignore
        except asyncio.TimeoutError:
            return await ctx.send(
                "Error: Timed out when trying to join your voice channel!")

        await ctx.send(embed=join_embed)

        if self.bot.blocked:
            blocked_embed = discord.Embed(
                title="TTS Bot is currently blocked by Google")
            blocked_embed.description = cleandoc(f"""
                During this temporary block, voice has been swapped to a worse quality voice.
                If you want to avoid this, consider TTS Bot Premium, which you can get by donating via Patreon: `{ctx.prefix}donate`
            """)
            blocked_embed.set_footer(
                text=
                "You can join the support server for more info: discord.gg/zWPWwQC"
            )

            await ctx.send(embed=blocked_embed)
    async def voices(self, ctx: utils.TypedGuildContext, lang: Optional[str] = None):
        "Lists all the language codes that TTS bot accepts"
        if lang in tts_langs:
            return await self.voice(ctx, lang)

        lang = (await self.bot.userinfo.get("lang", ctx.author, default="en")).split("-")[0]
        langs_string = str(tts_langs).strip("{}")

        embed = discord.Embed(title="TTS Bot Languages")
        embed.set_footer(text=pick_random(utils.FOOTER_MSGS))
        embed.add_field(name="Currently Supported Languages", value=langs_string)
        embed.add_field(name="Current Language used", value=f"{langs_lookup[lang]} | {lang}")
        embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.avatar.url)

        await ctx.send(embed=embed)
Esempio n. 4
0
    async def setup(self, ctx, channel: discord.TextChannel):
        "Setup the bot to read messages from `<channel>`"
        await self.bot.settings.set(ctx.guild, "channel", str(channel.id))

        embed = discord.Embed(title="TTS Bot has been setup!",
                              description=cleandoc(f"""
                TTS Bot will now accept commands and read from {channel.mention}.
                Just do `-join` and start talking!
                """))
        embed.set_footer(text=pick_random(basic.footer_messages))
        embed.set_thumbnail(url=str(self.bot.user.avatar_url))
        embed.set_author(name=ctx.author.display_name,
                         icon_url=str(ctx.author.avatar_url))

        await ctx.send(embed=embed)
Esempio n. 5
0
    async def voices(self, ctx, lang=None):
        "Lists all the language codes that TTS bot accepts"
        if lang in tts_langs:
            return await self.voice(ctx, lang)

        lang = await self.bot.userinfo.get("lang", ctx.author).split("-")[0]
        langs_string = basic.remove_chars(list(tts_langs.keys()), "[", "]")

        embed = discord.Embed(title="TTS Bot Languages")
        embed.set_footer(text=pick_random(basic.footer_messages))
        embed.add_field(name="Currently Supported Languages", value=langs_string)
        embed.add_field(name="Current Language used", value=f"{tts_langs[lang]} | {lang}")
        embed.set_author(name=ctx.author.display_name, icon_url=str(ctx.author.avatar_url))

        await ctx.send(embed=embed)
    async def setup(self, ctx: utils.TypedGuildContext, channel: discord.TextChannel):
        "Setup the bot to read messages from `<channel>`"
        await self.bot.settings.set(ctx.guild, "channel", channel.id)

        embed = discord.Embed(
            title="TTS Bot has been setup!",
            description=cleandoc(f"""
                TTS Bot will now accept commands and read from {channel.mention}.
                Just do `{ctx.prefix}join` and start talking!
            """)
        )
        embed.set_footer(text=pick_random(utils.FOOTER_MSGS))
        embed.set_thumbnail(url=self.bot.user.avatar.url)
        embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.avatar.url)

        await ctx.send(embed=embed)
Esempio n. 7
0
    async def join(self, ctx):
        "Joins the voice channel you're in!"
        if ctx.channel.id != int(await ctx.bot.settings.get(
                ctx.guild, "channel")):
            return await ctx.send(
                f"Error: Wrong channel, do {ctx.bot.command_prefix}channel get the channel that has been setup."
            )

        if not ctx.author.voice:
            return await ctx.send(
                "Error: You need to be in a voice channel to make me join your voice channel!"
            )

        channel = ctx.author.voice.channel
        permissions = channel.permissions_for(ctx.guild.me)

        if not permissions.view_channel:
            return await ctx.send(
                "Error: Missing Permission to view your voice channel!")

        if not permissions.speak or not permissions.use_voice_activation:
            return await ctx.send("Error: I do not have permssion to speak!")

        if ctx.guild.voice_client and ctx.guild.voice_client == channel:
            return await ctx.send("Error: I am already in your voice channel!")

        if ctx.guild.voice_client and ctx.guild.voice_client != channel:
            return await ctx.send("Error: I am already in a voice channel!")

        embed = discord.Embed(
            title="Joined your voice channel!",
            description="Just type normally and TTS Bot will say your messages!"
        )
        embed.set_thumbnail(url=str(self.bot.user.avatar_url))
        embed.set_author(name=ctx.author.display_name,
                         icon_url=str(ctx.author.avatar_url))
        embed.set_footer(text=pick_random(basic.footer_messages))

        self.bot.should_return[ctx.guild.id] = True
        self.bot.queue[ctx.guild.id] = dict()

        await channel.connect()
        self.bot.should_return[ctx.guild.id] = False

        await ctx.send(embed=embed)
Esempio n. 8
0
 def reset(self) -> None:
     self.already_playing = True
     self.word = pick_random(word_list)
     self.guessed_letters.clear()
     self.answer_list = [c for c in self.word]
     self.incorrect_left = 6
Esempio n. 9
0
 def start(self) -> None:
     self.already_playing = True
     self.word = pick_random(word_list)
     self.answer_list = [c for c in self.word]
     self.incorrect_left = 6
Esempio n. 10
0
    async def on_message(self, message):
        if message.guild is not None:
            # Get settings
            repeated_chars_limit, bot_ignore, max_length, autojoin, channel, prefix, xsaid = await self.bot.settings.get(
                message.guild,
                settings=(
                    "repeated_chars",
                    "bot_ignore",
                    "msg_length",
                    "auto_join",
                    "channel",
                    "prefix",
                    "xsaid",
                ))

            message_clean = message.clean_content.lower()
            starts_with_tts = message_clean.startswith(f"{prefix}tts")

            # if author is a bot and bot ignore is on
            if bot_ignore and message.author.bot:
                return

            # if not a webhook but still a user, return to fix errors
            if message.author.discriminator != "0000" and isinstance(
                    message.author, discord.User):
                return

            # if author is not a bot, and is not in a voice channel, and doesn't start with -tts
            if not message.author.bot and not message.author.voice and not starts_with_tts:
                return

            # if bot not in voice channel and autojoin is off
            if not message.guild.voice_client and not autojoin:
                return

            # Check if a setup channel
            if message.channel.id != channel:
                return

            # If message is empty and there is no attachments
            if not message_clean and not message.attachments:
                return

            # Ignore messages starting with -
            if message_clean.startswith(prefix) and not starts_with_tts:
                return

            # if not autojoin and message doesn't start with tts and the author isn't a bot and the author is in the wrong voice channel
            if not autojoin and not starts_with_tts and not message.author.bot and message.author.voice.channel != message.guild.voice_client.channel:
                return

            # Auto Join
            if not message.guild.voice_client and autojoin:
                try:
                    voice_channel = message.author.voice.channel
                except AttributeError:
                    return

                await voice_channel.connect(cls=TTSVoicePlayer)

            # Get lang
            lang = await self.bot.userinfo.get("lang",
                                               message.author,
                                               default="en")

            # Emoji filter
            message_clean = basic.emojitoword(message_clean)

            # Acronyms and removing -tts
            message_clean = f" {message_clean} "
            acronyms = {
                "iirc": "if I recall correctly",
                "afaik": "as far as I know",
                "wdym": "what do you mean",
                "imo": "in my opinion",
                "brb": "be right back",
                "irl": "in real life",
                "jk": "just kidding",
                "btw": "by the way",
                ":)": "smiley face",
                "gtg": "got to go",
                "rn": "right now",
                ":(": "sad face",
                "ig": "i guess",
                "rly": "really",
                "cya": "see ya",
                "ik": "i know",
                "uwu": "oowoo",
                "@": "at",
                "™️": "tm"
            }

            if starts_with_tts:
                acronyms[f"{prefix}tts"] = ""

            for toreplace, replacewith in acronyms.items():
                message_clean = message_clean.replace(f" {toreplace} ",
                                                      f" {replacewith} ")

            message_clean = message_clean[1:-1]
            if message_clean == "?":
                message_clean = "what"

            # Regex replacements
            regex_replacements = {
                r"\|\|.*?\|\|": ". spoiler avoided.",
                r"```.*?```": ". code block.",
                r"`.*?`": ". code snippet.",
            }

            for regex, replacewith in regex_replacements.items():
                message_clean = re.sub(regex,
                                       replacewith,
                                       message_clean,
                                       flags=re.DOTALL)

            # Url filter
            with_urls = message_clean
            link_starters = ("https://", "http://", "www.")
            message_clean = " ".join(
                w if not w.startswith(link_starters) else ""
                for w in with_urls.split())

            contained_url = message_clean != with_urls
            # Toggleable xsaid and attachment + links detection
            if xsaid:
                said_name = await self.bot.nicknames.get(
                    message.guild, message.author)
                file_format = basic.exts_to_format(message.attachments)

                if contained_url:
                    if message_clean:
                        message_clean += " and sent a link."
                    else:
                        message_clean = "a link."

                if message.attachments:
                    if not message_clean:
                        message_clean = f"{said_name} sent {file_format}"
                    else:
                        message_clean = f"{said_name} sent {file_format} and said {message_clean}"
                else:
                    message_clean = f"{said_name} said: {message_clean}"

            elif contained_url:
                if message_clean:
                    message_clean += ". This message contained a link"
                else:
                    message_clean = "a link."

            if basic.remove_chars(message_clean, " ", "?", ".", ")", "'", "!",
                                  '"', ":") == "":
                return

            # Repeated chars removal if setting is not 0
            if message_clean.isprintable() and repeated_chars_limit != 0:
                message_clean_list = list()
                message_clean_chars = [
                    "".join(grp) for num, grp in groupby(message_clean)
                ]

                for char in message_clean_chars:
                    if len(char) > repeated_chars_limit:
                        message_clean_list.append(char[0] *
                                                  repeated_chars_limit)
                    else:
                        message_clean_list.append(char)

                message_clean = "".join(message_clean_list)

            # Adds filtered message to queue
            await message.guild.voice_client.queue(message, message_clean,
                                                   lang, channel, prefix,
                                                   max_length)

        elif not (message.author.bot or message.content.startswith("-")):
            pins = self.dm_pins.get(message.author.id, None)
            if not pins:
                self.dm_pins[
                    message.author.id] = pins = await message.author.pins()

            if any(map(self.is_welcome_message, pins)):
                if "https://discord.gg/" in message.content.lower():
                    await message.author.send(
                        f"Join https://discord.gg/zWPWwQC and look in <#694127922801410119> to invite {self.bot.user.mention}!"
                    )

                elif message.content.lower() == "help":
                    await asyncio.gather(
                        self.bot.channels["logs"].send(
                            f"{message.author} just got the 'dont ask to ask' message"
                        ),
                        message.channel.send(
                            "We cannot help you unless you ask a question, if you want the help command just do `-help`!"
                        ))

                elif not await self.bot.userinfo.get(
                        "blocked", message.author, default=False):
                    if not message.attachments and not message.content:
                        return

                    files = [
                        await attachment.to_file()
                        for attachment in message.attachments
                    ]
                    await self.bot.channels["dm_logs"].send(
                        message.content,
                        files=files,
                        username=str(message.author),
                        avatar_url=message.author.avatar_url)

            else:
                if len(pins) >= 49:
                    return await message.channel.send(
                        "Error: Pinned messages are full, cannot pin the Welcome to Support DMs message!"
                    )

                embed = discord.Embed(
                    title=f"Welcome to {self.bot.user.name} Support DMs!",
                    description=DM_WELCOME_MESSAGE).set_footer(
                        text=pick_random(basic.footer_messages))

                dm_message = await message.author.send(
                    "Please do not unpin this notice, if it is unpinned you will get the welcome message again!",
                    embed=embed)

                await asyncio.gather(
                    self.bot.channels["logs"].send(
                        f"{message.author} just got the 'Welcome to Support DMs' message"
                    ), dm_message.pin())
Esempio n. 11
0
    async def on_message(self, message):
        if message.guild is not None:
            saythis = message.clean_content.lower()

            # Get settings
            autojoin, bot_ignore, channel = await self.bot.settings.get(
                message.guild, settings=("auto_join", "bot_ignore", "channel"))

            starts_with_tts = saythis.startswith(
                f"{self.bot.command_prefix}tts")

            # if author is a bot and bot ignore is on
            if bot_ignore and message.author.bot:
                return

            # if not a webhook but still a user, return to fix errors
            if message.author.discriminator != "0000" and isinstance(
                    message.author, discord.User):
                return

            # if author is not a bot, and is not in a voice channel, and doesn't start with -tts
            if not message.author.bot and not message.author.voice and not starts_with_tts:
                return

            # if bot not in voice channel and autojoin is off
            if not message.guild.voice_client and not autojoin:
                return

            # Check if a setup channel
            if message.channel.id != int(channel):
                return

            # If message is empty and there is no attachments
            if not saythis and not message.attachments:
                return

            # Ignore messages starting with -
            if saythis.startswith(
                    self.bot.command_prefix) and not starts_with_tts:
                return

            # if not autojoin and message doesn't start with tts and the author isn't a bot and the author is in the wrong voice channel
            if not autojoin and not starts_with_tts and not message.author.bot and message.author.voice.channel != message.guild.voice_client.channel:
                return

            # Fix values
            if message.guild.id not in self.bot.queue:
                self.bot.queue[message.guild.id] = dict()
            if message.guild.id not in self.bot.message_locks:
                self.bot.message_locks[message.guild.id] = asyncio.Lock()

            should_return = self.bot.should_return.get(message.guild.id)

            # Auto Join
            if message.guild.voice_client is None and autojoin and not should_return:
                try:
                    channel = message.author.voice.channel
                except AttributeError:
                    return

                self.bot.should_return[message.guild.id] = True
                await channel.connect()
                self.bot.should_return[message.guild.id] = False

            # Get settings
            lang = await self.bot.setlangs.get(message.author)
            xsaid, repeated_chars_limit, msg_length = await self.bot.settings.get(
                message.guild,
                settings=("xsaid", "repeated_chars", "msg_length"))

            # Emoji filter
            saythis = basic.emojitoword(saythis)

            # Acronyms and removing -tts
            saythis = f" {saythis} "
            acronyms = {
                "iirc": "if I recall correctly",
                "afaik": "as far as I know",
                "wdym": "what do you mean",
                "imo": "in my opinion",
                "brb": "be right back",
                "irl": "in real life",
                "jk": "just kidding",
                "btw": "by the way",
                ":)": "smiley face",
                "gtg": "got to go",
                "rn": "right now",
                ":(": "sad face",
                "ig": "i guess",
                "rly": "really",
                "cya": "see ya",
                "ik": "i know",
                "uwu": "oowoo",
                "@": "at",
                "™️": "tm"
            }

            if starts_with_tts:
                acronyms["-tts"] = ""

            for toreplace, replacewith in acronyms.items():
                saythis = saythis.replace(f" {toreplace} ", f" {replacewith} ")

            saythis = saythis[1:-1]
            if saythis == "?":
                saythis = "what"

            # Regex replacements
            regex_replacements = {
                r"\|\|.*?\|\|": ". spoiler avoided.",
                r"```.*?```": ". code block.",
                r"`.*?`": ". code snippet.",
            }

            for regex, replacewith in regex_replacements.items():
                saythis = re.sub(regex, replacewith, saythis, flags=re.DOTALL)

            # Url filter
            contained_url = False
            for word in saythis.split(" "):
                if word.startswith(("https://", "http://", "www.")):
                    saythis = saythis.replace(word, "")
                    contained_url = True

            # Toggleable xsaid and attachment + links detection
            if xsaid:
                said_name = await self.bot.nicknames.get(
                    message.guild, message.author)
                format = basic.exts_to_format(message.attachments)

                if contained_url:
                    if saythis:
                        saythis += " and sent a link."
                    else:
                        saythis = "a link."

                if message.attachments:
                    if not saythis:
                        saythis = f"{said_name} sent {format}"
                    else:
                        saythis = f"{said_name} sent {format} and said {saythis}"
                else:
                    saythis = f"{said_name} said: {saythis}"

            elif contained_url:
                if saythis:
                    saythis += ". This message contained a link"
                else:
                    saythis = "a link."

            if basic.remove_chars(saythis, " ", "?", ".", ")", "'", "!",
                                  '"') == "":
                return

            # Repeated chars removal if setting is not 0
            repeated_chars_limit = int(repeated_chars_limit)
            if saythis.isprintable() and repeated_chars_limit != 0:
                saythis_chars = ["".join(grp) for num, grp in groupby(saythis)]
                saythis_list = list()

                for char in saythis_chars:
                    if len(char) > repeated_chars_limit:
                        saythis_list.append(char[0] * repeated_chars_limit)
                    else:
                        saythis_list.append(char)

                saythis = "".join(saythis_list)

            # Adds filtered message to queue
            try:
                await self.get_tts(message, saythis, lang, msg_length)
            except ValueError:
                return print(f"Run out of attempts generating {saythis}.")
            except AssertionError:
                return print(f"Skipped {saythis}, apparently blank message.")

            async with self.bot.message_locks[message.guild.id]:
                if self.bot.should_return[message.guild.id]:
                    return

                while self.bot.queue.get(message.guild.id) not in (dict(),
                                                                   None):
                    # Sort Queue
                    self.bot.queue[message.guild.id] = basic.sort_dict(
                        self.bot.queue[message.guild.id])

                    # Select first in queue
                    message_id_to_read = next(
                        iter(self.bot.queue[message.guild.id]))
                    selected = self.bot.queue[
                        message.guild.id][message_id_to_read]

                    # Play selected audio
                    vc = message.guild.voice_client
                    if vc:
                        self.bot.currently_playing[
                            message.guild.id] = self.bot.loop.create_future()
                        finish_future = make_func(
                            self.finish_future,
                            self.bot.currently_playing[message.guild.id])

                        try:
                            vc.play(FFmpegPCMAudio(
                                selected,
                                pipe=True,
                                options='-loglevel "quiet"'),
                                    after=finish_future)
                        except discord.errors.ClientException:
                            self.bot.currently_playing[
                                message.guild.id].set_result("done")

                        try:
                            result = await asyncio.wait_for(
                                self.bot.currently_playing[message.guild.id],
                                timeout=int(msg_length) + 1)
                        except asyncio.TimeoutError:
                            await self.bot.channels["errors"].send(
                                f"```asyncio.TimeoutError``` Future Failed to be finished in guild: `{message.guild.id}`"
                            )
                            result = "failed"

                        if result == "skipped":
                            self.bot.queue[message.guild.id] = dict()

                        # Delete said message from queue
                        elif message_id_to_read in self.bot.queue.get(
                                message.guild.id, ()):
                            del self.bot.queue[
                                message.guild.id][message_id_to_read]

                    else:
                        # If not in a voice channel anymore, clear the queue
                        self.bot.queue[message.guild.id] = dict()

        elif not message.author.bot:
            pins = await message.author.pins()

            if [
                    True for pinned_message in pins
                    if pinned_message.embeds and pinned_message.embeds[0].title
                    == f"Welcome to {self.bot.user.name} Support DMs!"
            ]:
                if "https://discord.gg/" in message.content.lower():
                    await message.author.send(
                        f"Join https://discord.gg/zWPWwQC and look in <#694127922801410119> to invite {self.bot.user.mention}!"
                    )

                elif message.content.lower() == "help":
                    await message.channel.send(
                        "We cannot help you unless you ask a question, if you want the help command just do `-help`!"
                    )
                    await self.bot.channels["logs"].send(
                        f"{message.author} just got the 'dont ask to ask' message"
                    )

                elif not await self.bot.blocked_users.check(message.author):
                    files = [
                        await attachment.to_file()
                        for attachment in message.attachments
                    ]
                    if not files and not message.content:
                        return

                    webhook = await basic.ensure_webhook(
                        self.bot.channels["dm_logs"], name="TTS-DM-LOGS")
                    await webhook.send(message.content,
                                       username=str(message.author),
                                       avatar_url=message.author.avatar_url,
                                       files=files)

            else:
                if len(pins) >= 49:
                    return await message.channel.send(
                        "Error: Pinned messages are full, cannot pin the Welcome to Support DMs message!"
                    )

                embed_message = cleandoc("""
                    **All messages after this will be sent to a private channel where we can assist you.**
                    Please keep in mind that we aren't always online and get a lot of messages, so if you don't get a response within a day repeat your message.
                    There are some basic rules if you want to get help though:
                    `1.` Ask your question, don't just ask for help
                    `2.` Don't spam, troll, or send random stuff (including server invites)
                    `3.` Many questions are answered in `-help`, try that first (also the prefix is `-`)
                """)

                embed = discord.Embed(
                    title=f"Welcome to {self.bot.user.name} Support DMs!",
                    description=embed_message)
                embed.set_footer(text=pick_random(basic.footer_messages))

                dm_message = await message.author.send(
                    "Please do not unpin this notice, if it is unpinned you will get the welcome message again!",
                    embed=embed)

                await self.bot.channels["logs"].send(
                    f"{message.author} just got the 'Welcome to Support DMs' message"
                )
                await dm_message.pin()
    async def join(self, ctx: utils.TypedGuildContext):
        "Joins the voice channel you're in!"
        if not ctx.author.voice:
            return await ctx.send_error(
                error=
                "you need to be in a voice channel to make me join your voice channel",
                fix="join a voice channel and try again")

        voice_client = ctx.guild.voice_client
        voice_channel = ctx.author.voice.channel
        permissions: discord.Permissions = voice_channel.permissions_for(
            ctx.guild.me)

        missing_perms = []
        if not permissions.view_channel:
            missing_perms.append("view_channel")
        if not permissions.speak:
            missing_perms.append("speak")

        if missing_perms:
            raise commands.BotMissingPermissions(missing_perms)

        if voice_client:
            if voice_client.channel == voice_channel:
                return await ctx.reply("I am already in your voice channel!")

            channel_mention = voice_client.channel.mention
            move_channel_view = utils.BoolView(ctx, "Yes", "No")
            await ctx.reply(
                f"I am already in {channel_mention}! Would you like me to move to this channel?",
                view=move_channel_view)

            if await move_channel_view.wait():
                await voice_client.move_to(voice_channel)

            return

        join_embed = discord.Embed(
            title="Joined your voice channel!",
            description="Just type normally and TTS Bot will say your messages!"
        )
        join_embed.set_thumbnail(url=self.bot.user.display_avatar.url)
        join_embed.set_author(name=ctx.author.display_name,
                              icon_url=ctx.author.display_avatar.url)
        join_embed.set_footer(text=pick_random(utils.FOOTER_MSGS))

        if ctx.interaction is not None:
            await ctx.interaction.response.defer()

        try:
            await voice_channel.connect(cls=TTSVoiceClient)  # type: ignore
        except asyncio.TimeoutError:
            return await ctx.send_error(
                "I took too long trying to join your voice channel",
                "try again later")

        await ctx.send(embed=join_embed)

        if self.bot.blocked:
            blocked_embed = discord.Embed(
                title="TTS Bot is currently blocked by Google")
            blocked_embed.description = cleandoc(f"""
                During this temporary block, voice has been swapped to a worse quality voice.
                If you want to avoid this, consider TTS Bot Premium, which you can get by donating via Patreon: `{ctx.prefix}donate`
            """)
            blocked_embed.set_footer(
                text=
                "You can join the support server for more info: discord.gg/zWPWwQC"
            )

            await ctx.send(embed=blocked_embed)