예제 #1
0
def weekly_groups_digest(bot, job):
    near_interval = '7 days'
    far_interval = '14 days'

    query = """
        SELECT
            group_id,
            lang,
            nsfw,
            joined_the_bot
        FROM supergroups
        WHERE weekly_digest = TRUE AND bot_inside = TRUE
        ORDER BY last_date DESC
        """
    lst = database.query_r(query)

    #############
    # MESSAGES
    ############

    query = """
        SELECT 
            group_id,
            COUNT(msg_id) AS msgs, 
            RANK() OVER(PARTITION BY s.lang ORDER BY COUNT(msg_id) DESC)
        FROM messages 
        LEFT OUTER JOIN supergroups as s 
        USING (group_id)
        WHERE 
            message_date > now() - interval %s
            AND (s.banned_until IS NULL OR s.banned_until < now()) 
            AND s.bot_inside IS TRUE
        GROUP BY s.lang, group_id

    """
    msgs_this_week = database.query_r(query, near_interval)

    query = """
        SELECT 
            group_id, 
            COUNT(msg_id) AS msgs,
            RANK() OVER(PARTITION BY s.lang ORDER BY COUNT(msg_id) DESC)
        FROM messages
        LEFT OUTER JOIN supergroups as s 
        USING (group_id)
        WHERE 
            message_date BETWEEN now() - interval %s AND now() - interval %s
            AND (s.banned_until IS NULL OR s.banned_until < now()) 
            AND s.bot_inside IS TRUE
        GROUP BY s.lang, group_id
    """
    msgs_last_week = database.query_r(query, far_interval, near_interval)
    
    #############
    # MEMBERS
    ############

    query = """
         SELECT
            last_members.group_id,
            last_members.amount, 
            RANK() OVER(PARTITION BY s.lang ORDER BY last_members.amount DESC)
        FROM
            (
            SELECT
                *,
                ROW_NUMBER() OVER (
                    PARTITION BY group_id
                    ORDER BY updated_date DESC
                    ) AS row
            FROM members
        ) AS last_members 
        LEFT OUTER JOIN supergroups AS s 
        USING (group_id)
        WHERE 
            last_members.row=1
            AND (s.banned_until IS NULL OR s.banned_until < now())
            AND s.bot_inside IS TRUE
    """
    members_this_week = database.query_r(query)


    query = """
        SELECT 
            last_members.group_id, 
            last_members.amount,
            RANK() OVER(PARTITION BY s.lang ORDER BY last_members.amount DESC)
        FROM
            (
            SELECT 
                *, 
                ROW_NUMBER() OVER (
                    PARTITION BY group_id
                    ORDER BY updated_date DESC
                    ) AS row 
            FROM members
            WHERE updated_date <= now() - interval %s
        ) AS last_members 
        LEFT OUTER JOIN supergroups AS s 
        USING (group_id)
        WHERE 
            last_members.row=1
            AND (s.banned_until IS NULL OR s.banned_until < now())
            AND s.bot_inside IS TRUE
        """
    members_last_week = database.query_r(query, near_interval)

    ####################
    # SUM AND AVG VOTES
    ####################

    query = """
        WITH myconst AS
        (SELECT 
            s.lang,
            AVG(vote)::float AS overall_avg
        FROM votes AS v
        LEFT OUTER JOIN supergroups AS s
        ON s.group_id = v.group_id
        WHERE (s.banned_until IS NULL OR s.banned_until < now() )
        AND s.bot_inside IS TRUE
        GROUP BY s.lang
        HAVING COUNT(vote) >= %s)

        SELECT 
          *,
          RANK() OVER (PARTITION BY sub.lang  ORDER BY bayesan DESC)
          FROM (
            SELECT 
                v.group_id,
                s_ref.title, 
                s_ref.username, 
                COUNT(vote) AS amount, 
                ROUND(AVG(vote), 1)::float AS average,
                s.nsfw,
                extract(epoch from s.joined_the_bot at time zone 'utc') AS dt,
                s.lang,
                s.category,
                -- (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C
                --    * R = average for the movie (mean) = (Rating)
                --    * v = number of votes for the movie = (votes)
                --    * m = minimum votes required to be listed in the Top 250 (currently 1300)
                --    * C = the mean vote across the whole report (currently 6.8)
                (  (COUNT(vote)::float / (COUNT(vote)+%s)) * AVG(vote)::float + (%s::float / (COUNT(vote)+%s)) * (m.overall_avg) ) AS bayesan
            FROM votes AS v
            LEFT OUTER JOIN supergroups_ref AS s_ref
            ON s_ref.group_id = v.group_id
            LEFT OUTER JOIN supergroups AS s
            ON s.group_id = v.group_id
            LEFT OUTER JOIN myconst AS m
            ON (s.lang = m.lang)
            GROUP BY v.group_id, s_ref.title, s_ref.username, s.nsfw, s.banned_until, s.lang, s.category, s.bot_inside, s.joined_the_bot, m.overall_avg
            HAVING 
                (s.banned_until IS NULL OR s.banned_until < now()) 
                AND COUNT(vote) >= %s
                AND s.bot_inside IS TRUE
          ) AS sub;
    """
    this_week_votes_avg = database.query_r(
        query, 
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS
    )

    query = """
        SELECT 
            group_id,
            COUNT(vote) AS amount,
            ROUND(AVG(vote), 1) AS average, 
            RANK() OVER(PARTITION BY s.lang ORDER BY ROUND(AVG(VOTE), 1)DESC, COUNT(VOTE)DESC)
        FROM votes
        LEFT OUTER JOIN supergroups AS s 
        USING (group_id)
        WHERE vote_date <= now() - interval %s
        GROUP BY group_id, s.lang, s.banned_until, s.bot_inside
        HAVING 
            (s.banned_until IS NULL OR s.banned_until < now()) 
            AND COUNT(vote) >= %s 
            AND s.bot_inside IS TRUE
    """
    query = """
        WITH myconst AS
        (SELECT 
            s.lang,
            AVG(vote)::float AS overall_avg
        FROM votes AS v
        LEFT OUTER JOIN supergroups AS s
        ON s.group_id = v.group_id
        WHERE (s.banned_until IS NULL OR s.banned_until < now() ) AND vote_date <= now() - interval %s
        AND s.bot_inside IS TRUE
        GROUP BY s.lang
        HAVING COUNT(vote) >= %s)

        SELECT 
          *,
          RANK() OVER (PARTITION BY sub.lang  ORDER BY bayesan DESC)
          FROM (
            SELECT 
                v.group_id,
                s_ref.title, 
                s_ref.username, 
                COUNT(vote) AS amount, 
                ROUND(AVG(vote), 1)::float AS average,
                s.nsfw,
                extract(epoch from s.joined_the_bot at time zone 'utc') AS dt,
                s.lang,
                s.category,
                -- (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C
                --    * R = average for the movie (mean) = (Rating)
                --    * v = number of votes for the movie = (votes)
                --    * m = minimum votes required to be listed in the Top 250 (currently 1300)
                --    * C = the mean vote across the whole report (currently 6.8)
                (  (COUNT(vote)::float / (COUNT(vote)+%s)) * AVG(vote)::float + (%s::float / (COUNT(vote)+%s)) * (m.overall_avg) ) AS bayesan
            FROM votes AS v
            LEFT OUTER JOIN supergroups_ref AS s_ref
            ON s_ref.group_id = v.group_id
            LEFT OUTER JOIN supergroups AS s
            ON s.group_id = v.group_id
            LEFT OUTER JOIN myconst AS m
            ON (s.lang = m.lang)
            WHERE vote_date <= now() - interval %s
            GROUP BY v.group_id, s_ref.title, s_ref.username, s.nsfw, s.banned_until, s.lang, s.category, s.bot_inside, s.joined_the_bot, m.overall_avg
            HAVING 
                (s.banned_until IS NULL OR s.banned_until < now()) 
                AND COUNT(vote) >= %s
                AND s.bot_inside IS TRUE
          ) AS sub;
    """
    last_week_votes_avg = database.query_r(
        query, 
        near_interval, 
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        leaderboards.VotesLeaderboard.MIN_REVIEWS,
        near_interval,
        leaderboards.VotesLeaderboard.MIN_REVIEWS
    )

    ##################
    # ACTIVE USERS
    ##################

    query = """
         SELECT
            group_id,
            COUNT(DISTINCT user_id), 
            RANK() OVER(PARTITION BY s.lang ORDER BY COUNT(DISTINCT user_id) DESC)
        FROM messages 
        LEFT OUTER JOIN supergroups AS s 
        USING (group_id)
        WHERE 
            message_date > (now() - interval %s)
            AND (s.banned_until IS NULL OR s.banned_until < now()) 
            AND s.bot_inside IS TRUE
        GROUP BY group_id, s.lang
        """
    this_week_active_users = database.query_r(query, near_interval)

    query = """
        SELECT 
            group_id,
            COUNT(DISTINCT user_id), 
            RANK() OVER(PARTITION BY s.lang ORDER BY COUNT(DISTINCT user_id) DESC)
        FROM messages
        LEFT OUTER JOIN supergroups AS s 
        USING (group_id)
        WHERE 
            message_date BETWEEN (now() - interval %s) AND (now() - interval %s)
            AND (s.banned_until IS NULL OR s.banned_until < now()) 
            AND s.bot_inside IS TRUE
        GROUP BY group_id, s.lang
        """
    last_week_active_users = database.query_r(query, far_interval, near_interval)

    start_in = 0
    for group in lst:
        start_in += 0.1
        group_id = group[0]
        lang = group[1]

        msgs_new = 0
        msgs_old = 0
        msgs_pos_old = 0
        msgs_pos_new = 0

        members_new = 0
        members_old = 0
        members_pos_old = 0
        members_pos_new = 0

        sum_v_new = 0
        avg_v_new = 0
        sum_v_old = 0
        avg_v_old = 0
        avg_pos_old = 0
        avg_pos_new = 0

        act_users_new = 0
        act_users_old = 0
        act_users_pos_old = 0
        act_users_pos_new = 0

        for i in msgs_this_week:
            if i[0] == group_id:
                msgs_new = i[1]
                msgs_pos_new = i[2]
                break

        for i in msgs_last_week:
            if i[0] == group_id:
                msgs_old = i[1]
                msgs_pos_old = i[2]
                break

        for i in members_this_week:
            if i[0] == group_id:
                members_new = i[1]
                members_pos_new = i[2]
                break

        for i in members_last_week:
            if i[0] == group_id:
                members_old = i[1]
                members_pos_old = i[2]
                break

        for i in this_week_votes_avg:
            if i[0] == group_id:
                sum_v_new = i[3]
                avg_v_new = i[4]
                avg_pos_new = i[10]
                break

        for i in last_week_votes_avg:
            if i[0] == group_id:
                sum_v_old = i[3]
                avg_v_old = i[4]
                avg_pos_old = i[10]
                break

        for i in this_week_active_users:
            if i[0] == group_id:
                act_users_new = i[1]
                act_users_pos_new = i[2]
                break

        for i in last_week_active_users:
            if i[0] == group_id:
                act_users_old = i[1]
                act_users_pos_old = i[2]
                break

        diff_msg, percent_msg = diff_percent(msgs_new, msgs_old, lang)
        diff_members, percent_members = diff_percent(members_new, members_old, lang) 
        diff_act, percent_act = diff_percent(act_users_new, act_users_old, lang)

        text = get_lang.get_string(lang, "weekly_groups_digest").format(
            # by messages
            utils.sep_l(msgs_old, lang),
            utils.sep_l(msgs_new, lang),
            diff_msg, percent_msg,
            utils.sep_l(msgs_pos_old, lang),
            utils.sep_l(msgs_pos_new, lang),
            # by members
            utils.sep_l(members_old, lang),
            utils.sep_l(members_new, lang),
            diff_members, percent_members,
            utils.sep_l(members_pos_old, lang),
            utils.sep_l(members_pos_new, lang),
            # by votes average
            utils.sep_l(avg_v_old, lang), emojis.STAR, utils.sep_l(sum_v_old, lang),
            utils.sep_l(avg_v_new, lang), emojis.STAR, utils.sep_l(sum_v_new, lang),
            utils.sep_l(avg_pos_old, lang),
            utils.sep_l(avg_pos_new, lang),
            # by active users
            utils.sep_l(act_users_old, lang),
            utils.sep_l(act_users_new, lang),
            diff_act, percent_act,
            utils.sep_l(act_users_pos_old, lang),
            utils.sep_l(act_users_pos_new, lang)
        )

        ##############
        # TOP n USERS
        ##############

        query_top_users = """
            SELECT 
                user_id,
                COUNT(msg_id) AS num_msgs, 
                name, 
                RANK() OVER (ORDER BY COUNT(msg_id) DESC)
            FROM messages AS m
            LEFT OUTER JOIN users_ref AS u_ref
            USING (user_id)
            WHERE group_id = %s AND m.message_date > (now() - interval %s)
            GROUP BY user_id, name
            LIMIT %s
            """
        top_users_of_the_group = database.query_r(query_top_users, group_id, near_interval, 10)
        for user in top_users_of_the_group:
            text += "{}) <a href=\"tg://user?id={}\">{}</a>: {}\n".format(
                    user[3],
                    user[0],
                    html.escape(utils.truncate(user[2], c.MAX_CHARS_LEADERBOARD_PAGE_GROUP)),
                    utils.sep_l(user[1], lang)
                    )

        text += "\n#weekly_group_digest"
        reply_markup = keyboards.disable_group_weekly_digest_kb(lang)
        # schedule send
        job.job_queue.run_once(
                send_one_by_one_weekly_group_digest, 
                start_in, 
                context=[group_id, text, reply_markup]
                )
예제 #2
0
    def build_page(self, group_username, only_admins=True):
        query = """
            SELECT 
                m.user_id, 
                COUNT(m.msg_id) AS leaderboard,
                u_ref.name, 
                u_ref.last_name, 
                u_ref.username,
                RANK() OVER (ORDER BY COUNT(m.msg_id) DESC)
            FROM messages AS m
            LEFT OUTER JOIN users_ref AS u_ref
            USING (user_id)
            WHERE m.group_id = %s
                AND m.message_date > date_trunc('week', now())
            GROUP BY m.user_id, u_ref.name, u_ref.last_name, u_ref.username
            """

        lst_and_time = self.get_list_from_cache()
        if lst_and_time is None:
            extract = database.query_r(query, self.group_id)
            self.cache_the_list(extract)
            cached_sec_ago = 1
        else:
            extract, cached_at = lst_and_time
            cached_sec_ago = int(time.time() - cached_at)

        updated_ago_string = utils.round_seconds(cached_sec_ago, self.lang, short=True)

        pages = Pages(extract, self.page)

        footer_buttons = keyboards.check_groupleaderboard_in_private_button(self.lang, self.group_id) if only_admins else None
        reply_markup = pages.build_buttons(
            base=self.buttons_callback_base(), 
            only_admins=only_admins, 
            footer_buttons=footer_buttons 
        )

        text = get_lang.get_string(self.lang, "pre_groupleaderboard").format(escape_markdown(group_username))
        text += "\n_{}: {}_".format(
            utils.get_lang.get_string(self.lang, "latest_update"),
            updated_ago_string
        )
        text += "\n\n"
        first_number_of_page = pages.first_number_of_page()
        offset = first_number_of_page - 1
        for user in pages.chosen_page_items():
            offset += 1  # for before IT numeration
            if only_admins:  # it means it's in a group
                text += "{}) [{}](tg://user?id={}): {}\n".format(
                    user[5], 
                    utils.replace_markdown_chars(utils.truncate(user[2], M_C_G)),
                    user[0],
                    utils.sep_l(user[1], self.lang)
                )
            else:  # it's a private chat
                text += "{}) {}: {}\n".format(
                    user[5], 
                    escape_markdown("@"+str(user[4]) if user[4] is not None else user[2]), 
                    utils.sep_l(user[1], self.lang)
                )
        return text, reply_markup
예제 #3
0
    def build_page(self):
        query = """
            SELECT 
                m.group_id, 
                COUNT (m.group_id) AS leaderboard,
                s_ref.title, 
                s_ref.username,
                s.nsfw, 
                extract(epoch from s.joined_the_bot at time zone 'utc') AS dt,
                RANK() OVER (ORDER BY COUNT(m.group_id) DESC),
                s.lang,
                s.category
            FROM messages AS m
            LEFT OUTER JOIN supergroups_ref AS s_ref
            ON s_ref.group_id = m.group_id
            LEFT OUTER JOIN supergroups AS s
            ON s.group_id = m.group_id
            WHERE m.message_date > date_trunc('week', now())
                AND (s.banned_until IS NULL OR s.banned_until < now()) 
                AND s.lang = %s
                AND s.bot_inside IS TRUE
            GROUP BY m.group_id, s_ref.title, s_ref.username, s.nsfw, dt, s.banned_until, s.lang, s.category, s.bot_inside
        """

        lst_and_time = self.get_list_from_cache()
        if lst_and_time is None:
            extract = database.query_r(query, self.region)
            self.cache_the_list(extract)
            cached_sec_ago = 1
        else:
            extract, cached_at = lst_and_time
            cached_sec_ago = int(time.time() - cached_at)
        updated_ago_string = utils.round_seconds(cached_sec_ago, self.lang, short=True)    

        if self.category != "":
            extract = [i for i in extract if i[self.INDEX_CATEGORY] == self.category]

        pages = Pages(extract, self.page)
        
        callback_base = self.buttons_callback_base()
        reply_markup = pages.build_buttons(base=callback_base, footer_buttons=keyboards.filter_category_button(self.lang, callback_base, pages.chosen_page))

        emoji_region = supported_langs.COUNTRY_FLAG[self.region]
        text = get_lang.get_string(self.lang, "pre_leadermessage").format(emoji_region)
        if self.category != "":
            text += "\n{}: {}".format(get_lang.get_string(self.lang, "category"), get_lang.get_string(self.lang, "categories")[categories.CODES[self.category]])
        text += "\n_{}: {}_".format(
            utils.get_lang.get_string(self.lang, "latest_update"),
            updated_ago_string
        )        
        text += "\n\n"
        for group in pages.chosen_page_items():
            nsfw = emojis.NSFW if group[4] is True else ""
            new = emojis.NEW if (group[5]+self.NEW_INTERVAL) > time.time() else ""
            text += "{}) {}[{}](t.me/{}): {}{}\n".format(
                    group[6],
                    nsfw, 
                    utils.replace_markdown_chars(utils.truncate(group[2], M_C_P)), 
                    group[3], 
                    utils.sep_l(group[1], self.lang), 
                    new
                    )
        return text, reply_markup
예제 #4
0
    def build_page(self):
        # Thank https://stackoverflow.com/a/46496407/8372336 to make clear this query
        query = """
        SELECT 
            members.*, 
            supergroups.lang, 
            supergroups_ref.title, 
            supergroups_ref.username, 
            extract(epoch from supergroups.joined_the_bot at time zone 'utc') AS dt,
            supergroups.nsfw,
            RANK() OVER(ORDER BY members.amount DESC),
            supergroups.category
        FROM
        -- Window function to get only de last_date:
            (SELECT last_members.group_id,last_members.amount
            FROM
            (SELECT *, ROW_NUMBER() OVER (PARTITION BY group_id
            ORDER BY updated_date DESC) AS row FROM members) AS last_members
            WHERE last_members.row=1) AS members
        -- Joins with other tables
        LEFT JOIN supergroups
        ON members.group_id = supergroups.group_id
        LEFT JOIN supergroups_ref 
        ON supergroups.group_id = supergroups_ref.group_id
        WHERE (supergroups.banned_until IS NULL OR supergroups.banned_until < now()) 
            AND lang = %s
            AND supergroups.bot_inside IS TRUE
        """

        lst_and_time = self.get_list_from_cache()
        if lst_and_time is None:
            extract = database.query_r(query, self.region)
            self.cache_the_list(extract)
            cached_sec_ago = 1
        else:
            extract, cached_at = lst_and_time
            cached_sec_ago = int(time.time() - cached_at)
        updated_ago_string = utils.round_seconds(cached_sec_ago, self.lang, short=True)            
        
        if self.category != "":
            extract = [i for i in extract if i[self.INDEX_CATEGORY] == self.category]    
        
        pages = Pages(extract, self.page)

        callback_base = self.buttons_callback_base()
        reply_markup = pages.build_buttons(base=callback_base, footer_buttons=keyboards.filter_category_button(self.lang, callback_base, pages.chosen_page))

        emoji_region = supported_langs.COUNTRY_FLAG[self.region]
        text = get_lang.get_string(self.lang, "pre_leadermember").format(emoji_region)
        if self.category != "":
            text += "\n{}: {}".format(get_lang.get_string(self.lang, "category"), get_lang.get_string(self.lang, "categories")[categories.CODES[self.category]])
        text += "\n_{}: {}_".format(
            utils.get_lang.get_string(self.lang, "latest_update"),
            updated_ago_string
        )
        text += "\n\n"
        for group in pages.chosen_page_items():
            nsfw = emojis.NSFW if group[6] is True else ""
            new = emojis.NEW if (group[5]+self.NEW_INTERVAL) > time.time() else ""
            text += "{}) {}[{}](t.me/{}): {}{}\n".format(
                group[7],
                nsfw, 
                utils.replace_markdown_chars(utils.truncate(group[3], M_C_P)),
                group[4], 
                utils.sep_l(group[1], self.lang), 
                new)
        return text, reply_markup
예제 #5
0
    def build_page(self):
        query = """
            WITH myconst AS
            (SELECT 
                  s.lang,
                  AVG(vote)::float AS overall_avg
            FROM votes AS v
            LEFT OUTER JOIN supergroups_ref AS s_ref
            ON s_ref.group_id = v.group_id
            LEFT OUTER JOIN supergroups AS s
            ON s.group_id = v.group_id
            GROUP BY s.banned_until, s.bot_inside, s.lang
            HAVING 
                  (s.banned_until IS NULL OR s.banned_until < now()) 
                  AND COUNT(vote) >= %s
                  AND s.bot_inside IS TRUE)

            SELECT 
              *,
              RANK() OVER (PARTITION BY sub.lang  ORDER BY bayesan DESC)
              FROM (
                SELECT 
                    v.group_id,
                    s_ref.title, 
                    s_ref.username, 
                    COUNT(vote) AS amount, 
                    ROUND(AVG(vote), 1)::float AS average,
                    s.nsfw,
                    extract(epoch from s.joined_the_bot at time zone 'utc') AS dt,
                    s.lang,
                    s.category,
                    -- (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C
                    --    * R = average for the movie (mean) = (Rating)
                    --    * v = number of votes for the movie = (votes)
                    --    * m = minimum votes required to be listed in the Top 250 (currently 1300)
                    --    * C = the mean vote across the whole report (currently 6.8)
                    (  (COUNT(vote)::float / (COUNT(vote)+%s)) * AVG(vote)::float + (%s::float / (COUNT(vote)+%s)) * (m.overall_avg) ) AS bayesan
                FROM votes AS v
                LEFT OUTER JOIN supergroups_ref AS s_ref
                ON s_ref.group_id = v.group_id
                LEFT OUTER JOIN supergroups AS s
                ON s.group_id = v.group_id
                LEFT OUTER JOIN myconst AS m
                ON (s.lang = m.lang)
                GROUP BY v.group_id, s_ref.title, s_ref.username, s.nsfw, s.banned_until, s.lang, s.category, s.bot_inside, s.joined_the_bot, m.overall_avg
                HAVING 
                    (s.banned_until IS NULL OR s.banned_until < now()) 
                    AND COUNT(vote) >= %s
                    AND s.lang = %s
                    AND s.bot_inside IS TRUE
              ) AS sub;
        """

        lst_and_time = self.get_list_from_cache()
        if lst_and_time is None:
            extract = database.query_r(
                query, 
                self.MIN_REVIEWS, 
                self.MIN_REVIEWS, 
                self.MIN_REVIEWS, 
                self.MIN_REVIEWS, 
                self.MIN_REVIEWS, 
                self.region
            )
            self.cache_the_list(extract)
            cached_sec_ago = 1
        else:
            extract, cached_at = lst_and_time
            cached_sec_ago = int(time.time() - cached_at)
        updated_ago_string = utils.round_seconds(cached_sec_ago, self.lang, short=True)

        if self.category != "":
            extract = [i for i in extract if i[self.INDEX_CATEGORY] == self.category]

        pages = Pages(extract, self.page)

        callback_base = self.buttons_callback_base()
        reply_markup = pages.build_buttons(base=callback_base, footer_buttons=keyboards.filter_category_button(self.lang, callback_base, pages.chosen_page))

        emoji_region = supported_langs.COUNTRY_FLAG[self.region]
        text = get_lang.get_string(self.lang, "pre_leadervote").format(self.MIN_REVIEWS, emoji_region)
        if self.category != "":
            text += "\n{}: {}".format(get_lang.get_string(self.lang, "category"), get_lang.get_string(self.lang, "categories")[categories.CODES[self.category]])
        text += "\n_{}: {}_".format(
            utils.get_lang.get_string(self.lang, "latest_update"),
            updated_ago_string
        )        
        text += "\n\n"
        for group in pages.chosen_page_items():
            nsfw = emojis.NSFW if group[5] is True else ""
            new = emojis.NEW if (group[6]+self.NEW_INTERVAL > time.time()) else ""
            text += "{}) {}[{}](t.me/{}): {}{}|{}{}\n".format(
                    group[10],
                    nsfw, 
                    utils.replace_markdown_chars(utils.truncate(group[1], M_C_P)), 
                    group[2],
                    group[4], 
                    emojis.STAR,
                    utils.sep_l(group[3], self.lang),
                    new
                    )
        return text, reply_markup