Example #1
0
    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))
Example #2
0
    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')
Example #3
0
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)
Example #4
0
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
Example #5
0
 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')
Example #6
0
    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)
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
    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)
Example #10
0
    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))
Example #11
0
    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')
Example #12
0
    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)
Example #13
0
    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)