This commit is contained in:
2026-04-18 11:01:48 +03:00
16 changed files with 1368 additions and 110 deletions

View File

@@ -7,7 +7,7 @@ __version__ = (1, 0, 0)
# 🔑 http://www.apache.org/licenses/LICENSE-2.0 # 🔑 http://www.apache.org/licenses/LICENSE-2.0
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png
# meta developer: @FModules # meta developer: @NFModules
# meta fhsdesc: brawlstars, game, funny # meta fhsdesc: brawlstars, game, funny
from .. import loader, utils from .. import loader, utils

View File

@@ -1,6 +1,6 @@
__version__ = (9, 3, 9) __version__ = (9, 3, 9)
# meta developer: @FModules # meta developer: @NFModules
# meta pic: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/logo.png # meta pic: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/logo.png
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/logo.png # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/logo.png
# scope: hikka_min 2.0.0 # scope: hikka_min 2.0.0
@@ -100,18 +100,6 @@ class MInstaller:
return "dependency", [] return "dependency", []
async def pip(self, dependencies: List[str]) -> bool:
virtualenv = hasattr(sys, 'real_prefix') or sys.prefix != getattr(sys, 'base_prefix', sys.prefix)
flags = ["--user"] if loader.USER_INSTALL and not virtualenv else []
process = await asyncio.create_subprocess_exec(
sys.executable, "-m", "pip", "install", "-U", "-q",
"--disable-pip-version-check", "--no-warn-script-location",
*flags, *dependencies
)
return await process.wait() == 0
async def load(self, plugin: 'loader.Module', code: str, origin: str, step: int) -> Union[str, List[str]]: async def load(self, plugin: 'loader.Module', code: str, origin: str, step: int) -> Union[str, List[str]]:
if step == 0: if step == 0:
try: try:
@@ -121,7 +109,7 @@ class MInstaller:
)) ))
if dependencies: if dependencies:
if not await self.pip(dependencies): if not await plugin.install_requirements(dependencies):
return dependencies return dependencies
importlib.invalidate_caches() importlib.invalidate_caches()
return "retry" return "retry"
@@ -171,7 +159,7 @@ class MInstaller:
alternative = {"sklearn": "scikit-learn", "pil": "Pillow", "herokutl": "Heroku-TL-New"}.get(exception.name.lower(), exception.name) alternative = {"sklearn": "scikit-learn", "pil": "Pillow", "herokutl": "Heroku-TL-New"}.get(exception.name.lower(), exception.name)
dependencies = [alternative] dependencies = [alternative]
if not alternative or not await self.pip(dependencies): if not alternative or not await plugin.install_requirements(dependencies):
return dependencies return dependencies
importlib.invalidate_caches() importlib.invalidate_caches()
@@ -314,7 +302,7 @@ class FHetaUI:
@loader.tds @loader.tds
class FHeta(loader.Module): class FHeta(loader.Module):
'''Module for searching modules! Watch all FHeta news in @FHeta_Updates!''' '''Module for searching modules! Watch all FHeta news in @NFHeta_Updates!'''
strings = { strings = {
"name": "FHeta", "name": "FHeta",
@@ -345,11 +333,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Error, module tried to overwrite built-in module!", "overwrite": "✘ Error, module tried to overwrite built-in module!",
"dependency": "✘ Dependencies installation error! {deps}", "dependency": "✘ Dependencies installation error! {deps}",
"docdevs": "Use only modules from official Heroku developers when searching?", "docdevs": "Use only modules from official Heroku developers when searching?",
"doctheme": "Theme for emojis." "doctheme": "Theme for emojis.",
"channel": "This is the channel with all updates in FHeta!"
} }
strings_ru = { strings_ru = {
"_cls_doc": "Модуль для поиска модулей! Следите за всеми новостями FHeta в @FHeta_Updates!", "_cls_doc": "Модуль для поиска модулей! Следите за всеми новостями FHeta в @NFHeta_Updates!",
"lang": "ru", "lang": "ru",
"author": "от", "author": "от",
"description": "Описание", "description": "Описание",
@@ -377,11 +366,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Ошибка, модуль пытался перезаписать встроенный модуль!", "overwrite": "✘ Ошибка, модуль пытался перезаписать встроенный модуль!",
"dependency": "✘ Ошибка установки зависимостей! {deps}", "dependency": "✘ Ошибка установки зависимостей! {deps}",
"docdevs": "Использовать только модули от официальных разработчиков Heroku при поиске?", "docdevs": "Использовать только модули от официальных разработчиков Heroku при поиске?",
"doctheme": "Тема для эмодзи." "doctheme": "Тема для эмодзи.",
"channel": "Это канал со всеми обновлениями в FHeta!"
} }
strings_ua = { strings_ua = {
"_cls_doc": "Модуль для пошуку модулів! Слідкуйте за всіма новинами FHeta в @FHeta_Updates!", "_cls_doc": "Модуль для пошуку модулів! Слідкуйте за всіма новинами FHeta в @NFHeta_Updates!",
"lang": "ua", "lang": "ua",
"author": "від", "author": "від",
"description": "Опис", "description": "Опис",
@@ -409,11 +399,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Помилка, модуль намагався перезаписати вбудований модуль!", "overwrite": "✘ Помилка, модуль намагався перезаписати вбудований модуль!",
"dependency": "✘ Помилка встановлення залежностей! {deps}", "dependency": "✘ Помилка встановлення залежностей! {deps}",
"docdevs": "Використовувати тільки модулі від офіційних розробників Heroku при пошуку?", "docdevs": "Використовувати тільки модулі від офіційних розробників Heroku при пошуку?",
"doctheme": "Тема для емодзі." "doctheme": "Тема для емодзі.",
"channel": "Це канал з усіма оновленнями в FHeta!"
} }
strings_kz = { strings_kz = {
"_cls_doc": "Модульдерді іздеу модулі! FHeta барлық жаңалықтарын @FHeta_Updates арнасында қадағалаңыз!", "_cls_doc": "Модульдерді іздеу модулі! FHeta барлық жаңалықтарын @NFHeta_Updates арнасында қадағалаңыз!",
"lang": "kz", "lang": "kz",
"author": "авторы", "author": "авторы",
"description": "Сипаттама", "description": "Сипаттама",
@@ -441,11 +432,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Қате, модуль кіріктірілген модульді қайта жазуға тырысты!", "overwrite": "✘ Қате, модуль кіріктірілген модульді қайта жазуға тырысты!",
"dependency": "✘ Тәуелділіктерді орнату қатесі! {deps}", "dependency": "✘ Тәуелділіктерді орнату қатесі! {deps}",
"docdevs": "Іздеу кезінде тек ресми Heroku әзірлеушілерінің модульдерін пайдалану керек пе?", "docdevs": "Іздеу кезінде тек ресми Heroku әзірлеушілерінің модульдерін пайдалану керек пе?",
"doctheme": "Эмодзилер үшін тақырып." "doctheme": "Эмодзилер үшін тақырып.",
"channel": "Бұл FHeta-дағы барлық жаңартулары бар арна!"
} }
strings_uz = { strings_uz = {
"_cls_doc": "Modullarni qidirish moduli! FHeta barcha yangilanishlarini @FHeta_Updates kanalida kuzatib boring!", "_cls_doc": "Modullarni qidirish moduli! FHeta barcha yangilanishlarini @NFHeta_Updates kanalida kuzatib boring!",
"lang": "uz", "lang": "uz",
"author": "muallif", "author": "muallif",
"description": "Tavsif", "description": "Tavsif",
@@ -473,11 +465,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Xatolik, modul o'rnatilgan modulni qayta yozishga harakat qildi!", "overwrite": "✘ Xatolik, modul o'rnatilgan modulni qayta yozishga harakat qildi!",
"dependency": "✘ Bog'liqliklarni o'rnatish xatosi! {deps}", "dependency": "✘ Bog'liqliklarni o'rnatish xatosi! {deps}",
"docdevs": "Qidiruv paytida faqat rasmiy Heroku ishlab chiquvchilarining modullaridan foydalanish kerakmi?", "docdevs": "Qidiruv paytida faqat rasmiy Heroku ishlab chiquvchilarining modullaridan foydalanish kerakmi?",
"doctheme": "Emojilar uchun mavzu." "doctheme": "Emojilar uchun mavzu.",
"channel": "Bu FHeta-dagi barcha yangilanishlari bo'lgan kanal!"
} }
strings_fr = { strings_fr = {
"_cls_doc": "Module de recherche de modules! Suivez toutes les actualités FHeta sur @FHeta_Updates!", "_cls_doc": "Module de recherche de modules! Suivez toutes les actualités FHeta sur @NFHeta_Updates!",
"lang": "fr", "lang": "fr",
"author": "par", "author": "par",
"description": "Description", "description": "Description",
@@ -505,11 +498,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Erreur, le module a tenté d'écraser le module intégré!", "overwrite": "✘ Erreur, le module a tenté d'écraser le module intégré!",
"dependency": "✘ Erreur d'installation des dépendances! {deps}", "dependency": "✘ Erreur d'installation des dépendances! {deps}",
"docdevs": "Utiliser uniquement les modules des développeurs Heroku officiels lors de la recherche?", "docdevs": "Utiliser uniquement les modules des développeurs Heroku officiels lors de la recherche?",
"doctheme": "Thème pour les emojis." "doctheme": "Thème pour les emojis.",
"channel": "Voici le canal avec toutes les mises à jour dans FHeta!"
} }
strings_de = { strings_de = {
"_cls_doc": "Modul zur Suche nach Modulen! Verfolgen Sie alle FHeta-Neuigkeiten auf @FHeta_Updates!", "_cls_doc": "Modul zur Suche nach Modulen! Verfolgen Sie alle FHeta-Neuigkeiten auf @NFHeta_Updates!",
"lang": "de", "lang": "de",
"author": "von", "author": "von",
"description": "Beschreibung", "description": "Beschreibung",
@@ -537,11 +531,12 @@ class FHeta(loader.Module):
"overwrite": "✘ Fehler, Modul hat versucht, das integrierte Modul zu überschreiben!", "overwrite": "✘ Fehler, Modul hat versucht, das integrierte Modul zu überschreiben!",
"dependency": "✘ Fehler bei der Installation von Abhängigkeiten! {deps}", "dependency": "✘ Fehler bei der Installation von Abhängigkeiten! {deps}",
"docdevs": "Nur Module von offiziellen Heroku-Entwicklern bei der Suche verwenden?", "docdevs": "Nur Module von offiziellen Heroku-Entwicklern bei der Suche verwenden?",
"doctheme": "Thema für Emojis." "doctheme": "Thema für Emojis.",
"channel": "Dies ist der Kanal mit allen Updates in FHeta!"
} }
strings_jp = { strings_jp = {
"_cls_doc": "モジュール検索用モジュール!@FHeta_UpdatesでFHetaのすべてのニュースをフォローしてください", "_cls_doc": "モジュール検索用モジュール!@NFHeta_UpdatesでFHetaのすべてのニュースをフォローしてください",
"lang": "jp", "lang": "jp",
"author": "作成者", "author": "作成者",
"description": "説明", "description": "説明",
@@ -569,7 +564,8 @@ class FHeta(loader.Module):
"overwrite": "✘ エラー、モジュールが組み込みモジュールを上書きしようとしました!", "overwrite": "✘ エラー、モジュールが組み込みモジュールを上書きしようとしました!",
"dependency": "✘ 依存関係のインストールエラー! {deps}", "dependency": "✘ 依存関係のインストールエラー! {deps}",
"docdevs": "検索時に公式Heroku開発者のモジュールのみを使用しますか", "docdevs": "検索時に公式Heroku開発者のモジュールのみを使用しますか",
"doctheme": "絵文字のテーマ。" "doctheme": "絵文字のテーマ。",
"channel": "これはFHetaのすべての更新を含むチャンネルです"
} }
THEMES = { THEMES = {
@@ -581,7 +577,7 @@ class FHeta(loader.Module):
"command": '<tg-emoji emoji-id="5341715473882955310">⚙️</tg-emoji>', "command": '<tg-emoji emoji-id="5341715473882955310">⚙️</tg-emoji>',
"placeholder": '<tg-emoji emoji-id="5359785904535774578">🗒️</tg-emoji>', "placeholder": '<tg-emoji emoji-id="5359785904535774578">🗒️</tg-emoji>',
"module": '<tg-emoji emoji-id="5454112830989025752">📦</tg-emoji>', "module": '<tg-emoji emoji-id="5454112830989025752">📦</tg-emoji>',
"channel": '<tg-emoji emoji-id="5278256077954105203">📢</tg-emoji>', "channel": '📢',
"modules_list": '<tg-emoji emoji-id="5197269100878907942">📋</tg-emoji>' "modules_list": '<tg-emoji emoji-id="5197269100878907942">📋</tg-emoji>'
}, },
"winter": { "winter": {
@@ -592,7 +588,7 @@ class FHeta(loader.Module):
"command": '<tg-emoji emoji-id="5199503707938505333">🎅</tg-emoji>', "command": '<tg-emoji emoji-id="5199503707938505333">🎅</tg-emoji>',
"placeholder": '<tg-emoji emoji-id="5204046675236109418">🗒️</tg-emoji>', "placeholder": '<tg-emoji emoji-id="5204046675236109418">🗒️</tg-emoji>',
"module": '<tg-emoji emoji-id="5197708768091061888">🎁</tg-emoji>', "module": '<tg-emoji emoji-id="5197708768091061888">🎁</tg-emoji>',
"channel": '<tg-emoji emoji-id="5278256077954105203">📢</tg-emoji>', "channel": '📢',
"modules_list": '<tg-emoji emoji-id="5345935030143196497">🎄</tg-emoji>' "modules_list": '<tg-emoji emoji-id="5345935030143196497">🎄</tg-emoji>'
}, },
"summer": { "summer": {
@@ -603,7 +599,7 @@ class FHeta(loader.Module):
"command": '<tg-emoji emoji-id="5442644589703866634">🏄</tg-emoji>', "command": '<tg-emoji emoji-id="5442644589703866634">🏄</tg-emoji>',
"placeholder": '<tg-emoji emoji-id="5434121252874756456">🗒️</tg-emoji>', "placeholder": '<tg-emoji emoji-id="5434121252874756456">🗒️</tg-emoji>',
"module": '<tg-emoji emoji-id="5433645645376264953">🏖️</tg-emoji>', "module": '<tg-emoji emoji-id="5433645645376264953">🏖️</tg-emoji>',
"channel": '<tg-emoji emoji-id="5278256077954105203">📢</tg-emoji>', "channel": '📢',
"modules_list": '<tg-emoji emoji-id="5472178859300363509">🏖️</tg-emoji>' "modules_list": '<tg-emoji emoji-id="5472178859300363509">🏖️</tg-emoji>'
}, },
"spring": { "spring": {
@@ -614,7 +610,7 @@ class FHeta(loader.Module):
"command": '<tg-emoji emoji-id="5449850741667668411">🦋</tg-emoji>', "command": '<tg-emoji emoji-id="5449850741667668411">🦋</tg-emoji>',
"placeholder": '<tg-emoji emoji-id="5434121252874756456">🗒️</tg-emoji>', "placeholder": '<tg-emoji emoji-id="5434121252874756456">🗒️</tg-emoji>',
"module": '<tg-emoji emoji-id="5440911110838425969">🌿</tg-emoji>', "module": '<tg-emoji emoji-id="5440911110838425969">🌿</tg-emoji>',
"channel": '<tg-emoji emoji-id="5278256077954105203">📢</tg-emoji>', "channel": '📢',
"modules_list": '<tg-emoji emoji-id="5440748683765227563">🌺</tg-emoji>' "modules_list": '<tg-emoji emoji-id="5440748683765227563">🌺</tg-emoji>'
}, },
"autumn": { "autumn": {
@@ -625,7 +621,7 @@ class FHeta(loader.Module):
"command": '<tg-emoji emoji-id="5212963577098417551">🍂</tg-emoji>', "command": '<tg-emoji emoji-id="5212963577098417551">🍂</tg-emoji>',
"placeholder": '<tg-emoji emoji-id="5363965354391388799">🗒️</tg-emoji>', "placeholder": '<tg-emoji emoji-id="5363965354391388799">🗒️</tg-emoji>',
"module": '<tg-emoji emoji-id="5249157915041865558">🍄</tg-emoji>', "module": '<tg-emoji emoji-id="5249157915041865558">🍄</tg-emoji>',
"channel": '<tg-emoji emoji-id="5278256077954105203">📢</tg-emoji>', "channel": '📢',
"modules_list": '<tg-emoji emoji-id="5305495722618010655">🍂</tg-emoji>' "modules_list": '<tg-emoji emoji-id="5305495722618010655">🍂</tg-emoji>'
} }
} }
@@ -664,6 +660,11 @@ class FHeta(loader.Module):
self.installer = MInstaller() self.installer = MInstaller()
self.ui = FHetaUI(self) self.ui = FHetaUI(self)
await self.request_join(
"NFHeta_Updates",
f"{self.ui.emoji('channel')} {self.strings('channel')}"
)
self.api.token = self.token self.api.token = self.token
router = None router = None
@@ -716,13 +717,20 @@ class FHeta(loader.Module):
self.api.token = self.token self.api.token = self.token
except Exception: except Exception:
pass pass
@loader.loop(interval=1, autostart=True) asyncio.create_task(self.sync())
async def sync(self): async def sync(self):
now = self.strings["lang"] ll = None
if now != getattr(self, "past_lang", None): while True:
await self.api.send("dataset", params={"user_id": getattr(self, "identifier", 0), "lang": now}) try:
self.past_lang = now cl = self.strings["lang"]
if cl != ll:
await self.api.send("dataset", user_id=self.identifier, lang=cl)
ll = cl
except Exception:
pass
await asyncio.sleep(1)
async def answer(self, callback: Union[CallbackQuery, ChosenInlineResult], text: Optional[str] = None, alert: bool = False) -> None: async def answer(self, callback: Union[CallbackQuery, ChosenInlineResult], text: Optional[str] = None, alert: bool = False) -> None:
try: try:
@@ -872,7 +880,7 @@ class FHeta(loader.Module):
return { return {
"title": self.strings["prompt"], "title": self.strings["prompt"],
"description": self.strings["hint"], "description": self.strings["hint"],
"message": f"{self.ui.emoji('error')} <b>{self.strings['prompt']}</b>", "message": f"{self.ui.emoji('error')} <b>{self.strings['noquery'].format(prefix=f'<code>@{self.inline.bot_username} ')}</code></b>",
"thumb": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/magnifying_glass.png" "thumb": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/magnifying_glass.png"
} }
@@ -890,7 +898,7 @@ class FHeta(loader.Module):
return { return {
"title": self.strings["retry"], "title": self.strings["retry"],
"description": self.strings["hint"], "description": self.strings["hint"],
"message": f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=utils.escape_html(query))}</b>", "message": f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=f'<code>{utils.escape_html(query)}</code>')}</b>",
"thumb": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/try_other_query.png" "thumb": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FHeta/try_other_query.png"
} }
@@ -941,18 +949,18 @@ class FHeta(loader.Module):
query = utils.get_args_raw(message) query = utils.get_args_raw(message)
if not query: if not query:
return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['noquery'].format(prefix=self.get_prefix())}</b>") return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['noquery'].format(prefix=f'<code>{self.get_prefix()}')}</code></b>")
if len(query) > 168: if len(query) > 168:
return await utils.answer(message, f"{self.ui.emoji('warn')} <b>{self.strings['toolong']}</b>") return await utils.answer(message, f"{self.ui.emoji('warn')} <b>{self.strings['toolong']}</b>")
message = await utils.answer(message, f"{self.ui.emoji('search')} <b>{self.strings['search'].format(query=utils.escape_html(query))}</b>") message = await utils.answer(message, f"{self.ui.emoji('search')} <b>{self.strings['search'].format(query=f'<code>{utils.escape_html(query)}</code>')}</b>")
modules = await self.api.fetch("search", query=query, inline="false", token=self.token, user_id=self.identifier, ood=str(self.config["only_official_developers"]).lower()) modules = await self.api.fetch("search", query=query, inline="false", token=self.token, user_id=self.identifier, ood=str(self.config["only_official_developers"]).lower())
if not modules or not isinstance(modules, list): if not modules or not isinstance(modules, list):
return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=utils.escape_html(query))}</b>") return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=f'<code>{utils.escape_html(query)}</code>')}</b>")
data = modules[0] data = modules[0]
buttons = self.ui.buttons(data.get("install", ""), data, 0, modules, query) buttons = self.ui.buttons(data.get("install", ""), data, 0, modules, query)
form = await self.inline.form("", message, reply_markup=buttons, silent=True) form = await self.inline.form("", message, reply_markup=buttons, silent=True)

View File

@@ -0,0 +1,628 @@
__version__ = (1, 0, 0)
# meta developer: @NFModules
import asyncio
import aiohttp
import html
import sys
import uuid
import copy
import hashlib
import json
import re
from contextlib import suppress
from .. import loader, utils
@loader.tds
class FSecurity(loader.Module):
"""Module for automatic AI-based security checks of installed modules."""
strings = {
"name": "FSecurity",
"lang": "English",
"unavailable": "AI module{} check is unavailable.",
"suspicious": "AI interrupted installation of a suspicious module{}, reason:",
"blocked": "AI blocked module installation{}, reason:",
"continue": "Continue installation?",
"strict_mode_doc": "Block loading modules by any method (lm/dlm allowed) if the AI API is unavailable or the module is suspicious. On restart, this also applies to already installed modules.",
"nvidia_api_key_doc": "API key from build.nvidia.com, used for AI checks. If not specified, a public key from GitHub will be used."
}
strings_ru = {
"lang": "Russian",
"_cls_doc": "Модуль для автоматической проверки устанавливаемых модулей через ИИ.",
"unavailable": "Проверка модуля{} через ИИ недоступна.",
"suspicious": "ИИ прервал установку подозрительного модуля{}, причина:",
"blocked": "ИИ заблокировал установку модуля{}, причина:",
"continue": "Продолжить установку?",
"strict_mode_doc": "Не позволять загружать модули любым методом (lm/dlm разрешено), если API ИИ недоступен или модуль подозрителен. При перезагрузке работает даже на уже установленные модули.",
"nvidia_api_key_doc": "API ключ от build.nvidia.com, используется для проверки через ИИ. Если вы его не укажете, будет использоваться общий ключ с GitHub."
}
strings_ua = {
"lang": "Ukraine",
"_cls_doc": "Модуль для автоматичної перевірки встановлюваних модулів через ШІ.",
"unavailable": "Перевірка модуля{} через ШІ недоступна.",
"suspicious": "ШІ перервав встановлення підозрілого модуля{}, причина:",
"blocked": "ШІ заблокував встановлення модуля{}, причина:",
"continue": "Продовжити встановлення?",
"strict_mode_doc": "Не дозволяти завантажувати модулі будь-яким методом (lm/dlm дозволено), якщо API ШІ недоступний або модуль підозрілий. При перезавантаженні працює навіть на вже встановлені модулі.",
"nvidia_api_key_doc": "API ключ від build.nvidia.com, використовується для перевірки через ШІ. Якщо ви його не вкажете, буде використовуватися загальний ключ з GitHub."
}
strings_de = {
"lang": "Germany",
"_cls_doc": "Modul zur automatischen Prüfung installierter Module mit KI.",
"unavailable": "Die KI-Modulprüfung{} ist nicht verfügbar.",
"suspicious": "Die KI hat die Installation eines verdächtigen Moduls unterbrochen{}, Grund:",
"blocked": "Die KI hat die Modulinstallation blockiert{}, Grund:",
"continue": "Installation fortsetzen?",
"strict_mode_doc": "Das Laden von Modulen mit jeder Methode blockieren (lm/dlm erlaubt), wenn die KI-API nicht verfügbar ist oder das Modul verdächtig ist. Beim Neustart gilt dies auch für bereits installierte Module.",
"nvidia_api_key_doc": "API-Schlüssel von build.nvidia.com, der für KI-Prüfungen verwendet wird. Wenn nicht angegeben, wird ein öffentlicher Schlüssel von GitHub verwendet."
}
strings_jp = {
"lang": "Japanese",
"_cls_doc": "AIでインストールされるモジュールを自動チェックするモジュール。",
"unavailable": "AIモジュール{}のチェックが利用できません。",
"suspicious": "AIが疑わしいモジュールのインストールを中断しました{}、理由:",
"blocked": "AIがモジュールのインストールをブロックしました{}、理由:",
"continue": "インストールを続行しますか?",
"strict_mode_doc": "AI APIが利用できない場合や疑わしいモジュールの場合、すべての方法でモジュールの読み込みをブロックしますlm/dlmは許可。再起動時にはインストール済みモジュールにも適用されます。",
"nvidia_api_key_doc": "build.nvidia.com のAPIキー。AIチェックに使用されます。指定しない場合は、GitHubのパブリックキーが使用されます。"
}
strings_tr = {
"lang": "Turkish",
"_cls_doc": "Kurulan modülleri yapay zeka ile otomatik kontrol eden modül.",
"unavailable": "Yapay zeka modül{} kontrolü kullanılamıyor.",
"suspicious": "Yapay zeka şüpheli bir modülün kurulumunu durdurdu{}, sebep:",
"blocked": "Yapay zeka modül kurulumunu engelledi{}, sebep:",
"continue": "Kuruluma devam edilsin mi?",
"strict_mode_doc": "AI API kullanılamıyorsa veya modül şüpheliyse, tüm yöntemlerle modül yüklenmesini engelle (lm/dlm izinli). Yeniden başlatmada zaten kurulu modüller için de geçerlidir.",
"nvidia_api_key_doc": "Yapay zeka kontrolleri için kullanılan build.nvidia.com API anahtarı. Belirtilmezse GitHub'daki genel anahtar kullanılacaktır."
}
strings_uz = {
"lang": "Uzbekistan",
"_cls_doc": "O'rnatilayotgan modullarni AI orqali avtomatik tekshiruvchi modul.",
"unavailable": "AI modul{} tekshiruvi mavjud emas.",
"suspicious": "AI shubhali modul o'rnatilishini to'xtatdi{}, sabab:",
"blocked": "AI modul o'rnatilishini blokladi{}, sabab:",
"continue": "O'rnatishni davom ettirasizmi?",
"strict_mode_doc": "AI API mavjud bo'lmasa yoki modul shubhali bo'lsa, barcha usullar bilan modul yuklashni bloklash (lm/dlm ruxsat etilgan). Qayta ishga tushirishda allaqachon o'rnatilgan modullarga ham ta'sir qiladi.",
"nvidia_api_key_doc": "build.nvidia.com API kaliti, AI orqali tekshirish uchun ishlatiladi. Agar ko'rsatmasangiz, GitHub-dan umumiy kalit ishlatiladi."
}
strings_kz = {
"lang": "Kazakhstan",
"_cls_doc": "Орнатылатын модульдерді ЖИ арқылы автоматты тексеретін модуль.",
"unavailable": "AI модуль{} тексеру қолжетімсіз.",
"suspicious": "AI күдікті модульді орнатуды тоқтатты{}, себебі:",
"blocked": "AI модульді орнатуды бұғаттады{}, себебі:",
"continue": "Орнатуды жалғастырасыз ба?",
"strict_mode_doc": "AI API қолжетімсіз болса немесе модуль күдікті болса, барлық әдістермен модуль жүктеуді бұғаттау (lm/dlm рұқсат етілген). Қайта іске қосқанда орнатылған модульдерге де қолданылады.",
"nvidia_api_key_doc": "build.nvidia.com API кілті, ЖИ арқылы тексеру үшін қолданылады. Егер оны көрсетпесеңіз, GitHub-тан ортақ кілт пайдаланылады."
}
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"strict_mode",
False,
lambda: self.strings("strict_mode_doc"),
validator=loader.validators.Boolean(),
),
loader.ConfigValue(
"nvidia_api_key",
"",
lambda: self.strings("nvidia_api_key_doc"),
validator=loader.validators.Hidden(),
)
)
self.tasks = {}
self.oreg = None
self.oload = None
async def client_ready(self, client, db):
self.__origin__ = "<fsecurity>"
self.core = self.lookup("loader")
self.modules = self.core.allmodules
self.restore_hooks()
self.patch()
async def on_unload(self):
self.unpatch()
def _render_prompt(self, prompt, **values):
rendered = prompt
for key, value in values.items():
rendered = rendered.replace("{" + key + "}", str(value))
return rendered
def _split_code(self, code):
chunk_size = 180000
if len(code) <= chunk_size:
return [code]
chunks = []
current =[]
current_len = 0
for line in code.splitlines(keepends=True):
if current and current_len + len(line) > chunk_size:
chunks.append("".join(current))
current =[]
current_len = 0
if len(line) > chunk_size:
if current:
chunks.append("".join(current))
current =[]
current_len = 0
for i in range(0, len(line), chunk_size):
chunks.append(line[i:i + chunk_size])
continue
current.append(line)
current_len += len(line)
if current:
chunks.append("".join(current))
return chunks or [code]
def _parse_ai_json(self, raw_text):
raw_text = (raw_text or "").strip()
if not raw_text:
return None
try:
parsed = json.loads(raw_text)
if isinstance(parsed, dict):
return parsed
except Exception:
pass
match = re.search(r"\{[\s\S]*\}", raw_text)
if not match:
return None
try:
parsed = json.loads(match.group())
except Exception:
return None
return parsed if isinstance(parsed, dict) else None
async def _fetch_prompt(self, session, url):
async with session.get(url, timeout=10) as resp:
if resp.status != 200:
return None
prompt = (await resp.text()).strip()
return prompt or None
async def _get_prompts(self, session):
main_prompt = await self._fetch_prompt(session, "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/prompts/main.txt")
chunk_prompt = await self._fetch_prompt(session, "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/prompts/chank.txt")
final_prompt = await self._fetch_prompt(session, "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/prompts/final.txt")
if not main_prompt or not chunk_prompt or not final_prompt:
return None
return {
"main": main_prompt,
"chunk": chunk_prompt,
"final": final_prompt,
}
async def _nvidia_request(self, session, api_key, system_prompt, user_prompt):
async with session.post(
"https://integrate.api.nvidia.com/v1/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json={
"model": "qwen/qwen3-coder-480b-a35b-instruct",
"messages":[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
"temperature": 0.4,
"max_tokens": 1000,
},
timeout=180,
) as resp:
if resp.status != 200:
return None
data = await resp.json()
choices = data.get("choices") or[]
if not choices:
return None
return self._parse_ai_json(choices[0].get("message", {}).get("content", ""))
async def _local_ai_check(self, session, code, lang, api_key):
prompts = await self._get_prompts(session)
if not prompts:
return None
chunks = self._split_code(code)
if len(chunks) == 1:
prompt = self._render_prompt(prompts["main"], lang=lang)
return await self._nvidia_request(
session,
api_key,
prompt,
f"Analyze this module:\n\n```python\n{code}\n```",
)
total = len(chunks)
findings =[]
for index, chunk in enumerate(chunks, start=1):
previous_context = "; ".join(
f"Part {i}: {finding}"
for i, finding in enumerate(findings, start=1)
if finding
) or "Previous parts: no issues found so far."
chunk_prompt = self._render_prompt(
prompts["chunk"],
total=total,
current=index,
previous_context=previous_context,
lang=lang,
)
chunk_result = await self._nvidia_request(
session,
api_key,
chunk_prompt,
f"Part {index}/{total}:\n\n```python\n{chunk}\n```",
)
if not chunk_result:
return None
chunk_verdict = str(chunk_result.get("chunk_verdict", "CLEAN")).lower()
chunk_finding = str(chunk_result.get("findings", "") or "")
if chunk_verdict == "blocked":
findings_text = "\n".join(
f"- Part {i}: {finding}"
for i, finding in enumerate(findings, start=1)
if finding
)
if chunk_finding:
findings_text = f"{findings_text}\n- Part {index}: {chunk_finding}".strip()
final_prompt = self._render_prompt(
prompts["final"],
total=total,
findings=findings_text or "No prior findings.",
lang=lang,
)
return await self._nvidia_request(
session,
api_key,
final_prompt,
"Give the final verdict based on all findings.",
)
findings.append(chunk_finding if chunk_verdict != "clean" else "")
findings_text = "\n".join(
f"- Part {i}: {finding}"
for i, finding in enumerate(findings, start=1)
if finding
) or "All parts: no issues found."
final_prompt = self._render_prompt(
prompts["final"],
total=total,
findings=findings_text,
lang=lang,
)
return await self._nvidia_request(
session,
api_key,
final_prompt,
"Give the final verdict based on all findings.",
)
async def check(self, code):
try:
lang = self.strings("lang") or "en"
module_hash = hashlib.sha256(code.encode("utf-8")).hexdigest()
db_cache = self.get("cache", {})
if module_hash in db_cache:
cached = db_cache[module_hash]
if cached.get("level") == "safe":
return True
return cached
async with aiohttp.ClientSession() as session:
api_keys = await self._get_api_keys(session)
for api_key in api_keys:
parsed = await self._local_ai_check(session, code, lang, api_key)
if not isinstance(parsed, dict):
continue
verdict = str(parsed.get("verdict", "BLOCKED")).lower()
if verdict not in {"safe", "suspicious", "blocked"}:
verdict = "blocked"
summary = str(parsed.get("summary", "") or "")
result = {"level": verdict if verdict != "safe" else "safe"}
if verdict != "safe":
result["reason"] = summary
db_cache[module_hash] = result
self.set("cache", db_cache)
if result["level"] == "safe":
return True
return result
return False
except Exception:
return False
async def _get_api_keys(self, session):
configured_key = self.config["nvidia_api_key"].strip()
if configured_key:
return [configured_key]
try:
async with session.get(
"https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/api_keys.txt",
timeout=10,
) as resp:
if resp.status != 200:
return[]
raw_keys = (await resp.text()).strip()
except Exception:
return []
return[key.strip() for key in raw_keys.split(",") if key.strip()]
def format(self, state, reason="", link=""):
link_part = f' (<code>{utils.escape_html(link)}</code>)' if link else ""
if state == "unavailable":
return f'<b>{self.strings("unavailable").format(link_part)}</b>\n<b>{self.strings("continue")}</b>'
if state == "suspicious":
return f'<b>{self.strings("suspicious").format(link_part)}</b>\n<blockquote expandable><b>{reason}</b></blockquote>\n<b>{self.strings("continue")}</b>'
return f'<b>{self.strings("blocked").format(link_part)}</b>\n<blockquote expandable><b>{reason}</b></blockquote>'
def buttons(self, task):
return [[
{"text": "", "callback": self.confirm, "args": (task, "yes")},
{"text": "", "callback": self.confirm, "args": (task, "no")}
]]
def closure_var(self, func, name):
raw = getattr(func, "__func__", func)
code = getattr(raw, "__code__", None)
closure = getattr(raw, "__closure__", None)
if not code or not closure or name not in code.co_freevars:
return None
with suppress(Exception):
return closure[code.co_freevars.index(name)].cell_contents
return None
def restore_hooks(self):
with suppress(Exception):
inst_reg = getattr(self.modules, "register_module")
owner = getattr(inst_reg, "__self__", None)
if (
owner
and owner is not self
and owner.__class__.__name__ == self.__class__.__name__
):
original = getattr(owner, "oreg", None)
if original:
if getattr(original, "__self__", None) is None:
self.modules.register_module = original.__get__(
self.modules,
self.modules.__class__,
)
else:
self.modules.register_module = original
with suppress(Exception):
inst_load = getattr(self.core, "load_module")
raw = getattr(inst_load, "__func__", inst_load)
if "FSecurity.patch.<locals>.load" in getattr(raw, "__qualname__", ""):
original = self.closure_var(raw, "original")
if original:
if getattr(original, "__self__", None) is None:
self.core.load_module = original.__get__(
self.core,
self.core.__class__,
)
else:
self.core.load_module = original
def patch(self):
if not self.oreg:
self.oreg = getattr(self.modules, "register_module")
if not self.oload:
self.oload = self.core.load_module
original = self.oload
async def load(_, *args, **kwargs):
base = utils.answer
async def answer(message, response, *a, **k):
if isinstance(response, str) and "😖</tg-emoji>" in response:
body = response.split("😖</tg-emoji>", 1)[1].strip()
if body in {"", "<b></b>", "<b> </b>"}:
with suppress(Exception):
if hasattr(message, "delete"):
await message.delete()
return message
if body.startswith("<b>") and body.endswith("</b>"):
decoded = html.unescape(body[3:-4])
response = response.split("😖</tg-emoji>", 1)[0] + f'😖</tg-emoji> {decoded}' if decoded else response.split("😖</tg-emoji>", 1)[0] + '😖</tg-emoji>'
try:
return await base(message, response, *a, **k)
except Exception:
with suppress(Exception):
return await self._client.send_message(
utils.get_chat_id(message),
response,
reply_to=getattr(message, "reply_to_msg_id", None),
buttons=k.get("reply_markup"),
)
return message
utils.answer = answer
try:
if getattr(original, "__self__", None) is None:
return await original(_, *args, **kwargs)
return await original(*args, **kwargs)
finally:
if utils.answer is answer:
utils.answer = base
self.core.load_module = load.__get__(self.core, self.core.__class__)
self.modules.register_module = self.register
def unpatch(self):
if self.oreg:
self.modules.register_module = self.oreg
if getattr(self, "core", None) and self.oload:
self.core.load_module = self.oload
def context(self):
frame = sys._getframe()
msg = None
fmsg = None
is_dlm_lm = False
while frame:
locals = frame.f_locals
if (
frame.f_code.co_name == "load_module"
and locals.get("self") is self.core
and 'message' in locals
and hasattr(locals['message'], 'edit')
):
if not msg:
msg = locals['message']
fmsg = locals.get('msg')
if frame.f_code.co_name in {"dlmod", "loadmod"}:
is_dlm_lm = True
if not msg and 'message' in locals and hasattr(locals['message'], 'edit'):
msg = locals['message']
if frame.f_code.co_name == "download_and_install":
if not msg and 'message' in locals and hasattr(locals['message'], 'edit'):
msg = locals['message']
frame = frame.f_back
return msg, fmsg, is_dlm_lm
def target_chat(self, msg=None, fmsg=None):
if not msg:
return None
if not fmsg:
return msg
with suppress(Exception):
target = copy.copy(msg)
target.reply_to_msg_id = fmsg.id
return target
return None
async def call_oreg(self, spec, name, origin="<core>", save_fs=False):
if getattr(self.oreg, "__self__", None) is None:
return await self.oreg(self.modules, spec, name, origin, save_fs=save_fs)
return await self.oreg(spec, name, origin, save_fs=save_fs)
async def register(self, spec, name, origin="<core>", save_fs=False):
if origin != "<core>":
code = ""
if hasattr(spec.loader, "data") and spec.loader.data:
code = spec.loader.data
if isinstance(code, bytes):
code = code.decode("utf-8", errors="ignore")
elif origin and origin.endswith(".py"):
with suppress(Exception):
with open(origin, "r", encoding="utf-8") as f:
code = f.read()
if code:
check = await self.check(code)
if check is not True:
msg, fmsg, is_dlm_lm = self.context()
target = self.target_chat(msg, fmsg)
if isinstance(check, dict):
status = check.get("level", "blocked")
reason = check.get("reason", "")
else:
status = "unavailable"
reason = ""
link = origin if origin.startswith("http") else ""
if status == "blocked":
if msg and target:
raise loader.LoadError(self.format("blocked", reason, link))
raise loader.LoadError("")
should_block = is_dlm_lm or self.config["strict_mode"]
if should_block and not (msg and target):
raise loader.LoadError("")
if should_block and msg and target:
task = str(uuid.uuid4())
event = asyncio.Event()
self.tasks[task] = {"event": event, "decision": False}
try:
form = await self.inline.form(
text=self.format(status, reason, link),
message=target,
reply_markup=self.buttons(task)
)
if not form:
raise loader.LoadError(reason)
await asyncio.wait_for(event.wait(), timeout=180.0)
if not self.tasks.pop(task)["decision"]:
with suppress(Exception):
await form.delete()
raise loader.LoadError("")
except asyncio.TimeoutError:
self.tasks.pop(task, None)
with suppress(Exception):
await form.delete()
raise loader.LoadError("")
except loader.LoadError:
raise
except Exception:
raise loader.LoadError("")
return await self.call_oreg(spec, name, origin, save_fs=save_fs)
async def confirm(self, call, task, action):
if task in self.tasks:
self.tasks[task]["decision"] = (action == "yes")
self.tasks[task]["event"].set()
with suppress(Exception):
await call.delete()

View File

@@ -0,0 +1,87 @@
__version__ = (1, 0, 0)
# meta developer: @NFModules
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/banner.png
# meta fhsdesc: security, guard, antiscam, antivirus
# scope: hikka_min 2.0.0
# ©️ Fixyres, 2024-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.
# You may obtain a copy of the License at
# 🔑 http://www.apache.org/licenses/LICENSE-2.0
import aiohttp
import os
from .. import loader
@loader.tds
class FSecurity(loader.Module):
"""Module for automatic AI-based security checks of installed modules."""
strings = {
"name": "FSecurity"
}
strings_ru = {
"_cls_doc": "Модуль для автоматической проверки устанавливаемых модулей через ИИ."
}
strings_ua = {
"_cls_doc": "Модуль для автоматичної перевірки встановлюваних модулів через ШІ."
}
strings_de = {
"_cls_doc": "Modul zur automatischen Prüfung installierter Module mit KI."
}
strings_jp = {
"_cls_doc": "AIでインストールされるモジュールを自動チェックするモジュール。"
}
strings_tr = {
"_cls_doc": "Kurulan modülleri yapay zeka ile otomatik kontrol eden modül."
}
strings_uz = {
"_cls_doc": "O'rnatilayotgan modullarni AI orqali avtomatik tekshiruvchi modul."
}
strings_kz = {
"_cls_doc": "Орнатылатын модульдерді ЖИ арқылы автоматты тексеретін модуль."
}
async def client_ready(self, client, db):
core = self.lookup("loader")
try:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/FSecurity.py",
timeout=aiohttp.ClientTimeout(total=15),
) as resp:
if resp.status != 200:
return
source = await resp.text()
except Exception:
return
target = os.path.join(
os.path.dirname(loader.__file__),
"modules",
"FSecurity.py",
)
try:
with open(target, "w", encoding="utf-8") as f:
f.write(source)
except Exception:
return
await core.unload_module("FSecurity")
try:
await core.load_module(source, None, "FSecurity", target, save_fs=False)
except Exception:
pass

View File

@@ -7,7 +7,7 @@ __version__ = (1, 0, 0)
# 🔑 http://www.apache.org/licenses/LICENSE-2.0 # 🔑 http://www.apache.org/licenses/LICENSE-2.0
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/SCD/banner.png # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/SCD/banner.png
# meta developer: @FModules # meta developer: @NFModules
# requires: curl_cffi # requires: curl_cffi

View File

@@ -7,7 +7,7 @@ __version__ = (1, 1, 0)
# 🔑 http://www.apache.org/licenses/LICENSE-2.0 # 🔑 http://www.apache.org/licenses/LICENSE-2.0
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png
# meta developer: @FModules # meta developer: @NFModules
# meta fhsdesc: game, funny, guess, question game # meta fhsdesc: game, funny, guess, question game
# requires: curl_cffi # requires: curl_cffi

View File

@@ -0,0 +1 @@
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -0,0 +1,25 @@
You must strictly follow these rules with no exceptions.
Analyze only part {current}/{total} of a Hikka userbot Python module. Do NOT give a final verdict for the whole module.
Previous context: {previous_context}
BLOCKED: encrypted/obfuscated code (base64, marshal, zlib, rot13, encoded exec, or any technique hiding real logic), account deletion, mass scam/spam/ads to all chats on load, session/auth_key/2FA exfiltration, bulk message/dialog dump to external destination, string "FSecurity" (if found → findings must be ONLY: "Attempted interaction with FSecurity." translated to {lang}, nothing else).
SUSPICIOUS: watcher/scheduler/client_ready auto-installing modules without owner confirmation, download + exec of remote Python code without confirmation, runtime pip install or library download, third-party OAuth redirect.
CLEAN: no security issue in this chunk.
Tie-breaking: BLOCKED vs SUSPICIOUS → SUSPICIOUS. SUSPICIOUS vs CLEAN → CLEAN.
@loader.inline_handler, @loader.command, async def NAMEcmd, async def NAME_inline_handler = owner-only by default = not a threat.
Owner-triggered exec/eval/shell = not a threat.
A command (any function decorated with @loader.command, named NAMEcmd, or accessible only to the owner) that executes arbitrary code, runs shell commands, evaluates expressions, or calls exec/eval on owner-provided input = always CLEAN, never SUSPICIOUS. This is a standard userbot feature.
Respond ONLY with valid JSON:
{"chunk_verdict":"CLEAN|SUSPICIOUS|BLOCKED","findings":"..."}
Findings rules (when not CLEAN):
- Write in {lang}. Max 1000 chars.
- Technical analysis for reading, not a reply. No "I found", no "you should". Third person only.
- Do NOT mention which rule was triggered. Just describe what the code does.
- Only the key threats in this chunk. Reference approximate line numbers within the chunk.
- Use <code>text</code> for code references: function names, variables, URLs, string literals.
- For obfuscation chains, wrap the whole chain in one <code> block: <code>base64.b64decode → zlib.decompress → exec</code>.
- If CLEAN → findings must be empty string "".

View File

@@ -0,0 +1,29 @@
You must strictly follow these rules with no exceptions.
A Hikka userbot module was split into {total} parts. Chunk findings:
{findings}
Give the final verdict for the entire module based on all findings above.
BLOCKED: encrypted/obfuscated code, account deletion, mass scam/spam on load, session/auth_key theft, bulk message dump, string "FSecurity" (if found → summary must be ONLY: "Attempted interaction with FSecurity." translated to {lang}, nothing else).
SUSPICIOUS: auto-install modules without confirmation, remote code download + exec without confirmation, runtime pip/library install, third-party OAuth redirect.
SAFE: no real security issue across all parts.
Auto-install = SUSPICIOUS, never BLOCKED.
Tie-breaking: BLOCKED vs SUSPICIOUS → SUSPICIOUS. SUSPICIOUS vs SAFE → SAFE.
@loader.inline_handler, @loader.command, async def NAMEcmd, async def NAME_inline_handler = owner-only by default = not a threat.
Owner-triggered exec/eval/shell = not a threat.
A command (any function decorated with @loader.command, named NAMEcmd, or accessible only to the owner) that executes arbitrary code, runs shell commands, evaluates expressions, or calls exec/eval on owner-provided input = always SAFE, never SUSPICIOUS. This is a standard userbot feature.
Respond ONLY with valid JSON:
{"verdict":"SAFE|SUSPICIOUS|BLOCKED","summary":"..."}
Summary rules (when not SAFE):
- Write in {lang}. Max 1000 chars.
- Combine the most important findings into one coherent technical analysis.
- This is a report for reading, NOT a reply to a person. No "I found", no "you should". Third person only.
- Do NOT mention which rule was triggered or explain criteria. Just describe what the code does.
- Only the key threats. Reference line numbers from findings where available.
- Use <code>text</code> for all code references: function names, variables, URLs, string literals.
- For obfuscation, show the full chain in one <code> block: <code>base64.b64decode → zlib.decompress → exec</code>.
- If SAFE → summary must be empty string "".

View File

@@ -0,0 +1,37 @@
You must strictly follow these classification rules with no exceptions.
Classify a Hikka userbot Python module as BLOCKED, SUSPICIOUS, or SAFE.
BLOCKED (any single match):
- Code is encrypted or obfuscated (base64, marshal, zlib, rot13, compile+exec of encoded data, or any technique that hides real logic).
- Attempts to delete Telegram account (DeleteAccountRequest, client.delete_account, or equivalent).
- On load (client_ready, __init__) automatically sends scam, spam, or ads to all chats/dialogs/contacts without owner action.
- Steals and sends session string, auth_key, or 2FA password anywhere outside the device.
- Collects and forwards all messages or dialogs to any external destination.
- Contains the string "FSecurity" → summary must be ONLY: "Attempted interaction with FSecurity." translated to {lang}. Nothing else, no extra text.
SUSPICIOUS (any single match, only if BLOCKED did not trigger):
- Watcher, scheduler, or client_ready auto-installs modules from any URL without per-action owner confirmation.
- Downloads and executes remote Python code (exec/eval on fetched content) without owner confirmation.
- Installs pip packages or downloads Python libraries at runtime from the internet.
- OAuth or auth flow redirected through a non-official third-party domain.
SAFE: everything that does not match any rule above.
- Owner-triggered exec/eval/shell = always SAFE.
- A command (any function decorated with @loader.command, named NAMEcmd, or accessible only to the owner) that executes arbitrary code, runs shell commands, evaluates expressions, or calls exec/eval on owner-provided input = always SAFE, never SUSPICIOUS. This is a standard feature of userbots and poses no threat.
- @loader.inline_handler, @loader.command, async def NAMEcmd, async def NAME_inline_handler = owner-only by default (no public access without explicit permission) = SAFE.
Tie-breaking: BLOCKED vs SUSPICIOUS → SUSPICIOUS. SUSPICIOUS vs SAFE → SAFE.
Respond ONLY with valid JSON:
{"verdict":"SAFE|SUSPICIOUS|BLOCKED","summary":"..."}
Summary rules (when not SAFE):
- Write in {lang}. Max 1000 chars.
- This is a technical analysis meant to be read, NOT a reply to a person. Never write "I found", "you should", "I recommend". Write in third person.
- Do NOT mention which rule was triggered or explain the classification criteria. Just describe what the code does.
- Point out ONLY the key threats. Do NOT describe what the module does overall or list safe parts.
- Reference the approximate line number where dangerous code appears: "line NN —".
- Use <code>text</code> for every code reference: function names, variables, URLs, string literals.
- For obfuscation, show the full decoding chain inside one <code> block: <code>base64.b64decode → zlib.decompress → marshal.loads → exec</code>.
- If SAFE → summary must be empty string "".

View File

@@ -1,9 +1,8 @@
#Midga3 #Midga3
#Placeholder system is the best #Placeholder system is the best
# meta banner: https://github.com/Midga3/heroku-modules/blob/main/new_module.jpg?raw=true
# meta developer: @midga3_modules # meta developer: @midga3_modules
__version__ = (1, 0, 0) __version__ = (1, 1, 2)
import logging import logging
import aiohttp import aiohttp
@@ -17,13 +16,20 @@ class PingEmoji(loader.Module):
strings = { strings = {
"name": "PingEmoji" "name": "PingEmoji"
} }
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"emoji",
"<tg-emoji emoji-id=5276307163529092252>🔴</tg-emoji>",
"Ping Emoji",
)
)
async def client_ready(self, client, db): async def client_ready(self, client, db):
self._client = client self._client = client
utils.register_placeholder("ping_emoji", self.get_emoji) utils.register_placeholder("ping_emoji", self.get_emoji)
async def get_emoji(self, data): async def get_emoji(self, data):
if data['ping'] > 300: if data['ping'] > 300:
return "<tg-emoji emoji-id=5276307163529092252>🔴</tg-emoji>" return self.config['emoji']
else: else:
return "" return ""

View File

@@ -0,0 +1,204 @@
# ______ ___ ___ _ _
# ____ | ___ \ | \/ | | | | |
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
# \____/ __/ |
# |___/
# На модуль распространяется лицензия "GNU General Public License v3.0"
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
import asyncio
import os
import toml
from .. import loader, utils
from herokutl.tl.types import Message
@loader.tds
class IwaAnimation(loader.Module):
"""Frame-by-frame text animations loaded from .anim TOML files"""
strings = {
"name": "IwaAnimation",
"err_no_reply": "<b>{e} Reply to a .anim file.</b>",
"err_not_anim": "<b>{e} File must have .anim extension.</b>",
"err_bad_format": "<b>{e} Invalid file format (missing name or cmd).</b>",
"err_no_frames": "<b>{e} No frames found in the file.</b>",
"err_not_found": "<b>{e} Animation not found.</b>",
"err_no_cmd": "<b>{e} Specify a command name.</b>",
"err_generic": "<b>{e} Error:</b>\n\n{exc}",
"ok_loaded": "<b>{s} Loaded: {name}\nCommand: <code>.anim {cmd}</code></b>",
"ok_deleted": "<b>{s} Deleted.</b>",
"list_header": "<blockquote><b>Animations:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row": "• <code>{cmd}</code> — {name} ({n} frames)\n",
"list_footer": "</b></blockquote>",
"list_empty": "<b>{e} No animations.</b>",
}
strings_ru = {
"name": "IwaAnimation",
"err_no_reply": "<b>{e} Ответьте на .anim файл.</b>",
"err_not_anim": "<b>{e} Файл должен быть формата .anim</b>",
"err_bad_format": "<b>{e} Неверный формат файла (нет name или cmd).</b>",
"err_no_frames": "<b>{e} В файле нет кадров.</b>",
"err_not_found": "<b>{e} Анимация не найдена.</b>",
"err_no_cmd": "<b>{e} Укажи команду.</b>",
"err_generic": "<b>{e} Ошибка:</b>\n\n{exc}",
"ok_loaded": "<b>{s} Загружено: {name}\nКоманда: <code>.anim {cmd}</code></b>",
"ok_deleted": "<b>{s} Удалено.</b>",
"list_header": "<blockquote><b>Анимации:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row": "• <code>{cmd}</code> — {name} ({n} кадров)\n",
"list_footer": "</b></blockquote>",
"list_empty": "<b>{e} Нет анимаций.</b>",
}
_E = "<emoji document_id=5774077015388852135>❌</emoji>"
_S = "<emoji document_id=5774022692642492953>✅</emoji>"
async def client_ready(self):
if not self.db.get("IwaAnimations", "anims", False):
self.db.set("IwaAnimations", "anims", {})
@loader.command(ru_doc="- Загрузить анимацию из полученного .anim файла")
async def lanimcmd(self, message: Message):
"""- Load animation from a replied .anim file"""
reply = await message.get_reply_message()
if not reply or not reply.document:
return await utils.answer(
message, self.strings["err_no_reply"].format(e=self._E)
)
filename = reply.file.name or ""
if not filename.endswith(".anim"):
return await utils.answer(
message, self.strings["err_not_anim"].format(e=self._E)
)
tmp = "anim_load.anim"
await reply.download_media(tmp)
try:
data = toml.load(tmp)
name = data.get("name")
cmd = data.get("cmd")
delay = float(data.get("time", 0.5))
if not name or not cmd:
return await utils.answer(
message, self.strings["err_bad_format"].format(e=self._E)
)
frames = []
for key in sorted(
(k for k in data if str(k).isdigit()), key=lambda x: int(x)
):
frame = data[key]
frames.append("\n".join(frame) if isinstance(frame, list) else str(frame))
if not frames:
return await utils.answer(
message, self.strings["err_no_frames"].format(e=self._E)
)
anims = self.db.get("IwaAnimations", "anims", {})
anims[cmd] = {"name": name, "frames": frames, "delay": delay}
self.db.set("IwaAnimations", "anims", anims)
await utils.answer(
message,
self.strings["ok_loaded"].format(s=self._S, name=name, cmd=cmd),
)
except Exception as exc:
await utils.answer(
message, self.strings["err_generic"].format(e=self._E, exc=exc)
)
finally:
if os.path.exists(tmp):
os.remove(tmp)
@loader.command(ru_doc="<cmd> - Воспроизвести загруженную анимацию")
async def animcmd(self, message: Message):
"""<cmd> - Play a loaded animation"""
cmd = utils.get_args_raw(message)
if not cmd:
return await utils.answer(
message, self.strings["err_no_cmd"].format(e=self._E)
)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anim = anims[cmd]
msg = await utils.answer(message, anim["frames"][0])
try:
for frame in anim["frames"][1:]:
await asyncio.sleep(anim["delay"])
await msg.edit(frame)
except Exception:
pass
@loader.command(ru_doc="- Отобразить список всех загруженных анимаций")
async def animscmd(self, message: Message):
"""- List all loaded animations"""
anims = self.db.get("IwaAnimations", "anims", {})
if not anims:
return await utils.answer(
message, self.strings["list_empty"].format(e=self._E)
)
text = self.strings["list_header"]
for cmd, data in anims.items():
text += self.strings["list_row"].format(
cmd=cmd, name=data["name"], n=len(data["frames"])
)
text += self.strings["list_footer"]
await utils.answer(message, text)
@loader.command(ru_doc="<cmd> - Удалить анимацию")
async def delanimcmd(self, message: Message):
"""<cmd> - Delete an animation"""
cmd = utils.get_args_raw(message)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anims.pop(cmd)
self.db.set("IwaAnimations", "anims", anims)
await utils.answer(message, self.strings["ok_deleted"].format(s=self._S))
@loader.command(ru_doc="<cmd> - Экспорт анимации в файл .anim")
async def dumpanimcmd(self, message: Message):
"""<cmd> - Export an animation to a .anim file"""
cmd = utils.get_args_raw(message)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anim = anims[cmd]
data = {"name": anim["name"], "cmd": cmd, "time": str(anim["delay"])}
for i, frame in enumerate(anim["frames"], start=1):
data[str(i)] = frame.split("\n")
file = f"{cmd}.anim"
try:
with open(file, "w", encoding="utf-8") as f:
toml.dump(data, f)
await message.delete()
await self._client.send_file(message.to_id, file)
finally:
if os.path.exists(file):
os.remove(file)

View File

@@ -26,4 +26,5 @@ aigenuser
github github
stream stream
placeholders+ placeholders+
PyInstall PyInstall
IwaAnimation

View File

@@ -26,7 +26,7 @@ from typing import Optional, Dict, Any
from collections import OrderedDict from collections import OrderedDict
from .. import loader, utils, validators from .. import loader, utils, validators
from herokutl.tl.functions.users import GetFullUserRequest from telethon.tl.functions.users import GetFullUserRequest
from herokutl.tl.functions.payments import GetStarsStatusRequest from herokutl.tl.functions.payments import GetStarsStatusRequest
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -118,21 +118,23 @@ class PlaceholdersMod(loader.Module):
) )
self.cache = LRUCache(max_size=100, ttl=300) self.cache = LRUCache(max_size=100, ttl=300)
async def client_ready(self): async def client_ready(self, client, db):
self._client = client
self.session = aiohttp.ClientSession() self.session = aiohttp.ClientSession()
self.me = await self._client.get_me() self.me = await client.get_me()
self.full_me = await self._client(GetFullUserRequest(self.me)) self.full_me = await client(GetFullUserRequest(self.me))
try: try:
stars_status = await self._client(GetStarsStatusRequest(entity="me")) stars_status = await self._client(GetStarsStatusRequest(entity='me'))
self.stars_balance = stars_status.balance self.stars_balance = stars_status.balance
except Exception: except:
self.stars_balance = 0 self.stars_balance = 0
self.tz = timezone(timedelta(hours=self.config["timezone"])) self.tz = timezone(timedelta(hours=self.config["timezone"]))
self.weekdays_ru = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"] self.weekdays_ru = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"]
# Регистрация плейсхолдеров
self._register_placeholders() self._register_placeholders()
def _register_placeholders(self): def _register_placeholders(self):
@@ -199,30 +201,18 @@ class PlaceholdersMod(loader.Module):
utils.register_placeholder(name, func, desc) utils.register_placeholder(name, func, desc)
async def get_premium_check(self): async def get_premium_check(self):
if not getattr(self.me, "premium", False): if not self.me.premium:
return "Нет Premium" return "Нет Premium"
# premium_until отсутствует в публичном MTProto API herokutl/Telethon — until = self.full_me.full_user.premium_until
# пробуем достать его, но не падаем если поля нет if not until or until < time.time():
until = None return "Премиум закончился"
try:
until = getattr(self.full_me.full_user, "premium_until", None)
# Иногда это datetime, иногда unix timestamp (int)
if isinstance(until, datetime):
until = until.timestamp()
except Exception:
until = None
if not until:
return "✅ Premium активен"
if until < time.time():
return "⚠️ Премиум истёк"
end_date = datetime.fromtimestamp(until, tz=self.tz) end_date = datetime.fromtimestamp(until, tz=self.tz)
days_left = (end_date.date() - datetime.now(self.tz).date()).days days_left = (end_date.date() - datetime.now(self.tz).date()).days
formatted = end_date.strftime("%d.%m.%Y") formatted = end_date.strftime("%d.%m.%Y")
return f"✅ до {formatted} (ещё {days_left} дн.)" return f"{formatted} (Осталось {days_left} дней)"
async def get_username(self): async def get_username(self):
return f"@{self.me.username}" if self.me.username else "Нет" return f"@{self.me.username}" if self.me.username else "Нет"
@@ -245,8 +235,10 @@ class PlaceholdersMod(loader.Module):
async def get_dc_id(self): async def get_dc_id(self):
return str(self.me.dc_id if hasattr(self.me, "dc_id") else "Неизвестно") return str(self.me.dc_id if hasattr(self.me, "dc_id") else "Неизвестно")
async def get_stars(self): async def get_stars(self):
return f"{self.stars_balance:,}".replace(",", " ") if self.stars_balance else "0" result = await self.client(GetStarsStatusRequest("me"))
stars = result.balance.amount if result and result.balance else 0
return f"{stars:,}".replace(",", " ") if stars else "0"
async def get_usd_to_rub(self): async def get_usd_to_rub(self):
cache_key = "usd_rub" cache_key = "usd_rub"
@@ -261,7 +253,7 @@ class PlaceholdersMod(loader.Module):
result = f"1 USD ≈ {rate:.2f} RUB" result = f"1 USD ≈ {rate:.2f} RUB"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
try: try:
async with self.session.get("https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/usd.json") as resp: async with self.session.get("https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/usd.json") as resp:
data = await resp.json() data = await resp.json()
@@ -269,7 +261,7 @@ class PlaceholdersMod(loader.Module):
result = f"1 USD ≈ {rate:.2f} RUB" result = f"1 USD ≈ {rate:.2f} RUB"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
return "Курс USD недоступен" return "Курс USD недоступен"
async def get_rub_to_usd(self): async def get_rub_to_usd(self):
@@ -278,7 +270,7 @@ class PlaceholdersMod(loader.Module):
try: try:
rate = float(usd_rub.split("")[1].strip().split()[0]) rate = float(usd_rub.split("")[1].strip().split()[0])
return f"1 RUB ≈ {1/rate:.4f} USD" return f"1 RUB ≈ {1/rate:.4f} USD"
except Exception: except:
pass pass
return "Курс RUB недоступен" return "Курс RUB недоступен"
@@ -301,7 +293,7 @@ class PlaceholdersMod(loader.Module):
result = f"1 TON ≈ {rate:.2f} RUB" result = f"1 TON ≈ {rate:.2f} RUB"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
return "Курс TON недоступен" return "Курс TON недоступен"
async def get_rub_to_ton(self): async def get_rub_to_ton(self):
@@ -310,7 +302,7 @@ class PlaceholdersMod(loader.Module):
try: try:
rate = float(ton_rub.split("")[1].strip().split()[0]) rate = float(ton_rub.split("")[1].strip().split()[0])
return f"1 RUB ≈ {1/rate:.6f} TON" return f"1 RUB ≈ {1/rate:.6f} TON"
except Exception: except:
pass pass
return "Курс недоступен" return "Курс недоступен"
@@ -327,7 +319,7 @@ class PlaceholdersMod(loader.Module):
result = f"1 BTC ≈ {rate:,.0f} RUB" result = f"1 BTC ≈ {rate:,.0f} RUB"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
return "Курс BTC недоступен" return "Курс BTC недоступен"
async def get_eth_to_rub(self): async def get_eth_to_rub(self):
@@ -343,7 +335,7 @@ class PlaceholdersMod(loader.Module):
result = f"1 ETH ≈ {rate:,.0f} RUB" result = f"1 ETH ≈ {rate:,.0f} RUB"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
return "Курс ETH недоступен" return "Курс ETH недоступен"
async def get_stars_to_rub(self): async def get_stars_to_rub(self):
@@ -373,7 +365,7 @@ class PlaceholdersMod(loader.Module):
sent_gb = net.bytes_sent // (1024**3) sent_gb = net.bytes_sent // (1024**3)
recv_gb = net.bytes_recv // (1024**3) recv_gb = net.bytes_recv // (1024**3)
return f"{sent_gb} GB │ ↓ {recv_gb} GB" return f"{sent_gb} GB │ ↓ {recv_gb} GB"
except Exception: except:
return "↑ 0 GB │ ↓ 0 GB" return "↑ 0 GB │ ↓ 0 GB"
async def get_speedtest(self): async def get_speedtest(self):
@@ -405,7 +397,7 @@ class PlaceholdersMod(loader.Module):
result = f"{speed_mbps:.1f} Mbps" result = f"{speed_mbps:.1f} Mbps"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
continue continue
return "Тест скорости недоступен" return "Тест скорости недоступен"
@@ -426,7 +418,7 @@ class PlaceholdersMod(loader.Module):
used_gb = usage.used // (1024**3) used_gb = usage.used // (1024**3)
total_gb = usage.total // (1024**3) total_gb = usage.total // (1024**3)
return f"{used_gb} GB / {total_gb} GB ({percent:.1f}%)" return f"{used_gb} GB / {total_gb} GB ({percent:.1f}%)"
except Exception: except:
return "Диск недоступен" return "Диск недоступен"
async def get_local_ip(self): async def get_local_ip(self):
@@ -436,7 +428,7 @@ class PlaceholdersMod(loader.Module):
ip = s.getsockname()[0] ip = s.getsockname()[0]
s.close() s.close()
return ip return ip
except Exception: except:
return "Неизвестно" return "Неизвестно"
async def get_user_hostname(self): async def get_user_hostname(self):
@@ -507,7 +499,7 @@ class PlaceholdersMod(loader.Module):
} }
self.cache.set(cache_key, weather_data) self.cache.set(cache_key, weather_data)
return weather_data return weather_data
except Exception: except:
pass pass
default = { default = {
@@ -595,7 +587,7 @@ class PlaceholdersMod(loader.Module):
result = f"🎵 {stats['playcount']} скробблов" result = f"🎵 {stats['playcount']} скробблов"
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
pass pass
return "Статистика недоступна" return "Статистика недоступна"
@@ -637,14 +629,10 @@ class PlaceholdersMod(loader.Module):
} }
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except Exception: except:
pass pass
return None return None
async def on_unload(self): async def on_unload(self):
utils.unregister_placeholders(self.__class__.__name__) await self.session.close()
try:
await self.session.close()
except Exception:
pass

View File

@@ -5289,6 +5289,139 @@
"has_on_unload": false, "has_on_unload": false,
"class_cmd_names": {} "class_cmd_names": {}
}, },
"fiksofficial/python-modules/IwaAnimation.py": {
"name": "IwaAnimation",
"description": "Frame-by-frame text animations loaded from .anim TOML files",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@pymodule"
},
"commands": [
{
"lanim": "- Load animation from a replied .anim file | (RU) - Загрузить анимацию из полученного .anim файла"
},
{
"anim": "<cmd> - Play a loaded animation | (RU) <cmd> - Воспроизвести загруженную анимацию"
},
{
"anims": "- List all loaded animations | (RU) - Отобразить список всех загруженных анимаций"
},
{
"delanim": "<cmd> - Delete an animation | (RU) <cmd> - Удалить анимацию"
},
{
"dumpanim": "<cmd> - Export an animation to a .anim file | (RU) <cmd> - Экспорт анимации в файл .anim"
}
],
"new_commands": [
{
"name": "lanim",
"original_name": "lanimcmd",
"description": {
"default": "- Load animation from a replied .anim file",
"ru": "- Загрузить анимацию из полученного .anim файла"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "anim",
"original_name": "animcmd",
"description": {
"default": "<cmd> - Play a loaded animation",
"ru": "<cmd> - Воспроизвести загруженную анимацию"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "anims",
"original_name": "animscmd",
"description": {
"default": "- List all loaded animations",
"ru": "- Отобразить список всех загруженных анимаций"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "delanim",
"original_name": "delanimcmd",
"description": {
"default": "<cmd> - Delete an animation",
"ru": "<cmd> - Удалить анимацию"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "dumpanim",
"original_name": "dumpanimcmd",
"description": {
"default": "<cmd> - Export an animation to a .anim file",
"ru": "<cmd> - Экспорт анимации в файл .anim"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "IwaAnimation",
"err_no_reply": "<b>{e} Reply to a .anim file.</b>",
"err_not_anim": "<b>{e} File must have .anim extension.</b>",
"err_bad_format": "<b>{e} Invalid file format (missing name or cmd).</b>",
"err_no_frames": "<b>{e} No frames found in the file.</b>",
"err_not_found": "<b>{e} Animation not found.</b>",
"err_no_cmd": "<b>{e} Specify a command name.</b>",
"err_generic": "<b>{e} Error:</b>\n\n{exc}",
"ok_loaded": "<b>{s} Loaded: {name}\nCommand: <code>.anim {cmd}</code></b>",
"ok_deleted": "<b>{s} Deleted.</b>",
"list_header": "<blockquote><b>Animations:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row": "• <code>{cmd}</code> — {name} ({n} frames)\n",
"list_footer": "</b></blockquote>",
"list_empty": "<b>{e} No animations.</b>",
"name_ru": "IwaAnimation",
"err_no_reply_ru": "<b>{e} Ответьте на .anim файл.</b>",
"err_not_anim_ru": "<b>{e} Файл должен быть формата .anim</b>",
"err_bad_format_ru": "<b>{e} Неверный формат файла (нет name или cmd).</b>",
"err_no_frames_ru": "<b>{e} В файле нет кадров.</b>",
"err_not_found_ru": "<b>{e} Анимация не найдена.</b>",
"err_no_cmd_ru": "<b>{e} Укажи команду.</b>",
"err_generic_ru": "<b>{e} Ошибка:</b>\n\n{exc}",
"ok_loaded_ru": "<b>{s} Загружено: {name}\nКоманда: <code>.anim {cmd}</code></b>",
"ok_deleted_ru": "<b>{s} Удалено.</b>",
"list_header_ru": "<blockquote><b>Анимации:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row_ru": "• <code>{cmd}</code> — {name} ({n} кадров)\n",
"list_footer_ru": "</b></blockquote>",
"list_empty_ru": "<b>{e} Нет анимаций.</b>"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"fiksofficial/python-modules/tagall2.0.py": { "fiksofficial/python-modules/tagall2.0.py": {
"name": "TagAllMod", "name": "TagAllMod",
"description": "TagAll 2.0 — smart mention of chat participants: .tagall {all/admins/online/active} {text}", "description": "TagAll 2.0 — smart mention of chat participants: .tagall {all/admins/online/active} {text}",
@@ -8310,6 +8443,117 @@
"has_on_unload": true, "has_on_unload": true,
"class_cmd_names": {} "class_cmd_names": {}
}, },
"Fixyres/FModules/LFSecurity.py": {
"name": "FSecurity",
"description": "Module for automatic AI-based security checks of installed modules.",
"cls_doc": {
"ru": "Модуль для автоматической проверки устанавливаемых модулей через ИИ.",
"ua": "Модуль для автоматичної перевірки встановлюваних модулів через ШІ.",
"de": "Modul zur automatischen Prüfung installierter Module mit KI.",
"jp": "AIでインストールされるモジュールを自動チェックするモジュール。",
"tr": "Kurulan modülleri yapay zeka ile otomatik kontrol eden modül.",
"uz": "O'rnatilayotgan modullarni AI orqali avtomatik tekshiruvchi modul.",
"kz": "Орнатылатын модульдерді ЖИ арқылы автоматты тексеретін модуль."
},
"meta": {
"pic": null,
"banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/banner.png",
"developer": "@NFModules",
"fhsdesc": "security, guard, antiscam, antivirus"
},
"commands": [],
"new_commands": [],
"inline_handlers": [],
"strings": {
"name": "FSecurity"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"Fixyres/FModules/FSecurity.py": {
"name": "FSecurity",
"description": "Module for automatic AI-based security checks of installed modules.",
"cls_doc": {
"ru": "Модуль для автоматической проверки устанавливаемых модулей через ИИ.",
"ua": "Модуль для автоматичної перевірки встановлюваних модулів через ШІ.",
"de": "Modul zur automatischen Prüfung installierter Module mit KI.",
"jp": "AIでインストールされるモジュールを自動チェックするモジュール。",
"tr": "Kurulan modülleri yapay zeka ile otomatik kontrol eden modül.",
"uz": "O'rnatilayotgan modullarni AI orqali avtomatik tekshiruvchi modul.",
"kz": "Орнатылатын модульдерді ЖИ арқылы автоматты тексеретін модуль."
},
"meta": {
"pic": null,
"banner": null,
"developer": "@NFModules"
},
"commands": [],
"new_commands": [],
"inline_handlers": [],
"strings": {
"name": "FSecurity",
"lang": "English",
"unavailable": "AI module{} check is unavailable.",
"suspicious": "AI interrupted installation of a suspicious module{}, reason:",
"blocked": "AI blocked module installation{}, reason:",
"continue": "Continue installation?",
"strict_mode_doc": "Block loading modules by any method (lm/dlm allowed) if the AI API is unavailable or the module is suspicious. On restart, this also applies to already installed modules.",
"nvidia_api_key_doc": "API key from build.nvidia.com, used for AI checks. If not specified, a public key from GitHub will be used.",
"lang_ru": "Russian",
"unavailable_ru": "Проверка модуля{} через ИИ недоступна.",
"suspicious_ru": "ИИ прервал установку подозрительного модуля{}, причина:",
"blocked_ru": "ИИ заблокировал установку модуля{}, причина:",
"continue_ru": "Продолжить установку?",
"strict_mode_doc_ru": "Не позволять загружать модули любым методом (lm/dlm разрешено), если API ИИ недоступен или модуль подозрителен. При перезагрузке работает даже на уже установленные модули.",
"nvidia_api_key_doc_ru": "API ключ от build.nvidia.com, используется для проверки через ИИ. Если вы его не укажете, будет использоваться общий ключ с GitHub.",
"lang_ua": "Ukraine",
"unavailable_ua": "Перевірка модуля{} через ШІ недоступна.",
"suspicious_ua": "ШІ перервав встановлення підозрілого модуля{}, причина:",
"blocked_ua": "ШІ заблокував встановлення модуля{}, причина:",
"continue_ua": "Продовжити встановлення?",
"strict_mode_doc_ua": "Не дозволяти завантажувати модулі будь-яким методом (lm/dlm дозволено), якщо API ШІ недоступний або модуль підозрілий. При перезавантаженні працює навіть на вже встановлені модулі.",
"nvidia_api_key_doc_ua": "API ключ від build.nvidia.com, використовується для перевірки через ШІ. Якщо ви його не вкажете, буде використовуватися загальний ключ з GitHub.",
"lang_de": "Germany",
"unavailable_de": "Die KI-Modulprüfung{} ist nicht verfügbar.",
"suspicious_de": "Die KI hat die Installation eines verdächtigen Moduls unterbrochen{}, Grund:",
"blocked_de": "Die KI hat die Modulinstallation blockiert{}, Grund:",
"continue_de": "Installation fortsetzen?",
"strict_mode_doc_de": "Das Laden von Modulen mit jeder Methode blockieren (lm/dlm erlaubt), wenn die KI-API nicht verfügbar ist oder das Modul verdächtig ist. Beim Neustart gilt dies auch für bereits installierte Module.",
"nvidia_api_key_doc_de": "API-Schlüssel von build.nvidia.com, der für KI-Prüfungen verwendet wird. Wenn nicht angegeben, wird ein öffentlicher Schlüssel von GitHub verwendet.",
"lang_jp": "Japanese",
"unavailable_jp": "AIモジュール{}のチェックが利用できません。",
"suspicious_jp": "AIが疑わしいモジュールのインストールを中断しました{}、理由:",
"blocked_jp": "AIがモジュールのインストールをブロックしました{}、理由:",
"continue_jp": "インストールを続行しますか?",
"strict_mode_doc_jp": "AI APIが利用できない場合や疑わしいモジュールの場合、すべての方法でモジュールの読み込みをブロックしますlm/dlmは許可。再起動時にはインストール済みモジュールにも適用されます。",
"nvidia_api_key_doc_jp": "build.nvidia.com のAPIキー。AIチェックに使用されます。指定しない場合は、GitHubのパブリックキーが使用されます。",
"lang_tr": "Turkish",
"unavailable_tr": "Yapay zeka modül{} kontrolü kullanılamıyor.",
"suspicious_tr": "Yapay zeka şüpheli bir modülün kurulumunu durdurdu{}, sebep:",
"blocked_tr": "Yapay zeka modül kurulumunu engelledi{}, sebep:",
"continue_tr": "Kuruluma devam edilsin mi?",
"strict_mode_doc_tr": "AI API kullanılamıyorsa veya modül şüpheliyse, tüm yöntemlerle modül yüklenmesini engelle (lm/dlm izinli). Yeniden başlatmada zaten kurulu modüller için de geçerlidir.",
"nvidia_api_key_doc_tr": "Yapay zeka kontrolleri için kullanılan build.nvidia.com API anahtarı. Belirtilmezse GitHub'daki genel anahtar kullanılacaktır.",
"lang_uz": "Uzbekistan",
"unavailable_uz": "AI modul{} tekshiruvi mavjud emas.",
"suspicious_uz": "AI shubhali modul o'rnatilishini to'xtatdi{}, sabab:",
"blocked_uz": "AI modul o'rnatilishini blokladi{}, sabab:",
"continue_uz": "O'rnatishni davom ettirasizmi?",
"strict_mode_doc_uz": "AI API mavjud bo'lmasa yoki modul shubhali bo'lsa, barcha usullar bilan modul yuklashni bloklash (lm/dlm ruxsat etilgan). Qayta ishga tushirishda allaqachon o'rnatilgan modullarga ham ta'sir qiladi.",
"nvidia_api_key_doc_uz": "build.nvidia.com API kaliti, AI orqali tekshirish uchun ishlatiladi. Agar ko'rsatmasangiz, GitHub-dan umumiy kalit ishlatiladi.",
"lang_kz": "Kazakhstan",
"unavailable_kz": "AI модуль{} тексеру қолжетімсіз.",
"suspicious_kz": "AI күдікті модульді орнатуды тоқтатты{}, себебі:",
"blocked_kz": "AI модульді орнатуды бұғаттады{}, себебі:",
"continue_kz": "Орнатуды жалғастырасыз ба?",
"strict_mode_doc_kz": "AI API қолжетімсіз болса немесе модуль күдікті болса, барлық әдістермен модуль жүктеуді бұғаттау (lm/dlm рұқсат етілген). Қайта іске қосқанда орнатылған модульдерге де қолданылады.",
"nvidia_api_key_doc_kz": "build.nvidia.com API кілті, ЖИ арқылы тексеру үшін қолданылады. Егер оны көрсетпесеңіз, GitHub-тан ортақ кілт пайдаланылады."
},
"has_on_load": false,
"has_on_unload": true,
"class_cmd_names": {}
},
"Fixyres/FModules/BSR.py": { "Fixyres/FModules/BSR.py": {
"name": "BSR", "name": "BSR",
"description": "Module for finding nearby game rooms in BrawlStars.", "description": "Module for finding nearby game rooms in BrawlStars.",
@@ -8325,7 +8569,7 @@
"meta": { "meta": {
"pic": null, "pic": null,
"banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png", "banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/BSR/banner.png",
"developer": "@FModules", "developer": "@NFModules",
"fhsdesc": "brawlstars, game, funny" "fhsdesc": "brawlstars, game, funny"
}, },
"commands": [ "commands": [
@@ -8427,7 +8671,7 @@
"meta": { "meta": {
"pic": null, "pic": null,
"banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/SCD/banner.png", "banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/SCD/banner.png",
"developer": "@FModules" "developer": "@NFModules"
}, },
"commands": [ "commands": [
{ {
@@ -8504,7 +8748,7 @@
"meta": { "meta": {
"pic": null, "pic": null,
"banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png", "banner": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png",
"developer": "@FModules", "developer": "@NFModules",
"fhsdesc": "game, funny, guess, question game" "fhsdesc": "game, funny, guess, question game"
}, },
"commands": [ "commands": [
@@ -84526,7 +84770,7 @@
"cls_doc": {}, "cls_doc": {},
"meta": { "meta": {
"pic": null, "pic": null,
"banner": "https://github.com/Midga3/heroku-modules/blob/main/new_module.jpg?raw=true", "banner": null,
"developer": "@midga3_modules" "developer": "@midga3_modules"
}, },
"commands": [], "commands": [],
@@ -84951,7 +85195,7 @@
} }
}, },
"meta": { "meta": {
"total_modules": 1057, "total_modules": 1060,
"generated_at": "2026-04-12T17:39:10.030299" "generated_at": "2026-04-18T01:49:43.246930"
} }
} }