def __init__(self, config, session, executor, *args, **kwargs): self.channels = {} self.config = config self.session = session self.executor = executor self.sent_fallback = False self.trusted = remove_chars(config["Main"]["trusted_ids"], "[", "]", "'").split(", ") super().__init__(*args, **kwargs)
async def voices(self, ctx, lang: str = None): if lang in tts_langs: try: return await self.voice(ctx, lang) except: return lang = setlangs.get(ctx.author) langs_string = basic.remove_chars(list(tts_langs.keys()), "[", "]") await ctx.send( f"My currently supported language codes are: \n{langs_string}\nAnd you are using: {tts_langs[lang]} | {lang}" )
async def on_ready(self): global settings_loaded global last_cached_message if settings_loaded: await self.bot.close() self.bot.queue = dict() self.bot.playing = dict() self.bot.channels = dict() self.bot.trusted = basic.remove_chars(config["Main"]["trusted_ids"], "[", "]", "'").split(", ") self.bot.supportserver = self.bot.get_guild( int(config["Main"]["main_server"])) config_channel = config["Channels"] for channel_name in config_channel: channel_id = int(config_channel[channel_name]) channel_object = self.bot.supportserver.get_channel(channel_id) self.bot.channels[channel_name] = channel_object print(f"Starting as {self.bot.user.name}!") starting_message = await self.bot.channels["logs"].send( f"Starting {self.bot.user.mention}") # Load some files with open("activity.txt") as f2, open("activitytype.txt") as f3, open( "status.txt") as f4: activity = f2.read() activitytype = f3.read() status = f4.read() activitytype1 = getattr(discord.ActivityType, activitytype) status1 = getattr(discord.Status, status) await self.bot.change_presence(status=status1, activity=discord.Activity( name=activity, type=activitytype1)) for guild in self.bot.guilds: self.bot.playing[guild.id] = 0 self.bot.queue[guild.id] = dict() self.avoid_file_crashes.start() ping = str(time.monotonic() - before).split(".")[0] await starting_message.edit( content=f"Started and ready! Took `{ping} seconds`") last_cached_message = await self.bot.channels["logs"].send( "Waiting to chunk a guild!")
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 on_message(self, message): if message.channel.id == 749971061843558440 and message.embeds and str( message.author) == "GitHub#0000": print("Message is from a github webhook") if " new commit" in message.embeds[0].title: print("Message is a commit") update_for_main = message.embeds[0].title.startswith( "[Discord-TTS-Bot:master]" ) and self.bot.user.id == 513423712582762502 update_for_dev = message.embeds[0].title.startswith( "[Discord-TTS-Bot:dev]" ) and self.bot.user.id == 698218518335848538 cog_update = message.embeds[0].title.startswith( "[Common-Cogs:master]") print(update_for_main, update_for_dev, cog_update, "\n===============================================") if update_for_main or update_for_dev: await self.bot.channels['logs'].send( "Detected new bot commit! Pulling changes") call(['git', 'pull']) print("===============================================") await self.bot.channels['logs'].send("Restarting bot...") await self.end(message) elif cog_update: await self.bot.channels['logs'].send( "Detected new cog commit! Pulling changes") call([ 'git', 'submodule', 'update', '--recursive', '--remote' ]) print("===============================================") await self.bot.channels['logs'].send("Reloading cog...") try: self.bot.reload_extension("cogs.common_user") self.bot.reload_extension("cogs.common_owner") self.bot.reload_extension("cogs.common_trusted") except Exception as e: await self.bot.channels['logs'].send( f"**`ERROR:`** {type(e).__name__} - {e}") else: await self.bot.channels['logs'].send('**`SUCCESS`**') elif message.guild is not None: saythis = message.clean_content.lower() # Get settings autojoin = settings.get(message.guild, "auto_join") bot_ignore = settings.get(message.guild, "bot_ignore") starts_with_tts = saythis.startswith("-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 message.author.voice is None and starts_with_tts is False: return # if bot **not** in voice channel and autojoin **is off**, return if message.guild.voice_client is None and autojoin is False: return # Check if a setup channel if message.channel.id != settings.get(message.guild, "channel"): return # If message is **not** empty **or** there is an attachment if int(len(saythis)) != 0 or message.attachments: # Ignore messages starting with - that are probably commands (also advertised as a feature when it is wrong lol) if saythis.startswith(BOT_PREFIX) is False or starts_with_tts: # This line :( | if autojoin is True **or** message starts with -tts **or** author in same voice channel as bot if autojoin or starts_with_tts or message.author.bot or message.author.voice.channel == message.guild.voice_client.channel: # Fixing values if not loaded if message.guild.id not in self.bot.playing: self.bot.playing[message.guild.id] = 0 # Auto Join if message.guild.voice_client is None and autojoin and self.bot.playing[ message.guild.id] in (0, 1): try: channel = message.author.voice.channel except AttributeError: return self.bot.playing[message.guild.id] = 3 await channel.connect() self.bot.playing[message.guild.id] = 0 # Sometimes bot.guilds is wrong, because intents if message.guild.id not in self.bot.queue: self.bot.queue[message.guild.id] = dict() # Emoji filter saythis = basic.emojitoword(saythis) # Acronyms and removing -tts saythis = f" {saythis} " acronyms = { "@": " at ", "irl": "in real life", "gtg": " got to go ", "iirc": "if I recall correctly", "™️": "tm", "rn": "right now", "wdym": "what do you mean", "imo": "in my opinion", "uwu": "oowoo" } 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 changed = False for word in saythis.split(" "): if word.startswith("https://") or word.startswith( "http://") or word.startswith("www."): saythis = saythis.replace(word, "") changed = True if changed: saythis += ". This message contained a link" # Toggleable X said and attachment detection if settings.get(message.guild, "xsaid"): said_name = settings.nickname.get( message.guild, message.author) format = basic.exts_to_format(message.attachments) if message.attachments: if len(saythis) == 0: saythis = f"{said_name} sent {format}." else: saythis = f"{said_name} sent {format} and said {saythis}" else: saythis = f"{said_name} said: {saythis}" if basic.remove_chars(saythis, " ", "?", ".", ")", "'", '"') == "": return # Read language file lang = setlangs.get(message.author) try: await self.get_tts(message, saythis, lang) except (gTTS.tts.gTTSError, ValueError, AssertionError): return print( f"Just skipped '{saythis}', sliently returned." ) # Queue, please don't touch this, it works somehow while self.bot.playing[message.guild.id] != 0: if self.bot.playing[message.guild.id] == 2: return await asyncio.sleep(0.5) self.bot.playing[message.guild.id] = 1 while self.bot.queue[message.guild.id] != dict(): # 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 is not None: try: vc.play( FFmpegPCMAudio( selected, pipe=True, options='-loglevel "quiet"')) except discord.errors.ClientException: pass # sliences desyncs between discord.py and discord, implement actual fix soon! while vc.is_playing(): await asyncio.sleep(0.5) # Delete said message from queue if message_id_to_read in self.bot.queue[ 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() # Queue should be empty now, let next on_message though self.bot.playing[message.guild.id] = 0 elif message.author.bot is False: 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 not blocked_users.check(message.author): files = [ await attachment.to_file() for attachment in message.attachments ] webhook = await basic.ensure_webhook( self.bot.channels["dm_logs"], name="TTS-DM-LOGS") if not files and not message.content: return 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 on the support server (-invite) 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) 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"{str(message.author)} just got the 'Welcome to Support DMs' message" ) await dm_message.pin()
status = getattr(discord.Status, config["Activity"]["status"]) bot = commands.AutoShardedBot( status=status, intents=intents, activity=activity, case_insensitive=True, command_prefix=BOT_PREFIX, chunk_guilds_at_startup=False, ) bot.queue = dict() bot.playing = dict() bot.channels = dict() bot.chunk_queue = list() bot.trusted = basic.remove_chars(config["Main"]["trusted_ids"], "[", "]", "'").split(", ") if exists("cogs/common_user.py"): bot.load_extension("cogs.common_owner") bot.load_extension("cogs.common_trusted") bot.load_extension("cogs.common_user") elif exists("cogs/common.py"): bot.load_extension("cogs.common") else: print( "Error: Cannot find cogs to load? Did you do 'git clone --recurse-submodules'?" ) raise SystemExit for overwriten_command in ("help", "end", "botstats"): bot.remove_command(overwriten_command)
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()