예제 #1
0
    async def chart(self, ctx, coin, pair="USDT", interval="1h", limit: int = 50):
        """Generates candlestick chart for a given cryptocurrency pair."""
        if interval not in self.binance_intervals:
            raise exceptions.Error("Invalid interval.")

        if limit > 100:
            raise exceptions.Error("Limit must be 100 or less.")

        symbol = (coin + pair).upper()
        async with aiohttp.ClientSession() as session:
            url = "https://api.binance.com/api/v3/klines"
            params = {"symbol": symbol, "interval": interval, "limit": limit}
            async with session.get(url, params=params) as response:
                data = await response.json()

        if isinstance(data, dict):
            raise exceptions.Error(data.get("msg"))

        candle_data = []
        for ticker in data:
            candle_data.append(str(ticker[:5]))

        current_price = Decimal(data[-1][4]).normalize()

        replacements = {
            "HEIGHT": 512,
            "TITLE": f"{coin.upper()} / {pair.upper()} | {interval} | {current_price:,f}",
            "DATA": ",".join(candle_data),
        }

        def dictsub(m):
            return str(replacements[m.group().strip("$")])

        formatted_html = re.sub(r"\$(\S*)\$", dictsub, self.candlestick_chart_html)
        async with aiohttp.ClientSession() as session:
            data = {
                "html": formatted_html,
                "width": 720,
                "height": 512,
                "imageFormat": "png",
            }
            async with session.post("http://localhost:3000/html", data=data) as response:
                with open("downloads/candlestick.png", "wb") as f:
                    while True:
                        block = await response.content.read(1024)
                        if not block:
                            break
                        f.write(block)

        with open("downloads/candlestick.png", "rb") as f:
            await ctx.send(file=discord.File(f))
예제 #2
0
    async def fastban(self, ctx, *discord_users):
        """Ban user(s) without confirmation box."""
        if not discord_users:
            return await util.send_command_help(ctx)

        for discord_user in discord_users:
            user = await util.get_user(ctx, discord_user)
            if user is None:
                try:
                    user = await self.bot.fetch_user(int(discord_user))
                except (ValueError, discord.NotFound):
                    raise exceptions.Warning(
                        f"Invalid user or id `{discord_user}`")

            if user.id == 133311691852218378:
                return await ctx.send("no.")

            try:
                await ctx.guild.ban(user, delete_message_days=0)
            except discord.errors.Forbidden:
                raise exceptions.Error(
                    f"It seems I don't have the permission to ban **{user}**")
            else:
                await ctx.send(embed=discord.Embed(
                    description=f":hammer: Banned `{user}`",
                    color=int("f4900c", 16)))
예제 #3
0
    async def unmute(self, ctx, member: discord.Member):
        """Unmute user."""
        mute_role_id = await self.bot.db.execute(
            """
            SELECT mute_role_id FROM guild_settings WHERE guild_id = %s
            """,
            ctx.guild.id,
            one_value=True,
        )
        mute_role = ctx.guild.get_role(mute_role_id)
        if not mute_role:
            raise exceptions.Warning(
                "Mute role for this server has been deleted or is not set, "
                f"please use `{ctx.prefix}muterole <role>` to set it.")
        try:
            await member.remove_roles(mute_role)
        except discord.errors.Forbidden:
            raise exceptions.Error(
                f"It seems I don't have permission to unmute {member.mention}")

        await util.send_success(ctx, f"Unmuted {member.mention}")
        await self.bot.db.execute(
            """
            DELETE FROM muted_user WHERE guild_id = %s AND user_id = %s
            """,
            ctx.guild.id,
            member.id,
        )
        self.cache_needs_refreshing = True
예제 #4
0
    async def purge(self, ctx, amount: int):
        """
        Delete some amount of messages in current channel.
        Optionally if users are mentioned, only messages by those users are deleted.

        Usage:
            >purge <amount> [mentions...]
        """
        if amount > 100:
            raise exceptions.Warning(
                "You cannot delete more than 100 messages at a time.")

        await ctx.message.delete()

        if ctx.message.mentions:
            deleted = []
            async for message in ctx.channel.history(limit=100,
                                                     oldest_first=False):
                if message.author in ctx.message.mentions:
                    deleted.append(message)
                    if len(deleted) >= amount:
                        break
            try:
                await ctx.channel.delete_messages(deleted)
            except discord.errors.HTTPException:
                raise exceptions.Error(
                    "You can only delete messages that are under 14 days old.")
        else:
            deleted = await ctx.channel.purge(limit=amount)

        await ctx.send(
            f":put_litter_in_its_place: Deleted `{len(deleted)}` messages.",
            delete_after=5,
        )
예제 #5
0
    async def youtube(self, ctx, *, query):
        """Search videos from youtube."""
        url = "https://www.googleapis.com/youtube/v3/search"
        params = {
            "key": GOOGLE_API_KEY,
            "part": "snippet",
            "type": "video",
            "maxResults": 25,
            "q": query,
        }
        async with aiohttp.ClientSession() as session:
            async with session.get(url, params=params) as response:
                if response.status == 403:
                    raise exceptions.Error("Daily youtube api quota reached.")

                data = await response.json()

        if not data.get("items"):
            return await ctx.send("No results found!")

        await util.paginate_list(
            ctx,
            [
                f"https://youtube.com/watch?v={item['id']['videoId']}"
                for item in data.get("items")
            ],
            use_locking=True,
            only_author=True,
            index_entries=True,
        )
예제 #6
0
 async def execute(self,
                   statement,
                   *params,
                   one_row=False,
                   one_value=False,
                   as_list=False):
     if await self.wait_for_pool():
         async with self.pool.acquire() as conn:
             async with conn.cursor() as cur:
                 await cur.execute(statement, params)
                 data = await cur.fetchall()
         if data is None:
             return ()
         else:
             if data:
                 if one_value:
                     return data[0][0]
                 elif one_row:
                     return data[0]
                 elif as_list:
                     return [row[0] for row in data]
                 else:
                     return data
             else:
                 return ()
     else:
         raise exceptions.Error(
             "Could not connect to the local MariaDB instance!")
예제 #7
0
 async def executemany(self, statement, params):
     if await self.wait_for_pool():
         async with self.pool.acquire() as conn:
             async with conn.cursor() as cur:
                 await cur.executemany(statement, params)
                 await conn.commit()
         return ()
     raise exceptions.Error(
         "Could not connect to the local MariaDB instance!")
예제 #8
0
파일: kpop.py 프로젝트: Thosles/miso-bot
    async def random(self, ctx, gender=None):
        """Get a random kpop idol."""
        gender = get_gender(gender)

        idol_id_list = await self.bot.db.execute(
            "SELECT idol_id FROM kpop_idol WHERE gender IN %s",
            gender,
            as_list=True,
        )
        if not idol_id_list:
            raise exceptions.Error("Looks like there are no idols in the database!")

        chosen_id = random.choice(idol_id_list)
        await self.send_idol(ctx, chosen_id)
예제 #9
0
    async def price(self, ctx, coin, pair="USDT"):
        """See the current price and 25h statistics of cryptocurrency pair."""
        symbol = (coin + pair).upper()
        url = "https://api.binance.com/api/v3/ticker/24hr"
        params = {"symbol": symbol}
        async with aiohttp.ClientSession() as session:
            async with session.get(url, params=params) as response:
                data = await response.json()

        error = data.get("msg")
        if error:
            raise exceptions.Error(error)

        content = discord.Embed(color=int("f3ba2e", 16))
        content.set_author(
            name=f"{data.get('symbol')} | Binance",
            icon_url=self.binance_icon,
            url=f"https://www.binance.com/en/trade/{data.get('symbol')}",
        )
        content.add_field(
            name="Current price", value=f"{Decimal(data.get('lastPrice')).normalize():,f}"
        )
        content.add_field(
            name="24h High", value=f"{Decimal(data.get('highPrice')).normalize():,f}"
        )
        content.add_field(name="24h Low", value=f"{Decimal(data.get('lowPrice')).normalize():,f}")
        pricechange = Decimal(data.get("priceChange")).normalize()
        if pricechange > 0:
            direction = emojis.GREEN_UP
        elif pricechange < 0:
            direction = emojis.RED_DOWN
        else:
            direction = ":white_small_square:"

        content.add_field(
            name="24h Change",
            value=f"{direction} {pricechange:,f} ({Decimal(data.get('priceChangePercent')).normalize():.2f}%)",
        )
        content.add_field(
            name=f"24h Volume ({coin.upper()})",
            value=f"{Decimal(data.get('volume')).normalize():,.2f}",
        )
        content.add_field(
            name=f"24h Volume ({pair.upper()})",
            value=f"{Decimal(data.get('quoteVolume')).normalize():,.2f}",
        )
        await ctx.send(embed=content)
예제 #10
0
    async def test(self, ctx, message: discord.Message = None):
        """
        Test if Miso can send you a notification.
        If supplied with a message id, will check if you would have been notified by it.
        """
        if message is None:
            try:
                await self.send_notification(ctx.author,
                                             message or ctx.message, ["test"],
                                             test=True)
                await ctx.send(":ok_hand: Check your DM")
            except discord.errors.Forbidden:
                raise exceptions.Warning(
                    "I was unable to send you a DM! Please check your privacy settings."
                )
        else:
            if ctx.author not in message.channel.members:
                raise exceptions.Error("You cannot see this message.")

            keywords = await self.bot.db.execute(
                "SELECT keyword FROM notification WHERE user_id = %s",
                ctx.author.id,
                as_list=True)

            pattern = regex.compile(self.keyword_regex,
                                    words=keywords,
                                    flags=regex.IGNORECASE)

            finds = pattern.findall(message.content)
            if not finds:
                await ctx.send(":x: This message would not notify you")
            else:
                keywords = list(set(finds))
                await self.send_notification(ctx.author,
                                             message,
                                             keywords,
                                             test=True)
                await ctx.send(":ok_hand: Check your DM")
예제 #11
0
    async def ban(self, ctx, *discord_users):
        """Ban user(s)."""
        if not discord_users:
            return await util.send_command_help(ctx)

        for discord_user in discord_users:
            user = await util.get_member(ctx, discord_user)
            if user is None:
                try:
                    user = await self.bot.fetch_user(int(discord_user))
                except (ValueError, discord.NotFound):
                    raise exceptions.Warning(
                        f"Invalid user or id `{discord_user}`")

            if user.id == 133311691852218378:
                return await ctx.send("no.")

            # confirmation dialog for guild members
            if isinstance(user, discord.Member):
                await self.send_ban_confirmation(ctx, user)

            elif isinstance(user, discord.User):
                try:
                    await ctx.guild.ban(user)
                except discord.errors.Forbidden:
                    raise exceptions.Error(
                        f"It seems I don't have the permission to ban **{user}**"
                    )
                else:
                    await ctx.send(embed=discord.Embed(
                        description=f":hammer: Banned `{user}`",
                        color=int("f4900c", 16)))
            else:
                raise exceptions.Warning(
                    f"There was an error finding discord user `{discord_user}`"
                )
예제 #12
0
    async def mute(self, ctx, member: discord.Member, *, duration=None):
        """Mute user."""
        mute_role_id = await self.bot.db.execute(
            """
            SELECT mute_role_id FROM guild_settings WHERE guild_id = %s
            """,
            ctx.guild.id,
            one_value=True,
        )
        mute_role = ctx.guild.get_role(mute_role_id)
        if not mute_role:
            raise exceptions.Warning(
                "Mute role for this server has been deleted or is not set, "
                f"please use `{ctx.prefix}muterole <role>` to set it.")

        if member.id == 133311691852218378:
            return await ctx.send("no.")

        seconds = None
        if duration is not None:
            seconds = util.timefromstring(duration)

            if seconds is None or seconds == 0:
                raise exceptions.Warning(f'Invalid mute duration "{duration}"')

            if seconds < 60:
                raise exceptions.Info(
                    "The minimum duration of a mute is **1 minute**")

            if seconds > 604800:
                raise exceptions.Info(
                    "The maximum duration of a mute is **1 week**")

        try:
            await member.add_roles(mute_role)
        except discord.errors.Forbidden:
            raise exceptions.Error(
                f"It seems I don't have permission to mute {member.mention}")

        await util.send_success(
            ctx,
            f"Muted {member.mention}" +
            (f" for **{util.stringfromtime(seconds)}**"
             if seconds is not None else ""),
        )

        if seconds is not None:
            unmute_on = arrow.now().shift(seconds=+seconds).datetime
        else:
            unmute_on = None

        await self.bot.db.execute(
            """
            INSERT INTO muted_user (guild_id, user_id, channel_id, unmute_on)
                VALUES (%s, %s, %s, %s)
            ON DUPLICATE KEY UPDATE
                unmute_on = VALUES(unmute_on)
            """,
            ctx.guild.id,
            member.id,
            ctx.channel.id,
            unmute_on,
        )
        self.cache_needs_refreshing = True
예제 #13
0
    async def send_idol(self, ctx, idol_id):
        idol_data = await self.bot.db.execute(
            """
            SELECT full_name, stage_name, korean_name, korean_stage_name,
                   date_of_birth, country, birthplace, group_name, height, weight, gender
                FROM kpop_idol
            WHERE idol_id = %s
            """,
            idol_id,
            one_row=True,
        )
        if not idol_data:
            raise exceptions.Error("There was an error getting idol data.")

        (
            full_name,
            stage_name,
            korean_name,
            korean_stage_name,
            date_of_birth,
            country,
            birthplace,
            group_name,
            height,
            weight,
            gender,
        ) = idol_data

        if group_name is None:
            search_term = full_name
        else:
            search_term = f"{group_name} {stage_name}"

        image = await self.google_image_search(search_term)
        content = discord.Embed()
        if gender == "F":
            content.color = int("e7586d", 16)
        elif gender == "M":
            content.color = int("226699", 16)

        content.title = (self.gender_icon.get(gender, "") +
                         (f"{group_name} " if group_name is not None else "") +
                         stage_name)
        today = datetime.date.today()
        age = (today.year - date_of_birth.year -
               ((today.month, today.day) <
                (date_of_birth.month, date_of_birth.day)))
        content.set_image(url=image)
        content.add_field(name="Full name", value=full_name)
        content.add_field(name="Korean name",
                          value=f"{korean_stage_name} ({korean_name})")
        content.add_field(name="Birthday",
                          value=arrow.get(date_of_birth).format("YYYY-MM-DD") +
                          f" (age {age})")
        content.add_field(name="Country", value=country)
        content.add_field(name="Height",
                          value=f"{height} cm" if height else "unknown")
        content.add_field(name="Weight",
                          value=f"{weight} kg" if weight else "unknown")

        await ctx.send(embed=content)
예제 #14
0
    async def instagram(self, ctx, **options):
        """Get all the images from one or more instagram posts."""
        async with aiohttp.ClientSession() as session:
            for url in options["urls"]:
                result = regex.findall("/p/(.*?)(/|\\Z)", url)
                if result:
                    url = f"https://www.instagram.com/p/{result[0][0]}"
                else:
                    url = f"https://www.instagram.com/p/{url.strip('/').split('/')[0]}"

                headers = {
                    "User-Agent":
                    self.user_agents.get_random_user_agent(),
                    "X-IG-App-ID":
                    "936619743392459",
                    "Cookie":
                    "ig_cb=2; ig_did=CD9C9CD6-A65D-4CA0-A810-DA55EF09C143; csrftoken=du0pHNPkxq5hpQTiFhWVefvZ01aneHYa; mid=X67owAAEAAHD89ozXg9Fx48IPef0; ds_user_id=5951951432; sessionid=5951951432%3A0eHKUlAtGE83k1%3A13; fbm_124024574287414=base_domain=.instagram.com; shbid=10480; shbts=1618475928.6377892; rur=RVA",
                }
                post_id = url.split("/")[-1]
                newurl = "https://www.instagram.com/graphql/query/"
                params = {
                    "query_hash":
                    "505f2f2dfcfce5b99cb7ac4155cbf299",
                    "variables":
                    '{"shortcode":"' + post_id +
                    '","include_reel":false,"include_logged_out":true}',
                }

                async with session.get(newurl,
                                       params=params,
                                       headers=headers,
                                       proxy=ROTATING_PROXY_URL) as response:
                    try:
                        data = await response.json()
                    except aiohttp.ContentTypeError:
                        raise exceptions.Error(
                            "Instagram is banning me from accessing their page. Please try again later."
                        )
                    data = data["data"]["shortcode_media"]

                if data is None:
                    await ctx.send(f":warning: Invalid instagram URL `{url}`")
                    continue

                medias = []
                try:
                    for x in data["edge_sidecar_to_children"]["edges"]:
                        medias.append(x["node"])
                except KeyError:
                    medias.append(data)

                avatar_url = data["owner"]["profile_pic_url"]
                username = data["owner"]["username"]
                content = discord.Embed(color=random.choice(self.ig_colors))
                content.set_author(name=f"@{username}",
                                   icon_url=avatar_url,
                                   url=url)

                if not medias:
                    await ctx.send(
                        f":warning: Could not find any media from `{url}`")
                    continue

                if options["download"]:
                    # send as files
                    async with aiohttp.ClientSession() as session:
                        await ctx.send(f"<{url}>")
                        timestamp = arrow.get(
                            data["taken_at_timestamp"]).format("YYMMDD")
                        for n, file in enumerate(medias, start=1):
                            if file.get("is_video"):
                                media_url = file.get("video_url")
                                extension = "mp4"
                            else:
                                media_url = file.get("display_url")
                                extension = "jpg"

                            filename = f"{timestamp}-@{username}-{post_id}-{n}.{extension}"
                            async with session.get(media_url) as response:
                                with open(filename, "wb") as f:
                                    while True:
                                        block = await response.content.read(
                                            1024)
                                        if not block:
                                            break
                                        f.write(block)

                            with open(filename, "rb") as f:
                                await ctx.send(file=discord.File(f))

                            os.remove(filename)
                else:
                    # send as embeds
                    for medianode in medias:
                        if medianode.get("is_video"):
                            await ctx.send(embed=content)
                            await ctx.send(medianode.get("video_url"))
                        else:
                            content.set_image(url=medianode.get("display_url"))
                            await ctx.send(embed=content)
                        content.description = None
                        content._author = None

        try:
            # delete discord automatic embed
            await ctx.message.edit(suppress=True)
        except discord.Forbidden:
            pass
예제 #15
0
파일: media.py 프로젝트: Thosles/miso-bot
    async def instagram(self, ctx, **options):
        """Get all the images from one or more instagram posts."""
        async with aiohttp.ClientSession() as session:
            for url in options["urls"]:
                result = regex.findall("/p/(.*?)(/|\\Z)", url)
                if result:
                    url = f"https://www.instagram.com/p/{result[0][0]}"
                else:
                    url = f"https://www.instagram.com/p/{url.strip('/').split('/')[0]}"

                headers = {
                    "User-Agent":
                    "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0",
                }
                post_id = url.split("/")[-1]
                newurl = "https://www.instagram.com/graphql/query/"
                params = {
                    "query_hash":
                    "505f2f2dfcfce5b99cb7ac4155cbf299",
                    "variables":
                    '{"shortcode":"' + post_id +
                    '","include_reel":false,"include_logged_out":true}',
                }

                async with session.get(newurl,
                                       params=params,
                                       headers=headers,
                                       proxy=ROTATING_PROXY_URL) as response:
                    try:
                        data = await response.json()
                    except aiohttp.ContentTypeError:
                        raise exceptions.Error(
                            "This proxy IP address has been banned by Instagram. Try again later."
                        )
                    data = data["data"]["shortcode_media"]

                if data is None:
                    await ctx.send(f":warning: Invalid instagram URL `{url}`")
                    continue

                medias = []
                try:
                    for x in data["edge_sidecar_to_children"]["edges"]:
                        medias.append(x["node"])
                except KeyError:
                    medias.append(data)

                avatar_url = data["owner"]["profile_pic_url"]
                username = data["owner"]["username"]
                content = discord.Embed(color=random.choice(self.ig_colors))
                content.set_author(name=f"@{username}",
                                   icon_url=avatar_url,
                                   url=url)

                if not medias:
                    await ctx.send(
                        f":warning: Could not find any media from `{url}`")
                    continue

                if options["download"]:
                    # send as files
                    async with aiohttp.ClientSession() as session:
                        await ctx.send(f"<{url}>")
                        timestamp = arrow.get(
                            data["taken_at_timestamp"]).format("YYMMDD")
                        for n, file in enumerate(medias, start=1):
                            if file.get("is_video"):
                                media_url = file.get("video_url")
                                extension = "mp4"
                            else:
                                media_url = file.get("display_url")
                                extension = "jpg"

                            filename = f"{timestamp}-@{username}-{post_id}-{n}.{extension}"
                            async with session.get(media_url) as response:
                                with open(filename, "wb") as f:
                                    while True:
                                        block = await response.content.read(
                                            1024)
                                        if not block:
                                            break
                                        f.write(block)

                            with open(filename, "rb") as f:
                                await ctx.send(file=discord.File(f))

                            os.remove(filename)
                else:
                    # send as embeds
                    for medianode in medias:
                        if medianode.get("is_video"):
                            await ctx.send(embed=content)
                            await ctx.send(medianode.get("video_url"))
                        else:
                            content.set_image(url=medianode.get("display_url"))
                            await ctx.send(embed=content)
                        content.description = None
                        content._author = None

        try:
            # delete discord automatic embed
            await ctx.message.edit(suppress=True)
        except discord.Forbidden:
            pass