async def sticker_top( raw_sticker: ('str', 'Pick an sticker', 'sticker'), months: (range(1, 13), 'The months to get') = 1, ): """List the users using the given sticker the most.""" sticker = GUILD__NEKO_DUNGEON.get_sticker_like(raw_sticker) if sticker is None: abort(f'There is not sticker with name `{raw_sticker}` in the guild.') async with DB_ENGINE.connect() as connector: response = await connector.execute( select([ sticker_counter_model.user_id, alchemy_function.count(sticker_counter_model.user_id).label('total'), ]). \ where(and_( sticker_counter_model.sticker_id == sticker.id, sticker_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months, )). \ limit(30). \ group_by(sticker_counter_model.user_id). \ order_by(desc('total')) ) results = await response.fetchall() if results: index = 0 limit = len(results) description_parts = [] while True: user_id, count = results[index] index += 1 try: user = USERS[user_id] except KeyError: continue try: guild_profile = user.guild_profiles[GUILD__NEKO_DUNGEON] except KeyError: nick = None else: nick = guild_profile.nick description_parts.append(str(index)) description_parts.append('.: **') description_parts.append(str(count)) description_parts.append('** x ') description_parts.append(user.full_name) if (nick is not None): description_parts.append(' *[') description_parts.append(nick) description_parts.append(']*') if index == limit: break description_parts.append('\n') continue description = ''.join(description_parts) else: description = '*No usages recorded*' return Embed( f'Top sticker users of {sticker.name}', description, ).add_thumbnail(sticker.url)
async def most_used( months: (range(1, 13), 'The months to get') = 1, page: ('int', 'Select a page') = 1, order: (ORDERS, 'Ordering?') = ORDER_DECREASING, ): """Shows the most used stickers.""" if page < 1: abort('Page value can be only positive') low_date_limit = datetime.utcnow() - RELATIVE_MONTH * months is_new_limit = datetime.utcnow() - MONTH async with DB_ENGINE.connect() as connector: response = await connector.execute( select([ sticker_counter_model.sticker_id, alchemy_function.count(sticker_counter_model.user_id).label('total'), ]). \ where(and_( sticker_counter_model.timestamp > low_date_limit, )). \ group_by(sticker_counter_model.sticker_id) ) results = await response.fetchall() items = [] guild_stickers = set(GUILD__NEKO_DUNGEON.stickers.values()) for sticker_id, count in results: try: sticker = STICKERS[sticker_id] except KeyError: continue guild_stickers.discard(sticker) is_new = (sticker.created_at >= is_new_limit) items.append((sticker, count, is_new)) for sticker in guild_stickers: is_new = (sticker.created_at >= is_new_limit) items.append((sticker, 0, is_new)) items.sort(key=item_sort_key, reverse=order) page_shift = (page - 1) * MOST_USED_PER_PAGE index = page_shift limit = min(len(items), index + MOST_USED_PER_PAGE) description_parts = [] if index < limit: while True: sticker, count, is_new = items[index] index += 1 description_parts.append(str(index)) description_parts.append('.: **') description_parts.append(str(count)) description_parts.append('** x ') description_parts.append(sticker.name) if is_new: description_parts.append(' *[New!]*') if index == limit: break description_parts.append('\n') continue description = ''.join(description_parts) else: description = '*No recorded data*' return Embed('Most used stickers:', description). \ add_footer(f'Page {page} / {(len(items)//MOST_USED_PER_PAGE)+1}')
async def __new__(cls, client, message, guild, changes): unused_emojis = set(message.reactions.keys()) used_emojis = {item[0] for item in changes.added} unused_emojis -= used_emojis for emoji in unused_emojis: try: await client.reaction_delete_emoji(message, emoji) except BaseException as err: if isinstance(err, ConnectionError): return if isinstance(err, DiscordException): if err.code in ( ERROR_CODES.unknown_message, # message deleted ERROR_CODES.unknown_channel, # channel deleted ERROR_CODES.invalid_access, # client removed ERROR_CODES. invalid_permissions, # permissions changed meanwhile ): return await client.events.error(client, f'{cls.__name__}.__new__', err) return for emoji in used_emojis: try: await client.reaction_add(message, emoji) except BaseException as err: if isinstance(err, ConnectionError): return if isinstance(err, DiscordException): if err.code in ( ERROR_CODES.unknown_emoji, # emoji deleted ERROR_CODES. max_reactions, # reached reaction 20, some1 is trolling us. ERROR_CODES.unknown_message, # message deleted ERROR_CODES.unknown_channel, # channel deleted ERROR_CODES.invalid_access, # client removed ERROR_CODES. invalid_permissions, # permissions changed meanwhile ): return await client.events.error(client, f'{cls.__name__}.__new__', err) return data = bytearray(320) position = 0 relations = {} for emoji, role in changes.added: data[position:position + 8] = emoji.id.to_bytes(8, byteorder='big') position += 8 data[position:position + 8] = role.id.to_bytes(8, byteorder='big') position += 8 relations[emoji] = role relations[role] = emoji async with DB_ENGINE.connect() as connector: await connector.execute(AUTO_REACT_ROLE_TABLE.insert().values( message_id=message.id, channel_id=message.channel.id, data=data, behaviour=changes.new_behaviour, client_id=client.id)) self = object.__new__(cls) self.message = message self.relations = relations self.behaviour = changes.new_behaviour self.guild = guild self.client = client self.destroy_called = False self.add_events() return self
async def buy(client, event, item : ([(item.name, item.id) for item in BUYABLE], 'Select the item to buy nya!'), amount : (int, 'How much items would you want to buy?'), ): """Buy?""" try: item = ITEMS[item] except KeyError: abort('Item not available.') permissions = event.channel.cached_permissions_for(client) if (not permissions.can_send_messages) or (not permissions.can_add_reactions): abort('I need `send messages` and `add reactions` permissions to execute the command.') yield user = event.user async with DB_ENGINE.connect() as connector: response = await connector.execute( select([currency_model.total_love]). \ where(currency_model.user_id==user.id)) results = await response.fetchall() if results: total_love = results[0] else: total_love = 0 embed = Embed('Confirm buying', f'Selected item: {item.emoji:e} **{item.name}**\n' f'Amount: **{amount}**\n' f'\n' f'Price: {calculate_buy_cost(item.market_cost, amount)} {EMOJI__HEART_CURRENCY:e}\n' f'Budget: {total_love} {EMOJI__HEART_CURRENCY:e}' ) embed.add_author(user.avaar_url, user.full_name) embed.add_footer('The prices of context of demand and supply.') message = await client.message_create(event.channel, embed=embed) await client.reaction_add(message, item.emoji) await client.reaction_add(message, CONFIRM_NAH) try: event = await wait_for_reaction(client, message, partial_func(check_confirm_emoji, item.emoji), 300.0) except TimeoutError: return if event.emoji is CONFIRM_NAH: embed.title = 'Buying cancelled' else: user = event.user async with DB_ENGINE.connect() as connector: response = await connector.execute( select([currency_model.total_love, currency_model.total_allocated]). \ where(currency_model.user_id==user.id)) results = await response.fetchall() if results: total_love, total_allocated = results[0] else: total_love = total_allocated = 0 if total_love == 0: amount = cost = 0 else: amount, cost = calculate_buyable_and_cost(item.market_cost, amount, total_love-total_allocated) item.market_cost += amount if cost == 0: new_love = total_love else: new_love = total_love-cost await connector.execute(update(currency_model.user_id==user.id). \ values(total_love = new_love)) response = await connector.execute(select([item_model.id, item_model.amount]). \ where(item_model.user_id==user.id).where(item_model.type==item.id)) results = await response.fetchall() if results: row_id, actual_amount = results[0] new_amount = actual_amount+amount to_execute = ITEM_TABLE.update().values( amount=new_amount ).where(item_model.id==row_id) else: to_execute = ITEM_TABLE.insert().values( user_id = user.id, amount = amount, type = item.id ) await connector.execute(to_execute) embed.title = 'Buying confirmed' embed.description = ( f'Selected item: {item.emoji:e} **{item.name}**\n' f'Bought mount: **{amount}**\n' f'\n' f'Hearts: {total_love} {EMOJI__HEART_CURRENCY:e} -> {new_love} {EMOJI__HEART_CURRENCY:e}' ) await client.message_edit(message, embed=embed)
async def most_used( months: (range(1, 13), 'The months to get') = 1, page: ('int', 'Select a page') = 1, type_: (EMOJI_MOST_USED_TYPES, 'Choose emoji type to filter on') = EMOJI_MOST_USED_TYPE_ALL, action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL, order: (ORDERS, 'Ordering?') = ORDER_DECREASING, ): """Shows the most used emojis.""" if page < 1: abort('Page value can be only positive') low_date_limit = datetime.utcnow()-RELATIVE_MONTH*months is_new_limit = datetime.utcnow()-MONTH async with DB_ENGINE.connect() as connector: statement = ( select([ emoji_counter_model.emoji_id, alchemy_function.count(emoji_counter_model.user_id).label('total'), ]). \ where(and_( emoji_counter_model.timestamp > low_date_limit, )). \ group_by(emoji_counter_model.emoji_id) ) if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL): statement = statement.where(emoji_counter_model.action_type==action_type) response = await connector.execute(statement) results = await response.fetchall() items = [] emoji_filter = EMOJI_MOST_USED_FILTERS[type_] guild_emojis = set(emoji for emoji in GUILD__NEKO_DUNGEON.emojis.values() if emoji_filter(emoji)) for emoji_id, count in results: try: emoji = EMOJIS[emoji_id] except KeyError: continue if not emoji_filter(emoji): continue guild_emojis.discard(emoji) is_new = (emoji.created_at >= is_new_limit) items.append((emoji, count, is_new)) for emoji in guild_emojis: is_new = (emoji.created_at >= is_new_limit) items.append((emoji, 0, is_new)) items.sort(key=item_sort_key, reverse=order) page_shift = (page-1)*MOST_USED_PER_PAGE index = page_shift limit = min(len(items), index+MOST_USED_PER_PAGE) description_parts = [] if index < limit: while True: emoji, count, is_new = items[index] index += 1 description_parts.append(str(index)) description_parts.append('.: **') description_parts.append(str(count)) description_parts.append('** x ') description_parts.append(emoji.as_emoji) if is_new: description_parts.append(' *[New!]*') if index == limit: break description_parts.append('\n') continue description = ''.join(description_parts) else: description = '*No recorded data*' return Embed('Most used emojis:', description). \ add_footer(f'Page {page} / {(len(items)//MOST_USED_PER_PAGE)+1}')
async def emoji_top( raw_emoji: ('str', 'Pick an emoji', 'emoji'), months: (range(1, 13), 'The months to get') = 1, action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL, ): """List the users using the given emoji the most.""" emoji = parse_emoji(raw_emoji) if emoji is None: emoji = GUILD__NEKO_DUNGEON.get_emoji_like(raw_emoji) if emoji is None: abort(f'`{raw_emoji}` is not an emoji.') else: if emoji.is_unicode_emoji(): abort(f'{emoji:e} is an unicode emoji. Please give custom.') if emoji.guild is not GUILD__NEKO_DUNGEON: abort(f'{emoji:e} is bound to an other guild.') async with DB_ENGINE.connect() as connector: statement = ( select([ emoji_counter_model.user_id, alchemy_function.count(emoji_counter_model.user_id).label('total'), ]). \ where(and_( emoji_counter_model.emoji_id == emoji.id, emoji_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months, )). \ limit(30). \ group_by(emoji_counter_model.user_id). \ order_by(desc('total')) ) if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL): statement = statement.where(emoji_counter_model.action_type==action_type) response = await connector.execute(statement) results = await response.fetchall() if results: index = 0 limit = len(results) description_parts = [] while True: user_id, count = results[index] index += 1 try: user = USERS[user_id] except KeyError: continue try: guild_profile = user.guild_profiles[GUILD__NEKO_DUNGEON] except KeyError: nick = None else: nick = guild_profile.nick description_parts.append(str(index)) description_parts.append('.: **') description_parts.append(str(count)) description_parts.append('** x ') description_parts.append(user.full_name) if (nick is not None): description_parts.append(' *[') description_parts.append(nick) description_parts.append(']*') if index == limit: break description_parts.append('\n') continue description = ''.join(description_parts) else: description = '*No usages recorded*' return Embed( f'Top emoji users of {emoji.name}', description, ).add_thumbnail(emoji.url)
async def user_top(event, user: ('user', 'By who?') = None, count: (range(10, 91, 10), 'The maximal amount of emojis to show') = 30, months: (range(1, 13), 'The months to get') = 1, action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL, ): """List the most used emojis at ND by you or by the selected user.""" if user is None: user = event.user async with DB_ENGINE.connect() as connector: statement = ( select([ emoji_counter_model.emoji_id, alchemy_function.count(emoji_counter_model.emoji_id).label('total'), ]). \ where(and_( emoji_counter_model.user_id == user.id, emoji_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months, )). \ limit(count). \ group_by(emoji_counter_model.emoji_id). \ order_by(desc('total')) ) if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL): statement = statement.where(emoji_counter_model.action_type==action_type) response = await connector.execute(statement) results = await response.fetchall() embed = Embed( f'Most used emojis by {user.full_name}', color = user.color_at(GUILD__NEKO_DUNGEON), ).add_thumbnail(user.avatar_url) if results: description_parts = [] start = 1 limit = len(results) index = 0 while True: emoji_id, count = results[index] index += 1 try: emoji = EMOJIS[emoji_id] except KeyError: continue description_parts.append(str(index)) description_parts.append('.: **') description_parts.append(str(count)) description_parts.append('** x ') description_parts.append(emoji.as_emoji) if (not index%10) or (index == limit): description = ''.join(description_parts) description_parts.clear() embed.add_field(f'{start} - {index}', description, inline=True) if (index == limit): break start = index+1 continue description_parts.append('\n') continue else: embed.description = '*No recorded data.*' return embed