async def set_presense(self): try: # https://stackoverflow.com/a/3155023 def millify(n): millnames = ['', 'K', 'M', 'B', 'T'] n = float(n) millidx = max( 0, min( len(millnames) - 1, int(math.floor(0 if n == 0 else math.log10(abs(n)) / 3)))) return '{:.0f}{}'.format(n / 10**(3 * millidx), millnames[millidx]) with session_scope() as session: pixels = session.query(func.sum( Template.size)).filter(Template.alert_id != None).scalar() if not pixels: pixels = "Pixels!" else: pixels = f"{millify(pixels)} Pixels!" await self.change_presence(status=discord.Status.online, activity=discord.Activity( name=pixels, type=discord.ActivityType.watching)) except Exception: log.exception("Error during status update task.")
def process(self, pixels, alert_template, days): # We need to begin a new session for this thread and migrate all # the pixel objects over to it so we can use them safely! with session_scope() as session: ps = [session.merge(p) for p in pixels] x_data = [] # Uses up wayyy more space than it's gonna need, maybe I should aim low and expand? y_data = np.zeros((len(ps), 2), dtype=np.int16) for i, (_, pixels) in enumerate( groupby(ps, key=lambda p: f"{p.placed.day} {p.placed.hour}")): counter = {"ally": 0, "enemy": 0} for pixel in pixels: color = alert_template.color_at(pixel.x, pixel.y) if color == -1: continue elif color == pixel.color: counter["ally"] += 1 else: counter["enemy"] += 1 x_data.append( datetime.datetime(pixel.placed.year, pixel.placed.month, pixel.placed.day, hour=pixel.placed.hour)) y_data[i, 0] = counter["ally"] y_data[i, 1] = counter["enemy"] y_data = y_data[0:i + 1, :] return x_data, y_data
def process_check(templates, chunks): # We need to begin a new session for this thread and migrate all # the template objects over to it so we can use them safely! with session_scope() as session: ts = [session.merge(t) for t in templates] example_chunk = next(iter(chunks)) for t in ts: empty_bcs, shape = example_chunk.get_intersecting( t.x, t.y, t.width, t.height) tmp = Image.new("RGBA", (example_chunk.width * shape[0], example_chunk.height * shape[1])) for i, ch in enumerate(empty_bcs): ch = next((x for x in chunks if x == ch)) if ch.is_in_bounds(): tmp.paste(ch.image, ((i % shape[0]) * ch.width, (i // shape[0]) * ch.height)) x, y = t.x - empty_bcs[0].p_x, t.y - empty_bcs[0].p_y tmp = tmp.crop((x, y, x + t.width, y + t.height)) template = Image.open(http.get_template_blocking( t.url, t.name)).convert('RGBA') alpha = Image.new('RGBA', template.size, (255, 255, 255, 0)) template = Image.composite(template, alpha, template) tmp = Image.composite(tmp, alpha, template) tmp = ImageChops.difference(tmp.convert('RGB'), template.convert('RGB')) t.errors = np.array(tmp).any(axis=-1).sum() return [{"tid": t.id, "errors": t.errors} for t in ts]
def get_guild_language(self, guild): with session_scope() as session: if isinstance(guild, discord.Guild): guild = session.query(Guild).get(guild.id) else: guild = session.query(Guild).get(guild) return guild.language.lower()
async def update_placements(x, y, color, canvas_name): with session_scope() as session: canvas = session.query(Canvas).filter_by(nick=canvas_name).first() if not canvas: log.exception(f"No row found for canvas {canvas_name}, placement stats were not updated.") return session.add(Pixel(x=x, y=y, color=color, canvas=canvas))
async def on_message(self, message): with session_scope() as session: if not message.author.bot and session.query(AnimoteUser).get( message.author.id): channel = message.channel content = emote_corrector(message) if content: await message.delete() await channel.send(content=content)
async def on_guild_role_delete(self, role): with session_scope() as session: guild = session.query(Guild).get(role.guild.id) if guild.template_admin == role.id: guild.template_admin = None if guild.template_adder == role.id: guild.template_adder = None if guild.bot_admin == role.id: guild.bot_admin = None
def canvas_check(self): with session_scope() as session: for nick, url in canvases.pretty_print.items(): canvas = session.query(Canvas).filter_by(nick=nick).first() if canvas: continue log.info(f"Canvas {nick} not found in database, creating...") session.add(Canvas(nick=nick, url=url))
async def on_message(self, message): # Ignore channels that can't be posted in if message.guild and not message.channel.permissions_for( message.guild.me).send_messages: return # Ignore other bots if message.author.bot: return # Ignore messages from users currently making a menu choice with session_scope() as session: lock = session.query(MenuLock).filter( message.author.id == MenuLock.user_id, message.channel.id == MenuLock.channel_id).first() if lock: return # Ignore messages with spoilered images for attachment in message.attachments: if attachment.is_spoiler(): return # Ignore messages with any spoilered text if re.match(r".*\|\|.*\|\|.*", message.content): return with session_scope() as session: # Create context from message, and assign a db session to it # we do that here because before_invoke doesn't happen # before checks ctx = await self.get_context(message, cls=GlimContext) ctx.session = session # Attempt to invoke a command from the context await self.invoke(ctx) # A command was recognised, so autoscan doesn't need to occur if ctx.invoked_with: return # Autoscan, since the message contained no command await utils.autoscan(ctx)
def get_prefix(bot_, msg: discord.Message): prefix_list = [config.PREFIX, bot_.user.mention + " "] if msg.guild: with session_scope() as session: guild = session.query(Guild).get(msg.guild.id) if guild and guild.prefix is not None: prefix_list[0] = guild.prefix return prefix_list
async def on_guild_remove(self, guild): log.info("Kicked from guild '{0.name}' (ID: {0.id})".format(guild)) if utils.config.CHANNEL_LOG_GUILD_KICKS: await utils.channel_log( self.bot, "Kicked from guild **{0.name}** (ID: `{0.id}`)".format(guild)) with session_scope() as session: db_guild = session.query(Guild).get(guild.id) session.delete(db_guild)
async def clear_old_stats(self): try: now = datetime.datetime.now(datetime.timezone.utc) seven_days_ago = now - datetime.timedelta(days=7) with session_scope() as session: session.query(Pixel).filter( Pixel.placed < seven_days_ago).delete() session.query(Online).filter( Online.time < seven_days_ago).delete() except Exception: log.exception("Error during old stats clearing task.")
def update_online(self, time, count): with session_scope() as session: canvas_query = session.query(Canvas).filter_by(nick=self.canvas) canvas = canvas_query.first() if not canvas: log.exception(f"No row found for canvas {self.canvas}, online stats were not updated.") return session.add(Online( time=datetime.datetime.fromtimestamp(time, tz=datetime.timezone.utc), count=count, canvas=canvas))
async def on_guild_update(self, before, after): if before.name != after.name: log.info("Guild {0.name} is now known as {1.name} (ID: {1.id})") if utils.config.CHANNEL_LOG_GUILD_RENAMES: await utils.channel_log( self.bot, "Guild **{0.name}** is now known as **{1.name}** (ID: `{1.id}`)" .format(before, after)) with session_scope() as session: db_guild = session.query(Guild).get(after.id) db_guild.name = after.name
async def on_guild_join(self, guild): log.info("Joined new guild '{0.name}' (ID: {0.id})".format(guild)) if utils.config.CHANNEL_LOG_GUILD_JOINS: await utils.channel_log( self.bot, "Joined new guild **{0.name}** (ID: `{0.id}`)".format(guild)) with session_scope() as session: db_guild = Guild(id=guild.id, name=guild.name, join_date=int(guild.me.joined_at.timestamp())) session.add(db_guild)
async def unmute(self): try: with session_scope() as session: mutes = session.query(MutedTemplate).filter( MutedTemplate.expires < time.time()).all() for mute in mutes: mute.template.alert_channel = mute.alert_id session.delete(mute) except Exception: log.exception("Error during unmute task.")
async def on_guild_channel_delete(self, channel): with session_scope() as session: guild = session.query(Guild).get(channel.guild.id) if guild.alert_channel == channel.id: guild.alert_channel = None session.query(Template).filter_by(guild_id=channel.guild.id, alert_id=channel.id).update( {Template.alert_id: None}) session.query(MutedTemplate).filter( MutedTemplate.template.guild_id == channel.guild.id, MutedTemplate.alert_id == channel.id).delete()
async def update(self): try: with session_scope() as session: # Get the templates currently in the db templates = session.query(TemplateDb).filter( TemplateDb.alert_id != None).all() # Remove any templates from self.templates that are no longer in db db_t_ids = [t.id for t in templates] for t in self.templates: if t.id not in db_t_ids: log.debug( f"Template {t} no longer in the database, removed." ) self.templates.remove(t) # Update any templates already in self.templates that have changed for old_t in self.templates: for t in templates: if old_t.id != t.id: continue if not old_t.changed(t): continue tp = await Template.new(t) if tp is not None: self.templates.remove(old_t) self.templates.append(tp) # Add any new templates from db to self.templates template_ids = [template.id for template in self.templates] for t in templates: if t.id in template_ids: continue tp = await Template.new(t) if tp is None: continue self.templates.append(tp) except Exception as e: log.exception(f'Failed to update. {e}')
async def database_check(self): with session_scope() as session: is_new_version = False old_version = session.query(Version).first() if not old_version: print("version initialized to {}".format(VERSION)) version = Version(version=VERSION) session.add(version) return is_new_version is_new_version = old_version.version != VERSION if not is_new_version: return is_new_version log.info("Database is a previous version. Updating...") print("updated to {}".format(VERSION)) old_version.version = VERSION return is_new_version
channel.send(f"```{message}```")) except discord.errors.Forbidden: log.warning("Forbidden from logging channel!") # Use a handler to try to send error level logs to my discord logging channel global_logger = logging.getLogger() error_log = DiscordLogger(bot) error_log.setLevel(logging.ERROR) error_log.setFormatter(config.formatter) global_logger.addHandler(error_log) # Delete all old menu locks with session_scope() as session: session.query(MenuLock).delete() @bot.before_invoke async def on_command_preprocess(ctx): if ctx.guild: log.info( "[uuid:{0}] {1.name}#{1.discriminator} used '{2}' in {3.name} (UID:{1.id} GID:{3.id})" .format(ctx.uuid, ctx.author, ctx.command.qualified_name, ctx.guild)) else: log.info( "[uuid:{0}] {1.name}#{1.discriminator} used '{2}' in DM (UID:{1.id})" .format(ctx.uuid, ctx.author, ctx.command.qualified_name)) log.info("[uuid:{0}] {1}".format(ctx.uuid, ctx.message.content))
async def guilds_check(self, is_new_version): with session_scope() as session: for g in bot.guilds: log.info("'{0.name}' (ID: {0.id})".format(g)) db_g = session.query(Guild).get(g.id) if db_g: prefix = db_g.prefix if db_g.prefix else config.PREFIX if g.name != db_g.name: if config.CHANNEL_LOG_GUILD_RENAMES: await utils.channel_log( bot, "Guild **{1}** is now known as **{0.name}** `(ID:{0.id})`" .format(g, db_g.name)) db_g.name = g.name if is_new_version: ch = next((x for x in g.channels if x.id == db_g.alert_channel), None) if ch: data = await http.get_changelog(VERSION) if data: e = discord.Embed(title=data['name'], url=data['url'], color=13594340, description=data['body']) \ .set_author(name=data['author']['login']) \ .set_thumbnail(url=data['author']['avatar_url']) \ .set_footer(text="Released " + data['published_at']) await ch.send(GlimContext.get_from_guild( self, g, "bot.update").format(VERSION, prefix), embed=e) else: await ch.send( GlimContext.get_from_guild( self, g, "bot.update_no_changelog").format( VERSION, prefix)) log.info("- Sent update message") else: log.info( "- Could not send update message: alert channel not found." ) else: j = g.me.joined_at if config.CHANNEL_LOG_GUILD_JOINS: await utils.channel_log( bot, "Joined guild **{0.name}** (ID: `{0.id}`)".format( g)) log.info( "Joined guild '{0.name}' (ID: {0.id}) between sessions at {1}" .format(g, j.timestamp())) session.add( Guild(id=g.id, name=g.name, join_date=int(j.timestamp()))) # await utils.print_welcome_message(g) db_guilds = session.query(Guild).all() if len(bot.guilds) != len(db_guilds): for g in db_guilds: if not any(x for x in bot.guilds if x.id == g.id): log.info( "Kicked from guild '{0}' (ID: {1}) between sessions" .format(g.name, g.id)) if config.CHANNEL_LOG_GUILD_KICKS: await utils.channel_log( bot, "Kicked from guild **{0}** (ID: `{1}`)".format( g.name, g.id)) session.delete(g)