diff --git a/Fixyres/FModules/FHeta.py b/Fixyres/FModules/FHeta.py
index 278fd92..c50e0a2 100644
--- a/Fixyres/FModules/FHeta.py
+++ b/Fixyres/FModules/FHeta.py
@@ -302,7 +302,7 @@ class FHetaUI:
@loader.tds
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 = {
"name": "FHeta",
@@ -338,7 +338,7 @@ class FHeta(loader.Module):
}
strings_ru = {
- "_cls_doc": "Модуль для поиска модулей! Следите за всеми новостями FHeta в @FHeta_Updates!",
+ "_cls_doc": "Модуль для поиска модулей! Следите за всеми новостями FHeta в @NFHeta_Updates!",
"lang": "ru",
"author": "от",
"description": "Описание",
@@ -371,7 +371,7 @@ class FHeta(loader.Module):
}
strings_ua = {
- "_cls_doc": "Модуль для пошуку модулів! Слідкуйте за всіма новинами FHeta в @FHeta_Updates!",
+ "_cls_doc": "Модуль для пошуку модулів! Слідкуйте за всіма новинами FHeta в @NFHeta_Updates!",
"lang": "ua",
"author": "від",
"description": "Опис",
@@ -404,7 +404,7 @@ class FHeta(loader.Module):
}
strings_kz = {
- "_cls_doc": "Модульдерді іздеу модулі! FHeta барлық жаңалықтарын @FHeta_Updates арнасында қадағалаңыз!",
+ "_cls_doc": "Модульдерді іздеу модулі! FHeta барлық жаңалықтарын @NFHeta_Updates арнасында қадағалаңыз!",
"lang": "kz",
"author": "авторы",
"description": "Сипаттама",
@@ -437,7 +437,7 @@ class FHeta(loader.Module):
}
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",
"author": "muallif",
"description": "Tavsif",
@@ -470,7 +470,7 @@ class FHeta(loader.Module):
}
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",
"author": "par",
"description": "Description",
@@ -503,7 +503,7 @@ class FHeta(loader.Module):
}
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",
"author": "von",
"description": "Beschreibung",
@@ -536,7 +536,7 @@ class FHeta(loader.Module):
}
strings_jp = {
- "_cls_doc": "モジュール検索用モジュール!@FHeta_UpdatesでFHetaのすべてのニュースをフォローしてください!",
+ "_cls_doc": "モジュール検索用モジュール!@NFHeta_UpdatesでFHetaのすべてのニュースをフォローしてください!",
"lang": "jp",
"author": "作成者",
"description": "説明",
@@ -577,7 +577,7 @@ class FHeta(loader.Module):
"command": '⚙️',
"placeholder": '🗒️',
"module": '📦',
- "channel": '📢',
+ "channel": '📢',
"modules_list": '📋'
},
"winter": {
@@ -588,7 +588,7 @@ class FHeta(loader.Module):
"command": '🎅',
"placeholder": '🗒️',
"module": '🎁',
- "channel": '📢',
+ "channel": '📢',
"modules_list": '🎄'
},
"summer": {
@@ -599,7 +599,7 @@ class FHeta(loader.Module):
"command": '🏄',
"placeholder": '🗒️',
"module": '🏖️',
- "channel": '📢',
+ "channel": '📢',
"modules_list": '🏖️'
},
"spring": {
@@ -610,7 +610,7 @@ class FHeta(loader.Module):
"command": '🦋',
"placeholder": '🗒️',
"module": '🌿',
- "channel": '📢',
+ "channel": '📢',
"modules_list": '🌺'
},
"autumn": {
@@ -621,7 +621,7 @@ class FHeta(loader.Module):
"command": '🍂',
"placeholder": '🗒️',
"module": '🍄',
- "channel": '📢',
+ "channel": '📢',
"modules_list": '🍂'
}
}
diff --git a/Fixyres/FModules/FSecurity.py b/Fixyres/FModules/FSecurity.py
new file mode 100644
index 0000000..f7c8c0a
--- /dev/null
+++ b/Fixyres/FModules/FSecurity.py
@@ -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__ = ""
+ 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' ({utils.escape_html(link)})' if link else ""
+ if state == "unavailable":
+ return f'{self.strings("unavailable").format(link_part)}\n{self.strings("continue")}'
+ if state == "suspicious":
+ return f'{self.strings("suspicious").format(link_part)}\n{reason}
\n{self.strings("continue")}'
+ return f'{self.strings("blocked").format(link_part)}\n{reason}
'
+
+ 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..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 "😖" in response:
+ body = response.split("😖", 1)[1].strip()
+ if body in {"", "", " "}:
+ with suppress(Exception):
+ if hasattr(message, "delete"):
+ await message.delete()
+ return message
+
+ if body.startswith("") and body.endswith(""):
+ decoded = html.unescape(body[3:-4])
+ response = response.split("😖", 1)[0] + f'😖 {decoded}' if decoded else response.split("😖", 1)[0] + '😖'
+
+ 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="", 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="", save_fs=False):
+ if origin != "":
+ 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()
diff --git a/Fixyres/FModules/LFSecurity.py b/Fixyres/FModules/LFSecurity.py
new file mode 100644
index 0000000..de8d65e
--- /dev/null
+++ b/Fixyres/FModules/LFSecurity.py
@@ -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
diff --git a/Fixyres/FModules/assets/FSecurity/api_keys.txt b/Fixyres/FModules/assets/FSecurity/api_keys.txt
new file mode 100644
index 0000000..b813928
--- /dev/null
+++ b/Fixyres/FModules/assets/FSecurity/api_keys.txt
@@ -0,0 +1 @@
+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
diff --git a/Fixyres/FModules/assets/FSecurity/banner.png b/Fixyres/FModules/assets/FSecurity/banner.png
new file mode 100644
index 0000000..95adf82
Binary files /dev/null and b/Fixyres/FModules/assets/FSecurity/banner.png differ
diff --git a/Fixyres/FModules/assets/FSecurity/prompts/chank.txt b/Fixyres/FModules/assets/FSecurity/prompts/chank.txt
new file mode 100644
index 0000000..505cf16
--- /dev/null
+++ b/Fixyres/FModules/assets/FSecurity/prompts/chank.txt
@@ -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 text for code references: function names, variables, URLs, string literals.
+- For obfuscation chains, wrap the whole chain in one block: base64.b64decode → zlib.decompress → exec.
+- If CLEAN → findings must be empty string "".
diff --git a/Fixyres/FModules/assets/FSecurity/prompts/final.txt b/Fixyres/FModules/assets/FSecurity/prompts/final.txt
new file mode 100644
index 0000000..0c61807
--- /dev/null
+++ b/Fixyres/FModules/assets/FSecurity/prompts/final.txt
@@ -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 text for all code references: function names, variables, URLs, string literals.
+- For obfuscation, show the full chain in one block: base64.b64decode → zlib.decompress → exec.
+- If SAFE → summary must be empty string "".
diff --git a/Fixyres/FModules/assets/FSecurity/prompts/main.txt b/Fixyres/FModules/assets/FSecurity/prompts/main.txt
new file mode 100644
index 0000000..a8e6b85
--- /dev/null
+++ b/Fixyres/FModules/assets/FSecurity/prompts/main.txt
@@ -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 text for every code reference: function names, variables, URLs, string literals.
+- For obfuscation, show the full decoding chain inside one block: base64.b64decode → zlib.decompress → marshal.loads → exec.
+- If SAFE → summary must be empty string "".
diff --git a/fiksofficial/python-modules/IwaAnimation.py b/fiksofficial/python-modules/IwaAnimation.py
new file mode 100644
index 0000000..1bb8f65
--- /dev/null
+++ b/fiksofficial/python-modules/IwaAnimation.py
@@ -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": "{e} Reply to a .anim file.",
+ "err_not_anim": "{e} File must have .anim extension.",
+ "err_bad_format": "{e} Invalid file format (missing name or cmd).",
+ "err_no_frames": "{e} No frames found in the file.",
+ "err_not_found": "{e} Animation not found.",
+ "err_no_cmd": "{e} Specify a command name.",
+ "err_generic": "{e} Error:\n\n{exc}",
+ "ok_loaded": "{s} Loaded: {name}\nCommand: .anim {cmd}",
+ "ok_deleted": "{s} Deleted.",
+ "list_header": "Animations:
\n\n",
+ "list_row": "• {cmd} — {name} ({n} frames)\n",
+ "list_footer": "
",
+ "list_empty": "{e} No animations.",
+ }
+
+ strings_ru = {
+ "name": "IwaAnimation",
+ "err_no_reply": "{e} Ответьте на .anim файл.",
+ "err_not_anim": "{e} Файл должен быть формата .anim",
+ "err_bad_format": "{e} Неверный формат файла (нет name или cmd).",
+ "err_no_frames": "{e} В файле нет кадров.",
+ "err_not_found": "{e} Анимация не найдена.",
+ "err_no_cmd": "{e} Укажи команду.",
+ "err_generic": "{e} Ошибка:\n\n{exc}",
+ "ok_loaded": "{s} Загружено: {name}\nКоманда: .anim {cmd}",
+ "ok_deleted": "{s} Удалено.",
+ "list_header": "Анимации:
\n\n",
+ "list_row": "• {cmd} — {name} ({n} кадров)\n",
+ "list_footer": "
",
+ "list_empty": "{e} Нет анимаций.",
+ }
+
+ _E = "❌"
+ _S = "✅"
+
+ 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=" - Воспроизвести загруженную анимацию")
+ async def animcmd(self, message: Message):
+ """ - 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=" - Удалить анимацию")
+ async def delanimcmd(self, message: Message):
+ """ - 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=" - Экспорт анимации в файл .anim")
+ async def dumpanimcmd(self, message: Message):
+ """ - 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)
\ No newline at end of file
diff --git a/fiksofficial/python-modules/full.txt b/fiksofficial/python-modules/full.txt
index 0d35b2a..5855795 100644
--- a/fiksofficial/python-modules/full.txt
+++ b/fiksofficial/python-modules/full.txt
@@ -26,4 +26,5 @@ aigenuser
github
stream
placeholders+
-PyInstall
\ No newline at end of file
+PyInstall
+IwaAnimation
\ No newline at end of file
diff --git a/modules.json b/modules.json
index 27e7e60..9b248df 100644
--- a/modules.json
+++ b/modules.json
@@ -5289,6 +5289,139 @@
"has_on_unload": false,
"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": " - Play a loaded animation | (RU) - Воспроизвести загруженную анимацию"
+ },
+ {
+ "anims": "- List all loaded animations | (RU) - Отобразить список всех загруженных анимаций"
+ },
+ {
+ "delanim": " - Delete an animation | (RU) - Удалить анимацию"
+ },
+ {
+ "dumpanim": " - Export an animation to a .anim file | (RU) - Экспорт анимации в файл .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": " - Play a loaded animation",
+ "ru": " - Воспроизвести загруженную анимацию"
+ },
+ "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": " - Delete an animation",
+ "ru": " - Удалить анимацию"
+ },
+ "cmd_names": {},
+ "aliases": [],
+ "usage": null,
+ "inline": false,
+ "is_inline_handler": false,
+ "decorators": []
+ },
+ {
+ "name": "dumpanim",
+ "original_name": "dumpanimcmd",
+ "description": {
+ "default": " - Export an animation to a .anim file",
+ "ru": " - Экспорт анимации в файл .anim"
+ },
+ "cmd_names": {},
+ "aliases": [],
+ "usage": null,
+ "inline": false,
+ "is_inline_handler": false,
+ "decorators": []
+ }
+ ],
+ "inline_handlers": [],
+ "strings": {
+ "name": "IwaAnimation",
+ "err_no_reply": "{e} Reply to a .anim file.",
+ "err_not_anim": "{e} File must have .anim extension.",
+ "err_bad_format": "{e} Invalid file format (missing name or cmd).",
+ "err_no_frames": "{e} No frames found in the file.",
+ "err_not_found": "{e} Animation not found.",
+ "err_no_cmd": "{e} Specify a command name.",
+ "err_generic": "{e} Error:\n\n{exc}",
+ "ok_loaded": "{s} Loaded: {name}\nCommand: .anim {cmd}",
+ "ok_deleted": "{s} Deleted.",
+ "list_header": "Animations:
\n\n",
+ "list_row": "• {cmd} — {name} ({n} frames)\n",
+ "list_footer": "
",
+ "list_empty": "{e} No animations.",
+ "name_ru": "IwaAnimation",
+ "err_no_reply_ru": "{e} Ответьте на .anim файл.",
+ "err_not_anim_ru": "{e} Файл должен быть формата .anim",
+ "err_bad_format_ru": "{e} Неверный формат файла (нет name или cmd).",
+ "err_no_frames_ru": "{e} В файле нет кадров.",
+ "err_not_found_ru": "{e} Анимация не найдена.",
+ "err_no_cmd_ru": "{e} Укажи команду.",
+ "err_generic_ru": "{e} Ошибка:\n\n{exc}",
+ "ok_loaded_ru": "{s} Загружено: {name}\nКоманда: .anim {cmd}",
+ "ok_deleted_ru": "{s} Удалено.",
+ "list_header_ru": "Анимации:
\n\n",
+ "list_row_ru": "• {cmd} — {name} ({n} кадров)\n",
+ "list_footer_ru": "
",
+ "list_empty_ru": "{e} Нет анимаций."
+ },
+ "has_on_load": false,
+ "has_on_unload": false,
+ "class_cmd_names": {}
+ },
"fiksofficial/python-modules/tagall2.0.py": {
"name": "TagAllMod",
"description": "TagAll 2.0 — smart mention of chat participants: .tagall {all/admins/online/active} {text}",
@@ -8310,6 +8443,117 @@
"has_on_unload": true,
"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": {
"name": "BSR",
"description": "Module for finding nearby game rooms in BrawlStars.",
@@ -84951,7 +85195,7 @@
}
},
"meta": {
- "total_modules": 1057,
- "generated_at": "2026-04-16T02:02:10.912643"
+ "total_modules": 1060,
+ "generated_at": "2026-04-18T01:49:43.246930"
}
}
\ No newline at end of file