async def projects(self, ctx, *, project_name: str = None): user_lookup = utils.UserLookup(ctx.bot) if not project_name: session = database.new_session() projects = sorted(session.query(database.Project).all(), key=lambda proj: proj.name) users = session.query(database.User).all() lookup = {} for user in users: for p in user.projects: if p.id not in lookup: lookup[p.id] = [] if user.mal_name: lookup[p.id].append( user_lookup.display_name_from_mal(user.mal_name)) message = '\n'.join( map(lambda x: self.project_string(x, lookup), projects)) await utils.safe_say( ctx, f'Use `!project [project_name]` to get details about a project.\n\n{message}' ) else: project_name = project_name.strip() session = database.new_session() await ctx.bot.say( self.project_build_message(ctx, session, user_lookup, project_name))
async def stats(self, ctx, subcommand: str = None, arg: str = None): if not subcommand: await ctx.bot.say( 'Available stats: `age`, `gender`, `country`, `language`, `prog`, `anime`, `manga`' ) return user_lookup = utils.UserLookup(ctx.bot) subcommand = subcommand.lower() if subcommand in ['age', 'ages']: await utils.safe_say(ctx, self.stat_age(ctx, user_lookup)) elif subcommand in ['gender', 'genders']: await utils.safe_say(ctx, self.stat_gender(ctx, user_lookup, arg)) elif subcommand in ['country', 'countries']: await utils.safe_say(ctx, self.stat_country(ctx, user_lookup, arg)) elif subcommand in ['language', 'languages']: await utils.safe_say(ctx, self.stat_language(ctx, user_lookup, arg)) elif subcommand in [ 'prog', 'programming', 'prog_language', 'prog_languages' ]: await utils.safe_say(ctx, self.stat_prog(ctx, user_lookup, arg)) elif subcommand in ['a', 'anime', 'animelist']: await self.entity_stats(ctx, user_lookup, arg, entity='anime') elif subcommand in ['m', 'manga', 'mangalist']: await self.entity_stats(ctx, user_lookup, arg, entity='manga')
async def display_grouped_entities(ctx, entities, settings, details): message = '' max_size = 2000 try: max = int(settings['results']) except: max = 5 style = settings['style'] user_lookup = utils.UserLookup(ctx.bot) if style == 'full' else None entities = entities[:max] if max > 0 else entities for item in entities: part = '' if style == 'short': part = item[0]['entity']['title'] + '\n' elif style == 'details': part = f"**{item[0]['entity']['title']}**: {details(item)}\n" elif style == 'full': members = ', '.join( map(lambda x: user_lookup.display_name_from_mal(x['user']), item)) part = f"**{item[0]['entity']['title']}**: {members} ({details(item)})\n" if len(message) + len(part) > max_size: await ctx.bot.say(message) return message += part await ctx.bot.say(message)
def build_entity_stats(ctx, data, lists, entity, easter_egg=False): mal_id = data['id'] statuses = {} user_lookup = utils.UserLookup(ctx.bot) for user, list in lists.items(): user_display_name = user_lookup.display_name_from_mal(user) if entity == 'anime': status_key = 'watched_status' special_statuses = ['watching', 'on-hold', 'dropped'] else: status_key = 'read_status' special_statuses = ['reading', 'on-hold', 'dropped'] user_data = next((x for x in list if x['id'] == mal_id), None) if easter_egg: key = user_data[status_key] if user_data else 'not in list' item = f'{user_display_name} (10\*)' elif user_data: key = user_data[status_key] if user_data[status_key] in special_statuses: if entity == 'anime': item = f'{user_display_name} ({user_data["watched_episodes"]} eps.)' else: if 'volumes_read' in user_data and user_data[ 'volumes_read'] > 0: item = f'{user_display_name} ({user_data["volumes_read"]} vol.)' else: item = f'{user_display_name} ({user_data["chapters_read"]} ch.)' else: item = f'{user_display_name}' if user_data['score'] > 0: item += f' ({user_data["score"]}\*)' else: key = 'not in list' item = user_display_name if key in statuses: statuses[key].append(item) else: statuses[key] = [item] message = '' if entity == 'anime': sorted_st = [ 'watching', 'completed', 'on-hold', 'dropped', 'plan to watch', 'not in list' ] else: sorted_st = [ 'reading', 'completed', 'on-hold', 'dropped', 'plan to read', 'not in list' ] for stat in sorted_st: if stat in statuses: users = ', '.join(statuses[stat]) message += f'**{stat.title()}**: {users}\n' return message
async def botstate(self, ctx): user_lookup = utils.UserLookup(ctx.bot) state = shared.state.users_in_command if state: message = '' for identifier, command in state.items(): message += f'{user_lookup.display_name_from_id(identifier)}: `{command}`\n' await ctx.bot.say(message) else: await ctx.bot.say('No user command running')
async def whois(self, ctx, member_raw): member = await utils.convert_member(ctx, member_raw) lookup = utils.UserLookup(ctx.bot) message = f"""MAL name: {_user_get_mal_name(lookup, member)} Discord name: {getattr(member, "name", None)} Discord nick: {getattr(member, "nick", None)} Display name (with ctx): {lookup.display_name_with_context(ctx, member)} Display name (from mal): {lookup.display_name_from_mal(_user_get_mal_name(lookup, member))}""" await ctx.bot.say(message)
async def scoredistribution(self, ctx, *, args: str = ''): settings = parse_arguments(args, default={ 'entity': 'anime', 'score': None, 'sort': 'percent' }) entity = settings['entity'] sorting = settings['sort'] try: score = int(settings['score']) except: score = None lists = await shared.cache.require_entity_lists(ctx, entity) scores_list = [] user_lookup = utils.UserLookup(ctx.bot) user_data = [] for user, list in lists.items(): user_display_name = user_lookup.display_name_from_mal(user) data = make_maluser(user, entity) user_data.append({'name': user_display_name, 'data': data}) if score: score = 10 if score > 10 or score <= 0 else score scores_list = self.sorted_scores_for_user(score, user_data, sorting, '{1}: **{2}** ({3})') message = f'Users with the most **{score}** in their {entity} list:\n\n' for item in scores_list: message += f'{item}\n' await ctx.bot.say(message) else: display_data = [] for i in range(10, 0, -1): scores_list = self.sorted_scores_for_user( i, user_data, sorting, '**{0}**: {1} (**{2}** - {3})') if scores_list: display_data.append(scores_list[0]) if sorting == 'amount': message = f'Users with the most {entity} of each score in their list:\n\n' elif sorting == 'percent': message = f'Users with the highest percentage of each score in their {entity} list:\n\n' else: message = f'Users with the most of each score in their {entity} list:\n\n' for item in display_data: message += f'{item}\n' await ctx.bot.say(message)
async def bans(self, ctx): message = f'Banned members: {len(shared.banlist)}\n' user_lookup = utils.UserLookup(ctx.bot) for member in shared.banlist.keys(): message += f'{user_lookup.display_name_from_id(member)} - {shared.banlist[member]}\n' message += '\n' message += 'Ban values:\n' for name, value in checks.PermissionLevel.__members__.items(): message += f'{name}: {value.value}\n' await ctx.bot.say(message)
async def meanscores(self, ctx, entity='anime'): lists = await shared.cache.require_entity_lists(ctx, entity) user_lookup = utils.UserLookup(ctx.bot) items = [] for user, list in lists.items(): mal = make_maluser(user, entity) items.append({'user': user, 'score': mal.mean_score}) items = sorted(items, key=lambda x: x['score'], reverse=True) message = '' for item in items: message += '**{0}**: {1:.2f}\n'.format( user_lookup.display_name_from_mal(item["user"]), item['score']) await utils.safe_say(ctx, message)
async def perform_airing_action(self, ctx, input, member_name=None, title_filter=None, watching_only=False): if input: content = input.strip().lower() member = await utils.convert_member(ctx, content, optional=True, critical_failure=False, print_error=False) if member: member_name = await utils.require_mal_username(ctx, member) if not member_name: return else: title_filter = content if member_name: airing_data = AiringData( await shared.cache.require_airing(), { member_name: await shared.cache.require_entity_list( ctx, member_name, 'anime') }) else: airing_data = AiringData( await shared.cache.require_airing(), await shared.cache.require_entity_lists(ctx, 'anime')) self_user = await utils.require_mal_username( ctx, ctx.message.author) if not member_name else None user_lookup = utils.UserLookup(ctx.bot) await utils.safe_say( ctx, self.airing_message(airing_data, user_lookup, member=member_name, title_filter=title_filter, watching_only=watching_only, hl_self=self_user))
async def tz(self, ctx, member_raw: str = None): member = await utils.convert_member(ctx, member_raw, optional=True) if member is None: user_lookup = utils.UserLookup(ctx.bot) session = database.new_session() users = session.query(database.User).filter( database.User.timezone.isnot(None)).all() timezones = {} now = datetime.datetime.utcnow() for user in users: local_time = pytz.utc.localize(now, is_dst=None).astimezone( pytz.timezone(user.timezone)) key = local_time.strftime('%Y%m%d %H:%M:%S') if key in timezones: timezones[key]['data'].append(user) else: timezones[key] = {'tz': local_time, 'data': [user]} days_tz = {} for key in timezones.keys(): day_string = key.split(' ')[0] if day_string not in days_tz: days_tz[day_string] = [] days_tz[day_string].append({ 'sorting': key, 'time': timezones[key]['tz'], 'users': timezones[key]['data'] }) sorted_tz = { k: sorted(v, key=lambda x: x['sorting']) for k, v in days_tz.items() } flat_tz = [] for item in sorted_tz.keys(): flat_tz.append({'day': item, 'data': sorted_tz[item]}) final_tz = sorted(flat_tz, key=lambda x: x['day']) message = '' for day in final_tz: day_string = day['data'][0]['time'].strftime('%A') message += f'**{day_string}:**\n\n' for item in day['data']: display_time = item['time'].strftime('%H:%M:%S') tz_users = ', '.join( map( lambda x: f'{user_lookup.display_name_from_mal(x.mal_name)} *({x.timezone})*', item['users'])) message += f'{display_time}:\n{tz_users}\n\n' await utils.safe_say(ctx, message) else: session = database.new_session() user = session.query(database.User).filter( database.User.discord_id == member.id).first() if user is None or user.timezone is None: await ctx.bot.say( f'{utils.UserLookup.display_name_from_user(member)} has not set their timezone!' ) return tz = pytz.timezone(user.timezone) time = pytz.utc.localize(datetime.datetime.utcnow(), is_dst=None).astimezone(tz) timezone_string = time.strftime('%A %H:%M:%S') await ctx.bot.say(f'{timezone_string} ({user.timezone})\n')
async def affinity(self, ctx, member1_raw=None, member2_raw=None, entity='anime'): if member1_raw in ['anime', 'manga']: entity = member1_raw member1_raw = None if member2_raw in ['anime', 'manga']: entity = member2_raw member2_raw = None member = await utils.convert_member(ctx, member1_raw, optional=True) mal_name = await utils.require_mal_username(ctx, member) if member2_raw: member = await utils.convert_member(ctx, member2_raw) mal_name2 = await utils.require_mal_username(ctx, member) else: mal_name2 = None if not mal_name: return user_list = await shared.cache.require_entity_list(ctx, mal_name, entity=entity) if mal_name2: list2 = await shared.cache.require_entity_list(ctx, mal_name2, entity=entity) items, score = self.get_weighted_score(user_list, list2) message = f'Shared {entity}: **{items}**\n' if score is None: message += 'Not enough shared scores to compute affinity\n' else: message += 'Affinity: **{0:.1f}%**\n'.format(score) await utils.safe_say(ctx, message) else: lists = await shared.cache.require_entity_lists(ctx, entity) user_lookup = utils.UserLookup(ctx.bot) message = '' data = [] for user, list in lists.items(): if user != mal_name: items, score = self.get_weighted_score(user_list, list) data.append({'items': items, 'score': score, 'user': user}) data = sorted(data, key=lambda x: (x.get('score') is not None, x.get('score')), reverse=True) none_newline = True for item in data: if not ('score' in item and item['score'] is not None) and none_newline: message += '\n' none_newline = False message += f'**{user_lookup.display_name_from_mal(item["user"])}**: {item["items"]} shared scores' if 'score' in item and item['score'] is not None: message += ', **{0:.1f}%** affinity\n'.format( item['score']) else: message += ', can\'t compute affinity\n' await utils.safe_say(ctx, message)
async def when(self, ctx, entity: str = 'anime', *, name: str = None): entity, name = extract_optional_entity(entity, name) if not name: raise commands.errors.BadArgument() entity_data, _ = await self.get_entity_from_string(ctx, name, entity) lists = await shared.cache.require_entity_lists(ctx, entity) message = discord.Embed( title=entity_data['title'], url=f'https://myanimelist.net/{entity}/{entity_data["id"]}') message.set_thumbnail(url=( entity_data['image_url'] if 'image_url' in entity_data else None)) description = '' if 'start_date' in entity_data: if 'end_date' in entity_data: aired_name = 'Aired' if entity == 'anime' else 'Published' description = f'{aired_name} from {entity_data["start_date"]} to {entity_data["end_date"]}\n\n' else: aired_name = 'Started airing' if entity == 'anime' else 'Started publishing' description = f'{aired_name}: {entity_data["start_date"]}\n\n' user_lookup = utils.UserLookup(ctx.bot) items_to_display = [] for user, list in lists.items(): user_display_name = user_lookup.display_name_from_mal(user) if entity == 'anime': status_key = 'watched_status' start_key = 'watching_start' end_key = 'watching_end' else: status_key = 'read_status' start_key = 'reading_start' end_key = 'reading_end' user_data = next((x for x in list if x['id'] == entity_data['id']), None) if user_data and (start_key in user_data or end_key in user_data): key = user_data[status_key] item_date = None item_display_string = None if start_key in user_data: if end_key in user_data: item_date = user_data[end_key] item_display_string = f'**{user_display_name}**: {user_data[status_key]} - {user_data[start_key]} to {user_data[end_key]} ({date_display_string_relative(user_data[end_key])})' else: item_date = user_data[start_key] item_display_string = f'**{user_display_name}**: {user_data[status_key]} - {user_data[start_key]} ({date_display_string_relative(user_data[start_key])})' else: item_date = user_data[end_key] item_display_string = f'**{user_display_name}**: {user_data[status_key]} - {user_data[end_key]} ({date_display_string_relative(user_data[end_key])})' items_to_display.append((item_date, item_display_string)) items = sorted(items_to_display, key=lambda x: x[0]) items = map(lambda x: x[1], items) description += '\n'.join(items) message.description = description await ctx.bot.say(embed=message)