Compare commits

..

2 Commits

Author SHA1 Message Date
github-actions[bot]
2eab67bbe4 Updated modules.json after parse 2026-04-13 02:02:20 2026-04-13 02:02:20 +00:00
github-actions[bot]
840aa567ea Added and updated repositories 2026-04-13 02:01:51 2026-04-13 02:01:51 +00:00
8 changed files with 65 additions and 58 deletions

View File

@@ -210,6 +210,7 @@ jobs:
notify_diffs: notify_diffs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: | if: |
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true) (github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true)
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@@ -860,7 +860,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['noquery'].format(prefix=f'<code>@{self.inline.bot_username} ')}</code></b>", "message": f"{self.ui.emoji('error')} <b>{self.strings['prompt']}</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"
} }
@@ -878,7 +878,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=f'<code>{utils.escape_html(query)}</code>')}</b>", "message": f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=utils.escape_html(query))}</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"
} }
@@ -929,17 +929,17 @@ 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=f'<code>{self.get_prefix()}')}</code></b>") return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['noquery'].format(prefix=self.get_prefix())}</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=f'<code>{utils.escape_html(query)}</code>')}</b>") message = await utils.answer(message, f"{self.ui.emoji('search')} <b>{self.strings['search'].format(query=utils.escape_html(query))}</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=f'<code>{utils.escape_html(query)}</code>')}</b>") return await utils.answer(message, f"{self.ui.emoji('error')} <b>{self.strings['notfound'].format(query=utils.escape_html(query))}</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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -381,7 +381,7 @@ class Limoka(loader.Module):
"404": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Not found by query: <i>{query}</i></b></blockquote>", "404": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Not found by query: <i>{query}</i></b></blockquote>",
"noargs": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>No args</b></blockquote>", "noargs": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>No args</b></blockquote>",
"?": "<blockquote><tg-emoji emoji-id=5951895176908640647>🔎</tg-emoji> Request too short / not found</blockquote>", "?": "<blockquote><tg-emoji emoji-id=5951895176908640647>🔎</tg-emoji> Request too short / not found</blockquote>",
"no_info": "No information", "no_info": "<blockquote>No information</blockquote>",
"facts": [ "facts": [
"<blockquote><tg-emoji emoji-id=5472193350520021357>🛡</tg-emoji> The limoka catalog is carefully moderated!</blockquote>", "<blockquote><tg-emoji emoji-id=5472193350520021357>🛡</tg-emoji> The limoka catalog is carefully moderated!</blockquote>",
"<blockquote><tg-emoji emoji-id=5940434198413184876>🚀</tg-emoji> Limoka performance allows you to search for modules quickly!</blockquote>", "<blockquote><tg-emoji emoji-id=5940434198413184876>🚀</tg-emoji> Limoka performance allows you to search for modules quickly!</blockquote>",
@@ -493,7 +493,7 @@ class Limoka(loader.Module):
"404": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Не найдено по запросу: <i>{query}</i></b></blockquote>", "404": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Не найдено по запросу: <i>{query}</i></b></blockquote>",
"noargs": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Нет аргументов</b></blockquote>", "noargs": "<blockquote><tg-emoji emoji-id=5210952531676504517>❌</tg-emoji> <b>Нет аргументов</b></blockquote>",
"?": "<blockquote><tg-emoji emoji-id=5951895176908640647>🔎</tg-emoji> Запрос слишком короткий / не найден</blockquote>", "?": "<blockquote><tg-emoji emoji-id=5951895176908640647>🔎</tg-emoji> Запрос слишком короткий / не найден</blockquote>",
"no_info": "Нет информации", "no_info": "<blockquote>Нет информации</blockquote>",
"facts": [ "facts": [
"<blockquote><tg-emoji emoji-id=5472193350520021357>🛡</tg-emoji> Каталог Limoka тщательно модерируется!</blockquote>", "<blockquote><tg-emoji emoji-id=5472193350520021357>🛡</tg-emoji> Каталог Limoka тщательно модерируется!</blockquote>",
"<blockquote><tg-emoji emoji-id=5940434198413184876>🚀</tg-emoji> Limoka позволяет искать модули с невероятной скоростью!</blockquote>", "<blockquote><tg-emoji emoji-id=5940434198413184876>🚀</tg-emoji> Limoka позволяет искать модули с невероятной скоростью!</blockquote>",

View File

@@ -1,8 +1,9 @@
#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, 1, 2) __version__ = (1, 0, 0)
import logging import logging
import aiohttp import aiohttp
@@ -16,20 +17,13 @@ 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 self.config['emoji'] return "<tg-emoji emoji-id=5276307163529092252>🔴</tg-emoji>"
else: else:
return "" return ""

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 telethon.tl.functions.users import GetFullUserRequest from herokutl.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,23 +118,21 @@ 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, client, db): async def client_ready(self):
self._client = client
self.session = aiohttp.ClientSession() self.session = aiohttp.ClientSession()
self.me = await client.get_me() self.me = await self._client.get_me()
self.full_me = await client(GetFullUserRequest(self.me)) self.full_me = await self._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: except Exception:
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):
@@ -201,18 +199,30 @@ 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 self.me.premium: if not getattr(self.me, "premium", False):
return "Нет Premium" return "Нет Premium"
until = self.full_me.full_user.premium_until # premium_until отсутствует в публичном MTProto API herokutl/Telethon —
if not until or until < time.time(): # пробуем достать его, но не падаем если поля нет
return "Премиум закончился" until = None
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 "Нет"
@@ -236,9 +246,7 @@ 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):
result = await self.client(GetStarsStatusRequest("me")) return f"{self.stars_balance:,}".replace(",", " ") if self.stars_balance else "0"
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"
@@ -253,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: except Exception:
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()
@@ -261,7 +269,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: except Exception:
return "Курс USD недоступен" return "Курс USD недоступен"
async def get_rub_to_usd(self): async def get_rub_to_usd(self):
@@ -270,7 +278,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: except Exception:
pass pass
return "Курс RUB недоступен" return "Курс RUB недоступен"
@@ -293,7 +301,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: except Exception:
return "Курс TON недоступен" return "Курс TON недоступен"
async def get_rub_to_ton(self): async def get_rub_to_ton(self):
@@ -302,7 +310,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: except Exception:
pass pass
return "Курс недоступен" return "Курс недоступен"
@@ -319,7 +327,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: except Exception:
return "Курс BTC недоступен" return "Курс BTC недоступен"
async def get_eth_to_rub(self): async def get_eth_to_rub(self):
@@ -335,7 +343,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: except Exception:
return "Курс ETH недоступен" return "Курс ETH недоступен"
async def get_stars_to_rub(self): async def get_stars_to_rub(self):
@@ -365,7 +373,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: except Exception:
return "↑ 0 GB │ ↓ 0 GB" return "↑ 0 GB │ ↓ 0 GB"
async def get_speedtest(self): async def get_speedtest(self):
@@ -397,7 +405,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: except Exception:
continue continue
return "Тест скорости недоступен" return "Тест скорости недоступен"
@@ -418,7 +426,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: except Exception:
return "Диск недоступен" return "Диск недоступен"
async def get_local_ip(self): async def get_local_ip(self):
@@ -428,7 +436,7 @@ class PlaceholdersMod(loader.Module):
ip = s.getsockname()[0] ip = s.getsockname()[0]
s.close() s.close()
return ip return ip
except: except Exception:
return "Неизвестно" return "Неизвестно"
async def get_user_hostname(self): async def get_user_hostname(self):
@@ -499,7 +507,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: except Exception:
pass pass
default = { default = {
@@ -587,7 +595,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: except Exception:
pass pass
return "Статистика недоступна" return "Статистика недоступна"
@@ -629,10 +637,14 @@ class PlaceholdersMod(loader.Module):
} }
self.cache.set(cache_key, result) self.cache.set(cache_key, result)
return result return result
except: except Exception:
pass pass
return None return None
async def on_unload(self): async def on_unload(self):
await self.session.close() utils.unregister_placeholders(self.__class__.__name__)
try:
await self.session.close()
except Exception:
pass

View File

@@ -84526,7 +84526,7 @@
"cls_doc": {}, "cls_doc": {},
"meta": { "meta": {
"pic": null, "pic": null,
"banner": null, "banner": "https://github.com/Midga3/heroku-modules/blob/main/new_module.jpg?raw=true",
"developer": "@midga3_modules" "developer": "@midga3_modules"
}, },
"commands": [], "commands": [],
@@ -84952,6 +84952,6 @@
}, },
"meta": { "meta": {
"total_modules": 1057, "total_modules": 1057,
"generated_at": "2026-04-15T01:53:44.103183" "generated_at": "2026-04-13T02:02:20.410901"
} }
} }

View File

@@ -242,12 +242,12 @@
}, },
{ {
"url": "https://github.com/Fixyres/FModules", "url": "https://github.com/Fixyres/FModules",
"tags": ["herokutrusted"], "tags": [],
"blacklist": ["FHeta.py"] "blacklist": ["FHeta.py"]
}, },
{ {
"url": "https://github.com/Midga3/Heroku-modules", "url": "https://github.com/Midga3/Heroku-modules",
"tags": ["newbie", "herokutrusted"], "tags": ["newbie"],
"blacklist": ["deletelinux.py", "bleabratanspapibobolshoyevyrychil.py"] "blacklist": ["deletelinux.py", "bleabratanspapibobolshoyevyrychil.py"]
}, },
{ {