예제 #1
0
 async def studijni(self, ctx):
     link = "https://www.fit.vut.cz/fit/room/C109/.cs"
     htmlparser = etree.HTMLParser()
     session = requests.session()
     result = session.get(link)
     xDoc2 = etree.fromstring(result.text, htmlparser)
     hours_div = xDoc2.xpath(
         "//*[b[contains(text(),'Úřední hodiny')]]//following-sibling::div")
     embed = disnake.Embed(title=Messages.studijni_title, url=link)
     if hours_div:
         hours = etree.tostring(hours_div[0], encoding=str, method="text")
         additional_info = xDoc2.xpath("//main//section/p")
         if additional_info:
             info = etree.tostring(additional_info[0],
                                   encoding=str,
                                   method="text").split(':', 1)
             if len(info) > 1:
                 embed.add_field(name=info[0], value=info[1], inline=False)
     else:
         hours_div = xDoc2.xpath("//main//section")
         if len(hours_div):
             hours = ''.join(hours_div[0].itertext())
             hours = hours.strip()
         else:
             hours = Messages.studijni_web_error
     embed.add_field(name=Messages.studijni_office_hours,
                     value=hours,
                     inline=False)
     add_author_footer(embed, ctx.message.author)
     await ctx.send(embed=embed)
예제 #2
0
    async def shortcut(self, ctx, shortcut=None):
        """Informations about subject specified by its shorcut"""
        if not shortcut:
            await ctx.send(utils.fill_message("shorcut_format", command=ctx.invoked_with))
            return
        programme = review_repo.get_programme(shortcut.upper())
        if programme:
            embed = discord.Embed(title=programme.shortcut, description=programme.name)
            embed.add_field(name="Link", value=programme.link)
        else:
            subject = review_repo.get_subject_details(shortcut.lower())
            if not subject:
                await ctx.send(messages.review_wrong_subject)
                return
            embed = discord.Embed(title=subject.shortcut, description=subject.name)
            if subject.semester == "L":
                embed.add_field(name="Semestr", value="Letní")
            else:
                embed.add_field(name="Semestr", value="Zimní")
            embed.add_field(name="Typ", value=subject.type)
            if subject.year:
                embed.add_field(name="Ročník", value=subject.year)
            embed.add_field(name="Kredity", value=subject.credits)
            embed.add_field(name="Ukončení", value=subject.end)
            embed.add_field(name="Karta předmětu", value=subject.card, inline=False)
            embed.add_field(
                name="Statistika úspěšnosti předmětu",
                value=f"http://fit.nechutny.net/?detail={subject.shortcut}",
                inline=False,
            )

        utils.add_author_footer(embed, ctx.author)
        await ctx.send(embed=embed)
예제 #3
0
    def urban_embeds(self, author, dict):
        """Generate embeds from dictionary of resposes"""
        embed_list = []

        for idx, item in enumerate(dict["list"]):
            definition = item["definition"]
            example = item["example"]

            if len(definition) > 1024:
                definition = definition[0:1021] + "`…`"
            if len(example) > 1024:
                example = example[0:1021] + "`…`"

            embed = disnake.Embed(
                title=item["word"],
                url=item["permalink"],
            )
            embed.add_field(name="Definition", value=definition, inline=False)
            if example:
                embed.add_field(name="Example", value=example, inline=False)
            embed.add_field(
                name="Page",
                value=f"{idx + 1}/{len(dict['list'])}",
                inline=False,
            )
            utils.add_author_footer(embed, author)

            embed_list.append(embed)

        return embed_list
예제 #4
0
    def create_embed_of_link(self, streamlink: StreamLink,
                             author: Union[discord.User,
                                           discord.Member], links_count: int,
                             current_pos: int) -> discord.Embed:
        embed = discord.Embed(color=0xEEE657)
        embed.set_author(name="Streamlinks")

        if streamlink.thumbnail_url is not None:
            embed.set_image(url=streamlink.thumbnail_url)

        embed.add_field(name="Předmět",
                        value=streamlink.subject.upper(),
                        inline=True)
        embed.add_field(name="Od", value=streamlink.member_name, inline=True)
        embed.add_field(name="Datum vydání",
                        value=streamlink.created_at.strftime("%d. %m. %Y"),
                        inline=True)
        embed.add_field(name="Odkaz",
                        value=f"[{streamlink.link}]({streamlink.link})",
                        inline=False)
        embed.add_field(name="Popis",
                        value=streamlink.description,
                        inline=False)
        embed.timestamp = datetime.utcnow()
        utils.add_author_footer(
            embed,
            author,
            additional_text=[
                f"[{streamlink.subject.upper()}] Page: {current_pos} / {links_count}"
                f" (#{streamlink.id})"
            ])

        return embed
예제 #5
0
    async def shortcut(self, ctx, shortcut=None):
        """Informations about subject specified by its shorcut"""
        if not shortcut:
            await ctx.send(
                utils.fill_message("shorcut_format", command=ctx.invoked_with))
            return
        programme = review_repo.get_programme(shortcut.upper())
        if programme:
            embed = disnake.Embed(title=programme.shortcut,
                                  description=programme.name)
            embed.add_field(name="Link", value=programme.link)
        else:
            subject = review_repo.get_subject_details(shortcut)
            if not subject:
                subject = review_repo.get_subject_details(f"TV-{shortcut}")
                if not subject:
                    await ctx.send(messages.review_wrong_subject)
                    return
            embed = disnake.Embed(title=subject.shortcut,
                                  description=subject.name)
            if subject.semester == "L":
                semester_value = "Letní"
            if subject.semester == "Z":
                semester_value = "Zimní"
            else:
                semester_value = "Zimní, Letní"
            embed.add_field(name="Semestr", value=semester_value)
            embed.add_field(name="Typ", value=subject.type)
            if subject.year:
                embed.add_field(name="Ročník", value=subject.year)
            embed.add_field(name="Kredity", value=subject.credits)
            embed.add_field(name="Ukončení", value=subject.end)
            if "*" in subject.name:
                embed.add_field(name="Upozornění",
                                value="Předmět není v tomto roce otevřen",
                                inline=False)
            if subject.shortcut.startswith("TV-"):
                embed.add_field(
                    name="Rozvrh předmětu v IS",
                    value=
                    f"https://www.vut.cz/studis/student.phtml?sn=rozvrhy&action=gm_rozvrh_predmetu&operation=rozvrh&predmet_id={subject.card}&fakulta_id=814",
                    inline=False)
            else:
                embed.add_field(
                    name="Karta předmětu",
                    value=
                    f"https://www.fit.vut.cz/study/course/{subject.shortcut}/.cs",
                    inline=False)
                embed.add_field(
                    name="Statistika úspěšnosti předmětu",
                    value=f"http://fit.nechutny.net/?detail={subject.shortcut}",
                    inline=False,
                )

        utils.add_author_footer(embed, ctx.author)
        await ctx.send(embed=embed)
예제 #6
0
    async def message_karma(self, channel_out, msg):
        author = channel_out.author
        reactions = msg.reactions
        colour = 0x6d6a69
        output = {'-1': [], '1': [], '0': []}
        karma = 0
        for react in reactions:
            emoji = react.emoji
            val = self.repo.emoji_value_raw(emoji)
            if val == 1:
                output['1'].append(emoji)
                karma += react.count
                async for user in react.users():
                    if user.id == msg.author.id:
                        karma -= 1
                        break
            elif val == -1:
                output['-1'].append(emoji)
                karma -= react.count
                async for user in react.users():
                    if user.id == msg.author.id:
                        karma += 1
                        break
            else:
                output['0'].append(emoji)
        embed = discord.Embed(title='Karma zprávy')
        embed.add_field(name="Zpráva", value=msg.jump_url, inline=False)
        for key in ['1', '-1', '0']:
            if output[key]:
                message = ""
                for emoji in output[key]:
                    message += str(emoji) + ' '
                if key == '1':
                    name = 'Pozitivní'
                elif key == '0':
                    name = 'Neutrální'
                else:
                    name = 'Negativní'
                embed.add_field(name=name, value=message, inline=False)
        if karma > 0:
            colour = 0x34cb0b
        elif karma < 0:
            colour = 0xcb410b
        embed.colour = colour
        embed.add_field(name='Celková karma za zprávu:',
                        value=karma,
                        inline=False)
        utils.add_author_footer(embed, author)

        await channel_out.send(embed=embed)
예제 #7
0
    async def weather(self, ctx, *, place: str = "Brno"):
        token = config.weather_token

        place = place[:100]
        if "&" in place:
            return await ctx.send("Takhle se žádné město určitě nejmenuje.")

        url = ("http://api.openweathermap.org/data/2.5/weather?q=" + place +
               "&units=metric&lang=cz&appid=" + token)
        res = requests.get(url).json()

        if str(res["cod"]) == "200":
            description = "Aktuální počasí v městě " + res[
                "name"] + ", " + res["sys"]["country"]
            embed = discord.Embed(title="Počasí", description=description)
            image = "http://openweathermap.org/img/w/" + res["weather"][0][
                "icon"] + ".png"
            embed.set_thumbnail(url=image)
            weather = res["weather"][0]["main"] + " ( " + res["weather"][0][
                "description"] + " ) "
            temp = str(res["main"]["temp"]) + "°C"
            feels_temp = str(res["main"]["feels_like"]) + "°C"
            humidity = str(res["main"]["humidity"]) + "%"
            wind = str(res["wind"]["speed"]) + "m/s"
            clouds = str(res["clouds"]["all"]) + "%"
            visibility = str(
                res["visibility"] /
                1000) + " km" if "visibility" in res else "bez dat"
            embed.add_field(name="Počasí", value=weather, inline=False)
            embed.add_field(name="Teplota", value=temp, inline=True)
            embed.add_field(name="Pocitová teplota",
                            value=feels_temp,
                            inline=True)
            embed.add_field(name="Vlhkost", value=humidity, inline=True)
            embed.add_field(name="Vítr", value=wind, inline=True)
            embed.add_field(name="Oblačnost", value=clouds, inline=True)
            embed.add_field(name="Viditelnost", value=visibility, inline=True)

            utils.add_author_footer(embed, ctx.author)

            await ctx.send(embed=embed)

        elif str(res["cod"]) == "404":
            await ctx.send("Město nenalezeno")
        elif str(res["cod"]) == "401":
            await ctx.send("Rip token -> Rebel pls fix")
        else:
            await ctx.send(
                "Město nenalezeno! <:pepeGun:484470874246742018> (" +
                res["message"] + ")")
예제 #8
0
파일: week.py 프로젝트: Misha12/rubbergod
    async def week(self, inter: disnake.ApplicationCommandInteraction):
        """See if the current week is odd or even"""
        cal_week = date.today().isocalendar()[1]
        stud_week = cal_week - config.starting_week
        even, odd = "sudý", "lichý"
        cal_type = even if cal_week % 2 == 0 else odd

        embed = disnake.Embed(title="Týden", color=0xE5DC37)
        embed.add_field(name="Studijní", value=stud_week)
        embed.add_field(name="Kalendářní", value=f"{cal_type} ({cal_week})")
        embed.add_field(name="Poznámka", value=Messages.week_warning, inline=False)

        utils.add_author_footer(embed, inter.author)

        await inter.response.send_message(embed=embed)
예제 #9
0
파일: week.py 프로젝트: Urumasi/rubbergod
    async def week(self, ctx: commands.Context):
        """See if the current week is odd or even"""
        cal_week = date.today().isocalendar()[1]
        stud_week = cal_week - config.starting_week
        even, odd = "sudý", "lichý"
        cal_type = even if cal_week % 2 == 0 else odd

        embed = discord.Embed(title="Týden", color=0xE5DC37)
        embed.add_field(name="Studijní", value=stud_week)
        embed.add_field(name="Kalendářní", value=f"{cal_type} ({cal_week})")
        embed.add_field(name="Poznámka",
                        value=messages.week_warning,
                        inline=False)

        utils.add_author_footer(embed, ctx.author)

        await ctx.send(embed=embed)
예제 #10
0
파일: week.py 프로젝트: janch32/rubbergod
    async def week(self, ctx: commands.Context):
        """See if the current week is odd or even"""
        cal_week = date.today().isocalendar()[1]
        stud_week = cal_week - config.starting_week
        even, odd = "sudý", "lichý"
        cal_type = even if cal_week % 2 == 0 else odd
        stud_type = even if stud_week % 2 == 0 else odd

        embed = discord.Embed(title="Týden", color=0xE5DC37)
        embed.add_field(name="Studijní",
                        value="{} ({})".format(stud_type, stud_week))
        embed.add_field(name="Kalendářní",
                        value="{} ({})".format(cal_type, cal_week))

        utils.add_author_footer(embed, ctx.author)

        await ctx.send(embed=embed)
예제 #11
0
    async def tierboard(self, ctx, type="V", sem="Z", year=""):
        """Board of suject based on average tier from reviews"""
        # TODO autochange sem based on week command?
        degree = None
        type = type.upper()
        if type == "HELP":
            await ctx.send(messages.tierboard_help)
            return
        sem = sem.upper()
        for role in ctx.author.roles:
            if "BIT" in role.name:
                degree = "BIT"
                if not year and type == "P":
                    if role.name == "4BIT+":
                        year = "3BIT"
                    elif role.name == "0BIT":
                        year = "1BIT"
                    else:
                        year = role.name
                break
            if "MIT" in role.name:
                degree = "MIT"
                if not year and type == "P":
                    year = ""
                    # TODO get programme from DB? or find all MIT P?
                break
        if not degree and not year:
            await ctx.send(messages.tierboard_missing_year)
            return
        board = review_repo.get_tierboard(type, sem, degree, year)
        output = ""
        cnt = 1
        for line in board:
            output += f"{cnt} - **{line.shortcut}**: {round(line.avg_tier, 1)}\n"
            cnt += 1
        embed = discord.Embed(title="Tierboard", description=output)
        embed.timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
        embed.add_field(name="Semester", value=sem)
        embed.add_field(name="Typ", value=type)
        if year:
            degree = year
        embed.add_field(name="Program", value=degree)

        utils.add_author_footer(embed, ctx.author, additional_text=("?tierboard help",))
        await ctx.send(embed=embed)
예제 #12
0
    async def format_page(self, menu, page: DatabasePage) -> Union[str, disnake.Embed, dict]:
        board_lines = []

        for i, entry in enumerate(page):  # type: int, Table
            board_lines.append(await self._format_row(
                entry=entry, position=(self.current_page * self.per_page) + i + 1, ctx=menu.ctx
            ))

        self.base_embed.description = "\n" + "\n".join(board_lines)

        # possibility to optimize, author could be set only once
        utils.add_author_footer(
            self.base_embed,
            menu.ctx.author,
            additional_text=(f"{self.current_page + 1}/{self.get_max_pages()} pages.",),
        )

        return self.base_embed
예제 #13
0
    async def leaderboard(self,
                          ctx: discord.ext.commands.Context,
                          action,
                          order,
                          start=1):
        if action == 'give':
            if order == "DESC":
                column = 'positive'
                attribute = Database_karma.positive.desc()
                emote = "<:peepolove:562305740132450359>"
                title = emote + "KARMA GIVINGBOARD " + emote
            else:
                column = 'negative'
                attribute = Database_karma.negative.desc()
                emote = "<:ishagrin:638277508651024394>"
                title = emote + " KARMA ISHABOARD " + emote
        elif action == 'get':
            column = 'karma'
            if order == "DESC":
                attribute = Database_karma.karma.desc()
                emote = ":trophy:"
                title = emote + " KARMA LEADERBOARD " + emote
            else:
                attribute = Database_karma.karma
                emote = "<:coolStoryArcasCZ:489539455271829514>"
                title = emote + " KARMA BAJKARBOARD " + emote
        else:
            raise Exception('Action neni get/give')

        output = self.gen_leaderboard_content(attribute, start, column)

        embed = discord.Embed(title=title, description=output)
        utils.add_author_footer(embed, ctx.author)

        if action == "get" and order == "DESC":
            value_num = math.ceil(start / cfg.karma_grillbot_leaderboard_size)
            value = msg.karma_web if value_num == 1 else f"{msg.karma_web}{value_num}"
            embed.add_field(name=msg.karma_web_title, value=value)

        message = await ctx.send(embed=embed)

        await message.add_reaction("⏪")
        await message.add_reaction("◀")
        await message.add_reaction("▶")
예제 #14
0
파일: review.py 프로젝트: Urumasi/rubbergod
 def make_embed(self, msg_author, review, subject, description, page):
     """Create new embed for reviews"""
     embed = discord.Embed(title=f"{subject.upper()} reviews",
                           description=description)
     colour = 0x6D6A69
     id = 0
     if review:
         id = review.id
         if review.anonym:
             author = "Anonym"
         else:
             guild = self.bot.get_guild(config.guild_id)
             author = guild.get_member(int(review.member_ID))
         embed.add_field(name="Author", value=author)
         embed.add_field(name="Tier", value=review.tier)
         embed.add_field(name="Date", value=review.date)
         text = review.text_review
         if text is not None:
             text_len = len(text)
             if text_len > 1024:
                 pages = text_len // 1024 + (text_len % 1024 > 0)
                 text = text[:1024]
                 embed.add_field(name="Text page",
                                 value=f"1/{pages}",
                                 inline=False)
             embed.add_field(name="Text", value=text, inline=False)
         likes = review_repo.get_votes_count(review.id, True)
         embed.add_field(name="Likes", value=f"👍{likes}")
         dislikes = review_repo.get_votes_count(review.id, False)
         embed.add_field(name="Dislikes", value=f"👎{dislikes}")
         diff = likes - dislikes
         if diff > 0:
             colour = 0x34CB0B
         elif diff < 0:
             colour = 0xCB410B
         embed.add_field(name="Help",
                         value=messages.reviews_reaction_help,
                         inline=False)
     embed.colour = colour
     utils.add_author_footer(embed,
                             msg_author,
                             additional_text=[f"Review: {page} | ID: {id}"])
     return embed
예제 #15
0
    async def room(self, ctx: commands.Context, *, room: str):
        url = f"https://www.fit.vut.cz/fit/map/.cs?show={room.upper()}&big=1"
        r = requests.get(url)
        if r.status_code != 200:
            return await ctx.send(Messages.fit_room_unreach)

        async with ctx.typing():
            try:
                soup = BeautifulSoup(r.content, 'html.parser')
                main_body = soup.find("main", {"id": "main"})
                floor_list = main_body.find("ul",
                                            {"class": "pagination__list"})
                active_floor = floor_list.find("a", {"aria-current": "page"})
                image = main_body.find("svg")
                overlay = image.find("g", {"id": "layer3"})
                cursor = overlay.find(
                    "polygon",
                    {"style": "fill:red;stroke:none;pointer-events:none"})
            except:
                return await ctx.send(Messages.fit_room_parsing_failed)

            if image is None or cursor is None:
                return await ctx.send(
                    utils.fill_message("fit_room_room_not_on_plan", room=room))

            image_bytes = BytesIO()
            svg2png(bytestring=str(image).encode("utf-8"),
                    write_to=image_bytes,
                    parent_width=720,
                    parent_height=1000,
                    background_color="white",
                    dpi=300)
            image_bytes.seek(0)

            embed = discord.Embed(title=f"Místnost: {room}",
                                  color=discord.Color.dark_blue())
            embed.set_image(url="attachment://plan.png")
            embed.description = f"[Odkaz na plánek]({url})"
            utils.add_author_footer(embed,
                                    ctx.author,
                                    additional_text=[str(active_floor.text)])
            file = discord.File(fp=image_bytes, filename="plan.png")
            await ctx.send(embed=embed, file=file)
예제 #16
0
    async def hugs(self, ctx: commands.Context, user: discord.Member = None):
        """
        Get your lovely hug stats.
        """
        if user is None or user == ctx.author:
            user = ctx.author
            user_str = utils.get_username(user)
            title = "{0} Your Lovely Hug Stats {0}"
        else:
            user_str = utils.get_username(user)
            title = f"{{0}} {user_str}'s Lovely Hug Stats {{0}}"

        async with ctx.typing():
            stats = self.hugs_repo.get_members_stats(user.id)
            positions = self.hugs_repo.get_member_position(stats)
            avg_position = int((positions[0] + positions[1]) // 2)

            embed = discord.Embed(
                title=title.format(
                    self.get_default_emoji("peepoHugger") or ""
                ),
                description=" | ".join(
                    (
                        "**Ranks**",
                        f"Given: **{positions[0]}.**",
                        f"Received: **{positions[1]}.**",
                        f"Avg: **{avg_position}.**",
                    )
                ),
            )

            embed.set_author(name=user_str, icon_url=user.avatar_url)
            utils.add_author_footer(embed, ctx.author)

            given_emoji = self.get_default_emoji("peepohugs") or ""
            recv_emoji = self.get_default_emoji("huggers") or ""

            embed.add_field(name=f"{given_emoji} Given", value=str(stats.given))
            embed.add_field(name=f"{recv_emoji} Received", value=str(stats.received))

        await ctx.send(embed=embed)
        await self.check.botroom_check(ctx.message)
예제 #17
0
파일: exams.py 프로젝트: Urumasi/rubbergod
    async def process_exams(self, ctx: commands.Context, year: Union[str,
                                                                     None]):
        date = datetime.date.today()

        semester = "ZS"
        if 3 < date.month < 9:
            semester = "LS"

        cal_year = date.year
        if semester == "ZS":
            cal_year -= 1

        all_url = f"https://minerva3.fit.vutbr.cz/rozvrhis/{semester}{cal_year}/zkousky"
        year_url = f"{all_url}/{year}"
        description = f"[Odkaz na zkoušky ročníku]({year_url})\n" if year else ""
        description += f"[Odkaz na všechny zkoušky]({all_url})"

        title = f"Zkoušky {year} {semester}{cal_year}-{cal_year + 1}" \
            if year else f"Zkoušky {semester}{cal_year}-{cal_year + 1}"

        r = requests.get(year_url)
        if r.status_code == 200:
            soup = BeautifulSoup(r.content, 'html.parser')

            try:
                table = soup.find("table", {"class": "exam"})
                body = table.find("tbody")

                if body is None:
                    # There is no table so no terms
                    embed = discord.Embed(title=title,
                                          description=description,
                                          color=discord.Color.dark_blue())
                    utils.add_author_footer(embed, ctx.author)
                    return await ctx.send(embed=embed)

                exams = body.find_all("tr")

                number_of_exams = len(exams)
                bs = config.exams_page_size
                number_of_batches = math.ceil(number_of_exams / bs)
                exam_batches = [
                    exams[i * bs:bs + i * bs] for i in range(number_of_batches)
                ]

                pages = []
                for exam_batch in exam_batches:
                    embed = discord.Embed(title=title,
                                          description=description,
                                          color=discord.Color.dark_blue())
                    utils.add_author_footer(embed, ctx.author)

                    for exam in exam_batch:
                        tag = exam.find("a")
                        cols = exam.find_all("td")
                        del cols[0]

                        subject_tag = tag.find("strong").contents[0]

                        col_count = len(cols)
                        if col_count == 1:
                            # Support for credits
                            col = cols[0]
                            strong_tag = col.find("strong")

                            if strong_tag is None:
                                # There is no term - Only text
                                embed.add_field(name=subject_tag,
                                                value=col.contents[0],
                                                inline=False)
                            else:
                                term = str(strong_tag.contents[0]).replace(
                                    " ", "")

                                date_splits = term.split(".")
                                term_date = datetime.date(
                                    int(date_splits[2]), int(date_splits[1]),
                                    int(date_splits[0]))

                                name = f"{subject_tag}"
                                term_time = f"{col.contents[0]}\n{term}"
                                if term_date < datetime.date.today():
                                    name = f"~~{name}~~"
                                    term_time = f"~~{term_time}~~"

                                embed.add_field(name=name,
                                                value=term_time,
                                                inline=False)
                        else:
                            # Classic terms
                            whole_term_count = 0
                            for idx, col in enumerate(cols):
                                terms = col.find_all("strong")
                                times = col.find_all("em")

                                number_of_terms = len(terms)
                                whole_term_count += number_of_terms

                                for idx2, (term, time) in enumerate(
                                        zip(terms, times)):
                                    term = str(term.contents[0]).replace(
                                        " ", "")
                                    time_cont = ""
                                    for c in time.contents:
                                        time_cont += str(c)
                                    time_cont = time_cont.replace(
                                        "<sup>", ":").replace("</sup>", "")

                                    date_splits = term.split(".")
                                    term_date = datetime.date(
                                        int(date_splits[2]),
                                        int(date_splits[1]),
                                        int(date_splits[0]))

                                    name = f"{idx + 1}. {subject_tag}" if number_of_terms == 1 else \
                                        f"{idx + 1}.{idx2 + 1} {subject_tag}"

                                    term_time = f"{term}\n{time_cont}"
                                    if term_date < datetime.date.today():
                                        name = f"~~{name}~~"
                                        term_time = f"~~{term_time}~~"

                                    embed.add_field(name=name, value=term_time)

                            to_add = math.ceil(
                                whole_term_count / 3) * 3 - whole_term_count
                            for _ in range(to_add):
                                embed.add_field(name='\u200b', value='\u200b')

                    pages.append(embed)

                number_of_pages = len(pages)
                if number_of_pages > 1:
                    page_sesstion = PaginatorSession(
                        self.bot,
                        ctx,
                        timeout=config.exams_paginator_duration,
                        pages=pages,
                        color=discord.Color.dark_blue(),
                        delete_after=False)

                    await page_sesstion.run()
                elif number_of_pages == 1:
                    # Only one page, no need paginator
                    await ctx.send(embed=pages[0])
                else:
                    # No pages were parsed, so we will post only default embed
                    embed = discord.Embed(title=title,
                                          description=description,
                                          color=discord.Color.dark_blue())
                    utils.add_author_footer(embed, ctx.author)
                    await ctx.send(embed=embed)
            except:
                # Parsing failed
                embed = discord.Embed(title=title,
                                      description=description,
                                      color=discord.Color.dark_blue())
                utils.add_author_footer(embed, ctx.author)
                await ctx.send(embed=embed)
                await ctx.send(Messages.exams_parsing_failed)
        else:
            # Site returned fail code
            embed = discord.Embed(title=title,
                                  description=description,
                                  color=discord.Color.dark_blue())
            utils.add_author_footer(embed, ctx.author)
            await ctx.send(embed=embed)
예제 #18
0
파일: exams.py 프로젝트: Misha12/rubbergod
    async def process_exams(
        self,
        ctx: Union[commands.Context, disnake.TextChannel, disnake.Message],
        year: Union[str, None],
        author: Optional[disnake.User] = None,
    ):
        date = datetime.date.today()

        semester = "ZS"
        if 3 < date.month < 9:
            semester = "LS"

        cal_year = date.year
        if date.month < 9:
            cal_year -= 1

        all_url = f"https://minerva3.fit.vutbr.cz/rozvrhis/{semester}{cal_year}/zkousky"
        year_url = f"{all_url}/{year}"
        description = f"[Odkaz na zkoušky ročníku]({year_url})\n" if year else ""
        description += f"[Odkaz na všechny zkoušky]({all_url})"

        title = (f"Zkoušky {year} {semester}{cal_year}-{cal_year + 1}"
                 if year else f"Zkoušky {semester}{cal_year}-{cal_year + 1}")

        r = requests.get(year_url)
        if r.status_code == 200:
            soup = BeautifulSoup(r.content, "html.parser")

            table = soup.find("table", {"class": "exam"})
            body = table.find("tbody")

            if body is None:
                # There is no table so no terms
                embed = disnake.Embed(title=title,
                                      description=description,
                                      color=disnake.Color.dark_blue())
                utils.add_author_footer(
                    embed, author if author is not None else self.bot.user)

                if isinstance(ctx, commands.Context):
                    return await ctx.send(embed=embed)

            # There is body so start parsing table
            exams = body.find_all("tr")

            number_of_exams = len(exams)
            bs = config.exams_page_size
            number_of_batches = math.ceil(number_of_exams / bs)
            exam_batches = [
                exams[i * bs:bs + i * bs] for i in range(number_of_batches)
            ]

            term_strings_dict = {}
            pages = []
            for exam_batch in exam_batches:
                embed = disnake.Embed(title=title,
                                      description=description,
                                      color=disnake.Color.dark_blue())
                utils.add_author_footer(
                    embed, author if author is not None else self.bot.user)

                for exam in exam_batch:
                    # Every exams row start with link tag
                    tag = exam.find("a") if str(exam).startswith(
                        "<tr><td><a") else None
                    cols = exam.find_all("td")

                    # Check if tag is not None and get strong and normal subject tag
                    subject_tag = (tag.find("strong") or tag.contents[0]
                                   ) if tag is not None else None

                    if subject_tag is None:
                        content = re.sub(CLEANR, "", str(cols[0]))
                        embed.add_field(name="Poznámka",
                                        value=content,
                                        inline=False)
                    else:
                        del cols[0]

                        if not isinstance(subject_tag, NavigableString):
                            subject_tag = subject_tag.contents[0]

                        col_count = len(cols)
                        if col_count == 1:
                            # Support for credits
                            col = cols[0]
                            strong_tag = col.find("strong")

                            if strong_tag is None:
                                # There is no term - Only text
                                embed.add_field(name=subject_tag,
                                                value=col.contents[0],
                                                inline=False)
                            else:
                                # Mainly for terms without specified time
                                term_date_string = strong_tag.contents[
                                    0].replace("\xa0", "").replace(" ", "")

                                date_splits = term_date_string.split(".")
                                # Without actual time set time to end of the day
                                term_datetime = datetime.datetime(
                                    int(date_splits[2]), int(date_splits[1]),
                                    int(date_splits[0]), 23, 59)

                                term_date = datetime.date(
                                    int(date_splits[2]), int(date_splits[1]),
                                    int(date_splits[0]))

                                term_content = f"{term_date_string}\n{col.contents[0]}"

                                # Calculate character offsets
                                padded_term_date = datetime.date.strftime(
                                    term_date, "%d.%m.%Y")
                                date_offset = " " * (DATE_OFFSET -
                                                     len(subject_tag))
                                time_offset = " " * (
                                    TIME_OFFSET - len(padded_term_date)
                                )  # Here used aas data offset
                                term_string = f"{subject_tag}{date_offset}{padded_term_date}"
                                term_string += f"{time_offset}{col.contents[0]}"

                                if term_date == datetime.date.today():
                                    term_strings_dict[
                                        term_datetime] = f"- {term_string}"
                                elif term_datetime < datetime.datetime.now():
                                    subject_tag = f"~~{subject_tag}~~"
                                    term_content = f"~~{term_content}~~"
                                else:
                                    term_strings_dict[
                                        term_datetime] = f"+ {term_string}"

                                embed.add_field(name=subject_tag,
                                                value=term_content,
                                                inline=False)
                        else:
                            # Classic terms
                            whole_term_count = 0
                            for idx, col in enumerate(cols):
                                terms = col.find_all("strong")
                                times = col.find_all("em")

                                number_of_terms = len(terms)
                                whole_term_count += number_of_terms

                                for idx2, (term_date_string,
                                           time) in enumerate(zip(
                                               terms, times)):
                                    term_date_string = (
                                        term_date_string.contents[0].replace(
                                            "\xa0", "").replace(" ", ""))
                                    term_time_string = ""
                                    for c in time.contents:
                                        term_time_string += str(c)
                                    term_time_string = term_time_string.replace(
                                        "<sup>", ":").replace("</sup>", "")

                                    date_splits = term_date_string.split(".")

                                    start_time_string_parts = (
                                        term_time_string.split("-")[0].replace(
                                            " ", "").split(":"))
                                    end_time_string_parts = (
                                        term_time_string.split("-")[1].replace(
                                            " ", "").split(":"))
                                    term_datetime = datetime.datetime(
                                        int(date_splits[2]),
                                        int(date_splits[1]),
                                        int(date_splits[0]),
                                        int(start_time_string_parts[0]),
                                        int(start_time_string_parts[1]),
                                    )

                                    term_date = datetime.date(
                                        int(date_splits[2]),
                                        int(date_splits[1]),
                                        int(date_splits[0]))

                                    name = (
                                        f"{idx + 1}.  {subject_tag}"
                                        if number_of_terms == 1 else
                                        f"{idx + 1}.{idx2 + 1} {subject_tag}")

                                    if (start_time_string_parts is not None and
                                            end_time_string_parts is not None):
                                        start_time = datetime.time(
                                            int(start_time_string_parts[0]),
                                            int(start_time_string_parts[1]))
                                        start_time_string = datetime.time.strftime(
                                            start_time, "%H:%M")
                                        end_time = datetime.time(
                                            int(end_time_string_parts[0]),
                                            int(end_time_string_parts[1]))
                                        end_time_string = datetime.time.strftime(
                                            end_time, "%H:%M")
                                        term_time_string = f"{start_time_string} - {end_time_string}"

                                    padded_term_date = datetime.date.strftime(
                                        term_date, "%d.%m.%Y")
                                    term_date_time_string = f"{padded_term_date} {term_time_string}"

                                    # Calculate character offsets
                                    date_offset = " " * (DATE_OFFSET -
                                                         len(name))
                                    time_offset = " " * (TIME_OFFSET -
                                                         len(padded_term_date))
                                    term_string = f"{name}{date_offset}{padded_term_date}"
                                    term_string += f"{time_offset}{term_time_string}"

                                    if term_date == datetime.date.today():
                                        term_strings_dict[
                                            term_datetime] = f"- {term_string}"
                                    elif term_datetime < datetime.datetime.now(
                                    ):
                                        name = f"~~{name}~~"
                                        term_date_time_string = f"~~{term_date_time_string}~~"
                                    else:
                                        term_strings_dict[
                                            term_datetime] = f"+ {term_string}"

                                    embed.add_field(
                                        name=name, value=term_date_time_string)

                            to_add = math.ceil(
                                whole_term_count / 3) * 3 - whole_term_count
                            for _ in range(to_add):
                                embed.add_field(name="\u200b", value="\u200b")

                pages.append(embed)

            if len(pages) == 0:
                embed = disnake.Embed(title=title,
                                      description=description,
                                      color=disnake.Color.dark_blue())
                utils.add_author_footer(
                    embed, author if author is not None else self.bot.user)
                pages.append(embed)
            if isinstance(ctx, commands.Context):
                view = EmbedView(pages)
                view.message = await ctx.reply(embed=pages[0], view=view)
            else:
                header = disnake.Embed(title=title,
                                       description=description,
                                       color=disnake.Color.dark_blue())
                await self.handle_exams_with_database_access(
                    term_strings_dict, header, ctx)
        else:
            # Site returned fail code
            embed = disnake.Embed(title=title,
                                  description=description,
                                  color=disnake.Color.dark_blue())
            utils.add_author_footer(
                embed, author if author is not None else self.bot.user)
            if isinstance(ctx, commands.Context):
                await ctx.send(embed=embed)
예제 #19
0
    async def tierboard(
        self,
        inter: disnake.ApplicationCommandInteraction,
        type: str = commands.Param(name='typ', choices=['P', 'PVT', 'PVA', 'V']),
        sem: str = commands.Param(name='semestr', choices=['Z', 'L']),
        year: str = commands.Param(
            name='rocnik', choices=["1BIT", "2BIT", "3BIT", "1MIT", "2MIT"], default=''
        )
    ):
        """Board of suject based on average tier from reviews"""
        degree = None

        author = inter.author
        if not inter.guild:  # DM
            guild = self.bot.get_guild(config.guild_id)
            author = guild.get_member(author.id)
        if not year:
            for role in author.roles:
                if any(deg in role.name for deg in ["BIT", "MIT"]):
                    if role.name == "4BIT+":
                        year = "3BIT"
                    elif role.name == "0BIT":
                        year = "1BIT"
                    elif role.name == "0MIT":
                        year = "1MIT"
                    elif role.name == "3MIT+":
                        year = "2MIT"
                    else:
                        year = role.name
                    break
        if "BIT" in year:
            degree = "BIT"
        if "MIT" in year:
            degree = "MIT"
        if not degree and not year:
            await inter.send(Messages.tierboard_missing_year, ephemeral=True)
            return
        embeds = []
        embed = disnake.Embed(title="Tierboard")
        embed.timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
        embed.add_field(name="Typ", value=type)
        embed.add_field(name="Semestr", value="Letní" if sem == "L" else "Zimní")
        if type != "P":
            embed.add_field(name="Program", value=degree)
            year = ""
        else:
            embed.add_field(name="Ročník", value=year)
        utils.add_author_footer(embed, author)

        pages_total = self.repo.get_tierboard_page_count(type, sem, degree, year)
        for page in range(pages_total):
            board = self.repo.get_tierboard(type, sem, degree, year, page*10)
            output = ""
            cnt = 1
            for line in board:
                output += f"{cnt} - **{line.shortcut}**: {round(line.avg_tier, 1)}\n"
                cnt += 1
            embed.description = output
            embeds.append(copy.copy(embed))

        if pages_total == 0:
            embed.description = ""
            embeds.append(embed)

        view = EmbedView(embeds)
        view.message = await inter.response.send_message(embed=embeds[0], view=view)
예제 #20
0
    async def __repost_message(self, ctx: ReactionContext,
                               reactions: List[discord.Reaction]):
        if self.repost_channel is None and config.meme_repost_room != 0:
            self.repost_channel = await self.bot.fetch_channel(
                config.meme_repost_room)

        # Invalid ID
        if self.repost_channel is None:
            return

        async with self.repost_lock:
            if self.repost_repo.find_repost_by_original_message_id(
                    ctx.message.id) is not None:
                return

            # Generate string with all reactions on post at the time
            title_string = ""
            for reaction in reactions:
                tmp_string = title_string + f"{reaction.count}x{reaction.emoji} "

                if len(tmp_string) >= 255:
                    break

                title_string = tmp_string

            embed = discord.Embed(color=discord.Color.dark_blue(),
                                  title=title_string)
            utils.add_author_footer(embed, author=ctx.message.author)
            embed.timestamp = ctx.message.created_at

            # Create link to original post
            link = utils.fill_message(
                "meme_repost_link",
                original_message_url=ctx.message.jump_url,
                original_channel=config.meme_room)
            embed.add_field(name="Link", value=link, inline=False)

            # Get all attachments of original post
            main_image = None
            more_images = False
            attachment_urls = []
            for attachment in ctx.message.attachments:
                content_type = attachment.content_type
                if content_type is not None and content_type.split(
                        "/")[0] == "image":
                    if main_image is None:
                        main_image = await attachment.to_file()
                    else:
                        more_images = True
                else:
                    if len(attachment.proxy_url) < 1023:
                        attachment_urls.append(attachment.proxy_url)

            # Set content from original message if present
            if ctx.message.content:
                content_splits = ctx.message.content.split(" ")
                for content_split in content_splits:
                    if content_split.startswith("https://"):
                        # Its attachement URL
                        for extension in config.meme_repost_image_extensions:
                            # Check for extension in URL
                            if f".{extension}" in content_split:
                                if main_image is None:
                                    main_image = content_split
                                else:
                                    more_images = True
                                break

                content = ctx.message.content[:900]
                if more_images:
                    content += "\n\nVíce obrázků v původním postu"
                embed.add_field(name="Obsah", value=content)
            elif more_images:
                embed.add_field(name="Obsah",
                                value="Více obrázků v původním postu")

            # Set main image if present
            if main_image is not None:
                if isinstance(main_image, discord.File):
                    embed.set_image(url=f"attachment://{main_image.filename}")
                elif isinstance(main_image, str):
                    embed.set_image(url=main_image)
                    main_image = None
                else:
                    main_image = None

            # Add all attachments as fields
            for idx, attachment_url in enumerate(attachment_urls):
                embed.add_field(name=f"Příloha {idx + 1}",
                                value=attachment_url,
                                inline=False)

            repost_message_id = -1
            if len(embed) < 6000:
                repost_message = await self.repost_channel.send(
                    embed=embed, file=main_image)
                repost_message_id = repost_message.id

            self.repost_repo.create_repost(ctx.message.id, repost_message_id,
                                           ctx.member.id)
예제 #21
0
    async def tierboard(self, ctx, type="V", sem="Z", year=""):
        """Board of suject based on average tier from reviews"""
        # TODO autochange sem based on week command?
        degree = None
        type = type.upper()
        sem = sem.upper()
        if type == "HELP" or sem not in ['Z', 'L'] or type not in ['P', 'PVT', 'PVA', 'V']:
            await ctx.send(f"`{utils.get_command_signature(ctx)}`\n{messages.tierboard_help}")
            return

        for role in ctx.author.roles:
            if "BIT" in role.name:
                degree = "BIT"
                if not year and type == "P":
                    if role.name == "4BIT+":
                        year = "3BIT"
                    elif role.name == "0BIT":
                        year = "1BIT"
                    else:
                        year = role.name
                break
            if "MIT" in role.name:
                degree = "MIT"
                if not year and type == "P":
                    year = ""
                    # TODO get programme from DB? or find all MIT P?
                break
        if not degree and not year:
            await ctx.send(messages.tierboard_missing_year)
            return
        board = review_repo.get_tierboard(type, sem, degree, year)
        output = ""
        cnt = 1
        for line in board:
            output += f"{cnt} - **{line.shortcut}**: {round(line.avg_tier, 1)}\n"
            cnt += 1
        embed = discord.Embed(title="Tierboard", description=output)
        embed.timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
        embed.add_field(name="Typ", value=type)
        embed.add_field(name="Semestr", value="Letní" if sem == "L" else "Zimní")
        if year:
            degree = year
        embed.add_field(name="Program", value=degree)

        utils.add_author_footer(embed, ctx.author, additional_text=("?tierboard help",))
        msg = await ctx.send(embed=embed)

        page_num = 0
        pages_total = review_repo.get_tierboard_page_count(type, sem, degree, year)

        if pages_total == 0:
            return

        await msg.add_reaction("⏪")
        await msg.add_reaction("◀")
        await msg.add_reaction("▶")

        while True:

            def check(reaction, user):
                return reaction.message.id == msg.id and not user.bot

            try:
                reaction, user = await self.bot.wait_for("reaction_add", check=check, timeout=300.0)
            except asyncio.TimeoutError:
                return
            emoji = str(reaction.emoji)
            if emoji in ["⏪", "◀", "▶"] and user.id == ctx.author.id:
                if emoji == "⏪":
                    page_num = 0
                elif emoji == "◀":
                    page_num -= 1
                    if page_num < 0:
                        page_num = pages_total - 1
                elif emoji == "▶":
                    page_num += 1
                    if page_num >= pages_total:
                        page_num = 0

                offset = page_num * 10
                board = review_repo.get_tierboard(type, sem, degree, year, offset)
                output = ""
                cnt = 1 + offset
                for line in board:
                    output += f"{cnt} - **{line.shortcut}**: {round(line.avg_tier, 1)}\n"
                    cnt += 1
                embed.description = output
                await msg.edit(embed=embed)
            try:
                await msg.remove_reaction(emoji, user)
            except discord.errors.Forbidden:
                pass
예제 #22
0
    async def __repost_message(self, ctx: ReactionContext,
                               reactions: List[disnake.Reaction]):
        if self.repost_channel is None and config.meme_repost_room != 0:
            self.repost_channel = await self.bot.fetch_channel(
                config.meme_repost_room)

        # Invalid ID
        if self.repost_channel is None:
            return

        async with self.repost_lock:
            if self.repost_repo.find_repost_by_original_message_id(
                    ctx.message.id) is not None:
                return

            # Generate string with all reactions on post at the time
            title_string = ""
            for reaction in reactions:
                if not isinstance(reaction.emoji, str):
                    # Remove all emoji reactions that are not from current server
                    if disnake.utils.get(ctx.guild.emojis,
                                         id=reaction.emoji.id) is None:
                        continue

                tmp_string = title_string + f"{reaction.count}x{reaction.emoji} "

                if len(tmp_string) >= 255:
                    break

                title_string = tmp_string

            embed = disnake.Embed(color=disnake.Color.dark_blue(),
                                  title=title_string)
            utils.add_author_footer(embed, author=ctx.message.author)
            embed.timestamp = ctx.message.created_at

            # Create link to original post
            link = utils.fill_message(
                "meme_repost_link",
                original_message_url=ctx.message.jump_url,
                original_channel=config.meme_room)
            embed.add_field(name="Link", value=link, inline=False)

            # Get all attachments of original post
            main_image = None
            other_attachments = []
            for attachment in ctx.message.attachments:
                content_type = attachment.content_type
                if content_type is not None and content_type.split(
                        "/")[0] == "image" and main_image is None:
                    # Set main image if its image and main image is not set
                    main_image = await attachment.to_file()
                else:
                    # Other attachments convert to file and append to list of attachments
                    attachment_file = await attachment.to_file()
                    if attachment_file is not None:
                        other_attachments.append(attachment_file)

            # Set content from original message if present
            if ctx.message.content:
                content_splits = ctx.message.content.split(" ")
                for content_split in content_splits:
                    if content_split.startswith("https://"):
                        # Its attachement URL
                        for extension in config.meme_repost_image_extensions:
                            # Check for extension in URL
                            if f".{extension}" in content_split:
                                if main_image is None:
                                    main_image = content_split
                                else:
                                    other_attachments.append(content_split)
                                break
                        else:
                            other_attachments.append(content_split)

                content = ctx.message.content[:900]
                embed.add_field(name="Obsah", value=content)

            # Set main image if present
            if main_image is not None:
                if isinstance(main_image, disnake.File):
                    embed.set_image(url=f"attachment://{main_image.filename}")
                elif isinstance(main_image, str):
                    embed.set_image(url=main_image)
                    main_image = None
                else:
                    main_image = None

            repost_message_id = -1
            secondary_message_id = None
            if len(embed) < 6000:
                repost_message = await self.repost_channel.send(
                    embed=embed, file=main_image)
                repost_message_id = repost_message.id

                if len(other_attachments) > 0:
                    # Files are getting send as files
                    files = [
                        file for file in other_attachments
                        if isinstance(file, disnake.File)
                    ]
                    files = files[:10] if files else None

                    # And urls as string in separated message
                    urls = [
                        file for file in other_attachments
                        if isinstance(file, str)
                    ]
                    urls = "\n".join(urls) if urls else None

                    secondary_message = await self.repost_channel.send(
                        urls, files=files)
                    secondary_message_id = secondary_message.id

            self.repost_repo.create_repost(ctx.message.id, repost_message_id,
                                           ctx.member.id, secondary_message_id)