mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-18 15:14:18 +02:00
Merge pull request #214 from MuRuLOSE/update-submodules_02b1aa9f68911e516619089e9065b26a7592e781
Update of repositories 2026-03-11 01:22:36
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
# meta pic: https://i.postimg.cc/Hx3Zm8rB/logo.png
|
# meta pic: https://i.postimg.cc/Hx3Zm8rB/logo.png
|
||||||
# meta banner: https://te.legra.ph/file/55fa6eebae860a359ac27.jpg
|
# meta banner: https://te.legra.ph/file/55fa6eebae860a359ac27.jpg
|
||||||
|
|
||||||
__version__ = (1, 3, 2)
|
__version__ = (1, 3, 3)
|
||||||
|
|
||||||
from .. import loader, utils # type: ignore
|
from .. import loader, utils # type: ignore
|
||||||
from telethon.tl import types # type: ignore
|
from telethon.tl import types # type: ignore
|
||||||
@@ -103,70 +103,70 @@ class SendMod(loader.Module):
|
|||||||
else:
|
else:
|
||||||
await message.edit(f'{self.strings["error"]} {str(e)}')
|
await message.edit(f'{self.strings["error"]} {str(e)}')
|
||||||
|
|
||||||
|
# telegram fixed bug
|
||||||
|
# @loader.command(
|
||||||
|
# ru_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Написать сообщение в закрытую тему",
|
||||||
|
# uz_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Yopiq mavzuga xabar yozing",
|
||||||
|
# de_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Schreiben Sie eine Nachricht zu einem geschlossenen Thema",
|
||||||
|
# es_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Escribir un mensaje a un tema cerrado",
|
||||||
|
# )
|
||||||
|
# async def sendclosedtopic(self, message: Message):
|
||||||
|
# """[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Write a message to a closed topic"""
|
||||||
|
# args = utils.get_args_raw(message)
|
||||||
|
# message_text = args if args else ""
|
||||||
|
# reply = await message.get_reply_message()
|
||||||
|
|
||||||
@loader.command(
|
# media = None
|
||||||
ru_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Написать сообщение в закрытую тему",
|
# temp_file = None
|
||||||
uz_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Yopiq mavzuga xabar yozing",
|
|
||||||
de_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Schreiben Sie eine Nachricht zu einem geschlossenen Thema",
|
|
||||||
es_doc="[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Escribir un mensaje a un tema cerrado",
|
|
||||||
)
|
|
||||||
async def sendclosedtopic(self, message: Message):
|
|
||||||
"""[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Write a message to a closed topic"""
|
|
||||||
args = utils.get_args_raw(message)
|
|
||||||
message_text = args if args else ""
|
|
||||||
reply = await message.get_reply_message()
|
|
||||||
|
|
||||||
media = None
|
# if reply and reply.media:
|
||||||
temp_file = None
|
# doc = getattr(reply.media, "document", None)
|
||||||
|
|
||||||
if reply and reply.media:
|
# if doc and any(a.__class__.__name__ == "DocumentAttributeSticker" for a in doc.attributes):
|
||||||
doc = getattr(reply.media, "document", None)
|
# media = InputDocument(
|
||||||
|
# id=doc.id,
|
||||||
|
# access_hash=doc.access_hash,
|
||||||
|
# file_reference=doc.file_reference
|
||||||
|
# )
|
||||||
|
# message_text = ""
|
||||||
|
|
||||||
if doc and any(a.__class__.__name__ == "DocumentAttributeSticker" for a in doc.attributes):
|
# elif doc and doc.mime_type == "image/webp":
|
||||||
media = InputDocument(
|
# temp_file = await reply.download_media()
|
||||||
id=doc.id,
|
# media = temp_file
|
||||||
access_hash=doc.access_hash,
|
# else:
|
||||||
file_reference=doc.file_reference
|
# media = reply.media
|
||||||
)
|
# else:
|
||||||
message_text = ""
|
# media = message.media
|
||||||
|
|
||||||
elif doc and doc.mime_type == "image/webp":
|
# if message_text and "," in message_text:
|
||||||
temp_file = await reply.download_media()
|
# lat_str, long_str = message_text.split(",", 1)
|
||||||
media = temp_file
|
# try:
|
||||||
else:
|
# gps_x = float(lat_str.strip())
|
||||||
media = reply.media
|
# gps_y = float(long_str.strip())
|
||||||
else:
|
# if -90 <= gps_x <= 90 and -180 <= gps_y <= 180:
|
||||||
media = message.media
|
# geo_point = types.InputGeoPoint(lat=gps_x, long=gps_y)
|
||||||
|
# media = types.InputMediaGeoPoint(geo_point)
|
||||||
|
# message_text = ""
|
||||||
|
# except ValueError:
|
||||||
|
# pass
|
||||||
|
|
||||||
if message_text and "," in message_text:
|
# if not message_text and not media:
|
||||||
lat_str, long_str = message_text.split(",", 1)
|
# await utils.answer(message, self.strings["error_send_2"])
|
||||||
try:
|
# return
|
||||||
gps_x = float(lat_str.strip())
|
|
||||||
gps_y = float(long_str.strip())
|
|
||||||
if -90 <= gps_x <= 90 and -180 <= gps_y <= 180:
|
|
||||||
geo_point = types.InputGeoPoint(lat=gps_x, long=gps_y)
|
|
||||||
media = types.InputMediaGeoPoint(geo_point)
|
|
||||||
message_text = ""
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not message_text and not media:
|
# await message.delete()
|
||||||
await utils.answer(message, self.strings["error_send_2"])
|
# await message.reply(
|
||||||
return
|
# message_text,
|
||||||
|
# file=media if media else None,
|
||||||
|
# parse_mode="html"
|
||||||
|
# )
|
||||||
|
|
||||||
await message.delete()
|
# if temp_file:
|
||||||
await message.reply(
|
# import os
|
||||||
message_text,
|
# try:
|
||||||
file=media if media else None,
|
# os.remove(temp_file)
|
||||||
parse_mode="html"
|
# except:
|
||||||
)
|
# pass
|
||||||
|
|
||||||
if temp_file:
|
|
||||||
import os
|
|
||||||
try:
|
|
||||||
os.remove(temp_file)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="[@UserName] [text or replay] - Написать сообщение в личные сообщения",
|
ru_doc="[@UserName] [text or replay] - Написать сообщение в личные сообщения",
|
||||||
|
|||||||
@@ -26,8 +26,10 @@
|
|||||||
# scope: Api AccountData 0.0.1
|
# scope: Api AccountData 0.0.1
|
||||||
# ---------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
@@ -35,6 +37,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class AccountData(loader.Module):
|
class AccountData(loader.Module):
|
||||||
"""Find out the approximate date of registration of the telegram account"""
|
"""Find out the approximate date of registration of the telegram account"""
|
||||||
@@ -45,9 +48,21 @@ class AccountData(loader.Module):
|
|||||||
"api_token",
|
"api_token",
|
||||||
"7518491974:1ea2284eec9dc40a9838cfbcb48a2b36",
|
"7518491974:1ea2284eec9dc40a9838cfbcb48a2b36",
|
||||||
"API token for datereg.pro",
|
"API token for datereg.pro",
|
||||||
validator=loader.validators.String(),
|
validator=loader.validators.Hidden(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
strings = {
|
strings = {
|
||||||
"name": "AccountData",
|
"name": "AccountData",
|
||||||
@@ -64,15 +79,16 @@ class AccountData(loader.Module):
|
|||||||
"no_reply": "<emoji document_id=6030512294109122096>💬</emoji> Вы не ответили на сообщение пользователя",
|
"no_reply": "<emoji document_id=6030512294109122096>💬</emoji> Вы не ответили на сообщение пользователя",
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_creation_date(self, user_id: int) -> str:
|
async def get_creation_date(self, user_id: int) -> dict:
|
||||||
api_token = self.config.get("api_token", "")
|
api_token = self.config["api_token"]
|
||||||
if not api_token:
|
if not api_token:
|
||||||
return {"error": "API token not configured"}
|
return {"error": "API token not configured"}
|
||||||
|
|
||||||
url = "https://api.datereg.pro/api/v1/users/getCreationDateFast"
|
url = "https://api.datereg.pro/api/v1/users/getCreationDateFast"
|
||||||
params = {"token": api_token, "user_id": user_id}
|
params = {"token": api_token, "user_id": user_id}
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
|
try:
|
||||||
async with session.get(url, params=params) as response:
|
async with session.get(url, params=params) as response:
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
json_response = await response.json()
|
json_response = await response.json()
|
||||||
@@ -80,11 +96,15 @@ class AccountData(loader.Module):
|
|||||||
return {
|
return {
|
||||||
"creation_date": json_response["creation_date"],
|
"creation_date": json_response["creation_date"],
|
||||||
"accuracy_percent": json_response["accuracy_percent"],
|
"accuracy_percent": json_response["accuracy_percent"],
|
||||||
} # type: ignore
|
}
|
||||||
else:
|
else:
|
||||||
return {"error": json_response["error"]["message"]} # type: ignore
|
return {"error": json_response["error"]["message"]}
|
||||||
else:
|
else:
|
||||||
return {"error": f"HTTP {response.status}"} # type: ignore
|
return {"error": f"HTTP {response.status}"}
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return {"error": "Request timed out"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": str(e)}
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Узнать примерную дату регистрации Telergam-аккаунта",
|
ru_doc="Узнать примерную дату регистрации Telergam-аккаунта",
|
||||||
@@ -100,9 +120,9 @@ class AccountData(loader.Module):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
month, year = map(int, result['creation_date'].split('.'))
|
month, year = map(int, result["creation_date"].split("."))
|
||||||
date_object = datetime(year, month, 1)
|
date_object = datetime(year, month, 1)
|
||||||
formatted = date_object.strftime('%B %Y')
|
formatted = date_object.strftime("%B %Y")
|
||||||
|
|
||||||
await utils.answer(
|
await utils.answer(
|
||||||
message,
|
message,
|
||||||
|
|||||||
@@ -45,20 +45,29 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
BASE_API_URL = "https://aniliberty.top/api/v1"
|
BASE_API_URL = "https://aniliberty.top/api/v1"
|
||||||
|
|
||||||
|
|
||||||
# Датаклассы для парсинга и хранения json
|
# Датаклассы для парсинга и хранения json
|
||||||
@dataclass
|
@dataclass
|
||||||
class Genre:
|
class Genre:
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Name:
|
class Name:
|
||||||
main: str
|
main: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Type:
|
class Type:
|
||||||
description: str
|
description: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Poster:
|
class Poster:
|
||||||
preview: str
|
preview: str
|
||||||
thumbnail: str
|
thumbnail: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ReleaseInfo:
|
class ReleaseInfo:
|
||||||
id: int
|
id: int
|
||||||
@@ -71,6 +80,7 @@ class ReleaseInfo:
|
|||||||
alias: str
|
alias: str
|
||||||
poster: Poster
|
poster: Poster
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class AniLibertyMod(loader.Module):
|
class AniLibertyMod(loader.Module):
|
||||||
"""Ищет и возвращает случайное аниме из базы Aniliberty"""
|
"""Ищет и возвращает случайное аниме из базы Aniliberty"""
|
||||||
@@ -92,9 +102,25 @@ class AniLibertyMod(loader.Module):
|
|||||||
"favorite": "<b>Избранное <3</b>:", # < == <
|
"favorite": "<b>Избранное <3</b>:", # < == <
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
async def search_title(self, query):
|
async def search_title(self, query):
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(f'{BASE_API_URL}/app/search/releases?query={query}&include=id%2Cname.main%2Cis_ongoing%2Ctype.description%2Cdescription%2Cadded_in_users_favorites%2Calias%2Cposter.preview%2Cposter.thumbnail') as resp:
|
async with session.get(
|
||||||
|
f"{BASE_API_URL}/app/search/releases?query={query}&include=id%2Cname.main%2Cis_ongoing%2Ctype.description%2Cdescription%2Cadded_in_users_favorites%2Calias%2Cposter.preview%2Cposter.thumbnail"
|
||||||
|
) as resp:
|
||||||
json_answer = await resp.json()
|
json_answer = await resp.json()
|
||||||
results = []
|
results = []
|
||||||
for i in json_answer:
|
for i in json_answer:
|
||||||
@@ -103,8 +129,10 @@ class AniLibertyMod(loader.Module):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
async def get_title(self, release_id):
|
async def get_title(self, release_id):
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(f'{BASE_API_URL}/anime/releases/{release_id}?include=id%2Cgenres.name%2Cname.main%2Cis_ongoing%2Ctype.description%2Cdescription%2Cadded_in_users_favorites%2Calias%2Cposter.preview%2Cposter.thumbnail') as resp:
|
async with session.get(
|
||||||
|
f"{BASE_API_URL}/anime/releases/{release_id}?include=id%2Cgenres.name%2Cname.main%2Cis_ongoing%2Ctype.description%2Cdescription%2Cadded_in_users_favorites%2Calias%2Cposter.preview%2Cposter.thumbnail"
|
||||||
|
) as resp:
|
||||||
try:
|
try:
|
||||||
json_answer = await resp.json()
|
json_answer = await resp.json()
|
||||||
data = from_dict(data_class=ReleaseInfo, data=json_answer)
|
data = from_dict(data_class=ReleaseInfo, data=json_answer)
|
||||||
@@ -113,13 +141,12 @@ class AniLibertyMod(loader.Module):
|
|||||||
logger.error("Ошибка парсинга JSON!")
|
logger.error("Ошибка парсинга JSON!")
|
||||||
|
|
||||||
async def get_random_title(self):
|
async def get_random_title(self):
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(f'{BASE_API_URL}/anime/releases/random?limit=1&include=id') as resp:
|
async with session.get(
|
||||||
|
f"{BASE_API_URL}/anime/releases/random?limit=1&include=id"
|
||||||
|
) as resp:
|
||||||
randid = await resp.json()
|
randid = await resp.json()
|
||||||
"""
|
data = await self.get_title(randid[0]["id"])
|
||||||
Приходится запрашивать по второму кругу, т.к. API в рандомных релизах не отдает жанры, даже если попросить через include
|
|
||||||
"""
|
|
||||||
data = await self.get_title(randid[0]['id'])
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
@@ -130,17 +157,18 @@ class AniLibertyMod(loader.Module):
|
|||||||
anime_release = await self.get_random_title()
|
anime_release = await self.get_random_title()
|
||||||
genres_str = ""
|
genres_str = ""
|
||||||
for genre in anime_release.genres[:-1]:
|
for genre in anime_release.genres[:-1]:
|
||||||
genres_str += f'{genre.name}, '
|
genres_str += f"{genre.name}, "
|
||||||
genres_str += anime_release.genres[-1].name
|
genres_str += anime_release.genres[-1].name
|
||||||
|
|
||||||
|
|
||||||
text = f"{anime_release.name.main} \n"
|
text = f"{anime_release.name.main} \n"
|
||||||
text += f"{self.strings['ongoing']} {'Да' if anime_release.is_ongoing else 'Нет'}\n\n"
|
text += f"{self.strings['ongoing']} {'Да' if anime_release.is_ongoing else 'Нет'}\n\n"
|
||||||
text += f"{self.strings['type']} {anime_release.type.description}\n"
|
text += f"{self.strings['type']} {anime_release.type.description}\n"
|
||||||
text += f"{self.strings['genres']} {genres_str}\n\n"
|
text += f"{self.strings['genres']} {genres_str}\n\n"
|
||||||
|
|
||||||
text += f"<code>{anime_release.description}</code>\n\n"
|
text += f"<code>{anime_release.description}</code>\n\n"
|
||||||
text += f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
|
text += (
|
||||||
|
f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
|
||||||
|
)
|
||||||
|
|
||||||
kb = [
|
kb = [
|
||||||
[
|
[
|
||||||
@@ -182,11 +210,11 @@ class AniLibertyMod(loader.Module):
|
|||||||
release_genres = await self.get_title(anime_release.id)
|
release_genres = await self.get_title(anime_release.id)
|
||||||
genres_str = ""
|
genres_str = ""
|
||||||
for genre in release_genres.genres[:-1]:
|
for genre in release_genres.genres[:-1]:
|
||||||
genres_str += f'{genre.name}, '
|
genres_str += f"{genre.name}, "
|
||||||
genres_str += release_genres.genres[-1].name
|
genres_str += release_genres.genres[-1].name
|
||||||
release_text = (
|
release_text = (
|
||||||
f"{anime_release.name.main}\n"
|
f"{anime_release.name.main}\n"
|
||||||
f"{self.strings['ongoing']} {"Да" if anime_release.is_ongoing else "Нет"}\n\n"
|
f"{self.strings['ongoing']} {'Да' if anime_release.is_ongoing else 'Нет'}\n\n"
|
||||||
f"{self.strings['type']} {anime_release.type.description}\n"
|
f"{self.strings['type']} {anime_release.type.description}\n"
|
||||||
f"{self.strings['genres']} {genres_str}\n\n"
|
f"{self.strings['genres']} {genres_str}\n\n"
|
||||||
f"<code>{anime_release.description}</code>\n\n"
|
f"<code>{anime_release.description}</code>\n\n"
|
||||||
@@ -214,16 +242,18 @@ class AniLibertyMod(loader.Module):
|
|||||||
anime_release = await self.get_random_title()
|
anime_release = await self.get_random_title()
|
||||||
genres_str = ""
|
genres_str = ""
|
||||||
for genre in anime_release.genres[:-1]:
|
for genre in anime_release.genres[:-1]:
|
||||||
genres_str += f'{genre.name}, '
|
genres_str += f"{genre.name}, "
|
||||||
genres_str += anime_release.genres[-1].name
|
genres_str += anime_release.genres[-1].name
|
||||||
|
|
||||||
text = f"{anime_release.name.main} \n"
|
text = f"{anime_release.name.main} \n"
|
||||||
text += f"{self.strings['ongoing']} {"Да" if anime_release.is_ongoing else "Нет"}\n\n"
|
text += f"{self.strings['ongoing']} {'Да' if anime_release.is_ongoing else 'Нет'}\n\n"
|
||||||
text += f"{self.strings['type']} {anime_release.type.description}\n"
|
text += f"{self.strings['type']} {anime_release.type.description}\n"
|
||||||
text += f"{self.strings['genres']} {genres_str}\n\n"
|
text += f"{self.strings['genres']} {genres_str}\n\n"
|
||||||
|
|
||||||
text += f"<code>{anime_release.description}</code>\n\n"
|
text += f"<code>{anime_release.description}</code>\n\n"
|
||||||
text += f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
|
text += (
|
||||||
|
f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
|
||||||
|
)
|
||||||
|
|
||||||
kb = [
|
kb = [
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
# ---------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class AnimeQuotesMod(loader.Module):
|
class AnimeQuotesMod(loader.Module):
|
||||||
"""A module for sending random quotes from anime"""
|
"""A module for sending random quotes from anime"""
|
||||||
@@ -58,6 +60,20 @@ class AnimeQuotesMod(loader.Module):
|
|||||||
"error": "<b>Не удалось получить цитату. Попробуйте позже!</b>",
|
"error": "<b>Не удалось получить цитату. Попробуйте позже!</b>",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Получить случайную цитату из аниме",
|
ru_doc="Получить случайную цитату из аниме",
|
||||||
en_doc="Get a random quote from the anime",
|
en_doc="Get a random quote from the anime",
|
||||||
@@ -66,7 +82,7 @@ class AnimeQuotesMod(loader.Module):
|
|||||||
url = "https://api.animechan.io/v1/quotes/random"
|
url = "https://api.animechan.io/v1/quotes/random"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
@@ -75,10 +91,10 @@ class AnimeQuotesMod(loader.Module):
|
|||||||
character_name = data["data"]["character"]["name"]
|
character_name = data["data"]["character"]["name"]
|
||||||
anime_name = data["data"]["anime"]["name"]
|
anime_name = data["data"]["anime"]["name"]
|
||||||
|
|
||||||
quote = self.strings["quote_template"].format(
|
quote = self.strings("quote_template").format(
|
||||||
quote=quote_content, character=character_name, anime=anime_name
|
quote=quote_content, character=character_name, anime=anime_name
|
||||||
)
|
)
|
||||||
await utils.answer(message, quote)
|
await utils.answer(message, quote)
|
||||||
|
|
||||||
except aiohttp.ClientError:
|
except aiohttp.ClientError:
|
||||||
await utils.answer(message, self.strings["error"])
|
await utils.answer(message, self.strings("error"))
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import aiohttp
|
|||||||
import aiofiles
|
import aiofiles
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from .. import loader, utils
|
from .. import loader, utils
|
||||||
from telethon.types import MessageMediaDocument
|
from telethon.types import MessageMediaDocument
|
||||||
@@ -53,19 +54,33 @@ class CodeShareMod(loader.Module):
|
|||||||
"link_ready": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>",
|
"link_ready": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>",
|
||||||
}
|
}
|
||||||
|
|
||||||
async def upload_to_kmi(self, content: str) -> str:
|
def __init__(self):
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
|
async def upload_to_kmi(self, content: str) -> Optional[str]:
|
||||||
url = "https://kmi.aeza.net"
|
url = "https://kmi.aeza.net"
|
||||||
data = aiohttp.FormData()
|
data = aiohttp.FormData()
|
||||||
data.add_field("kmi", content)
|
data.add_field("kmi", content)
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.post(url, data=data) as response:
|
async with session.post(url, data=data) as response:
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
link = await response.text()
|
link = await response.text()
|
||||||
return link
|
return link
|
||||||
else:
|
else:
|
||||||
logger.error(f"Error occurred! Status code: {response.status}")
|
logger.error(f"Error occurred! Status code: {response.status}")
|
||||||
return
|
return None
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Загрузка кода на сайт",
|
ru_doc="Загрузка кода на сайт",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
# ---------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class CryptoCurrencyMod(loader.Module):
|
class CryptoCurrencyMod(loader.Module):
|
||||||
"""Module for displaying current cryptocurrency exchange rates."""
|
"""Module for displaying current cryptocurrency exchange rates."""
|
||||||
@@ -49,9 +51,23 @@ class CryptoCurrencyMod(loader.Module):
|
|||||||
"coin_not_found": "Криптовалюта '{query}' не найдена.",
|
"coin_not_found": "Криптовалюта '{query}' не найдена.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
async def fetch_json(self, url):
|
async def fetch_json(self, url):
|
||||||
"""Fetch JSON data from a given URL."""
|
"""Fetch JSON data from a given URL."""
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return await response.json()
|
return await response.json()
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class FolderAutoReadMod(loader.Module):
|
|||||||
"wrong_args": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Wrong arguments!</b> Usage: .addfolder/delfolder FolderName\n\n<i>Tip: If you trying to delete the folder from the tracking list, double-check that it really still tracking using .listfolders</i>",
|
"wrong_args": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Wrong arguments!</b> Usage: .addfolder/delfolder FolderName\n\n<i>Tip: If you trying to delete the folder from the tracking list, double-check that it really still tracking using .listfolders</i>",
|
||||||
"listfolders": "<emoji document_id=5278227821364275264>📁</emoji> <b>List of tracked folders:</b>\n",
|
"listfolders": "<emoji document_id=5278227821364275264>📁</emoji> <b>List of tracked folders:</b>\n",
|
||||||
"delfolder": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Folder is successfully deleted from the tracking list!</b>",
|
"delfolder": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Folder is successfully deleted from the tracking list!</b>",
|
||||||
"addfolder": "<emoji document_id=5278227821364275264>📁</emoji> <b>Folder is successfully added to the tracking list!</b>"
|
"addfolder": "<emoji document_id=5278227821364275264>📁</emoji> <b>Folder is successfully added to the tracking list!</b>",
|
||||||
}
|
}
|
||||||
|
|
||||||
strings_ru = {
|
strings_ru = {
|
||||||
@@ -59,79 +59,96 @@ class FolderAutoReadMod(loader.Module):
|
|||||||
"wrong_args": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Неверные аргументы!</b> Использование: .addfolder/delfolder НазваниеПапки\n\n<i>Совет: Если вы пытаетесь удалить папку из списка отслеживания, проверьте, что она вообще отслеживается, используя .listfolders</i>",
|
"wrong_args": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Неверные аргументы!</b> Использование: .addfolder/delfolder НазваниеПапки\n\n<i>Совет: Если вы пытаетесь удалить папку из списка отслеживания, проверьте, что она вообще отслеживается, используя .listfolders</i>",
|
||||||
"listfolders": "<emoji document_id=5278227821364275264>📁</emoji> <b>Список отслеживаемых папок:</b>\n",
|
"listfolders": "<emoji document_id=5278227821364275264>📁</emoji> <b>Список отслеживаемых папок:</b>\n",
|
||||||
"delfolder": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Папка успешно удалена из листа отслеживания!</b>",
|
"delfolder": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Папка успешно удалена из листа отслеживания!</b>",
|
||||||
"addfolder": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>"
|
"addfolder": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.tracked_folders = []
|
self.tracked_folders = []
|
||||||
|
|
||||||
async def client_ready(self, client, db):
|
async def client_ready(self, client, db):
|
||||||
self.tracked_folders = self.get("tracked_folders", [])
|
self.tracked_folders = self.pointer("tracked_folders", [])
|
||||||
|
|
||||||
async def on_unload(self):
|
async def _read_peers(self, peers):
|
||||||
self.tracked_folders = []
|
for peer in peers:
|
||||||
self.set("tracked_folders", [])
|
try:
|
||||||
|
await self._client(functions.messages.ReadMentionsRequest(peer=peer))
|
||||||
|
await self._client(functions.messages.ReadReactionsRequest(peer=peer))
|
||||||
|
if isinstance(peer, InputPeerChannel):
|
||||||
|
await self._client(
|
||||||
|
functions.channels.ReadHistoryRequest(channel=peer, max_id=0)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self._client(
|
||||||
|
functions.messages.ReadHistoryRequest(peer=peer, max_id=0)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Failed to read peer {peer}: {e}")
|
||||||
|
|
||||||
@loader.loop(interval=60, autostart=True)
|
@loader.loop(interval=60, autostart=True)
|
||||||
async def read_chats_in_folders(self):
|
async def read_chats_in_folders(self):
|
||||||
if self.tracked_folders:
|
if self.tracked_folders:
|
||||||
all_folders = await self._client(functions.messages.GetDialogFiltersRequest())
|
all_folders = await self._client(
|
||||||
for i in range(len(self.tracked_folders)):
|
functions.messages.GetDialogFiltersRequest()
|
||||||
match = next(
|
|
||||||
(f for f in all_folders.filters
|
|
||||||
if isinstance(f, DialogFilter) and f.title.text == self.tracked_folders[i]),
|
|
||||||
None
|
|
||||||
)
|
)
|
||||||
for peer in match.pinned_peers:
|
for folder_name in self.tracked_folders:
|
||||||
await self._client(functions.messages.ReadMentionsRequest(peer=peer))
|
match = next(
|
||||||
await self._client(functions.messages.ReadReactionsRequest(peer=peer))
|
(
|
||||||
if isinstance(peer, InputPeerChannel):
|
f
|
||||||
await self._client(functions.channels.ReadHistoryRequest(channel=peer, max_id=0))
|
for f in all_folders.filters
|
||||||
else:
|
if isinstance(f, DialogFilter) and f.title.text == folder_name
|
||||||
await self._client(functions.messages.ReadHistoryRequest(peer=peer, max_id=0))
|
),
|
||||||
for peer in match.include_peers:
|
None,
|
||||||
await self._client(functions.messages.ReadMentionsRequest(peer=peer))
|
)
|
||||||
await self._client(functions.messages.ReadReactionsRequest(peer=peer))
|
if match is None:
|
||||||
if isinstance(peer, InputPeerChannel):
|
continue
|
||||||
await self._client(functions.channels.ReadHistoryRequest(channel=peer, max_id=0))
|
await self._read_peers(match.pinned_peers)
|
||||||
else:
|
await self._read_peers(match.include_peers)
|
||||||
await self._client(functions.messages.ReadHistoryRequest(peer=peer, max_id=0))
|
|
||||||
|
|
||||||
@loader.command()
|
@loader.command(
|
||||||
|
ru_doc="Добавить папку в список отслеживания",
|
||||||
|
en_doc="Add folder to the tracking list",
|
||||||
|
)
|
||||||
async def addfolder(self, message):
|
async def addfolder(self, message):
|
||||||
arg = utils.get_args_raw(message)
|
arg = utils.get_args_raw(message)
|
||||||
if arg:
|
if arg:
|
||||||
all_folders = await self._client(functions.messages.GetDialogFiltersRequest())
|
all_folders = await self._client(
|
||||||
match = next(
|
functions.messages.GetDialogFiltersRequest()
|
||||||
(f for f in all_folders.filters
|
|
||||||
if isinstance(f, DialogFilter) and f.title.text == arg),
|
|
||||||
None
|
|
||||||
)
|
)
|
||||||
if match and match not in self.tracked_folders:
|
match = next(
|
||||||
|
(
|
||||||
|
f
|
||||||
|
for f in all_folders.filters
|
||||||
|
if isinstance(f, DialogFilter) and f.title.text == arg
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if match and arg not in self.tracked_folders:
|
||||||
self.tracked_folders.append(arg)
|
self.tracked_folders.append(arg)
|
||||||
self.set("tracked_folders", self.tracked_folders)
|
await utils.answer(message, self.strings("addfolder"))
|
||||||
await utils.answer(message, self.strings['addfolder'])
|
|
||||||
else:
|
else:
|
||||||
await utils.answer(message, self.strings["not_exists_or_already_added"])
|
await utils.answer(message, self.strings("not_exists_or_already_added"))
|
||||||
|
else:
|
||||||
|
await utils.answer(message, self.strings("wrong_args"))
|
||||||
|
|
||||||
@loader.command()
|
@loader.command(
|
||||||
|
ru_doc="Удалить папку из списка отслеживания",
|
||||||
|
en_doc="Delete folder from the tracking list",
|
||||||
|
)
|
||||||
async def delfolder(self, message):
|
async def delfolder(self, message):
|
||||||
arg = utils.get_args_raw(message)
|
arg = utils.get_args_raw(message)
|
||||||
if arg and arg in self.tracked_folders:
|
if arg and arg in self.tracked_folders:
|
||||||
self.tracked_folders.remove(arg)
|
self.tracked_folders.remove(arg)
|
||||||
self.set("tracked_folders", self.tracked_folders)
|
await utils.answer(message, self.strings("delfolder"))
|
||||||
await utils.answer(message, self.strings['delfolder'])
|
|
||||||
else:
|
else:
|
||||||
await utils.answer(message, self.strings["wrong_args"])
|
await utils.answer(message, self.strings("wrong_args"))
|
||||||
|
|
||||||
@loader.command()
|
@loader.command(
|
||||||
|
ru_doc="Список отслеживаемых папок",
|
||||||
|
en_doc="List tracked folders",
|
||||||
|
)
|
||||||
async def listfolders(self, message):
|
async def listfolders(self, message):
|
||||||
await utils.answer(message, self.strings["listfolders"] + "\n".join(
|
await utils.answer(
|
||||||
f"• {folder}" for folder in self.tracked_folders
|
message,
|
||||||
))
|
self.strings("listfolders")
|
||||||
|
+ "\n".join(f"• {folder}" for folder in self.tracked_folders),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -465,6 +465,7 @@ class AutoFarmbotMod(loader.Module):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.client = client
|
self.client = client
|
||||||
|
self.tg_id = (await client.get_me()).id
|
||||||
self.db = 0
|
self.db = 0
|
||||||
self.redis = await aioredis.from_url(
|
self.redis = await aioredis.from_url(
|
||||||
self.config["config_redis_cloud_link"],
|
self.config["config_redis_cloud_link"],
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
# ---------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import re
|
import re
|
||||||
@@ -37,6 +38,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class face(loader.Module):
|
class face(loader.Module):
|
||||||
"""random face"""
|
"""random face"""
|
||||||
@@ -62,6 +64,20 @@ class face(loader.Module):
|
|||||||
"error": "Произошла ошибка!",
|
"error": "Произошла ошибка!",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Рандом kaomoji",
|
ru_doc="Рандом kaomoji",
|
||||||
en_doc="Random kaomoji",
|
en_doc="Random kaomoji",
|
||||||
@@ -71,14 +87,14 @@ class face(loader.Module):
|
|||||||
|
|
||||||
url = "https://files.archquise.ru/kaomoji.txt"
|
url = "https://files.archquise.ru/kaomoji.txt"
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
data = await response.text()
|
data = await response.text()
|
||||||
kaomoji_list = [s.strip() for s in re.split(r'[\t\r\n]+', data) if s.strip()]
|
kaomoji_list = [
|
||||||
|
s.strip() for s in re.split(r"[\t\r\n]+", data) if s.strip()
|
||||||
|
]
|
||||||
kaomoji = random.choice(kaomoji_list)
|
kaomoji = random.choice(kaomoji_list)
|
||||||
await utils.answer(
|
await utils.answer(message, self.strings("random_face").format(kaomoji))
|
||||||
message, self.strings("random_face").format(kaomoji)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await utils.answer(message, self.strings("error"))
|
await utils.answer(message, self.strings("error"))
|
||||||
|
|||||||
@@ -676,7 +676,7 @@ class GlobalRestrict(loader.Module):
|
|||||||
utils.get_entity_url(user),
|
utils.get_entity_url(user),
|
||||||
utils.escape_html(get_full_name(user)),
|
utils.escape_html(get_full_name(user)),
|
||||||
(
|
(
|
||||||
self.strings("unmutes_in_n_chats").format(counter)
|
self.strings("unmute_in_n_chats").format(counter)
|
||||||
if silent
|
if silent
|
||||||
else chats
|
else chats
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HostApi:
|
class HostApi:
|
||||||
"""
|
"""
|
||||||
A class for interacting with a Host API.
|
A class for interacting with a Host API.
|
||||||
@@ -58,8 +59,11 @@ class HostApi:
|
|||||||
Returns:
|
Returns:
|
||||||
dict: The API response as a dictionary.
|
dict: The API response as a dictionary.
|
||||||
"""
|
"""
|
||||||
url = "http://api.hikka.host" + path
|
url = "https://api.hikka.host" + path
|
||||||
async with aiohttp.ClientSession(trust_env=True) as session:
|
async with aiohttp.ClientSession(
|
||||||
|
trust_env=True,
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15),
|
||||||
|
) as session:
|
||||||
async with session.request(
|
async with session.request(
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
@@ -67,7 +71,6 @@ class HostApi:
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"token": self.token,
|
"token": self.token,
|
||||||
},
|
},
|
||||||
ssl=False,
|
|
||||||
) as response:
|
) as response:
|
||||||
return await response.json()
|
return await response.json()
|
||||||
|
|
||||||
@@ -290,14 +293,20 @@ class HikkahostMod(loader.Module):
|
|||||||
token = self.config["token"]
|
token = self.config["token"]
|
||||||
user_id = token.split(":")[0]
|
user_id = token.split(":")[0]
|
||||||
api = HostApi(token)
|
api = HostApi(token)
|
||||||
data = await api.logs(user_id, token)
|
data = await api.logs(user_id)
|
||||||
|
|
||||||
files_log = data["logs"]
|
files_log = data["logs"]
|
||||||
|
|
||||||
with open("log.txt", "w") as log_file:
|
import tempfile
|
||||||
json.dump(files_log, log_file)
|
import os
|
||||||
|
|
||||||
await utils.answer_file(message, "log.txt", self.strings("logs"))
|
fd, tmp_path = tempfile.mkstemp(suffix=".txt", prefix="hikkahost_log_")
|
||||||
|
try:
|
||||||
|
with os.fdopen(fd, "w") as log_file:
|
||||||
|
json.dump(files_log, log_file)
|
||||||
|
await utils.answer_file(message, tmp_path, self.strings("logs"))
|
||||||
|
finally:
|
||||||
|
os.unlink(tmp_path)
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Рестарт HikkaHost",
|
ru_doc="Рестарт HikkaHost",
|
||||||
@@ -314,4 +323,4 @@ class HikkahostMod(loader.Module):
|
|||||||
user_id = token.split(":")[0]
|
user_id = token.split(":")[0]
|
||||||
api = HostApi(token)
|
api = HostApi(token)
|
||||||
|
|
||||||
await api.action(user_id, token)
|
await api.action(user_id)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
from textwrap import wrap
|
from textwrap import wrap
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
@@ -38,6 +39,7 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class JacquesMod(loader.Module):
|
class JacquesMod(loader.Module):
|
||||||
"""Жаконизатор"""
|
"""Жаконизатор"""
|
||||||
@@ -50,6 +52,7 @@ class JacquesMod(loader.Module):
|
|||||||
self.name = self.strings["name"]
|
self.name = self.strings["name"]
|
||||||
self._me = None
|
self._me = None
|
||||||
self._ratelimit = []
|
self._ratelimit = []
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
self.config = loader.ModuleConfig(
|
self.config = loader.ModuleConfig(
|
||||||
loader.ConfigValue(
|
loader.ConfigValue(
|
||||||
"font",
|
"font",
|
||||||
@@ -64,6 +67,17 @@ class JacquesMod(loader.Module):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=30)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="<реплай на сообщение/свой текст>",
|
ru_doc="<реплай на сообщение/свой текст>",
|
||||||
en_doc="<reply to the message/your own text>",
|
en_doc="<reply to the message/your own text>",
|
||||||
@@ -81,7 +95,7 @@ class JacquesMod(loader.Module):
|
|||||||
else:
|
else:
|
||||||
txt = args
|
txt = args
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(self.config["font"]) as font_response:
|
async with session.get(self.config["font"]) as font_response:
|
||||||
font_data = await font_response.read()
|
font_data = await font_response.read()
|
||||||
|
|
||||||
@@ -96,7 +110,8 @@ class JacquesMod(loader.Module):
|
|||||||
draw = ImageDraw.Draw(img)
|
draw = ImageDraw.Draw(img)
|
||||||
font = ImageFont.truetype(io.BytesIO(font_data), 32, encoding="UTF-8")
|
font = ImageFont.truetype(io.BytesIO(font_data), 32, encoding="UTF-8")
|
||||||
|
|
||||||
text_size = draw.multiline_textsize(wrapped_text, font=font)
|
text_bbox = draw.multiline_textbbox((0, 0), wrapped_text, font=font)
|
||||||
|
text_size = (text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1])
|
||||||
imtext = Image.new("RGBA", (text_size[0] + 10, text_size[1] + 10), (0, 0, 0, 0))
|
imtext = Image.new("RGBA", (text_size[0] + 10, text_size[1] + 10), (0, 0, 0, 0))
|
||||||
draw_imtext = ImageDraw.Draw(imtext)
|
draw_imtext = ImageDraw.Draw(imtext)
|
||||||
draw_imtext.multiline_text(
|
draw_imtext.multiline_text(
|
||||||
|
|||||||
@@ -114,13 +114,13 @@ class NumbersAPI(loader.Module):
|
|||||||
|
|
||||||
async def _get_number_fact(self, number: int, fact_type: str) -> str:
|
async def _get_number_fact(self, number: int, fact_type: str) -> str:
|
||||||
"""Get fact about number"""
|
"""Get fact about number"""
|
||||||
url = f"http://numbersapi.com/{number}/{fact_type}"
|
url = f"https://numbersapi.com/{number}/{fact_type}"
|
||||||
return await self._fetch_fact(url)
|
return await self._fetch_fact(url)
|
||||||
|
|
||||||
async def _get_date_fact(self, month: int, day: int) -> str:
|
async def _get_date_fact(self, month: int, day: int) -> str:
|
||||||
"""Get fact about date"""
|
"""Get fact about date"""
|
||||||
date_str = f"{month:02d}/{day:02d}"
|
date_str = f"{month:02d}/{day:02d}"
|
||||||
url = f"http://numbersapi.com/{date_str}/date"
|
url = f"https://numbersapi.com/{date_str}/date"
|
||||||
return await self._fetch_fact(url)
|
return await self._fetch_fact(url)
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from .. import loader, utils
|
from .. import loader, utils
|
||||||
@@ -69,6 +71,18 @@ class Shortener(loader.Module):
|
|||||||
validator=loader.validators.Hidden(),
|
validator=loader.validators.Hidden(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None or self._session.closed:
|
||||||
|
self._session = aiohttp.ClientSession(
|
||||||
|
timeout=aiohttp.ClientTimeout(total=15)
|
||||||
|
)
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
async def on_unload(self):
|
||||||
|
if self._session and not self._session.closed:
|
||||||
|
await self._session.close()
|
||||||
|
|
||||||
def _validate_url(self, url: str) -> bool:
|
def _validate_url(self, url: str) -> bool:
|
||||||
"""Validate URL format"""
|
"""Validate URL format"""
|
||||||
@@ -87,27 +101,32 @@ class Shortener(loader.Module):
|
|||||||
|
|
||||||
return url_pattern.match(url) is not None
|
return url_pattern.match(url) is not None
|
||||||
|
|
||||||
async def shorten_url(self, url: str, token: str) -> str:
|
async def shorten_url(self, url: str, token: str) -> Optional[str]:
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.post("https://api-ssl.bitly.com/v4/shorten", json={'long_url': url}, headers={"Authorization": f"Bearer {token}"}) as resp:
|
async with session.post(
|
||||||
|
"https://api-ssl.bitly.com/v4/shorten",
|
||||||
|
json={"long_url": url},
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
) as resp:
|
||||||
if resp.status == 201:
|
if resp.status == 201:
|
||||||
json_response = await resp.json()
|
json_response = await resp.json()
|
||||||
return json_response['link']
|
return json_response["link"]
|
||||||
else:
|
else:
|
||||||
logger.error(f"Error occurred! Status code: {resp.status}")
|
logger.error(f"Error occurred! Status code: {resp.status}")
|
||||||
return
|
return None
|
||||||
|
|
||||||
async def get_bitlink_stats(self, bitlink: str, token: str) -> str:
|
async def get_bitlink_stats(self, bitlink: str, token: str) -> Optional[int]:
|
||||||
async with aiohttp.ClientSession() as session:
|
session = await self._get_session()
|
||||||
async with session.get(f"https://api-ssl.bitly.com/v4/bitlinks/{bitlink}/clicks/summary", headers={"Authorization": f"Bearer {token}"}) as resp:
|
async with session.get(
|
||||||
|
f"https://api-ssl.bitly.com/v4/bitlinks/{bitlink}/clicks/summary",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
) as resp:
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
json_response = await resp.json()
|
json_response = await resp.json()
|
||||||
return json_response['total_clicks']
|
return json_response["total_clicks"]
|
||||||
else:
|
else:
|
||||||
logger.error(f"Error occurred! Status code: {resp.status}")
|
logger.error(f"Error occurred! Status code: {resp.status}")
|
||||||
return
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="Сократить ссылку через bit.ly (ссылка с https://)",
|
ru_doc="Сократить ссылку через bit.ly (ссылка с https://)",
|
||||||
@@ -129,7 +148,13 @@ class Shortener(loader.Module):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
short_url = await self.shorten_url(url=args, token=self.config['token'])
|
short_url = await self.shorten_url(url=args, token=self.config["token"])
|
||||||
|
if short_url is None:
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings("api_error").format(error="Failed to shorten URL"),
|
||||||
|
)
|
||||||
|
return
|
||||||
await utils.answer(message, self.strings("shortencmd").format(c=short_url))
|
await utils.answer(message, self.strings("shortencmd").format(c=short_url))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error shortening URL: {e}")
|
logger.error(f"Error shortening URL: {e}")
|
||||||
@@ -155,7 +180,17 @@ class Shortener(loader.Module):
|
|||||||
await utils.answer(message, self.strings("invalid_url"))
|
await utils.answer(message, self.strings("invalid_url"))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
clicks = await self.get_bitlink_stats(bitlink=args, token=self.config['token'])
|
clicks = await self.get_bitlink_stats(
|
||||||
|
bitlink=args, token=self.config["token"]
|
||||||
|
)
|
||||||
|
if clicks is None:
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings("api_error").format(
|
||||||
|
error="Failed to get statistics"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
await utils.answer(message, self.strings("statclcmd").format(c=clicks))
|
await utils.answer(message, self.strings("statclcmd").format(c=clicks))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error getting statistics: {e}")
|
logger.error(f"Error getting statistics: {e}")
|
||||||
|
|||||||
15
fiksofficial/python-modules/.github/FUNDING.yml
vendored
Normal file
15
fiksofficial/python-modules/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
polar: # Replace with a single Polar username
|
||||||
|
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||||
|
thanks_dev: gh/fiksofficial
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
@@ -15,5 +15,5 @@
|
|||||||
- [x] Попасть в FHeta
|
- [x] Попасть в FHeta
|
||||||
- [x] Попасть в Limoka
|
- [x] Попасть в Limoka
|
||||||
- [x] Попасть в команду верефицированных разработчиков модулей Heroku
|
- [x] Попасть в команду верефицированных разработчиков модулей Heroku
|
||||||
- [] Soon...
|
- [ ] Сойти с ума...
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,4 @@ point
|
|||||||
deviceinfo
|
deviceinfo
|
||||||
mpi
|
mpi
|
||||||
aigenuser
|
aigenuser
|
||||||
|
github
|
||||||
1034
fiksofficial/python-modules/github.py
Normal file
1034
fiksofficial/python-modules/github.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
# -- version --
|
# -- version --
|
||||||
__version__ = (1, 2, 2)
|
__version__ = (1, 2, 3)
|
||||||
# -- version --
|
# -- version --
|
||||||
|
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ class SenderGifts(loader.Module):
|
|||||||
"user_not_found": "<emoji document_id=4958526153955476488>❌</emoji> Пользователь не найден",
|
"user_not_found": "<emoji document_id=4958526153955476488>❌</emoji> Пользователь не найден",
|
||||||
"gift_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выберите категорию подарков.\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}\n<tg-emoji emoji-id=5321485469249198987>⭐️</tg-emoji> Баланс: {} звезд",
|
"gift_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выберите категорию подарков.\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}\n<tg-emoji emoji-id=5321485469249198987>⭐️</tg-emoji> Баланс: {} звезд",
|
||||||
"category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Подарки за {} ⭐\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
"category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Подарки за {} ⭐\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
||||||
|
"unique_category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> {}\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
||||||
"privacy_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выбран подарок: {}\n\nКак отправить подарок?",
|
"privacy_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выбран подарок: {}\n\nКак отправить подарок?",
|
||||||
"sending_gift": "<emoji document_id=5201691993775818138>🛫</emoji> Отправка подарка...",
|
"sending_gift": "<emoji document_id=5201691993775818138>🛫</emoji> Отправка подарка...",
|
||||||
"gift_sent": "<emoji document_id=5021905410089550576>✅</emoji> Подарок успешно отправлен!",
|
"gift_sent": "<emoji document_id=5021905410089550576>✅</emoji> Подарок успешно отправлен!",
|
||||||
@@ -46,7 +47,7 @@ class SenderGifts(loader.Module):
|
|||||||
"btn_anon": "🕵️ Анонимно",
|
"btn_anon": "🕵️ Анонимно",
|
||||||
}
|
}
|
||||||
|
|
||||||
gift_categories = {
|
regular_gifts = {
|
||||||
15: [
|
15: [
|
||||||
{"id": 5170145012310081615, "emoji": "❤️", "name": "Сердце"},
|
{"id": 5170145012310081615, "emoji": "❤️", "name": "Сердце"},
|
||||||
{"id": 5170233102089322756, "emoji": "🧸", "name": "Мишка"},
|
{"id": 5170233102089322756, "emoji": "🧸", "name": "Мишка"},
|
||||||
@@ -59,8 +60,6 @@ class SenderGifts(loader.Module):
|
|||||||
{"id": 5170144170496491616, "emoji": "🎂", "name": "Тортик"},
|
{"id": 5170144170496491616, "emoji": "🎂", "name": "Тортик"},
|
||||||
{"id": 5170314324215857265, "emoji": "💐", "name": "Цветы"},
|
{"id": 5170314324215857265, "emoji": "💐", "name": "Цветы"},
|
||||||
{"id": 5170564780938756245, "emoji": "🚀", "name": "Ракета"},
|
{"id": 5170564780938756245, "emoji": "🚀", "name": "Ракета"},
|
||||||
{"id": 5922558454332916696, "emoji": "🎄", "name": "Ёлка"},
|
|
||||||
{"id": 5956217000635139069, "emoji": "🧸", "name": "Новогодний мишка"}
|
|
||||||
],
|
],
|
||||||
100: [
|
100: [
|
||||||
{"id": 5168043875654172773, "emoji": "🏆", "name": "Кубок"},
|
{"id": 5168043875654172773, "emoji": "🏆", "name": "Кубок"},
|
||||||
@@ -69,8 +68,28 @@ class SenderGifts(loader.Module):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async def client_ready(self, client, db):
|
unique_gifts = {
|
||||||
self.client = client
|
"new_year": {
|
||||||
|
"name": "🎄 Новогодние подарки",
|
||||||
|
"gifts": [
|
||||||
|
{"id": 5922558454332916696, "emoji": "🎄", "name": "Ёлка", "price": 50},
|
||||||
|
{"id": 5956217000635139069, "emoji": "🧸", "name": "Новогодний мишка", "price": 50},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"valentines": {
|
||||||
|
"name": "💘 День святого валентина",
|
||||||
|
"gifts": [
|
||||||
|
{"id": 5800655655995968830, "emoji": "🧸", "name": "14 Февраля мишка", "price": 50},
|
||||||
|
{"id": 5801108895304779062, "emoji": "💘", "name": "14 Февраля сердце", "price": 50},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"march_8th": {
|
||||||
|
"name": "🌷 8 Марта",
|
||||||
|
"gifts": [
|
||||||
|
{"id": 5866352046986232958, "emoji": "🧸", "name": "8 Марта мишка", "price": 50},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async def get_star_balance(self):
|
async def get_star_balance(self):
|
||||||
try:
|
try:
|
||||||
@@ -100,6 +119,10 @@ class SenderGifts(loader.Module):
|
|||||||
text = parts[1] if len(parts) > 1 else ""
|
text = parts[1] if len(parts) > 1 else ""
|
||||||
if username.startswith('@'):
|
if username.startswith('@'):
|
||||||
username = username[1:]
|
username = username[1:]
|
||||||
|
try:
|
||||||
|
username = int(username)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
msg = await utils.answer(message, self.strings["checking_user"])
|
msg = await utils.answer(message, self.strings["checking_user"])
|
||||||
try:
|
try:
|
||||||
user = await self.client.get_entity(username)
|
user = await self.client.get_entity(username)
|
||||||
@@ -116,115 +139,54 @@ class SenderGifts(loader.Module):
|
|||||||
await utils.answer(balance_msg, self.strings["balance_error"])
|
await utils.answer(balance_msg, self.strings["balance_error"])
|
||||||
return
|
return
|
||||||
|
|
||||||
min_price = min(self.gift_categories.keys())
|
min_price = min(self.regular_gifts.keys())
|
||||||
if balance < min_price:
|
if balance < min_price:
|
||||||
await utils.answer(balance_msg, self.strings["min_stars_error"])
|
await utils.answer(balance_msg, self.strings["min_stars_error"])
|
||||||
return
|
return
|
||||||
|
|
||||||
available_categories = [price for price in self.gift_categories.keys() if balance >= price]
|
|
||||||
if not available_categories:
|
|
||||||
await utils.answer(balance_msg, self.strings["no_available_gifts"])
|
|
||||||
return
|
|
||||||
buttons = []
|
|
||||||
row = []
|
|
||||||
for price in sorted(available_categories):
|
|
||||||
row.append({
|
|
||||||
"text": f"{price} ⭐",
|
|
||||||
"callback": self._show_category,
|
|
||||||
"args": (user.id, price, text, balance, message.id),
|
|
||||||
})
|
|
||||||
if len(row) == 2:
|
|
||||||
buttons.append(row)
|
|
||||||
row = []
|
|
||||||
|
|
||||||
if row:
|
|
||||||
buttons.append(row)
|
|
||||||
|
|
||||||
helper_msg = await self.inline.form("🪐", balance_msg)
|
helper_msg = await self.inline.form("🪐", balance_msg)
|
||||||
|
|
||||||
await utils.answer(
|
|
||||||
helper_msg,
|
|
||||||
self.strings["gift_menu"].format(
|
|
||||||
f"@{user.username}" if user.username else user.first_name,
|
|
||||||
text if text else "-",
|
|
||||||
balance
|
|
||||||
),
|
|
||||||
reply_markup=buttons
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _show_category(self, call, user_id, price, text, balance, msg_id):
|
await self._show_main_menu_logic(helper_msg, user.id, text, balance, message.id, answer=True)
|
||||||
gifts = self.gift_categories[price]
|
|
||||||
buttons = []
|
|
||||||
row = []
|
|
||||||
for gift in gifts:
|
|
||||||
row.append({
|
|
||||||
"text": gift["emoji"],
|
|
||||||
"callback": self._select_privacy,
|
|
||||||
"args": (user_id, gift["id"], text, gift["emoji"], msg_id, balance, price),
|
|
||||||
})
|
|
||||||
if len(row) == 3:
|
|
||||||
buttons.append(row)
|
|
||||||
row = []
|
|
||||||
|
|
||||||
if row:
|
|
||||||
buttons.append(row)
|
|
||||||
buttons.append([{
|
|
||||||
"text": "⬅️ Назад",
|
|
||||||
"callback": self._back_to_categories,
|
|
||||||
"args": (user_id, text, balance, msg_id),
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
async def _show_main_menu_logic(self, msg_or_call, user_id, text, balance, msg_id, answer=False):
|
||||||
try:
|
try:
|
||||||
user = await self.client.get_entity(user_id)
|
user = await self.client.get_entity(user_id)
|
||||||
user_display = f"@{user.username}" if user.username else user.first_name
|
user_display = f"@{user.username}" if user.username else user.first_name
|
||||||
except:
|
except:
|
||||||
user_display = f"ID: {user_id}"
|
user_display = f"ID: {user_id}"
|
||||||
|
|
||||||
await call.edit(
|
|
||||||
self.strings["category_menu"].format(
|
|
||||||
price,
|
|
||||||
user_display,
|
|
||||||
text if text else "-"
|
|
||||||
),
|
|
||||||
reply_markup=buttons
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _select_privacy(self, call, user_id, gift_id, text, gift_emoji, msg_id, balance, price):
|
|
||||||
buttons = [
|
buttons = [
|
||||||
[
|
[{
|
||||||
{
|
"text": "🎁 Обычные подарки",
|
||||||
"text": self.strings["btn_public"],
|
"callback": self._show_regular_categories,
|
||||||
"callback": self._send_gift,
|
"args": (user_id, text, balance, msg_id),
|
||||||
"args": (user_id, gift_id, text, gift_emoji, msg_id, balance, False) # hide_name=False публично
|
}],
|
||||||
},
|
[{
|
||||||
{
|
"text": "✨ Уникальные подарки",
|
||||||
"text": self.strings["btn_anon"],
|
"callback": self._show_unique_categories,
|
||||||
"callback": self._send_gift,
|
"args": (user_id, text, balance, msg_id),
|
||||||
"args": (user_id, gift_id, text, gift_emoji, msg_id, balance, True) # hide_name=True анонимно
|
}]
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"text": "⬅️ Назад",
|
|
||||||
"callback": self._show_category,
|
|
||||||
"args": (user_id, price, text, balance, msg_id)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
await call.edit(
|
text_menu = self.strings["gift_menu"].format(user_display, text if text else "-", balance)
|
||||||
self.strings["privacy_menu"].format(gift_emoji),
|
|
||||||
reply_markup=buttons
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _back_to_categories(self, call, user_id, text, balance, msg_id):
|
if answer:
|
||||||
|
await utils.answer(msg_or_call, text_menu, reply_markup=buttons)
|
||||||
|
else:
|
||||||
|
await msg_or_call.edit(text_menu, reply_markup=buttons)
|
||||||
|
|
||||||
|
async def _show_main_menu(self, call, user_id, text, balance, msg_id):
|
||||||
|
await self._show_main_menu_logic(call, user_id, text, balance, msg_id)
|
||||||
|
|
||||||
|
async def _show_regular_categories(self, call, user_id, text, balance, msg_id):
|
||||||
try:
|
try:
|
||||||
user = await self.client.get_entity(user_id)
|
user = await self.client.get_entity(user_id)
|
||||||
|
user_display = f"@{user.username}" if user.username else user.first_name
|
||||||
except:
|
except:
|
||||||
await call.answer("Ошибка получения пользователя", show_alert=True)
|
user_display = f"ID: {user_id}"
|
||||||
return
|
|
||||||
|
|
||||||
available_categories = [price for price in self.gift_categories.keys() if balance >= price]
|
available_categories = [price for price in self.regular_gifts.keys() if balance >= price]
|
||||||
|
|
||||||
buttons = []
|
buttons = []
|
||||||
row = []
|
row = []
|
||||||
@@ -237,16 +199,151 @@ class SenderGifts(loader.Module):
|
|||||||
if len(row) == 2:
|
if len(row) == 2:
|
||||||
buttons.append(row)
|
buttons.append(row)
|
||||||
row = []
|
row = []
|
||||||
|
|
||||||
if row:
|
if row:
|
||||||
buttons.append(row)
|
buttons.append(row)
|
||||||
|
|
||||||
|
buttons.append([{
|
||||||
|
"text": "⬅️ Назад",
|
||||||
|
"callback": self._show_main_menu,
|
||||||
|
"args": (user_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
await call.edit(
|
await call.edit(
|
||||||
self.strings["gift_menu"].format(
|
self.strings["gift_menu"].format(user_display, text if text else "-", balance),
|
||||||
f"@{user.username}" if user.username else user.first_name,
|
reply_markup=buttons
|
||||||
text if text else "-",
|
)
|
||||||
balance
|
|
||||||
),
|
async def _show_unique_categories(self, call, user_id, text, balance, msg_id):
|
||||||
|
try:
|
||||||
|
user = await self.client.get_entity(user_id)
|
||||||
|
user_display = f"@{user.username}" if user.username else user.first_name
|
||||||
|
except:
|
||||||
|
user_display = f"ID: {user_id}"
|
||||||
|
|
||||||
|
buttons = []
|
||||||
|
for cat_id, cat_data in self.unique_gifts.items():
|
||||||
|
if any(balance >= gift["price"] for gift in cat_data["gifts"]):
|
||||||
|
buttons.append([{
|
||||||
|
"text": cat_data["name"],
|
||||||
|
"callback": self._show_unique_category_gifts,
|
||||||
|
"args": (user_id, cat_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
|
if not buttons:
|
||||||
|
buttons.append([{
|
||||||
|
"text": "❌ Нет доступных (баланс)",
|
||||||
|
"callback": self._show_main_menu,
|
||||||
|
"args": (user_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
|
buttons.append([{
|
||||||
|
"text": "⬅️ Назад",
|
||||||
|
"callback": self._show_main_menu,
|
||||||
|
"args": (user_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
|
await call.edit(
|
||||||
|
self.strings["gift_menu"].format(user_display, text if text else "-", balance),
|
||||||
|
reply_markup=buttons
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _show_category(self, call, user_id, price, text, balance, msg_id):
|
||||||
|
gifts = self.regular_gifts[price]
|
||||||
|
buttons = []
|
||||||
|
row = []
|
||||||
|
for gift in gifts:
|
||||||
|
row.append({
|
||||||
|
"text": gift["emoji"],
|
||||||
|
"callback": self._select_privacy,
|
||||||
|
"args": (user_id, gift["id"], text, gift["emoji"], msg_id, balance, "regular", price),
|
||||||
|
})
|
||||||
|
if len(row) == 3:
|
||||||
|
buttons.append(row)
|
||||||
|
row = []
|
||||||
|
|
||||||
|
if row:
|
||||||
|
buttons.append(row)
|
||||||
|
buttons.append([{
|
||||||
|
"text": "⬅️ Назад",
|
||||||
|
"callback": self._show_regular_categories,
|
||||||
|
"args": (user_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = await self.client.get_entity(user_id)
|
||||||
|
user_display = f"@{user.username}" if user.username else user.first_name
|
||||||
|
except:
|
||||||
|
user_display = f"ID: {user_id}"
|
||||||
|
|
||||||
|
await call.edit(
|
||||||
|
self.strings["category_menu"].format(price, user_display, text if text else "-"),
|
||||||
|
reply_markup=buttons
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _show_unique_category_gifts(self, call, user_id, cat_id, text, balance, msg_id):
|
||||||
|
category = self.unique_gifts[cat_id]
|
||||||
|
buttons = []
|
||||||
|
row = []
|
||||||
|
for gift in category["gifts"]:
|
||||||
|
if balance >= gift["price"]:
|
||||||
|
row.append({
|
||||||
|
"text": gift["emoji"],
|
||||||
|
"callback": self._select_privacy,
|
||||||
|
"args": (user_id, gift["id"], text, gift["emoji"], msg_id, balance, "unique", cat_id),
|
||||||
|
})
|
||||||
|
if len(row) == 3:
|
||||||
|
buttons.append(row)
|
||||||
|
row = []
|
||||||
|
|
||||||
|
if row:
|
||||||
|
buttons.append(row)
|
||||||
|
buttons.append([{
|
||||||
|
"text": "⬅️ Назад",
|
||||||
|
"callback": self._show_unique_categories,
|
||||||
|
"args": (user_id, text, balance, msg_id),
|
||||||
|
}])
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = await self.client.get_entity(user_id)
|
||||||
|
user_display = f"@{user.username}" if user.username else user.first_name
|
||||||
|
except:
|
||||||
|
user_display = f"ID: {user_id}"
|
||||||
|
|
||||||
|
await call.edit(
|
||||||
|
self.strings["unique_category_menu"].format(category["name"], user_display, text if text else "-"),
|
||||||
|
reply_markup=buttons
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _select_privacy(self, call, user_id, gift_id, text, gift_emoji, msg_id, balance, gift_type, type_arg):
|
||||||
|
if gift_type == "regular":
|
||||||
|
back_callback = self._show_category
|
||||||
|
else:
|
||||||
|
back_callback = self._show_unique_category_gifts
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"text": self.strings["btn_public"],
|
||||||
|
"callback": self._send_gift,
|
||||||
|
"args": (user_id, gift_id, text, gift_emoji, msg_id, balance, False)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": self.strings["btn_anon"],
|
||||||
|
"callback": self._send_gift,
|
||||||
|
"args": (user_id, gift_id, text, gift_emoji, msg_id, balance, True)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"text": "⬅️ Назад",
|
||||||
|
"callback": back_callback,
|
||||||
|
"args": (user_id, type_arg, text, balance, msg_id)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
await call.edit(
|
||||||
|
self.strings["privacy_menu"].format(gift_emoji),
|
||||||
reply_markup=buttons
|
reply_markup=buttons
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
401
modules.json
401
modules.json
@@ -19441,6 +19441,7 @@
|
|||||||
"user_not_found": "<emoji document_id=4958526153955476488>❌</emoji> Пользователь не найден",
|
"user_not_found": "<emoji document_id=4958526153955476488>❌</emoji> Пользователь не найден",
|
||||||
"gift_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выберите категорию подарков.\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}\n<tg-emoji emoji-id=5321485469249198987>⭐️</tg-emoji> Баланс: {} звезд",
|
"gift_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выберите категорию подарков.\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}\n<tg-emoji emoji-id=5321485469249198987>⭐️</tg-emoji> Баланс: {} звезд",
|
||||||
"category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Подарки за {} ⭐\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
"category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Подарки за {} ⭐\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
||||||
|
"unique_category_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> {}\n\n<tg-emoji emoji-id=6048471184461271609>👤</tg-emoji> Пользователь: {}\n<tg-emoji emoji-id=6048762138430803961>📂</tg-emoji> Текст: {}",
|
||||||
"privacy_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выбран подарок: {}\n\nКак отправить подарок?",
|
"privacy_menu": "<tg-emoji emoji-id=5370781982886220096>🎁</tg-emoji> Выбран подарок: {}\n\nКак отправить подарок?",
|
||||||
"sending_gift": "<emoji document_id=5201691993775818138>🛫</emoji> Отправка подарка...",
|
"sending_gift": "<emoji document_id=5201691993775818138>🛫</emoji> Отправка подарка...",
|
||||||
"gift_sent": "<emoji document_id=5021905410089550576>✅</emoji> Подарок успешно отправлен!",
|
"gift_sent": "<emoji document_id=5021905410089550576>✅</emoji> Подарок успешно отправлен!",
|
||||||
@@ -46620,9 +46621,6 @@
|
|||||||
{
|
{
|
||||||
"send": "[text] - Write a message | (RU) [text] - Написать сообщение | (UZ) [text] - xabar yozing | (DE) [text] - Nachricht schreiben | (ES) [text] - escribe un mensaje"
|
"send": "[text] - Write a message | (RU) [text] - Написать сообщение | (UZ) [text] - xabar yozing | (DE) [text] - Nachricht schreiben | (ES) [text] - escribe un mensaje"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"sendclosedtopic": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Write a message to a closed topic | (RU) [text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Написать сообщение в закрытую тему | (UZ) [text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Yopiq mavzuga xabar yozing | (DE) [text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Schreiben Sie eine Nachricht zu einem geschlossenen Thema | (ES) [text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Escribir un mensaje a un tema cerrado"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"sendpm": "[@UserName] [text or replay] - Write a message to personal messages | (RU) [@UserName] [text or replay] - Написать сообщение в личные сообщения | (UZ) [@UserName] [text or replay] - Shaxsiy xabarlarga xabar yozing | (DE) [@UserName] [text or replay] - Schreiben Sie eine Nachricht zu persönlichen Nachrichten | (ES) [@UserName] [text or replay] - Escribir un mensaje a mensajes personales."
|
"sendpm": "[@UserName] [text or replay] - Write a message to personal messages | (RU) [@UserName] [text or replay] - Написать сообщение в личные сообщения | (UZ) [@UserName] [text or replay] - Shaxsiy xabarlarga xabar yozing | (DE) [@UserName] [text or replay] - Schreiben Sie eine Nachricht zu persönlichen Nachrichten | (ES) [@UserName] [text or replay] - Escribir un mensaje a mensajes personales."
|
||||||
},
|
},
|
||||||
@@ -46648,23 +46646,6 @@
|
|||||||
"is_inline_handler": false,
|
"is_inline_handler": false,
|
||||||
"decorators": []
|
"decorators": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "sendclosedtopic",
|
|
||||||
"original_name": "sendclosedtopic",
|
|
||||||
"description": {
|
|
||||||
"default": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Write a message to a closed topic",
|
|
||||||
"ru": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Написать сообщение в закрытую тему",
|
|
||||||
"uz": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Yopiq mavzuga xabar yozing",
|
|
||||||
"de": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Schreiben Sie eine Nachricht zu einem geschlossenen Thema",
|
|
||||||
"es": "[text or reply(media/file/sticker) or coordinates (<lat>, <long>)] - Escribir un mensaje a un tema cerrado"
|
|
||||||
},
|
|
||||||
"cmd_names": {},
|
|
||||||
"aliases": [],
|
|
||||||
"usage": null,
|
|
||||||
"inline": false,
|
|
||||||
"is_inline_handler": false,
|
|
||||||
"decorators": []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "sendpm",
|
"name": "sendpm",
|
||||||
"original_name": "sendpm",
|
"original_name": "sendpm",
|
||||||
@@ -61901,6 +61882,181 @@
|
|||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
|
"fiksofficial/python-modules/github.py": {
|
||||||
|
"name": "GitHubMod",
|
||||||
|
"description": "GitHub repository monitor — commits, issues, PRs, releases and stars",
|
||||||
|
"cls_doc": {
|
||||||
|
"ru": "Мониторинг GitHub репозиториев — коммиты, issues, PR, релизы и звёзды"
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"pic": null,
|
||||||
|
"banner": null,
|
||||||
|
"developer": "@pymodule"
|
||||||
|
},
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"github": "- Open GitHub Monitor control panel | (RU) - Открыть панель управления GitHub Monitor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"new_commands": [
|
||||||
|
{
|
||||||
|
"name": "github",
|
||||||
|
"original_name": "githubcmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- Open GitHub Monitor control panel",
|
||||||
|
"ru": "- Открыть панель управления GitHub Monitor"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inline_handlers": [],
|
||||||
|
"strings": {
|
||||||
|
"name": "GitHubMonitor",
|
||||||
|
"setup_welcome": "🐙 <b>GitHub Monitor</b>\n\nChoose a destination to configure.\nEach channel/group has its own repository list and settings.\nNotifications are sent on behalf of the bot.",
|
||||||
|
"enter_dest": "{icon} <b>{label} setup</b>\n\nEnter the <b>@username or ID</b> of the {label_lc}.\nThe bot will be added as admin automatically.",
|
||||||
|
"dest_not_found": "❌ <b>Chat not found.</b>\n\nCheck the @username or ID and try again.\nMake sure you are an admin of that chat.",
|
||||||
|
"dest_configured": "✅ <b>{label}</b> configured: <b>{title}</b>\n\nNow add the first repository to track\nin <code>owner/repo</code> format:",
|
||||||
|
"bot_invite_fail": "⚠️ Could not add the bot automatically.\nPlease add <code>{bot}</code> as admin with <b>Post Messages</b> right manually,\nthen open <code>.github</code> again.",
|
||||||
|
"dest_removed": "🗑 <b>{title}</b> removed.",
|
||||||
|
"repo_already": "⚠️ <code>{repo}</code> is already tracked in <b>{title}</b>.",
|
||||||
|
"repo_not_tracked": "⚠️ <code>{repo}</code> is not tracked in <b>{title}</b>.",
|
||||||
|
"repo_not_found": "❌ Repository <code>{repo}</code> not found or inaccessible.",
|
||||||
|
"repo_added": "✅ Added <code>{repo}</code> to <b>{title}</b>.",
|
||||||
|
"repo_removed": "✅ Removed <code>{repo}</code> from <b>{title}</b>.",
|
||||||
|
"no_dests": "❌ <b>No destinations configured.</b>\n\nRun <code>.github</code> to set up a channel or group.",
|
||||||
|
"setup_canceled": "❌ Setup canceled.",
|
||||||
|
"panel_title": "{icon} <b>{title}</b>\n\n📦 <b>Repositories:</b> {repos}\n📣 <b>Events:</b> {events}\n⏱ <b>Interval:</b> {interval}s\n🔑 <b>Token:</b> {token}",
|
||||||
|
"panel_repos_empty": "none",
|
||||||
|
"interval_invalid": "❌ Enter a number between 60 and 3600.",
|
||||||
|
"rate_limit": "⚠️ <b>GitHub API rate limit.</b>\nResets at <code>{reset}</code>.\nSet a personal token in the destination panel.",
|
||||||
|
"dests_list": "📋 <b>Configured destinations:</b>\n\n{list}",
|
||||||
|
"notify_push_header": "<b>📏 On </b><a href='https://github.com/{repo}'><b>{repo}:{branch}</b></a><b> new commits!</b>\n{count} commits pushed.\n<a href='{compare}'>Compare changes</a>",
|
||||||
|
"notify_push_commit": "\n<blockquote expandable><b>Commit </b><a href='{url}'><b>#{sha}</b></a><b> by <i>{name} (</i></b><a href='https://github.com/{login}'><b><i>@{login}</i></b></a><b><i>)</i></b>\n<i>{msg}</i>\n\n{files_section}{diff_section}</blockquote>",
|
||||||
|
"notify_push_footer": "",
|
||||||
|
"notify_push_created": "<b>🔧 Created files:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_removed": "<b>🗑 Removed files:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_modified": "<b>🖊 Modified files:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_diff": "<b>⌨️ Diff:</b>\n➕ {added}\n➖ {removed}\n",
|
||||||
|
"notify_push_empty": "<b>📏 On </b><a href='https://github.com/{repo}'><b>{repo}:{branch}</b></a><b> new empty push</b>",
|
||||||
|
"notify_issue": "<b>{e} On </b><a href='{url}'><b>{repo}</b></a><b> {action} issue!</b>\n\n<i>{title}</i>\n<a href='{url}'>#{num}</a> by <a href='https://github.com/{author}'><i>@{author}</i></a>",
|
||||||
|
"notify_pr": "<b>{e} On </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> {action} pull request!</b>\n\n<i>{title}</i>\n<blockquote expandable>{body}</blockquote>\n\nUser: <a href='https://github.com/{author}'><i>@{author}</i></a>\n\n<a href='{url}'>#{num}</a>",
|
||||||
|
"notify_release": "<b>{e} On </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> {action} release!</b>\n\n🏷 <code>{tag}</code> · <b>{name}</b>\n👤 <a href='https://github.com/{author}'><i>@{author}</i></a>\n<a href='{url}'>Open release</a>",
|
||||||
|
"notify_star_added": "<b>⭐️ On </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> added star!</b>\n\nTotal stars: <i>{stars}</i>\nUser: <a href='https://github.com/{user}'><i>@{user}</i></a>",
|
||||||
|
"notify_star_removed": "<b>💔 On </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> removed star!</b>\n\nTotal stars: <i>{stars}</i>\nUser: <a href='https://github.com/{user}'><i>@{user}</i></a>",
|
||||||
|
"_cfg_interval": "Default polling interval in seconds (60–3600). Overridden per destination.",
|
||||||
|
"star_label": "⭐ Stars",
|
||||||
|
"_cfg_token": "Default GitHub token for destinations without a personal token.\nWithout token: 60 req/h. With token: 5000 req/h.\nCreate at: github.com/settings/tokens",
|
||||||
|
"push_label": "🔨 Push",
|
||||||
|
"issues_label": "🐛 Issues",
|
||||||
|
"pull_request_label": "🔀 Pull Requests",
|
||||||
|
"release_label": "🚀 Releases",
|
||||||
|
"token_set": "✅ set",
|
||||||
|
"token_not_set": "❌ not set",
|
||||||
|
"btn_channel": "➕ Channel",
|
||||||
|
"btn_group": "➕ Group",
|
||||||
|
"btn_close": "✖️ Close",
|
||||||
|
"btn_back": "◀️ Back",
|
||||||
|
"btn_skip": "⏩ Skip",
|
||||||
|
"btn_add_repo": "➕ Add repository",
|
||||||
|
"btn_set_interval": "⏱ Set interval",
|
||||||
|
"btn_set_token": "🔑 Set token",
|
||||||
|
"btn_clear_token": "🔑 Clear token",
|
||||||
|
"btn_remove": "🗑 Remove",
|
||||||
|
"btn_enter_dest": "✏️ Enter {label} username / ID",
|
||||||
|
"btn_add_repo_confirm": "✏️ Add repository",
|
||||||
|
"input_dest": "@username or ID of the {label}",
|
||||||
|
"input_repo": "owner/repo (e.g. torvalds/linux)",
|
||||||
|
"input_interval": "Interval in seconds (60 – 3600)",
|
||||||
|
"input_token": "GitHub Personal Access Token",
|
||||||
|
"repo_invalid_format": "❌ Invalid format. Use <code>owner/repo</code>.",
|
||||||
|
"checking_repo": "🔍 Checking repository...",
|
||||||
|
"issue_opened": "opened",
|
||||||
|
"issue_closed": "closed",
|
||||||
|
"pr_merged": "merged",
|
||||||
|
"pr_closed": "closed",
|
||||||
|
"pr_opened": "opened",
|
||||||
|
"release_prerelease": "pre-release",
|
||||||
|
"release_published": "published",
|
||||||
|
"dest_label_channel": "Channel",
|
||||||
|
"dest_label_group": "Group",
|
||||||
|
"name_ru": "GitHubMonitor",
|
||||||
|
"setup_welcome_ru": "🐙 <b>GitHub Monitor</b>\n\nВыберите назначение для настройки.\nУ каждого канала/группы свой список репозиториев и настройки.\nУведомления отправляются от имени бота.",
|
||||||
|
"enter_dest_ru": "{icon} <b>Настройка {label_lc}а</b>\n\nВведите <b>@username или ID</b> {label_lc}а.\nБот будет добавлен администратором автоматически.",
|
||||||
|
"dest_not_found_ru": "❌ <b>Чат не найден.</b>\n\nПроверьте @username или ID.\nУбедитесь, что вы администратор этого чата.",
|
||||||
|
"dest_configured_ru": "✅ <b>{label}</b> настроен: <b>{title}</b>\n\nТеперь добавьте первый репозиторий для отслеживания\nв формате <code>owner/repo</code>:",
|
||||||
|
"bot_invite_fail_ru": "⚠️ Не удалось добавить бота автоматически.\nДобавьте <code>{bot}</code> вручную как администратора с правом <b>Публикация сообщений</b>,\nзатем откройте <code>.github</code> снова.",
|
||||||
|
"dest_removed_ru": "🗑 <b>{title}</b> удалён.",
|
||||||
|
"repo_already_ru": "⚠️ <code>{repo}</code> уже отслеживается в <b>{title}</b>.",
|
||||||
|
"repo_not_tracked_ru": "⚠️ <code>{repo}</code> не отслеживается в <b>{title}</b>.",
|
||||||
|
"repo_not_found_ru": "❌ Репозиторий <code>{repo}</code> не найден или недоступен.",
|
||||||
|
"repo_added_ru": "✅ Репозиторий <code>{repo}</code> добавлен в <b>{title}</b>.",
|
||||||
|
"repo_removed_ru": "✅ Репозиторий <code>{repo}</code> удалён из <b>{title}</b>.",
|
||||||
|
"no_dests_ru": "❌ <b>Нет настроенных назначений.</b>\n\nЗапустите <code>.github</code> чтобы добавить канал или группу.",
|
||||||
|
"setup_canceled_ru": "❌ Настройка отменена.",
|
||||||
|
"panel_title_ru": "{icon} <b>{title}</b>\n\n📦 <b>Репозитории:</b> {repos}\n📣 <b>События:</b> {events}\n⏱ <b>Интервал:</b> {interval} сек\n🔑 <b>Токен:</b> {token}",
|
||||||
|
"panel_repos_empty_ru": "нет",
|
||||||
|
"interval_invalid_ru": "❌ Введите число от 60 до 3600.",
|
||||||
|
"rate_limit_ru": "⚠️ <b>GitHub API rate limit.</b>\nСброс в <code>{reset}</code>.\nУстановите токен в панели назначения.",
|
||||||
|
"dests_list_ru": "📋 <b>Настроенные назначения:</b>\n\n{list}",
|
||||||
|
"notify_push_header_ru": "<b>📏 На </b><a href='https://github.com/{repo}'><b>{repo}:{branch}</b></a><b> новые коммиты!</b>\n{count} коммитов отправлено.\n<a href='{compare}'>Сравнить изменения</a>",
|
||||||
|
"notify_push_commit_ru": "\n<blockquote expandable><b>Коммит </b><a href='{url}'><b>#{sha}</b></a><b> от <i>{name} (</i></b><a href='https://github.com/{login}'><b><i>@{login}</i></b></a><b><i>)</i></b>\n<i>{msg}</i>\n\n{files_section}{diff_section}</blockquote>",
|
||||||
|
"notify_push_footer_ru": "",
|
||||||
|
"notify_push_created_ru": "<b>🔧 Созданные файлы:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_removed_ru": "<b>🗑 Удалённые файлы:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_modified_ru": "<b>🖊 Изменённые файлы:</b>\n<code>{files}</code>\n\n",
|
||||||
|
"notify_push_diff_ru": "<b>⌨️ Diff:</b>\n➕ {added}\n➖ {removed}\n",
|
||||||
|
"notify_push_empty_ru": "<b>📏 На </b><a href='https://github.com/{repo}'><b>{repo}:{branch}</b></a><b> пустой push</b>",
|
||||||
|
"notify_issue_ru": "<b>{e} На </b><a href='{url}'><b>{repo}</b></a><b> {action} issue!</b>\n\n<i>{title}</i>\n<a href='{url}'>#{num}</a> от <a href='https://github.com/{author}'><i>@{author}</i></a>",
|
||||||
|
"notify_pr_ru": "<b>{e} На </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> {action} pull request!</b>\n\n<i>{title}</i>\n<blockquote expandable>{body}</blockquote>\n\nПользователь: <a href='https://github.com/{author}'><i>@{author}</i></a>\n\n<a href='{url}'>#{num}</a>",
|
||||||
|
"notify_release_ru": "<b>{e} На </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> {action} релиз!</b>\n\n🏷 <code>{tag}</code> · <b>{name}</b>\n👤 <a href='https://github.com/{author}'><i>@{author}</i></a>\n<a href='{url}'>Открыть релиз</a>",
|
||||||
|
"notify_star_added_ru": "<b>⭐️ На </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> добавлена звезда!</b>\n\nВсего звёзд: <i>{stars}</i>\nПользователь: <a href='https://github.com/{user}'><i>@{user}</i></a>",
|
||||||
|
"notify_star_removed_ru": "<b>💔 На </b><a href='https://github.com/{repo}'><b>{repo}</b></a><b> убрана звезда!</b>\n\nВсего звёзд: <i>{stars}</i>\nПользователь: <a href='https://github.com/{user}'><i>@{user}</i></a>",
|
||||||
|
"_cfg_interval_ru": "Интервал опроса по умолчанию (60–3600 сек). Переопределяется в настройках назначения.",
|
||||||
|
"star_label_ru": "⭐ Звёзды",
|
||||||
|
"_cfg_token_ru": "Глобальный GitHub-токен для назначений без персонального токена.\nБез токена: 60 запросов/час. С токеном: 5000.\nСоздать: github.com/settings/tokens",
|
||||||
|
"push_label_ru": "🔨 Push",
|
||||||
|
"issues_label_ru": "🐛 Issues",
|
||||||
|
"pull_request_label_ru": "🔀 Pull Requests",
|
||||||
|
"release_label_ru": "🚀 Релизы",
|
||||||
|
"token_set_ru": "✅ установлен",
|
||||||
|
"token_not_set_ru": "❌ не установлен",
|
||||||
|
"btn_channel_ru": "➕ Канал",
|
||||||
|
"btn_group_ru": "➕ Группа",
|
||||||
|
"btn_close_ru": "✖️ Закрыть",
|
||||||
|
"btn_back_ru": "◀️ Назад",
|
||||||
|
"btn_skip_ru": "⏩ Пропустить",
|
||||||
|
"btn_add_repo_ru": "➕ Добавить репозиторий",
|
||||||
|
"btn_set_interval_ru": "⏱ Установить интервал",
|
||||||
|
"btn_set_token_ru": "🔑 Установить токен",
|
||||||
|
"btn_clear_token_ru": "🔑 Очистить токен",
|
||||||
|
"btn_remove_ru": "🗑 Удалить",
|
||||||
|
"btn_enter_dest_ru": "✏️ Ввести {label} username / ID",
|
||||||
|
"btn_add_repo_confirm_ru": "✏️ Добавить репозиторий",
|
||||||
|
"input_dest_ru": "@username или ID {label}а",
|
||||||
|
"input_repo_ru": "owner/repo (например: torvalds/linux)",
|
||||||
|
"input_interval_ru": "Интервал в секундах (60 – 3600)",
|
||||||
|
"input_token_ru": "GitHub Personal Access Token",
|
||||||
|
"repo_invalid_format_ru": "❌ Неверный формат. Используйте <code>owner/repo</code>.",
|
||||||
|
"checking_repo_ru": "🔍 Проверяю репозиторий...",
|
||||||
|
"issue_opened_ru": "открыт",
|
||||||
|
"issue_closed_ru": "закрыт",
|
||||||
|
"pr_merged_ru": "смёрджен",
|
||||||
|
"pr_closed_ru": "закрыт",
|
||||||
|
"pr_opened_ru": "открыт",
|
||||||
|
"release_prerelease_ru": "пре-релиз",
|
||||||
|
"release_published_ru": "опубликован",
|
||||||
|
"dest_label_channel_ru": "Канал",
|
||||||
|
"dest_label_group_ru": "Группа"
|
||||||
|
},
|
||||||
|
"has_on_load": false,
|
||||||
|
"has_on_unload": true,
|
||||||
|
"class_cmd_names": {}
|
||||||
|
},
|
||||||
"fiksofficial/python-modules/checkhost.py": {
|
"fiksofficial/python-modules/checkhost.py": {
|
||||||
"name": "CheckHostMod",
|
"name": "CheckHostMod",
|
||||||
"description": "Check host via check-host.net",
|
"description": "Check host via check-host.net",
|
||||||
@@ -62999,7 +63155,7 @@
|
|||||||
"no_reply_ru": "<emoji document_id=6030512294109122096>💬</emoji> Вы не ответили на сообщение пользователя"
|
"no_reply_ru": "<emoji document_id=6030512294109122096>💬</emoji> Вы не ответили на сообщение пользователя"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/animals.py": {
|
"archquise/H.Modules/animals.py": {
|
||||||
@@ -64784,7 +64940,7 @@
|
|||||||
"usage_ru": "Напиши <code>.help Жаконизатор</code>"
|
"usage_ru": "Напиши <code>.help Жаконизатор</code>"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/Music.py": {
|
"archquise/H.Modules/Music.py": {
|
||||||
@@ -64946,7 +65102,7 @@
|
|||||||
"error_ru": "<b>Не удалось получить цитату. Попробуйте позже!</b>"
|
"error_ru": "<b>Не удалось получить цитату. Попробуйте позже!</b>"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/TaskManager.py": {
|
"archquise/H.Modules/TaskManager.py": {
|
||||||
@@ -65401,6 +65557,53 @@
|
|||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
|
"archquise/H.Modules/SMArchiver.py": {
|
||||||
|
"name": "SMArchiver",
|
||||||
|
"description": "unloads all messages from Favorites",
|
||||||
|
"cls_doc": {},
|
||||||
|
"meta": {
|
||||||
|
"pic": null,
|
||||||
|
"banner": null,
|
||||||
|
"developer": "@hikka_mods"
|
||||||
|
},
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"smdump": "(RU) выгружает все сообщения из Избранного / Saved Messages и собирает их в одном архиве. | (EN) downloads all messages from Favorites / Saved Messages and collects them in one archive."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"new_commands": [
|
||||||
|
{
|
||||||
|
"name": "smdump",
|
||||||
|
"original_name": "smdump",
|
||||||
|
"description": {
|
||||||
|
"default": "",
|
||||||
|
"ru": "выгружает все сообщения из Избранного / Saved Messages и собирает их в одном архиве.",
|
||||||
|
"en": "downloads all messages from Favorites / Saved Messages and collects them in one archive."
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inline_handlers": [],
|
||||||
|
"strings": {
|
||||||
|
"name": "SMArchiver",
|
||||||
|
"archive_created": "🎉 Archive with messages has been successfully created: {filename}",
|
||||||
|
"no_messages": "⚠️ There are no messages in Saved Messages.",
|
||||||
|
"error": "❌ An error occurred: {error}",
|
||||||
|
"processing": "🛠️ Processing messages... Please wait.\n\nP.S: Be careful, if you have a lot of messages, you may get flooding, and if you have a lot of heavy files, the download will be slower than usual.",
|
||||||
|
"archive_created_ru": "🎉 Архив с сообщениями успешно создан: {filename}",
|
||||||
|
"no_messages_ru": "⚠️ В Сохраненных сообщениях нет сообщений.",
|
||||||
|
"error_ru": "❌ Произошла ошибка: {error}",
|
||||||
|
"processing_ru": "🛠️ Обработка сообщений... Пожалуйста, подождите.\n\nP.S: Будьте осторожны, если у вас много сообщений, вы можете получить флуд, а если у вас много тяжелых файлов, загрузка будет медленнее обычного."
|
||||||
|
},
|
||||||
|
"has_on_load": false,
|
||||||
|
"has_on_unload": false,
|
||||||
|
"class_cmd_names": {}
|
||||||
|
},
|
||||||
"archquise/H.Modules/CryptoCurrency.py": {
|
"archquise/H.Modules/CryptoCurrency.py": {
|
||||||
"name": "CryptoCurrencyMod",
|
"name": "CryptoCurrencyMod",
|
||||||
"description": "Module for displaying current cryptocurrency exchange rates.",
|
"description": "Module for displaying current cryptocurrency exchange rates.",
|
||||||
@@ -65441,7 +65644,7 @@
|
|||||||
"coin_not_found_ru": "Криптовалюта '{query}' не найдена."
|
"coin_not_found_ru": "Криптовалюта '{query}' не найдена."
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/InlineCoin.py": {
|
"archquise/H.Modules/InlineCoin.py": {
|
||||||
@@ -65604,53 +65807,6 @@
|
|||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/SMAcrhiver.py": {
|
|
||||||
"name": "SMArchiver",
|
|
||||||
"description": "unloads all messages from Favorites",
|
|
||||||
"cls_doc": {},
|
|
||||||
"meta": {
|
|
||||||
"pic": null,
|
|
||||||
"banner": null,
|
|
||||||
"developer": "@hikka_mods"
|
|
||||||
},
|
|
||||||
"commands": [
|
|
||||||
{
|
|
||||||
"smdump": "(RU) выгружает все сообщения из Избранного / Saved Messages и собирает их в одном архиве. | (EN) downloads all messages from Favorites / Saved Messages and collects them in one archive."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"new_commands": [
|
|
||||||
{
|
|
||||||
"name": "smdump",
|
|
||||||
"original_name": "smdump",
|
|
||||||
"description": {
|
|
||||||
"default": "",
|
|
||||||
"ru": "выгружает все сообщения из Избранного / Saved Messages и собирает их в одном архиве.",
|
|
||||||
"en": "downloads all messages from Favorites / Saved Messages and collects them in one archive."
|
|
||||||
},
|
|
||||||
"cmd_names": {},
|
|
||||||
"aliases": [],
|
|
||||||
"usage": null,
|
|
||||||
"inline": false,
|
|
||||||
"is_inline_handler": false,
|
|
||||||
"decorators": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"inline_handlers": [],
|
|
||||||
"strings": {
|
|
||||||
"name": "SMArchiver",
|
|
||||||
"archive_created": "🎉 Archive with messages has been successfully created: {filename}",
|
|
||||||
"no_messages": "⚠️ There are no messages in Saved Messages.",
|
|
||||||
"error": "❌ An error occurred: {error}",
|
|
||||||
"processing": "🛠️ Processing messages... Please wait.\n\nP.S: Be careful, if you have a lot of messages, you may get flooding, and if you have a lot of heavy files, the download will be slower than usual.",
|
|
||||||
"archive_created_ru": "🎉 Архив с сообщениями успешно создан: {filename}",
|
|
||||||
"no_messages_ru": "⚠️ В Сохраненных сообщениях нет сообщений.",
|
|
||||||
"error_ru": "❌ Произошла ошибка: {error}",
|
|
||||||
"processing_ru": "🛠️ Обработка сообщений... Пожалуйста, подождите.\n\nP.S: Будьте осторожны, если у вас много сообщений, вы можете получить флуд, а если у вас много тяжелых файлов, загрузка будет медленнее обычного."
|
|
||||||
},
|
|
||||||
"has_on_load": false,
|
|
||||||
"has_on_unload": false,
|
|
||||||
"class_cmd_names": {}
|
|
||||||
},
|
|
||||||
"archquise/H.Modules/TempChat.py": {
|
"archquise/H.Modules/TempChat.py": {
|
||||||
"name": "TempChatMod",
|
"name": "TempChatMod",
|
||||||
"description": "Creates a temporary private chat with a message forwarding restriction and adds the specified user to it.",
|
"description": "Creates a temporary private chat with a message forwarding restriction and adds the specified user to it.",
|
||||||
@@ -65866,20 +66022,76 @@
|
|||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/AniLiberty.py": {
|
"archquise/H.Modules/AniLiberty.py": {
|
||||||
"name": "AniLiberty",
|
"name": "AniLibertyMod",
|
||||||
"description": "",
|
"description": "Ищет и возвращает случайное аниме из базы Aniliberty",
|
||||||
"cls_doc": {},
|
"cls_doc": {},
|
||||||
"meta": {
|
"meta": {
|
||||||
"pic": null,
|
"pic": null,
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"developer": "@hikka_mods"
|
"developer": "@hikka_mods"
|
||||||
},
|
},
|
||||||
"commands": [],
|
"commands": [
|
||||||
"new_commands": [],
|
{
|
||||||
"inline_handlers": [],
|
"arandom": "(RU) Возвращает случайный релиз из базы | (EN) Returns a random release from the database"
|
||||||
"strings": {},
|
},
|
||||||
|
{
|
||||||
|
"asearchinlinehandler": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"new_commands": [
|
||||||
|
{
|
||||||
|
"name": "arandom",
|
||||||
|
"original_name": "arandom",
|
||||||
|
"description": {
|
||||||
|
"default": "",
|
||||||
|
"ru": "Возвращает случайный релиз из базы",
|
||||||
|
"en": "Returns a random release from the database"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "asearchinlinehandler",
|
||||||
|
"original_name": "asearch_inline_handler",
|
||||||
|
"description": {
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": true,
|
||||||
|
"is_inline_handler": true,
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inline_handlers": [
|
||||||
|
{
|
||||||
|
"name": "asearchinlinehandler",
|
||||||
|
"description": {
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"strings": {
|
||||||
|
"name": "AniLiberty",
|
||||||
|
"announce": "<b>The announcement</b>:",
|
||||||
|
"ongoing": "<b>Ongoing</b>:",
|
||||||
|
"type": "<b>Type</b>:",
|
||||||
|
"genres": "<b>Genres</b>:",
|
||||||
|
"favorite": "<b>Favourites <3</b>:",
|
||||||
|
"announce_ru": "<b>Анонс</b>:",
|
||||||
|
"ongoing_ru": "<b>Онгоинг</b>:",
|
||||||
|
"type_ru": "<b>Тип</b>:",
|
||||||
|
"genres_ru": "<b>Жанры</b>:",
|
||||||
|
"favorite_ru": "<b>Избранное <3</b>:"
|
||||||
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/GigaChat.py": {
|
"archquise/H.Modules/GigaChat.py": {
|
||||||
@@ -66846,7 +67058,7 @@
|
|||||||
"error_ru": "Произошла ошибка!"
|
"error_ru": "Произошла ошибка!"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/CodeShare.py": {
|
"archquise/H.Modules/CodeShare.py": {
|
||||||
@@ -66893,7 +67105,7 @@
|
|||||||
"link_ready_ru": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>"
|
"link_ready_ru": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/KBSwapper.py": {
|
"archquise/H.Modules/KBSwapper.py": {
|
||||||
@@ -67202,13 +67414,13 @@
|
|||||||
},
|
},
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"addfolder": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName | (R) Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки | (RU) Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки"
|
"addfolder": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName | (RU) Добавить папку в список отслеживания | (EN) Add folder to the tracking list | (R) Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки | (RU) Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"delfolder": "Deletes folder from the tracking list | (R) Удаляет папку из списка для отслежнивания | (RU) Удаляет папку из списка для отслежнивания"
|
"delfolder": "Deletes folder from the tracking list | (RU) Удалить папку из списка отслеживания | (EN) Delete folder from the tracking list | (R) Удаляет папку из списка для отслежнивания | (RU) Удаляет папку из списка для отслежнивания"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"listfolders": "Prints list of tracked folders | (R) Выводит список отслеживаемых папок | (RU) Выводит список отслеживаемых папок"
|
"listfolders": "Prints list of tracked folders | (RU) Список отслеживаемых папок | (EN) List tracked folders | (R) Выводит список отслеживаемых папок | (RU) Выводит список отслеживаемых папок"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new_commands": [
|
"new_commands": [
|
||||||
@@ -67217,8 +67429,9 @@
|
|||||||
"original_name": "addfolder",
|
"original_name": "addfolder",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName",
|
"default": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName",
|
||||||
"r": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
|
"ru": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
|
||||||
"ru": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки"
|
"en": "Add folder to the tracking list",
|
||||||
|
"r": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки"
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -67232,8 +67445,9 @@
|
|||||||
"original_name": "delfolder",
|
"original_name": "delfolder",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "Deletes folder from the tracking list",
|
"default": "Deletes folder from the tracking list",
|
||||||
"r": "Удаляет папку из списка для отслежнивания",
|
"ru": "Удаляет папку из списка для отслежнивания",
|
||||||
"ru": "Удаляет папку из списка для отслежнивания"
|
"en": "Delete folder from the tracking list",
|
||||||
|
"r": "Удаляет папку из списка для отслежнивания"
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -67247,8 +67461,9 @@
|
|||||||
"original_name": "listfolders",
|
"original_name": "listfolders",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "Prints list of tracked folders",
|
"default": "Prints list of tracked folders",
|
||||||
"r": "Выводит список отслеживаемых папок",
|
"ru": "Выводит список отслеживаемых папок",
|
||||||
"ru": "Выводит список отслеживаемых папок"
|
"en": "List tracked folders",
|
||||||
|
"r": "Выводит список отслеживаемых папок"
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -67283,7 +67498,7 @@
|
|||||||
"addfolder_ru": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>"
|
"addfolder_ru": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": true,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/shortener.py": {
|
"archquise/H.Modules/shortener.py": {
|
||||||
@@ -67356,7 +67571,7 @@
|
|||||||
"api_error_ru": "<emoji document_id=5854929766146118183>❌</emoji> Ошибка API: {error}"
|
"api_error_ru": "<emoji document_id=5854929766146118183>❌</emoji> Ошибка API: {error}"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": true,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"archquise/H.Modules/timezone.py": {
|
"archquise/H.Modules/timezone.py": {
|
||||||
@@ -82079,7 +82294,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"total_modules": 1020,
|
"total_modules": 1021,
|
||||||
"generated_at": "2026-03-03T01:28:23.435183"
|
"generated_at": "2026-03-11T01:22:17.528364"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user