__version__ = (1, 0, 0) # ©️ Fixyres, 2026-2030 # 🌐 https://github.com/Fixyres/FModules # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # 🔑 http://www.apache.org/licenses/LICENSE-2.0 # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png # meta developer: @NFModules # meta fhsdesc: brawlstars, game, funny from .. import loader, utils from urllib.parse import urlparse, parse_qs async def extract_code(value: str) -> str: if value.startswith("http"): tags = parse_qs(urlparse(value).query).get("tag") return tags[0] if tags else value return value async def to_id(code: str) -> int: code = code.strip().upper() if not code.startswith("X"): return 0 val = 0 for ch in code[1:]: i = "QWERTYUPASDFGHJKLZCVBNM23456789".find(ch) if i == -1: return 0 val = val * 31 + i return val >> 8 async def to_code(n: int) -> str: if n < 0: return "X" n_shifted = n << 8 res = [] chars = "QWERTYUPASDFGHJKLZCVBNM23456789" while n_shifted > 0: res.append(chars[n_shifted % 31]) n_shifted //= 31 return "X" + "".join(reversed(res)) @loader.tds class BSR(loader.Module): '''Module for finding nearby game rooms in BrawlStars.''' strings = { "name": "BSR", "invalid_args": "Usage: {prefix}bsr (room code/link) (previous) (next)", "invalid_code": "Invalid room code!", "at_least_one": "At least one argument (previous or next) must be greater than 0!", "prev_block": "Previous:\n
{prev_list}
", "next_block": "Next:\n
{next_list}
", "btn_target": "Target Room" } strings_ru = { "_cls_doc": "Модуль для поиска ближайших игровых комнат в BrawlStars.", "invalid_args": "Использование: {prefix}bsr (код комнаты/ссылка) (предыдущие) (следующие)", "invalid_code": "Неверный код комнаты!", "at_least_one": "Хотя бы один аргумент (предыдущие или следующие) должен быть больше 0!", "prev_block": "Предыдущие:\n
{prev_list}
", "next_block": "Следующие:\n
{next_list}
", "btn_target": "Целевая комната" } strings_ua = { "_cls_doc": "Модуль для пошуку найближчих ігрових кімнат у BrawlStars.", "invalid_args": "Використання: {prefix}bsr (код кімнати/посилання) (попередні) (наступні)", "invalid_code": "Невірний код кімнати!", "at_least_one": "Хоча б один аргумент (попередні або наступні) повинен бути більшим за 0!", "prev_block": "Попередні:\n
{prev_list}
", "next_block": "Наступні:\n
{next_list}
", "btn_target": "Цільова кімната" } strings_kz = { "_cls_doc": "BrawlStars ойынында жақын маңдағы ойын бөлмелерін табуға арналған модуль.", "invalid_args": "Қолдану: {prefix}bsr (бөлме коды/сілтеме) (алдыңғы) (келесі)", "invalid_code": "Қате бөлме коды!", "at_least_one": "Кем дегенде бір аргумент (алдыңғы немесе келесі) 0-ден үлкен болуы керек!", "prev_block": "Алдыңғы:\n
{prev_list}
", "next_block": "Келесі:\n
{next_list}
", "btn_target": "Мақсатты бөлме" } strings_uz = { "_cls_doc": "BrawlStars'da eng yaqin o'yin xonalarini topish uchun modul.", "invalid_args": "Qo'llanilishi: {prefix}bsr (xona kodi/havolasi) (oldingi) (keyingi)", "invalid_code": "Noto'g'ri xona kodi!", "at_least_one": "Kamida bitta argument (oldingi yoki keyingi) 0 dan katta bo'lishi kerak!", "prev_block": "Oldingi:\n
{prev_list}
", "next_block": "Keyingi:\n
{next_list}
", "btn_target": "Maqsadli xona" } strings_fr = { "_cls_doc": "Module pour trouver des salles de jeu à proximité dans BrawlStars.", "invalid_args": "Utilisation: {prefix}bsr (code/lien) (précédents) (suivants)", "invalid_code": "Code de salle invalide!", "at_least_one": "Au moins un argument doit être supérieur à 0 !", "prev_block": "Précédents:\n
{prev_list}
", "next_block": "Suivants:\n
{next_list}
", "btn_target": "Salle cible" } strings_de = { "_cls_doc": "Modul zum Finden von nahegelegenen Spielräumen in BrawlStars.", "invalid_args": "Verwendung: {prefix}bsr (Raumcode/Link) (vorherige) (nächste)", "invalid_code": "Ungültiger Raumcode!", "at_least_one": "Mindestens ein argument muss größer als 0 sein!", "prev_block": "Vorherige:\n
{prev_list}
", "next_block": "Nächste:\n
{next_list}
", "btn_target": "Zielraum" } strings_jp = { "_cls_doc": "BrawlStarsで近くのゲームルームを検索するためのモジュール。", "invalid_args": "使用法: {prefix}bsr (コード/リンク) (前) (次)", "invalid_code": "無効なルームコード!", "at_least_one": "少なくとも1つの引数は0より大きくなければなりません!", "prev_block": "前:\n
{prev_list}
", "next_block": "次:\n
{next_list}
", "btn_target": "ターゲットルーム" } @loader.command( ru_doc="(код комнаты/ссылка) (предыдущие) (следующие) - найти комнаты.", ua_doc="(код кімнати/посилання) (попередні) (наступні) - знайти кімнати.", kz_doc="(бөлме коды/сілтеме) (алдыңғы) (келесі) - бөлмелерді табу.", uz_doc="(xona kodi/havolasi) (oldingi) (keyingi) - xonalarni topish.", fr_doc="(code/lien) (précédents) (suivants) - trouver des salles.", de_doc="(Raumcode/Link) (vorherige) (nächste) - Räume finden.", jp_doc="(コード/リンク) (前) (次) - ルームを検索します。" ) async def bsr(self, message): '''(room code/link) (previous) (next) - find rooms.''' args = utils.get_args_raw(message).split() if not args: return await utils.answer(message, self.strings("invalid_args").format(prefix=self.get_prefix())) raw_input = args[0] before = 0 nxt = 10 if len(args) >= 2: try: before = int(args[1]) except ValueError: pass if len(args) >= 3: try: nxt = int(args[2]) except ValueError: pass before = max(0, min(before, 5000)) nxt = max(0, min(nxt, 5000)) if before == 0 and nxt == 0: return await utils.answer(message, self.strings("at_least_one")) clean_tag = await extract_code(raw_input) base_id = await to_id(clean_tag) if base_id == 0: return await utils.answer(message, self.strings("invalid_code")) text, page, total_pages = await self.get_page_content(base_id, before, nxt, 0) kb = self.build_keyboard(base_id, before, nxt, page, total_pages, clean_tag) await self.inline.form( message=message, text=text, photo="https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png", reply_markup=kb ) async def get_page_content(self, base_id: int, before: int, nxt: int, page: int): actual_before = min(before, base_id) total_pages = max(1, (actual_before + 9) // 10, (nxt + 9) // 10) if page < 0: page = total_pages - 1 if page >= total_pages: page = 0 start = page * 10 prev_list = [] for i in range(start + 1, min(start + 10, actual_before) + 1): c = await to_code(base_id - i) link = f'{c}' prev_list.append(link) next_list = [] for i in range(start + 1, min(start + 10, nxt) + 1): c = await to_code(base_id + i) link = f'{c}' next_list.append(link) blocks = [] if prev_list: blocks.append(self.strings("prev_block").format(prev_list="\n".join(prev_list))) if next_list: blocks.append(self.strings("next_block").format(next_list="\n".join(next_list))) res = "\n\n".join(blocks) if not res.strip(): res = " " return res, page, total_pages def build_keyboard(self, base_id: int, before: int, nxt: int, page: int, total_pages: int, clean_tag: str): kb = [ [ { "text": self.strings("btn_target"), "copy": clean_tag } ] ] if total_pages > 1: nav_row = [] if page > 0: nav_row.append({"text": "←", "callback": self.page_cb, "args": (base_id, before, nxt, page - 1, clean_tag)}) nav_row.append({"text": f"{page + 1} / {total_pages}", "callback": self.dummy_cb, "args": ()}) if page < total_pages - 1: nav_row.append({"text": "→", "callback": self.page_cb, "args": (base_id, before, nxt, page + 1, clean_tag)}) kb.append(nav_row) return kb async def dummy_cb(self, call): await call.answer() async def page_cb(self, call, base_id: int, before: int, nxt: int, page: int, clean_tag: str): text, new_page, total_pages = await self.get_page_content(base_id, before, nxt, page) kb = self.build_keyboard(base_id, before, nxt, new_page, total_pages, clean_tag) await call.edit( text=text, photo="https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png", reply_markup=kb )