async def manualregister(
        self,
        ctx: commands.Context,
        channel: discord.TextChannel,
        limit: int,
        after: discord.Message = None,
    ):
        """
        Effecture un enregistrement manuel en cas de problème.

        Vous devez donner les éléments suivants dans l'ordre :
        - `channel` Le channel où a eu lieu l'inscription
        - `limit` Le nombre de participants maximum à inscrire
        - `after` (Optionel) Le lien vers le message à partir duquel il faut vérifier les messages
        """
        guild = ctx.guild
        if not channel.permissions_for(guild.me).read_message_history:
            await ctx.send(
                "Je ne peux pas lire l'historique des messages dans ce channel."
            )
            return
        participants = []
        if after:
            after = after.created_at
        blacklist = await self.data.guild(guild).blacklisted()
        await self.data.guild(guild).current.set([])
        async with ctx.typing():
            async for message in channel.history(oldest_first=True,
                                                 after=after):
                if not MESSAGE_CHECK.match(message.content):
                    return
                member = message.author
                if member.id in blacklist:
                    return
                participants.append(member)
                if len(participants) >= limit:
                    break
        if len(participants) < limit:
            await ctx.send(
                f"Pas assez de participants trouvés ({len(participants)}/{limit})"
            )
            return
        await self.data.guild(guild).current.set(participants)
        await ctx.send(
            f"Inscription terminée, {len(participants)} membres enregistrés. Envoi du fichier..."
        )
        async with ctx.typing():
            content = "\n".join(
                (str(guild.get_member(x)) for x in participants))
            file = text_to_file(content, "participants.txt")
            await ctx.send(file=file)
Example #2
0
    async def massmove(
        self,
        ctx: commands.Context,
        from_channel: discord.VoiceChannel,
        to_channel: discord.VoiceChannel = None,
    ):
        """Move all members from one voice channel to another

        Use double quotes if channel name has spaces"""
        fails = 0
        if not from_channel.members:
            await ctx.send(
                chat.error(
                    _("There is no users in channel {}.").format(
                        from_channel.mention)))
            return
        if not from_channel.permissions_for(ctx.me).move_members:
            await ctx.send(chat.error(_("I cant move users from that channel"))
                           )
            return
        if to_channel and not to_channel.permissions_for(ctx.me).connect:
            await ctx.send(chat.error(_("I cant move users to that channel")))
            return
        async with ctx.typing():
            for member in from_channel.members:
                try:
                    await member.move_to(to_channel,
                                         reason=get_audit_reason(
                                             ctx.author, _("Massmove")))
                except discord.HTTPException:
                    fails += 1
                    continue
        await ctx.send(
            _("Finished moving users. {} members could not be moved.").format(
                fails))
Example #3
0
    async def _to_zip_server(self, ctx: commands.Context):
        """
        Get a `.zip` archive of all custom emojis in the server.

        The returned `.zip` archive can be used for the `[p]emojitools add fromzip` command.
        """

        async with ctx.typing():
            count = 0
            async with TemporaryDirectory() as temp_dir:
                for e in ctx.guild.emojis:
                    count += 1
                    if e.animated:
                        await e.url.save(
                            os.path.join(temp_dir, f"{e.name}.gif"))
                    else:
                        await e.url.save(
                            os.path.join(temp_dir, f"{e.name}.png"))

                aiozip = AioZipStream(await self.getfiles(temp_dir),
                                      chunksize=32768)
                async with NamedTemporaryFile('wb+') as z:
                    async for chunk in aiozip.stream():
                        await z.write(chunk)
                    await z.seek(0)
                    zip_file_obj = discord.File(
                        z.name, filename=f"{ctx.guild.name}.zip")

        return await ctx.send(
            f"{count} emojis were saved to this `.zip` archive!",
            file=zip_file_obj)
Example #4
0
    async def _add_all_reactions_from(self, ctx: commands.Context,
                                      message: discord.Message):
        """Add emojis to this server from all reactions in a message."""

        async with ctx.typing():
            added_emojis = []
            for r in message.reactions:
                if not r.custom_emoji:
                    continue
                try:
                    fe = await asyncio.wait_for(ctx.guild.create_custom_emoji(
                        name=r.emoji.name,
                        image=await r.emoji.url.read(),
                        reason=
                        f"EmojiTools: emoji added by {ctx.author.name}#{ctx.author.discriminator}"
                    ),
                                                timeout=10)
                    added_emojis.append(fe)
                except asyncio.TimeoutError:
                    return await ctx.send(TIME_OUT)
                except discord.Forbidden:
                    return await ctx.send(FORBIDDEN)
                except commands.CommandInvokeError:
                    return await ctx.send(INVOKE_ERROR)
                except discord.HTTPException:
                    return await ctx.send(HTTP_EXCEPTION)

        return await ctx.send(
            f"{len(added_emojis)} emojis were added to this server: {' '.join([str(e) for e in added_emojis])}"
        )
Example #5
0
    async def _add_emojis(self, ctx: commands.Context, *emojis: str):
        """Add some emojis to this server."""

        async with ctx.typing():
            added_emojis = []
            for e in emojis:
                try:
                    em = await commands.PartialEmojiConverter().convert(
                        ctx=ctx, argument=e)
                except commands.BadArgument:
                    return await ctx.send(f"Invalid emoji: {e}")
                em_image = await em.url.read()
                try:
                    fe = await asyncio.wait_for(ctx.guild.create_custom_emoji(
                        name=em.name,
                        image=em_image,
                        reason=
                        f"EmojiTools: emoji added by {ctx.author.name}#{ctx.author.discriminator}"
                    ),
                                                timeout=10)
                    added_emojis.append(fe)
                except asyncio.TimeoutError:
                    return await ctx.send(TIME_OUT)
                except discord.Forbidden:
                    return await ctx.send(FORBIDDEN)
                except commands.CommandInvokeError:
                    return await ctx.send(INVOKE_ERROR)
                except discord.HTTPException:
                    return await ctx.send(HTTP_EXCEPTION)

        return await ctx.send(
            f"{len(added_emojis)} emojis were added to this server: {' '.join([str(e) for e in added_emojis])}"
        )
Example #6
0
    async def _getzip(self, ctx: commands.Context, folder_number: int):
        """Zip and upload an EmojiTools folder."""

        async with ctx.typing():
            dirs = sorted(os.listdir(f"{data_manager.cog_data_path(self)}"))
            for d in dirs:
                if d.endswith(".zip"):
                    os.remove(
                        os.path.join(f"{data_manager.cog_data_path(self)}",
                                     f"{d}"))
            try:
                to_zip = dirs[folder_number]
            except IndexError:
                return await ctx.send("Invalid folder number.")

            zip_path = os.path.join(f"{data_manager.cog_data_path(self)}",
                                    f"{to_zip}")
            aiozip = AioZipStream(await self.getfiles(zip_path),
                                  chunksize=32768)
            async with aiofiles.open(zip_path + ".zip", mode='wb+') as z:
                async for chunk in aiozip.stream():
                    await z.write(chunk)

            zip_file_obj = discord.File(zip_path + ".zip")

        return await ctx.send(file=zip_file_obj)
Example #7
0
    async def leave_guilds(self, ctx: commands.Context, guilds: list, message: str):
        data = await self.config.all()
        unwl_guilds = [guild for guild in guilds if guild.id not in data["whitelist"]]
        if not unwl_guilds:
            await ctx.send("There are no servers to leave that aren't whitelisted.")
            return
        name_ids = "\n".join([f"{guild.name} - ({guild.id})" for guild in unwl_guilds][:5])
        guild_preview = name_ids + (
            f"\nand {len(unwl_guilds) - 5} other guilds.." if len(unwl_guilds) > 5 else ""
        )

        msg = await ctx.send(
            f"Are you sure you want me to leave the following {len(unwl_guilds)} guilds?\n"
            + box(guild_preview, "py")
        )
        start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
        pred = ReactionPredicate.yes_or_no(msg, ctx.author)
        try:
            await self.bot.wait_for("reaction_add", check=pred, timeout=60)
        except asyncio.TimeoutError:
            await ctx.send("Action cancelled.")

        if pred.result is True:
            async with ctx.typing():
                for guild in unwl_guilds:
                    await self.notify_guild(guild, message)
                    await guild.leave()
                await self.baron_log("mass_leave", guilds=unwl_guilds, author=ctx.author)
            await ctx.send(f"Done. I left {len(unwl_guilds)} servers.")
        else:
            await ctx.send("Action cancelled.")
Example #8
0
 async def super_massrole(
     self,
     ctx: commands.Context,
     members: list,
     role: discord.Role,
     fail_message: str = "Everyone in the server has this role.",
     adding: bool = True,
 ):
     member_list = self.get_member_list(members, role, adding)
     if not member_list:
         await ctx.send(fail_message)
         return
     verb = "add" if adding else "remove"
     word = "to" if adding else "from"
     await ctx.send(
         f"Beginning to {verb} `{role.name}` {word} **{len(member_list)}** members. "
         f"This will take around {humanize_timedelta(timedelta=datetime.timedelta(seconds=len(member_list) * 0.75))}."
     )
     async with ctx.typing():
         result = await self.massrole(member_list, [role],
                                      get_audit_reason(ctx.author), adding)
         result_text = f"{verb.title()[:5]}ed `{role.name}` {word} **{len(result['completed'])}** members."
         if result["skipped"]:
             result_text += (
                 f"\nSkipped {verb[:5]}ing roles for **{len(result['skipped'])}** members."
             )
         if result["failed"]:
             result_text += (
                 f"\nFailed {verb[:5]}ing roles for **{len(result['failed'])}** members."
             )
     await ctx.send(result_text)
Example #9
0
    async def system_red(self, ctx: commands.Context):
        """
        See what resources [botname] is using.

        Platforms: Windows, Linux, Mac OS
        Note: SWAP memory information is only available on Linux.
        """
        # i jolly hope we are logged in...
        if TYPE_CHECKING:
            assert self.bot.user is not None

        async with ctx.typing():
            red = (await get_red())["red"]

        botname = self.bot.user.name

        if await ctx.embed_requested():
            embed = discord.Embed(title=f"{botname}'s resource usage",
                                  colour=await ctx.embed_colour())
            embed.add_field(name="Resource usage", value=box(red))
            await ctx.send(embed=self.finalise_embed(embed))
        else:
            msg = f"**{botname}'s resource usage**\n"
            msg += box(f"Resource usage\n{red}\n")
            await ctx.send(msg)
Example #10
0
    async def system_cpu(self, ctx: commands.Context):
        """
        Get metrics about the CPU.

        This will show the CPU usage as a percent for each core, and frequency depending on
        platform.
        It will also show the time spent idle, user and system as well as uptime.

        Platforms: Windows, Linux, Mac OS
        Note: CPU frequency is nominal and overall on Windows and Mac OS,
        on Linux it's current and per-core.
        """
        async with ctx.typing():
            data = await get_cpu()
            percent = data["percent"]
            time = data["time"]
            freq = data["freq"]
            if await ctx.embed_requested():
                embed = discord.Embed(title="CPU Metrics",
                                      colour=await ctx.embed_colour())
                embed.add_field(name="CPU Usage", value=box(percent))
                embed.add_field(name="CPU Times", value=box(time))
                extra = data["freq_note"]
                embed.add_field(name=f"CPU Frequency{extra}", value=box(freq))
                await ctx.send(embed=self.finalise_embed(embed))
            else:
                msg = "**CPU Metrics**\n"
                to_box = f"CPU Usage\n{percent}\n"
                to_box += f"CPU Times\n{time}\n"
                extra = data["freq_note"]
                to_box += f"CPU Frequency{extra}\n{freq}\n"
                msg += box(to_box)
                await ctx.send(msg)
Example #11
0
    async def restore_tags(self, ctx: commands.Context, guild: Optional[discord.Guild] = None):
        slashtags: Dict[str, SlashTag] = (
            self.guild_tag_cache[guild.id] if guild else self.global_tag_cache
        )
        if not slashtags:
            message = "No slash tags have been created"
            if guild is not None:
                message += " for this server"
            return await ctx.send(message + ".")

        pred = MessagePredicate.yes_or_no(ctx)
        try:
            text = f"Are you sure you want to restore {len(slashtags)} slash tags"
            if guild is not None:
                text += " on this server"
            await self.send_and_query_response(
                ctx,
                text + " from the database? (Y/n)",
                pred,
            )
        except asyncio.TimeoutError:
            return await ctx.send("Timed out, not restoring slash tags.")
        if not pred.result:
            return await ctx.send("Ok, not restoring slash tags.")
        msg = await ctx.send(f"Restoring {len(slashtags)} slash tags...")
        async with ctx.typing():
            for tag in slashtags.copy().values():
                await tag.restore()
        await self.delete_quietly(msg)
        await ctx.send(f"Restored {len(slashtags)} slash tags.")
Example #12
0
    async def chatter_model(self, ctx: commands.Context, model_number: int):
        """
        Switch the active model to one of the three. Default after reload is Medium

        0: Small
        1: Medium
        2: Large (Requires additional setup)
        """

        models = [ENG_SM, ENG_MD, ENG_LG]

        if model_number < 0 or model_number > 2:
            await ctx.send_help()
            return

        if model_number == 2:
            await ctx.maybe_send_embed(
                "Additional requirements needed. See guide before continuing.\n"
                "Continue?")
            pred = MessagePredicate.yes_or_no(ctx)
            try:
                await self.bot.wait_for("message", check=pred, timeout=30)
            except TimeoutError:
                await ctx.send("Response timed out, please try again later.")
                return
            if not pred.result:
                return

        self.tagger_language = models[model_number]
        async with ctx.typing():
            self.chatbot = self._create_chatbot()

            await ctx.maybe_send_embed(
                f"Model has been switched to {self.tagger_language.ISO_639_1}")
Example #13
0
    async def chatter_algorithm(self,
                                ctx: commands.Context,
                                algo_number: int,
                                threshold: float = None):
        """
        Switch the active logic algorithm to one of the three. Default after reload is Spacy

        0: Spacy
        1: Jaccard
        2: Levenshtein
        """

        algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]

        if algo_number < 0 or algo_number > 2:
            await ctx.send_help()
            return

        if threshold is not None:
            if threshold >= 1 or threshold <= 0:
                await ctx.maybe_send_embed(
                    "Threshold must be a number between 0 and 1 (exclusive)")
                return
            else:
                self.similarity_algo = threshold

        self.similarity_algo = algos[algo_number]
        async with ctx.typing():
            self.chatbot = self._create_chatbot()

            await ctx.tick()
Example #14
0
    async def chatter_cleardata(self,
                                ctx: commands.Context,
                                confirm: bool = False):
        """
        This command will erase all training data and reset your configuration settings

        Use `[p]chatter cleardata True`
        """

        if not confirm:
            await ctx.maybe_send_embed(
                "Warning, this command will erase all your training data and reset your configuration\n"
                "If you want to proceed, run the command again as `[p]chatter cleardata True`"
            )
            return
        async with ctx.typing():
            await self.config.clear_all()
            self.chatbot = None
            await asyncio.sleep(
                10
            )  # Pause to allow pending commands to complete before deleting sql data
            if os.path.isfile(self.data_path):
                try:
                    os.remove(self.data_path)
                except PermissionError:
                    await ctx.maybe_send_embed(
                        "Failed to clear training database. Please wait a bit and try again"
                    )

            self._create_chatbot()

        await ctx.tick()
Example #15
0
    async def next(self, ctx: commands.Context, num_launches: int = 1):
        """
        Show the next launches

        Use `num_launches` to get more than one.
        """
        # launches = await api.async_next_launches(num_launches)
        # loop = asyncio.get_running_loop()
        #
        # launches = await loop.run_in_executor(
        #     None, functools.partial(self.api.fetch_launch, num=num_launches)
        # )
        #
        launches = await self.api.async_fetch_launch(num=num_launches)

        # log.debug(str(launches))
        async with ctx.typing():
            for x, launch in enumerate(launches):
                if x >= num_launches:
                    return

                em = await self._embed_launch_data(launch)
                if em is not None:
                    try:
                        await ctx.send(embed=em)
                    except discord.HTTPException:
                        await ctx.send(str(launch))
                        log.exception("Failed to send embed")
                await asyncio.sleep(2)
Example #16
0
    async def missions(self, ctx: commands.Context):
        """Returns all missions of SpaceX."""
        async with ctx.typing():
            resp = await self._get_data(ctx, "missions")
            if resp is None:
                return

            msg = []
            page = 1
            for data in resp:
                description = await self._missions_texts(data)
                manufacturers = ", ".join(data["manufacturers"])
                payloads = ", ".join(data["payload_ids"])
                em = discord.Embed(
                    color=await ctx.embed_colour(),
                    title="Name: {name} • ID: {id}".format(
                        name=data["mission_name"], id=data["mission_id"]),
                    description=description,
                )
                em.add_field(
                    name="Infos:",
                    value=("Manufacturer{s}: **{manufacturers}**\n"
                           "Payloads IDs: **{payloads_ids}**").format(
                               s="s"
                               if len(data["manufacturers"]) >= 2 else "",
                               manufacturers=manufacturers,
                               payloads_ids=payloads,
                           ),
                )
                em.set_footer(text="Page {} of {}".format(page, len(resp)))
                page += 1
                msg.append(em)

        await menu(ctx, msg, DEFAULT_CONTROLS)
Example #17
0
    async def _site_status_add(self, ctx: commands.Context, sitename: str,
                               url: str):
        """Set up SiteStatus to monitor a website."""
        async with ctx.typing():
            async with self.config.guild(ctx.guild).sites() as sites:
                try:
                    async with aiohttp.ClientSession() as session:
                        async with session.get(url) as response:
                            await ctx.send(
                                f"Site returned status code `{response.status}`."
                            )
                except (aiohttp.InvalidURL, aiohttp.ClientConnectorError):
                    return await ctx.send(
                        "There was an error connecting to this site. Is the url valid?"
                    )

                sites[sitename] = {
                    "url": url,
                    "status": 200,
                    "channel": None,
                    "online": None,
                    "offline": None,
                    "notify_channel": None,
                    "notify_role": None,
                    "last": None
                }
        return await ctx.tick()
Example #18
0
  async def feedback(self, ctx: commands.Context, *, the_feedback: str):
    #check if we're in tells or not
    if type(ctx.message.channel) is not discord.DMChannel:
      #if not in tells, delete the invocation and send a tell to the user
      #TODO: do we need to make sure the user can receive tells??
      await ctx.message.author.send(f"You need to use the <feedback> command here in DMs!")
      await ctx.message.delete()
    else:
      ctx.feedback = the_feedback
    #look for mutual servers
      mutuals = self._get_mutual_servers(ctx.message.author)
      #TODO: interactively ask which server to send to
      if len(mutuals) > 1:
        embed_pages = []
        for mutual in mutuals:
          this_embed = discord.Embed(
              colour=discord.Colour.from_rgb(r=82, g=182, b=119)
          )
          this_embed.set_author(
              name="Which server do you want to send feedback to?", icon_url=self.choosey_icon_url)
          this_embed.add_field(name="Server", value=mutual.name)
          this_embed.set_thumbnail(url=mutual.icon_url)
          this_embed.set_footer(text=mutual.id)
          embed_pages.append(this_embed)

        await menus.menu(ctx, embed_pages, self.guildChooserControls)
      elif len(mutuals) == 1:
        await self._process_feedback(ctx, mutuals[0].id)
      else:
        await ctx.send("We don't appear to share any servers!")
Example #19
0
    async def wikipedia(self, ctx: commands.Context, *, query: str):
        """Get information from Wikipedia."""
        can_not_embed_links = not ctx.channel.permissions_for(
            ctx.me).embed_links
        can_not_add_reactions = not ctx.channel.permissions_for(
            ctx.me).add_reactions
        only_first_result = can_not_embed_links or can_not_add_reactions
        async with ctx.typing():
            embeds, url = await self.perform_search(
                query, only_first_result=only_first_result)

        if not embeds:
            await ctx.send(
                error(f"I'm sorry, I couldn't find \"{query}\" on Wikipedia"))
        elif can_not_embed_links:
            await ctx.send(
                warning(
                    f"I'm not allowed to do embeds here, so here's the first result:\n{url}"
                ))
        elif can_not_add_reactions:
            embeds[0].set_author(
                name=f"Result 1 (I need add reactions permission to show more)"
            )
            await ctx.send(embed=embeds[0])
        elif len(embeds) == 1:
            embeds[0].set_author(name="Result 1 of 1")
            await ctx.send(embed=embeds[0])
        else:
            count = 0
            for embed in embeds:
                count += 1
                embed.set_author(name=f"Result {count} of {len(embeds)}")
            await menu(ctx, embeds, DEFAULT_CONTROLS, timeout=60.0)
Example #20
0
    async def _server(self, ctx: commands.Context, folder_name: str = None):
        """Save to a folder all custom emojis from this server (folder name defaults to server name)."""

        async with ctx.typing():
            if folder_name is None:
                folder_name = ctx.guild.name
            folder_path = os.path.join(f'{data_manager.cog_data_path(self)}',
                                       f'{folder_name}')
            try:
                os.mkdir(folder_path)
            except OSError:
                await ctx.send(
                    "The emojis will be added to the existing folder with this name."
                )

            count = 0
            for e in ctx.guild.emojis:
                count += 1
                if e.animated:
                    await e.url.save(os.path.join(folder_path,
                                                  f"{e.name}.gif"))
                else:
                    await e.url.save(os.path.join(folder_path,
                                                  f"{e.name}.png"))

        return await ctx.send(f"{count} emojis were saved to `{folder_name}`.")
Example #21
0
    async def ownercleanup(self, ctx: Context):
        """
        Cleanup old/missing reaction roles and settings on the bot.

        Note: This will also clear out reaction roles if the bot is just
        missing permissions to see the reactions.
        """
        async with ctx.typing():
            for guild_id in self.settings:
                guild = self.bot.get_guild(guild_id)
                if not guild:
                    continue
                async with self.config.guild(
                        ctx.guild).reaction_roles() as cur_settings:
                    to_remove = []
                    for key, role_id in cur_settings.items():
                        chan_id, message_id, emoji = key.split("-")
                        channel = guild.get_channel(int(chan_id))
                        if not channel:
                            to_remove.append((key, role_id))
                            continue
                        message = await channel.fetch_message(int(message_id))
                        if not message:
                            to_remove.append((key, role_id))
                            continue
                        role = guild.get_role(int(role_id))
                        if not role:
                            to_remove.append((key, role_id))
                    for key, role_id in to_remove:
                        del cur_settings[key]
                        del self.settings[guild.id]["reaction_roles"][key]
                        async with self.config.role_from_id(
                                role_id).reactions() as reactions:
                            reactions.remove(key)
        await ctx.send(_("I am finished deleting old settings."))
Example #22
0
    async def _add_emoji(self,
                         ctx: commands.Context,
                         emoji: discord.PartialEmoji,
                         name: str = None):
        """Add an emoji to this server (leave `name` blank to use the emoji's original name)."""

        async with ctx.typing():
            e_image = await emoji.url.read()
            e_name = name or emoji.name
            try:
                final_emoji = await asyncio.wait_for(
                    ctx.guild.create_custom_emoji(
                        name=e_name,
                        image=e_image,
                        reason=
                        f"EmojiTools: emoji added by {ctx.author.name}#{ctx.author.discriminator}"
                    ),
                    timeout=10)
            except asyncio.TimeoutError:
                return await ctx.send(TIME_OUT)
            except discord.Forbidden:
                return await ctx.send(FORBIDDEN)
            except commands.CommandInvokeError:
                return await ctx.send(INVOKE_ERROR)
            except discord.HTTPException:
                return await ctx.send(HTTP_EXCEPTION)

        return await ctx.send(f"{final_emoji} has been added to this server!")
Example #23
0
    async def _initialize(self, ctx: commands.Context,
                          enter_true_to_confirm: bool):
        """Adds current members to the already-redeemed list (except those that joined within time limit)."""

        if not enter_true_to_confirm:
            return await ctx.send(
                "Please provide `true` as the parameter to confirm.")

        async with ctx.typing():
            time_limit = await self.config.guild(ctx.guild).time_limit()

            if not time_limit:
                return await ctx.send(
                    f"Please set the time limit first using `{ctx.clean_prefix}referset timelimit`!"
                )

            async with self.config.guild(
                    ctx.guild).already_redeemed() as already_redeemed:
                async for m in AsyncIter(ctx.guild.members, steps=500):
                    if (m.joined_at and
                        (m.joined_at <
                         (datetime.now() - timedelta(hours=time_limit)))
                            and m.id not in already_redeemed):
                        already_redeemed.append(m.id)

        return await ctx.send(
            "The already-redeemed list was updated successfully!")
Example #24
0
    async def _add_from_reaction(self,
                                 ctx: commands.Context,
                                 specific_reaction: str,
                                 message: discord.Message,
                                 new_name: str = None):
        """Add an emoji to this server from a specific reaction on a message."""

        final_emoji = None
        async with ctx.typing():
            for r in message.reactions:
                if r.custom_emoji and r.emoji.name == specific_reaction:
                    try:
                        final_emoji = await asyncio.wait_for(
                            ctx.guild.create_custom_emoji(
                                name=new_name or r.emoji.name,
                                image=await r.emoji.url.read(),
                                reason=
                                f"EmojiTools: emoji added by {ctx.author.name}#{ctx.author.discriminator}"
                            ),
                            timeout=10)
                    except asyncio.TimeoutError:
                        return await ctx.send(TIME_OUT)
                    except discord.Forbidden:
                        return await ctx.send(FORBIDDEN)
                    except commands.CommandInvokeError:
                        return await ctx.send(INVOKE_ERROR)
                    except discord.HTTPException:
                        return await ctx.send(HTTP_EXCEPTION)
        if final_emoji:
            return await ctx.send(
                f"{final_emoji} has been added to this server!")
        else:
            return await ctx.send(
                f"No reaction called `{specific_reaction}` was found on that message!"
            )
Example #25
0
 async def super_massrole(
     self,
     ctx: commands.Context,
     members: list,
     role: discord.Role,
     fail_message: str = "Everyone in the server has this role.",
     adding: bool = True,
 ):
     if guild_roughly_chunked(ctx.guild) is False and self.bot.intents.members:
         await ctx.guild.chunk()
     member_list = self.get_member_list(members, role, adding)
     if not member_list:
         await ctx.send(fail_message)
         return
     verb = "add" if adding else "remove"
     word = "to" if adding else "from"
     await ctx.send(f"Beginning to {verb} `{role.name}` {word} **{len(member_list)}** members.")
     async with ctx.typing():
         result = await self.massrole(member_list, [role], get_audit_reason(ctx.author), adding)
         result_text = f"{verb.title()[:5]}ed `{role.name}` {word} **{len(result['completed'])}** members."
         if result["skipped"]:
             result_text += (
                 f"\nSkipped {verb[:5]}ing roles for **{len(result['skipped'])}** members."
             )
         if result["failed"]:
             result_text += (
                 f"\nFailed {verb[:5]}ing roles for **{len(result['failed'])}** members."
             )
     await ctx.send(result_text)
Example #26
0
    async def _to_zip_emojis(self, ctx: commands.Context, *emojis: str):
        """
        Get a `.zip` archive of a list of emojis.

        The returned `.zip` archive can be used for the `[p]emojitools add fromzip` command.
        """

        async with ctx.typing():
            async with TemporaryDirectory() as temp_dir:
                for e in emojis:
                    try:
                        em = await commands.PartialEmojiConverter().convert(
                            ctx=ctx, argument=e)
                    except commands.BadArgument:
                        return await ctx.send(f"Invalid emoji: {e}")

                    if em.animated:
                        await em.url.save(
                            os.path.join(temp_dir, f"{em.name}.gif"))
                    else:
                        await em.url.save(
                            os.path.join(temp_dir, f"{em.name}.png"))

                aiozip = AioZipStream(await self.getfiles(temp_dir),
                                      chunksize=32768)
                async with NamedTemporaryFile('wb+') as z:
                    async for chunk in aiozip.stream():
                        await z.write(chunk)
                    await z.seek(0)
                    zip_file_obj = discord.File(z.name, filename="emojis.zip")

        return await ctx.send(
            f"{len(emojis)} emojis were saved to this `.zip` archive!",
            file=zip_file_obj)
Example #27
0
async def send_preview(
    ctx: commands.Context,
    pages: list,
    controls: dict,
    message: discord.Message,
    page: int,
    timeout: float,
    emoji: str,
):
    with suppress(discord.NotFound):
        await message.delete()
    doc = ctx.search_docs[page]
    async with ctx.typing():
        try:
            async with ctx.cog.session.get(
                doc.preview_scene, raise_for_status=True
            ) as video_preview:
                video_preview = BytesIO(await video_preview.read())
                await ctx.send(
                    embed=pages[page],
                    file=discord.File(video_preview, filename=doc.filename),
                )
                video_preview.close()
        except aiohttp.ClientResponseError as e:
            await ctx.send(_("Unable to get video preview: {}").format(e.message))
        except discord.HTTPException as e:
            await ctx.send(_("Unable to send video preview: {}").format(e))
Example #28
0
    async def _emojis(self, ctx: commands.Context, folder_name: str,
                      *emojis: str):
        """Save to a folder the specified custom emojis (can be from any server)."""

        async with ctx.typing():
            folder_path = os.path.join(f'{data_manager.cog_data_path(self)}',
                                       f'{folder_name}')
            try:
                os.mkdir(folder_path)
            except OSError:
                await ctx.send(
                    "The emojis will be added to the existing folder with this name."
                )

            for e in emojis:
                try:
                    em = await commands.PartialEmojiConverter().convert(
                        ctx=ctx, argument=e)
                except commands.BadArgument:
                    return await ctx.send(f"Invalid emoji: {e}")

                em_image = await em.url.read()
                if em.animated:
                    ext = ".gif"
                else:
                    ext = ".png"

                async with aiofiles.open(os.path.join(folder_path,
                                                      f"{em.name}{ext}"),
                                         mode='wb') as f:
                    await f.write(em_image)

        return await ctx.send(
            f"{len(emojis)} emojis were saved to `{folder_name}`.")
Example #29
0
    async def _about_cog(self, ctx: commands.Context, version: str):
        async with ctx.typing():
            data = await self._get_data(ctx)
            description = data["description"]
            docs = data["docs"]
            project_link = data["project_link"]
            if data is None:
                description = (
                    "Open Source REST API for rocket, core, capsule, pad, and launch data, "
                    "created and maintained by the developers of the r/SpaceX organization"
                )
                docs = "https://documenter.getpostman.com/view/2025350/RWaEzAiG"
                project_link = "https://github.com/r-spacex/SpaceX-API"
                return

            title_api = "About SpaceX-API:\n"
            title_cog = "About this cog:\n"
            desc_api = (
                description +
                "\n**[Docs]({docs})** • **[Project Link]({project})**").format(
                    docs=docs, project=project_link)
            desc_cog = (
                f"Cog version: {version}\nYou can also use "
                "[Space cog from kennnyshiwa](https://github.com/kennnyshiwa/kennnyshiwa-cogs) "
                "for more about space in general, space pics, Astronomy Picture of the Day from Nasa, "
                "ISS location ...")
            em = discord.Embed(color=await ctx.embed_colour())
            em.add_field(name=title_api, value=desc_api)
            em.add_field(name=title_cog, value=desc_cog)
        return await ctx.send(embed=em)
Example #30
0
    async def listcases(self, ctx: commands.Context, *,
                        member: Union[discord.Member, int]):
        """List cases for the specified member."""
        async with ctx.typing():
            try:
                if isinstance(member, int):
                    cases = await modlog.get_cases_for_member(bot=ctx.bot,
                                                              guild=ctx.guild,
                                                              member_id=member)
                else:
                    cases = await modlog.get_cases_for_member(bot=ctx.bot,
                                                              guild=ctx.guild,
                                                              member=member)
            except discord.NotFound:
                return await ctx.send(_("That user does not exist."))
            except discord.HTTPException:
                return await ctx.send(
                    _("Something unexpected went wrong while fetching that user by ID."
                      ))
            if not cases:
                return await ctx.send(_("That user does not have any cases."))

            rendered_cases = []
            message = ""
            for case in cases:
                message += _("{case}\n**Timestamp:** {timestamp}\n\n").format(
                    case=await case.message_content(embed=False),
                    timestamp=datetime.utcfromtimestamp(
                        case.created_at).strftime("%Y-%m-%d %H:%M:%S UTC"),
                )
            for page in pagify(message, ["\n\n", "\n"], priority=True):
                rendered_cases.append(page)
        await menu(ctx, rendered_cases, DEFAULT_CONTROLS)
Example #31
0
    async def dataconversioncommand(self, ctx: commands.Context, v2path: str):
        """Interactive prompt for importing data from Red V2.

        Takes the path where the V2 install is, and overwrites
        values which have entries in both V2 and v3; use with caution.
        """
        resolver = SpecResolver(Path(v2path.strip()))

        if not resolver.available:
            return await ctx.send(
                _(
                    "There don't seem to be any data files I know how to "
                    "handle here. Are you sure you gave me the base "
                    "installation path?"
                )
            )
        while resolver.available:
            menu = _("Please select a set of data to import by number, or 'exit' to exit")
            for index, entry in enumerate(resolver.available, 1):
                menu += "\n{}. {}".format(index, entry)

            menu_message = await ctx.send(box(menu))

            try:
                message = await self.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=60
                )
            except asyncio.TimeoutError:
                return await ctx.send(_("Try this again when you are ready."))
            else:
                if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]:
                    return await ctx.tick()
                try:
                    message = int(message.content.strip())
                    to_conv = resolver.available[message - 1]
                except (ValueError, IndexError):
                    await ctx.send(_("That wasn't a valid choice."))
                    continue
                else:
                    async with ctx.typing():
                        await resolver.convert(self.bot, to_conv)
                    await ctx.send(_("{} converted.").format(to_conv))
            await menu_message.delete()
        else:
            return await ctx.send(
                _(
                    "There isn't anything else I know how to convert here.\n"
                    "There might be more things I can convert in the future."
                )
            )