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)
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)
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)
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)
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
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
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())
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)