mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-17 23:04:17 +02:00
Compare commits
2 Commits
main
...
update-sub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
850dd58628 | ||
|
|
192adeabc3 |
@@ -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()
|
||||||
|
|||||||
298
Fixyres/FModules/FSecurity.py
Normal file
298
Fixyres/FModules/FSecurity.py
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
__version__ = (1, 0, 0)
|
||||||
|
|
||||||
|
# meta developer: @FModules
|
||||||
|
# meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/banner.png
|
||||||
|
# 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 asyncio
|
||||||
|
import aiohttp
|
||||||
|
import html
|
||||||
|
import sys
|
||||||
|
import uuid
|
||||||
|
import copy
|
||||||
|
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": "en",
|
||||||
|
"unavailable": "AI module check is unavailable.",
|
||||||
|
"suspicious": "AI interrupted installation of a suspicious module, reason:",
|
||||||
|
"blocked": "AI blocked module installation, reason:",
|
||||||
|
"continue": "Continue installation?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_ru = {
|
||||||
|
"lang": "ru",
|
||||||
|
"_cls_doc": "Модуль для автоматической проверки устанавливаемых модулей через ИИ.",
|
||||||
|
"unavailable": "Проверка модуля через ИИ недоступна.",
|
||||||
|
"suspicious": "ИИ прервал установку подозрительного модуля, причина:",
|
||||||
|
"blocked": "ИИ заблокировал установку модуля, причина:",
|
||||||
|
"continue": "Продолжить установку?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_ua = {
|
||||||
|
"lang": "ua",
|
||||||
|
"_cls_doc": "Модуль для автоматичної перевірки встановлюваних модулів через ШІ.",
|
||||||
|
"unavailable": "Перевірка модуля через ШІ недоступна.",
|
||||||
|
"suspicious": "ШІ перервав встановлення підозрілого модуля, причина:",
|
||||||
|
"blocked": "ШІ заблокував встановлення модуля, причина:",
|
||||||
|
"continue": "Продовжити встановлення?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_de = {
|
||||||
|
"lang": "de",
|
||||||
|
"_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?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_jp = {
|
||||||
|
"lang": "jp",
|
||||||
|
"_cls_doc": "AIでインストールされるモジュールを自動チェックするモジュール。",
|
||||||
|
"unavailable": "AIモジュールのチェックが利用できません。",
|
||||||
|
"suspicious": "AIが疑わしいモジュールのインストールを中断しました、理由:",
|
||||||
|
"blocked": "AIがモジュールのインストールをブロックしました、理由:",
|
||||||
|
"continue": "インストールを続行しますか?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_tr = {
|
||||||
|
"lang": "tr",
|
||||||
|
"_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?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_uz = {
|
||||||
|
"lang": "uz",
|
||||||
|
"_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?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_kz = {
|
||||||
|
"lang": "kz",
|
||||||
|
"_cls_doc": "Орнатылатын модульдерді ЖИ арқылы автоматты тексеретін модуль.",
|
||||||
|
"unavailable": "AI модульін тексеру қолжетімсіз.",
|
||||||
|
"suspicious": "AI күдікті модульді орнатуды тоқтатты, себебі:",
|
||||||
|
"blocked": "AI модульді орнатуды бұғаттады, себебі:",
|
||||||
|
"continue": "Орнатуды жалғастырасыз ба?"
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.tasks = {}
|
||||||
|
self.oreg = None
|
||||||
|
self.oload = None
|
||||||
|
|
||||||
|
async def client_ready(self, client, db):
|
||||||
|
self.core = self.lookup("loader")
|
||||||
|
self.modules = self.core.allmodules
|
||||||
|
self.patch()
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
self.unpatch()
|
||||||
|
|
||||||
|
async def check(self, code):
|
||||||
|
try:
|
||||||
|
form = aiohttp.FormData()
|
||||||
|
form.add_field('file', code.encode('utf-8'), filename='module.py', content_type='text/x-python')
|
||||||
|
form.add_field('lang', self.strings("lang") or "en")
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.post("https://api.fixyres.com/check", data=form, timeout=30) as resp:
|
||||||
|
if resp.status != 200:
|
||||||
|
return False
|
||||||
|
return await resp.json()
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def format(self, state, reason=""):
|
||||||
|
if state == "unavailable":
|
||||||
|
return f'<b>{self.strings("unavailable")}</b>\n<b>{self.strings("continue")}</b>'
|
||||||
|
if state == "suspicious":
|
||||||
|
return f'<b>{self.strings("suspicious")}</b>\n<blockquote expandable>{utils.escape_html(reason)}</blockquote>\n<b>{self.strings("continue")}</b>'
|
||||||
|
return f'<b>{self.strings("blocked")}</b>\n<blockquote expandable>{utils.escape_html(reason)}</blockquote>'
|
||||||
|
|
||||||
|
def buttons(self, task):
|
||||||
|
return [[
|
||||||
|
{"text": "✓", "callback": self.confirm, "args": (task, "yes")},
|
||||||
|
{"text": "✗", "callback": self.confirm, "args": (task, "no")}
|
||||||
|
]]
|
||||||
|
|
||||||
|
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>'
|
||||||
|
|
||||||
|
return await base(message, response, *a, **k)
|
||||||
|
|
||||||
|
utils.answer = answer
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
autoload = 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')
|
||||||
|
):
|
||||||
|
msg = locals['message']
|
||||||
|
fmsg = locals.get('msg')
|
||||||
|
break
|
||||||
|
if (
|
||||||
|
frame.f_code.co_name in {"_register_modules", "register_all"}
|
||||||
|
and locals.get("self") is self.modules
|
||||||
|
):
|
||||||
|
autoload = True
|
||||||
|
frame = frame.f_back
|
||||||
|
|
||||||
|
return msg, fmsg, autoload
|
||||||
|
|
||||||
|
def target_chat(self, msg=None, fmsg=None):
|
||||||
|
if msg:
|
||||||
|
with suppress(Exception):
|
||||||
|
target = copy.copy(msg)
|
||||||
|
if fmsg:
|
||||||
|
target.reply_to_msg_id = fmsg.id
|
||||||
|
elif not getattr(target, 'reply_to_msg_id', None):
|
||||||
|
target.reply_to_msg_id = target.id
|
||||||
|
return target
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def register(self, spec, name, origin="<core>", save_fs=False):
|
||||||
|
if origin != "<core>" and name != self.__module__:
|
||||||
|
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, autoload = 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 = ""
|
||||||
|
|
||||||
|
if autoload:
|
||||||
|
return await self.oreg(spec, name, origin, save_fs=save_fs)
|
||||||
|
|
||||||
|
if not msg or not target:
|
||||||
|
raise loader.LoadError("")
|
||||||
|
|
||||||
|
if msg:
|
||||||
|
with suppress(Exception):
|
||||||
|
msg.out = False
|
||||||
|
|
||||||
|
if status == "blocked":
|
||||||
|
text = self.format("blocked", reason)
|
||||||
|
raise loader.LoadError(text)
|
||||||
|
|
||||||
|
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),
|
||||||
|
message=target,
|
||||||
|
reply_markup=self.buttons(task)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not form:
|
||||||
|
raise loader.LoadError(reason)
|
||||||
|
|
||||||
|
await asyncio.wait_for(event.wait(), timeout=60.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.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()
|
||||||
BIN
Fixyres/FModules/assets/FSecurity/banner.png
Normal file
BIN
Fixyres/FModules/assets/FSecurity/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
@@ -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 ""
|
||||||
@@ -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 "Нет"
|
||||||
@@ -246,7 +236,9 @@ class PlaceholdersMod(loader.Module):
|
|||||||
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__)
|
|
||||||
try:
|
|
||||||
await self.session.close()
|
await self.session.close()
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
73
modules.json
73
modules.json
@@ -8310,6 +8310,73 @@
|
|||||||
"has_on_unload": true,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"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": "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/FSecurity/banner.png",
|
||||||
|
"developer": "@FModules"
|
||||||
|
},
|
||||||
|
"commands": [],
|
||||||
|
"new_commands": [],
|
||||||
|
"inline_handlers": [],
|
||||||
|
"strings": {
|
||||||
|
"name": "FSecurity",
|
||||||
|
"lang": "en",
|
||||||
|
"unavailable": "AI module check is unavailable.",
|
||||||
|
"suspicious": "AI interrupted installation of a suspicious module, reason:",
|
||||||
|
"blocked": "AI blocked module installation, reason:",
|
||||||
|
"continue": "Continue installation?",
|
||||||
|
"lang_ru": "ru",
|
||||||
|
"unavailable_ru": "Проверка модуля через ИИ недоступна.",
|
||||||
|
"suspicious_ru": "ИИ прервал установку подозрительного модуля, причина:",
|
||||||
|
"blocked_ru": "ИИ заблокировал установку модуля, причина:",
|
||||||
|
"continue_ru": "Продолжить установку?",
|
||||||
|
"lang_ua": "ua",
|
||||||
|
"unavailable_ua": "Перевірка модуля через ШІ недоступна.",
|
||||||
|
"suspicious_ua": "ШІ перервав встановлення підозрілого модуля, причина:",
|
||||||
|
"blocked_ua": "ШІ заблокував встановлення модуля, причина:",
|
||||||
|
"continue_ua": "Продовжити встановлення?",
|
||||||
|
"lang_de": "de",
|
||||||
|
"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?",
|
||||||
|
"lang_jp": "jp",
|
||||||
|
"unavailable_jp": "AIモジュールのチェックが利用できません。",
|
||||||
|
"suspicious_jp": "AIが疑わしいモジュールのインストールを中断しました、理由:",
|
||||||
|
"blocked_jp": "AIがモジュールのインストールをブロックしました、理由:",
|
||||||
|
"continue_jp": "インストールを続行しますか?",
|
||||||
|
"lang_tr": "tr",
|
||||||
|
"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?",
|
||||||
|
"lang_uz": "uz",
|
||||||
|
"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?",
|
||||||
|
"lang_kz": "kz",
|
||||||
|
"unavailable_kz": "AI модульін тексеру қолжетімсіз.",
|
||||||
|
"suspicious_kz": "AI күдікті модульді орнатуды тоқтатты, себебі:",
|
||||||
|
"blocked_kz": "AI модульді орнатуды бұғаттады, себебі:",
|
||||||
|
"continue_kz": "Орнатуды жалғастырасыз ба?"
|
||||||
|
},
|
||||||
|
"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.",
|
||||||
@@ -84526,7 +84593,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 +85018,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"total_modules": 1057,
|
"total_modules": 1058,
|
||||||
"generated_at": "2026-04-12T17:39:10.030299"
|
"generated_at": "2026-04-14T01:57:03.389942"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user