Merge pull request #257 from MuRuLOSE/update-submodules_e50c7c1688b89901690bc01609544e5c3e238097

Update of repositories 2026-04-19 02:02:27
This commit is contained in:
Macsim
2026-04-19 14:16:50 +03:00
committed by GitHub
12 changed files with 3 additions and 2259 deletions

View File

@@ -1,273 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 Archquise
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com
# ---------------------------------------------------------------------------------
# Name: Aniliberty
# Description: Searches and gives random anime on the Aniliberty database.
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# requires: dacite
# scope: AniLiberty
# scope: AniLiberty 0.0.1
# ---------------------------------------------------------------------------------
import logging
from aiogram.types import CallbackQuery, InlineQueryResultPhoto
from dataclasses import dataclass
from json import JSONDecodeError
from dacite import from_dict
from typing import Optional
import aiohttp
from .. import loader
from ..inline.types import InlineQuery
logger = logging.getLogger(__name__)
BASE_API_URL = "https://aniliberty.top/api/v1"
# Датаклассы для парсинга и хранения json
@dataclass
class Genre:
name: str
@dataclass
class Name:
main: str
@dataclass
class Type:
description: str
@dataclass
class Poster:
preview: str
thumbnail: str
@dataclass
class ReleaseInfo:
id: int
genres: Optional[list[Genre]]
name: Name
is_ongoing: bool
type: Type
description: str
added_in_users_favorites: int
alias: str
poster: Poster
@loader.tds
class AniLibertyMod(loader.Module):
"""Ищет и возвращает случайное аниме из базы Aniliberty"""
strings = {
"name": "AniLiberty",
"announce": "<b>The announcement</b>:",
"ongoing": "<b>Ongoing</b>:",
"type": "<b>Type</b>:",
"genres": "<b>Genres</b>:",
"favorite": "<b>Favourites &lt;3</b>:", # &lt; == <
}
strings_ru = {
"announce": "<b>Анонс</b>:",
"ongoing": "<b>Онгоинг</b>:",
"type": "<b>Тип</b>:",
"genres": "<b>Жанры</b>:",
"favorite": "<b>Избранное &lt;3</b>:", # &lt; == <
}
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):
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:
json_answer = await resp.json()
results = []
for i in json_answer:
obj = from_dict(data_class=ReleaseInfo, data=i)
results.append(obj)
return results
async def get_title(self, release_id):
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:
try:
json_answer = await resp.json()
data = from_dict(data_class=ReleaseInfo, data=json_answer)
return data
except JSONDecodeError:
logger.error("Ошибка парсинга JSON!")
async def get_random_title(self):
session = await self._get_session()
async with session.get(
f"{BASE_API_URL}/anime/releases/random?limit=1&include=id"
) as resp:
randid = await resp.json()
data = await self.get_title(randid[0]["id"])
return data
@loader.command(
ru_doc="Возвращает случайный релиз из базы",
en_doc="Returns a random release from the database",
)
async def arandom(self, message) -> None:
anime_release = await self.get_random_title()
genres_str = ""
for genre in anime_release.genres[:-1]:
genres_str += f"{genre.name}, "
genres_str += anime_release.genres[-1].name
text = f"{anime_release.name.main} \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['genres']} {genres_str}\n\n"
text += f"<code>{anime_release.description}</code>\n\n"
text += (
f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
)
kb = [
[
{
"text": "Ссылка",
"url": f"https://aniliberty.top/anime/releases/release/{anime_release.alias}/episodes",
}
]
]
kb.append([{"text": "🔃 Обновить", "callback": self.inline__update}])
kb.append([{"text": "🚫 Закрыть", "callback": self.inline__close}])
await self.inline.form(
text=text,
photo=f"https://aniliberty.top{anime_release.poster.preview}",
message=message,
reply_markup=kb,
silent=True,
)
@loader.inline_handler(
ru_doc="Возвращает список найденных по названию тайтлов",
en_doc="Returns a list of titles found by name",
)
async def asearch_inline_handler(self, query: InlineQuery) -> None:
text = query.args
if not text:
return
anime_releases = await self.search_title(text)
inline_query = []
for anime_release in anime_releases:
"""
Приходится запрашивать по второму кругу, т.к. API в поиске не отдает жанры, даже если попросить через include
"""
release_genres = await self.get_title(anime_release.id)
genres_str = ""
for genre in release_genres.genres[:-1]:
genres_str += f"{genre.name}, "
genres_str += release_genres.genres[-1].name
release_text = (
f"{anime_release.name.main}\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['genres']} {genres_str}\n\n"
f"<code>{anime_release.description}</code>\n\n"
f"{self.strings['favorite']} {anime_release.added_in_users_favorites}"
)
inline_query.append(
InlineQueryResultPhoto(
id=str(anime_release.id),
title=anime_release.name.main,
description=anime_release.type.description,
caption=release_text,
thumbnail_url=f"https://aniliberty.top{anime_release.poster.thumbnail}",
photo_url=f"https://aniliberty.top{anime_release.poster.preview}",
parse_mode="html",
)
)
method = query.answer(inline_query, cache_time=0)
await method.as_(self.inline.bot)
async def inline__close(self, call: CallbackQuery) -> None:
await call.delete()
async def inline__update(self, call: CallbackQuery) -> None:
anime_release = await self.get_random_title()
genres_str = ""
for genre in anime_release.genres[:-1]:
genres_str += f"{genre.name}, "
genres_str += anime_release.genres[-1].name
text = f"{anime_release.name.main} \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['genres']} {genres_str}\n\n"
text += f"<code>{anime_release.description}</code>\n\n"
text += (
f"{self.strings['favorite']} {str(anime_release.added_in_users_favorites)}"
)
kb = [
[
{
"text": "Ссылка",
"url": f"https://aniliberty.top/anime/releases/release/{anime_release.alias}/episodes",
}
]
]
kb.append([{"text": "🔃 Обновить", "callback": self.inline__update}])
kb.append([{"text": "🚫 Закрыть", "callback": self.inline__close}])
await call.edit(
text=text,
photo=f"https://aniliberty.top{anime_release.poster.preview}",
reply_markup=kb,
)

View File

@@ -1,104 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2026-2029 Archquise
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com
# ---------------------------------------------------------------------------------
# Name: CodeShare
# Description: Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# requires: aiofiles
# ---------------------------------------------------------------------------------
import aiohttp
import aiofiles
import os
import logging
from typing import Optional
from .. import loader, utils
from telethon.types import MessageMediaDocument
logger = logging.getLogger(__name__)
@loader.tds
class CodeShareMod(loader.Module):
"""Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)"""
strings = {
"name": "CodeShare",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or reply with a file, or they are invalid",
"_cls_doc": "Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)",
"link_ready": "<emoji document_id=5854762571659218443>✅</emoji> <b>Code uploaded! Link:</b> <code>{}</code>",
}
strings_ru = {
"_cls_doc": "Загружает ваш код на kmi.aeza.net (альтернатива Pastebin и GitHub Gist)",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или реплая с файлом, или они неверны",
"link_ready": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>",
}
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"
data = aiohttp.FormData()
data.add_field("kmi", content)
session = await self._get_session()
async with session.post(url, data=data) as response:
if response.status == 200:
link = await response.text()
return link
else:
logger.error(f"Error occurred! Status code: {response.status}")
return None
@loader.command(
ru_doc="Загрузка кода на сайт",
en_doc="Upload code to the site",
)
async def codesharecmd(self, message):
args = utils.get_args(message)
reply = await message.get_reply_message()
if args:
link = await self.upload_to_kmi(args)
await utils.answer(message, self.strings["link_ready"].format(link))
return
if reply and isinstance(reply.media, MessageMediaDocument):
file_name = await reply.download_media()
async with aiofiles.open(file_name, mode="r") as f:
content = await f.read()
link = await self.upload_to_kmi(content)
await os.remove(file_name)
await utils.answer(message, self.strings["link_ready"].format(link))
return
await utils.answer(message, self.strings["invalid_args"])

View File

@@ -1,154 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 Archquise
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com.
# ---------------------------------------------------------------------------------
# Name: FolderAutoRead
# Description: Automatically reads chats in selected folders
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# ---------------------------------------------------------------------------------
import logging
from telethon import functions
from telethon.tl.types import DialogFilter, InputPeerChannel
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class FolderAutoReadMod(loader.Module):
"""Automatically reads chats in selected folders"""
strings = {
"name": "FolderAutoRead",
"not_exists_or_already_added": "<emoji document_id=5278578973595427038>🚫</emoji> <b>This folder does not exists or it is already added for tracking!</b>",
"_cls_doc": "Automatically reads chats in selected folders every 60 seconds!",
"_cmd_doc_addfolder": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName",
"_cmd_doc_listfolders": "Prints list of tracked folders",
"_cmd_doc_delfolder": "Deletes folder from the tracking list",
"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",
"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>",
}
strings_ru = {
"not_exists_or_already_added": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Такой папки не существует, или она уже добавлена для отслеживания!</b>",
"_cls_doc": "Автоматически читает чаты в выбранных папках каждые 60 секунд!",
"_cmd_doc_addfolder": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
"_cmd_doc_listfolders": "Выводит список отслеживаемых папок",
"_cmd_doc_delfolder": "Удаляет папку из списка для отслежнивания",
"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",
"delfolder": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Папка успешно удалена из листа отслеживания!</b>",
"addfolder": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>",
}
def __init__(self):
self.tracked_folders = []
async def client_ready(self, client, db):
self.tracked_folders = self.pointer("tracked_folders", [])
async def _read_peers(self, peers):
for peer in peers:
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)
async def read_chats_in_folders(self):
if self.tracked_folders:
all_folders = await self._client(
functions.messages.GetDialogFiltersRequest()
)
for folder_name in self.tracked_folders:
match = next(
(
f
for f in all_folders.filters
if isinstance(f, DialogFilter) and f.title.text == folder_name
),
None,
)
if match is None:
continue
await self._read_peers(match.pinned_peers)
await self._read_peers(match.include_peers)
@loader.command(
ru_doc="Добавить папку в список отслеживания",
en_doc="Add folder to the tracking list",
)
async def addfolder(self, message):
arg = utils.get_args_raw(message)
if arg:
all_folders = await self._client(
functions.messages.GetDialogFiltersRequest()
)
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)
await utils.answer(message, self.strings("addfolder"))
else:
await utils.answer(message, self.strings("not_exists_or_already_added"))
else:
await utils.answer(message, self.strings("wrong_args"))
@loader.command(
ru_doc="Удалить папку из списка отслеживания",
en_doc="Delete folder from the tracking list",
)
async def delfolder(self, message):
arg = utils.get_args_raw(message)
if arg and arg in self.tracked_folders:
self.tracked_folders.remove(arg)
await utils.answer(message, self.strings("delfolder"))
else:
await utils.answer(message, self.strings("wrong_args"))
@loader.command(
ru_doc="Список отслеживаемых папок",
en_doc="List tracked folders",
)
async def listfolders(self, message):
await utils.answer(
message,
self.strings("listfolders")
+ "\n".join(f"{folder}" for folder in self.tracked_folders),
)

View File

@@ -1,133 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 CodWiz
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact codwiz@yandex.ru.
# ---------------------------------------------------------------------------------
# Name: IrisSimpleMod
# Description: Module for basic interaction with Iris.
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# scope: IrisSimpleMod
# scope: IrisSimpleMod 1.0.1
# ---------------------------------------------------------------------------------
import logging
from typing import Optional
from .. import loader, utils
__version__ = (1, 0, 1)
logger = logging.getLogger(__name__)
@loader.tds
class IrisSimpleMod(loader.Module):
"""Module for basic interaction with Iris bot"""
strings = {
"name": "IrisSimpleMod",
"checking_bag": "<emoji document_id=5188311512791393083>🌎</emoji> Checking bag...",
"bag_result": "<emoji document_id=5854762571659218443>✅</emoji> Your bag: <code>{}</code>",
"farming": "<emoji document_id=5188311512791393083>🌎</emoji> Farming iris-coins...",
"farm_result": "<emoji document_id=5854762571659218443>✅</emoji> Farm result: <code>{}</code>",
"getting_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Getting user stats...",
"stats_result": "<emoji document_id=5854762571659218443>✅</emoji> User stats: <code>{}</code>",
"bot_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Getting bot stats...",
"bot_stats_result": "<emoji document_id=5854762571659218443>✅</emoji> Bot stats: <code>{}</code>",
"error_no_response": "<emoji document_id=5854929766146118183>❌</emoji> No response from bot. Please try again.",
"error_timeout": "<emoji document_id=5854929766146118183>❌</emoji> Request timeout. Please try again.",
"error_general": "<emoji document_id=5854929766146118183>❌</emoji> An error occurred: {error}",
}
strings_ru = {
"checking_bag": "<emoji document_id=5188311512791393083>🌎</emoji> Проверка мешка...",
"bag_result": "<emoji document_id=5854762571659218443>✅</emoji> Ваш мешок: <code>{}</code>",
"farming": "<emoji document_id=5188311512791393083>🌎</emoji> Фарм ирис-коинов...",
"farm_result": "<emoji document_id=5854762571659218443>✅</emoji> Результат фарма: <code>{}</code>",
"getting_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Получение статистики пользователя...",
"stats_result": "<emoji document_id=5854762571659218443>✅</emoji> Статистика пользователя: <code>{}</code>",
"bot_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Получение статистики ботов...",
"bot_stats_result": "<emoji document_id=5854762571659218443>✅</emoji> Статистика ботов: <code>{}</code>",
"error_no_response": "<emoji document_id=5854929766146118183>❌</emoji> Нет ответа от бота. Попробуйте еще раз.",
"error_timeout": "<emoji document_id=5854929766146118183>❌</emoji> Таймаут запроса. Попробуйте еще раз.",
"error_general": "<emoji document_id=5854929766146118183>❌</emoji> Произошла ошибка: {error}",
}
async def _send_and_delete(
self, message, command_message: str, response_timeout: int = 15
) -> Optional[str]:
"""Send command to Iris and get response with timeout"""
try:
async with self.client.conversation(
self._iris_user_id, timeout=self._timeout
) as conv:
await conv.send_message(command_message)
await message.delete()
response_msg = await conv.get_response()
if response_msg:
await utils.answer(message, response_msg.text)
return response_msg.text
else:
return None
except Exception as e:
logger.error(f"Error in conversation: {e}")
await utils.answer(
message, self.strings["error_general"].format(error=str(e))
)
return None
@loader.command(
ru_doc="Проверить мешок",
en_doc="Check bag",
)
async def bag(self, message):
"""Check bag"""
await utils.answer(message, self.strings["checking_bag"])
result = await self._send_and_delete(message, "мешок", response_timeout=20)
if result:
await utils.answer(message, self.strings["bag_result"].format(result))
@loader.command(
ru_doc="Зафармить ирис-коины",
en_doc="Farm iris-coins",
)
async def farm(self, message):
"""Farm iris-coins"""
await utils.answer(message, self.strings["farming"])
result = await self._send_and_delete(message, "ферма", response_timeout=25)
if result:
await utils.answer(message, self.strings["farm_result"].format(result))
@loader.command(
ru_doc="Вывести анкету",
en_doc="Display user stats",
)
async def irisstats(self, message):
"""Display user stats"""
await utils.answer(message, self.strings["getting_stats"])
result = await self._send_and_delete(message, "анкета", response_timeout=20)
if result:
await utils.answer(message, self.strings["stats_result"].format(result))

View File

@@ -1,158 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 CodWiz
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact codwiz@yandex.ru.
# ---------------------------------------------------------------------------------
# Name: TempChat
# Description: Creates a temporary private chat with a message forwarding restriction and adds the specified user to it.
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# scope: TempChat
# scope: TempChat 0.0.1
# ---------------------------------------------------------------------------------
import logging
from hikkatl import functions
from datetime import datetime as dt
from .. import loader, utils
logging.basicConfig(level=logging.ERROR)
logger = logging.getLogger(__name__)
@loader.tds
class TempChatMod(loader.Module):
"""Creates a temporary private chat with a message forwarding restriction and adds the specified user to it."""
strings = {
"name": "TempChat",
"selfchat": "You can't create a chat with yourself.",
"wrongargs": "<emoji document_id=5980953710157632545>❌</emoji> <b>Wrong arguments. Use </b><code>.tmpchat [@user/reply] [time]</code><b>",
"alreadychatting": "<emoji document_id=5980953710157632545>❌</emoji> <b>You already have an active conversation with this person.</b>",
"invalidtime": "<emoji document_id=5980953710157632545>❌</emoji> <b>Invalid time format. Use combinations like 1h30m.</b>",
"invitemsg": "<emoji document_id=5818967120213445821>🛡</emoji> You've been invited to a temporary private chat!\n\n<emoji document_id=5451646226975955576>⌛️</emoji> Auto-deletes in ",
"joinlink": "🔗 Join link: ",
"chatcreated": "<emoji document_id=5980930633298350051>✅</emoji> The temporary chat has been successfully created!",
}
strings_ru = {
"selfchat": "Ты не можешь создать чат сам с собой.",
"wrongargs": "<emoji document_id=5980953710157632545>❌</emoji> <b>Неверные аргументы. Используй </b><code>.tmpchat [@user/reply] [время]</code>",
"alreadychatting": "<emoji document_id=5980953710157632545>❌</emoji> <b>У вас уже есть открытая переписка с этим человеком.</b>",
"invalidtime": "<emoji document_id=5980953710157632545>❌</emoji> <b>Неверный формат времени. Убедитесь, что вы вводите время в формате 1h, 2h30m.</b>",
"invitemsg": "<emoji document_id=5818967120213445821>🛡</emoji> Вы были приглашены во временный приватный чат!\n\n<emoji document_id=5451646226975955576>⌛️</emoji> Авто-удаление через ",
"joinlink": "🔗 Ссылка: ",
"chatcreated": "<emoji document_id=5980930633298350051>✅</emoji> Временный чат успешно создан!",
}
def __init__(self):
self.temp_chats = {}
@loader.loop(interval=30, autostart=True)
async def check_expired_chats(self):
now = dt.now().timestamp()
for chat_id in list(self.temp_chats.keys()):
if self.temp_chats[chat_id][1] <= now:
try:
await self.client(
functions.channels.DeleteChannelRequest(chat_id)
)
del self.temp_chats[chat_id]
self.set("temp_chats", self.temp_chats)
except Exception as e:
logger.error(f"Error deleting chat {chat_id}: {e}")
try:
self.client(
functions.channels.GetFullChannelRequest(
channel=chat_id
)
)
except Exception:
del self.temp_chats[chat_id]
self.set("temp_chats", self.temp_chats)
async def client_ready(self, client, db):
self.hmodslib = await self.import_lib(
"https://files.archquise.ru/HModsLibrary.py"
)
self.temp_chats = self.get("temp_chats", {})
@loader.command(
ru_doc="Создает временный чат. Использование: .tmpchat [@user/reply] [time]"
)
async def tmpchat(self, message):
"""Create temporary chat. Usage: .tmpchat [@user/reply] [time]"""
args = utils.get_args_raw(message)
reply = await message.get_reply_message()
if reply:
user = await self.client.get_entity(reply.sender_id)
time_str = args.strip() if args else None
else:
parts = args.split(",", 1) if "," in args else args.rsplit(" ", 1)
if len(parts) != 2:
return await utils.answer(message, self.strings["wrongargs"])
user_str, time_str = parts[0].strip(), parts[1].strip()
try:
user = await self.client.get_entity(user_str)
except Exception:
return await utils.answer(message, self.strings["wrongargs"])
if not time_str:
return await utils.answer(message, self.strings["wrongargs"])
seconds = await self.hmodslib.parse_time(time_str)
if not seconds:
return await utils.answer(message, self.strings["invalidtime"])
if any(user.id == uid for uid, _ in self.temp_chats.values()):
return await utils.answer(message, self.strings["alreadychatting"])
try:
created = await self.client(
functions.channels.CreateChannelRequest(
title=f"TempChat #{user.id}",
about=f"Temporary private chat with {user.id} | Expires after: {time_str}",
megagroup=True,
)
)
chat_id = created.chats[0].id
expires_at = dt.now().timestamp() + seconds
await self.client(
functions.messages.ToggleNoForwardsRequest(peer=chat_id, enabled=True)
)
self.temp_chats[chat_id] = (user.id, expires_at)
self.set("temp_chats", self.temp_chats)
invite = await self.client(
functions.messages.ExportChatInviteRequest(peer=chat_id, usage_limit=1)
)
invite_message = (
self.strings["invitemsg"]
+ time_str
+ f"\n{self.strings['joinlink']} {invite.link}"
)
await self.client.send_message(user.id, invite_message)
await utils.answer(message, self.strings["chatcreated"])
except Exception as e:
logger.error(f"Error creating temp chat: {e}")
await utils.answer(message, "❌ Error! Check log-chat.")

View File

@@ -1,135 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 CodWiz
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact codwiz@yandex.ru.
# ---------------------------------------------------------------------------------
# Name: WindowsKeys
# Description: Provides you Windows activation keys
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# scope: WindowsKeys
# scope: WindowsKeys 0.0.1
# requires: requests
# ---------------------------------------------------------------------------------
import logging
import time
import aiohttp
from .. import loader
logger = logging.getLogger(__name__)
@loader.tds
class WindowsKeysMod(loader.Module):
"""Windows activation keys"""
strings = {
"name": "WindowsKeys",
"winkey": "✅ Key: <code>{}</code>\n\n⚠ For KMS activation only",
"error": "❌ Failed to get key",
"select": "🔓 Select version:",
"close": "🎈 Close",
"loading": "⌛ Loading...",
}
strings_ru = {
"winkey": "✅ Ключ: <code>{}</code>\n\n⚠ Только для KMS активации",
"error": "❌ Ошибка получения",
"select": "🔓 Выберите версию:",
"close": "🎈 Закрыть",
"loading": "⌛ Загрузка...",
}
def __init__(self):
self.cache = None
self.cache_time = 0
self.CACHE_TTL = 3600
async def client_ready(self, client, db):
self.client = client
self.db = db
@loader.command(ru_doc="Меню ключей Windows", en_doc="Windows keys menu")
async def winkey(self, message):
await self.inline.form(
self.strings["select"],
message=message,
reply_markup=[
[
{
"text": "Win 10/11 Pro",
"callback": self._key,
"args": ("win10_11pro",),
}
],
[
{
"text": "Win 10/11 LTSC",
"callback": self._key,
"args": ("win10_11enterpriseLTSC",),
}
],
[
{
"text": "Win 8.1 Pro",
"callback": self._key,
"args": ("win8.1pro",),
}
],
[{"text": "Win 8 Pro", "callback": self._key, "args": ("win8pro",)}],
[{"text": "Win 7 Pro", "callback": self._key, "args": ("win7pro",)}],
[
{
"text": "Vista Business",
"callback": self._key,
"args": ("winvistabusiness",),
}
],
[{"text": self.strings["close"], "action": "close"}],
],
)
async def _key(self, call, version):
await call.edit(self.strings["loading"])
keys = await self._get_keys()
key = keys.get(version) if keys else None
await call.edit(
self.strings["winkey"].format(key) if key else self.strings["error"],
reply_markup=[
[{"text": "← Back", "callback": self.winkey}],
[{"text": self.strings["close"], "action": "close"}],
],
)
async def _get_keys(self):
if time.time() - self.cache_time < self.CACHE_TTL:
return self.cache
try:
async with aiohttp.ClientSession(
timeout=aiohttp.ClientTimeout(10)
) as session:
async with session.get("https://files.archquise.ru/winkeys.json") as r:
self.cache = await r.json()
self.cache_time = time.time()
return self.cache
except Exception: # noqa: E722
return None

View File

@@ -1,100 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2024-29 CodWiz
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact codwiz@yandex.ru.
# ---------------------------------------------------------------------------------
# Name: face
# Description: Random face
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# scope: Api face
# scope: Api face 0.0.1
# requires: aiohttp
# ---------------------------------------------------------------------------------
import logging
from typing import Optional
import aiohttp
import re
import random
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class face(loader.Module):
"""random face"""
strings = {
"name": "face",
"loading": (
"<emoji document_id=5348399448017871250>🔍</emoji> I'm looking for you kaomoji"
),
"random_face": (
"<emoji document_id=5208878706717636743>🗿</emoji> Here is your random one kaomoji\n<code>{}</code>"
),
"error": "An error has occurred!",
}
strings_ru = {
"loading": (
"<emoji document_id=5348399448017871250>🔍</emoji> Ищю вам kaomoji"
),
"random_face": (
"<emoji document_id=5208878706717636743>🗿</emoji> Вот ваш рандомный kaomoji\n<code>{}</code>"
),
"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(
ru_doc="Рандом kaomoji",
en_doc="Random kaomoji",
)
async def rfacecmd(self, message):
await utils.answer(message, self.strings("loading"))
url = "https://files.archquise.ru/kaomoji.txt"
session = await self._get_session()
async with session.get(url) as response:
if response.status == 200:
data = await response.text()
kaomoji_list = [
s.strip() for s in re.split(r"[\t\r\n]+", data) if s.strip()
]
kaomoji = random.choice(kaomoji_list)
await utils.answer(message, self.strings("random_face").format(kaomoji))
else:
await utils.answer(message, self.strings("error"))

View File

@@ -1,197 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2026-2029 Archquise
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com
# ---------------------------------------------------------------------------------
# Name: Shortener
# Description: Module for using bit.ly API
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# scope: Shortener
# scope: Shortener 0.0.1
# ---------------------------------------------------------------------------------
import logging
import re
from typing import Optional
import aiohttp
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class Shortener(loader.Module):
"""Module for using bit.ly API"""
strings = {
"name": "Shortener",
"no_api": "<emoji document_id=5854929766146118183>❌</emoji> You have not specified an API token from the site <a href='https://app.bitly.com/settings/api/'>bit.ly</a>",
"statclcmd": "<emoji document_id=5787384838411522455>📊</emoji> <b>Statistics on clicks for this link:</b> {c}",
"shortencmd": "<emoji document_id=5854762571659218443>✅</emoji> <b>Your shortened link is ready:</b> <code>{c}</code>",
"no_args": "<emoji document_id=5854929766146118183>❌</emoji> Please provide a URL to shorten.",
"invalid_url": "<emoji document_id=5854929766146118183>❌</emoji> Invalid URL format.",
"api_error": "<emoji document_id=5854929766146118183>❌</emoji> API error: {error}",
"_cls_doc": "Module for using bit.ly API",
}
strings_ru = {
"no_api": "<emoji document_id=5854929766146118183>❌</emoji> Вы не указали api токен с сайта <a href='https://app.bitly.com/settings/api/'>bit.ly</a>",
"statclcmd": "<emoji document_id=5787384838411522455>📊</emoji> <b>Статистика о переходе по этой ссылке:</b> {c}",
"shortencmd": "<emoji document_id=5854762571659218443>✅</emoji> <b>Ваша сокращённая ссылка готова:</b> <code>{c}</code>",
"no_args": "<emoji document_id=5854929766146118183>❌</emoji> Пожалуйста, укажите URL для сокращения.",
"invalid_url": "<emoji document_id=5854929766146118183>❌</emoji> Неверный формат URL.",
"api_error": "<emoji document_id=5854929766146118183>❌</emoji> Ошибка API: {error}",
"_cls_doc": "Модуль для использования API bit.ly",
}
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"token",
None,
lambda: "Need a token with https://app.bitly.com/settings/api/",
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:
"""Validate URL format"""
if not url:
return False
url_pattern = re.compile(
r"^https?://"
r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|"
r"localhost|"
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
r"(?::\d+)?"
r"(?:/?|[/?]\S+)$",
re.IGNORECASE,
)
return url_pattern.match(url) is not None
async def shorten_url(self, url: str, token: str) -> Optional[str]:
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:
if resp.status == 201:
json_response = await resp.json()
return json_response["link"]
else:
logger.error(f"Error occurred! Status code: {resp.status}")
return None
async def get_bitlink_stats(self, bitlink: str, token: str) -> Optional[int]:
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:
if resp.status == 200:
json_response = await resp.json()
return json_response["total_clicks"]
else:
logger.error(f"Error occurred! Status code: {resp.status}")
return None
@loader.command(
ru_doc="Сократить ссылку через bit.ly (ссылка с https://)",
en_doc="Shorten the link via bit.ly (url with https://)",
)
async def shortencmd(self, message):
"""Shorten URL using bit.ly API"""
if self.config["token"] is None:
await utils.answer(message, self.strings("no_api"))
return
args = utils.get_args_raw(message)
if not args:
await utils.answer(message, self.strings("no_args"))
return
if not self._validate_url(args):
await utils.answer(message, self.strings("invalid_url"))
return
try:
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))
except Exception as e:
logger.error(f"Error shortening URL: {e}")
await utils.answer(message, self.strings("api_error").format(error=str(e)))
@loader.command(
ru_doc="Посмотреть статистику ссылки через bit.ly (ссылка без https:// | Доступно только на платных аккаунтах)",
en_doc="View link statistics via bit.ly (link without https:// | Works only on paid accounts)",
)
async def statclcmd(self, message):
"""Get click statistics for shortened URL"""
if self.config["token"] is None:
await utils.answer(message, self.strings("no_api"))
return
args = utils.get_args_raw(message)
if not args:
await utils.answer(message, self.strings("no_args"))
return
try:
if not args.startswith("bit.ly/"):
await utils.answer(message, self.strings("invalid_url"))
return
else:
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))
except Exception as e:
logger.error(f"Error getting statistics: {e}")
await utils.answer(message, self.strings("api_error").format(error=str(e)))

View File

@@ -633,7 +633,7 @@ class SoundCloudMod(loader.Module):
"oauth_token",
"",
"SoundCloud OAuth token",
validator=loader.validators.String(),
validator=loader.validators.Hidden(),
),
loader.ConfigValue(
"history_count",

View File

@@ -1,92 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2026-2029 Archquise
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com
# ---------------------------------------------------------------------------------
# Name: TimeZone
# Description: Prints current time in selected timezone (UTC+n and tzdata formats supported)
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# requires: tzdata
# ---------------------------------------------------------------------------------
import logging
import tzdata
from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class TimeZoneMod(loader.Module):
"""Prints current time in selected timezone (UTC+n and tzdata formats supported)"""
strings = {
"name": "TimeZone",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or they are invalid",
"_cls_doc": "Prints current time in selected timezone (UTC+n and tzdata formats supported)",
"time_utc": "<emoji document_id=5276412364458059956>🕓</emoji> Current time by UTC+{}: {}",
"time_tzdata": "<emoji document_id=5276412364458059956>🕓</emoji> Current time in {}: {}",
}
strings_ru = {
"_cls_doc": "Выводит текущее время в выбранном часовом поясе (поддерживаются форматы UTC+n и tzdata)",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или они неверны",
"tzdata_error": "<emoji document_id=5854929766146118183>❌</emoji> Произошла ошибка при получении времени по tzdata: {}\n\nУбедитесь, что часовой пояс указан верно",
"time_utc": "<emoji document_id=5276412364458059956>🕓</emoji> Текущее время по UTC+{}: {}",
"time_tzdata": "<emoji document_id=5276412364458059956>🕓</emoji> Текущее время в {}: {}",
}
@loader.command(
ru_doc="Выводит время по UTC+n | Использование: .utc 4",
en_doc="Prints UTC+n time | Usage: .utc 4",
)
async def utccmd(self, message):
args = utils.get_args(message)
if not args or not args[0].isdigit() or len(args) > 1:
await utils.answer(message, self.strings["invalid_args"])
return
offset = timedelta(hours=int(args[0]))
tz = timezone(offset)
time = datetime.now(tz)
await utils.answer(
message, self.strings["time_utc"].format(args[0], time.strftime("%H:%M:%S"))
)
@loader.command(
ru_doc="Выводит время по часовому поясу tzdata | Использование: .tzdata Europe/Moscow",
en_doc="Prints time by tzdata timezone | Usage: .tzdata Europe/Moscow",
)
async def tzdatacmd(self, message):
args = utils.get_args(message)
if args[0].isdigit() or not args or len(args) > 1:
await utils.answer(message, self.strings["invalid_args"])
return
try:
time = datetime.now(ZoneInfo(args[0]))
except Exception as e:
await utils.answer(message, self.strings["tzdata_error"].format(e))
logger.error(self.strings["tzdata_error"].format(e))
return
await utils.answer(
message,
self.strings["time_tzdata"].format(args[0], time.strftime("%H:%M:%S")),
)

View File

@@ -1,238 +0,0 @@
# Proprietary License Agreement
# Copyright (c) 2026-2029
# Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
# 1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
# 2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
# 3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
# 4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
# 5. By using the Software, you agree to be bound by the terms and conditions of this license.
# For any inquiries or requests for permissions, please contact archquise@gmail.com
# ---------------------------------------------------------------------------------
# Name: YTDL
# Description: Downloads and sends audio/video from YouTube
# Author: @hikka_mods
# ---------------------------------------------------------------------------------
# meta developer: @hikka_mods
# requires: yt_dlp ffmpeg
# ---------------------------------------------------------------------------------
import shutil
import platform
import aiohttp
import aiofiles
import zipfile
import os
import re
import logging
from pathlib import Path
from yt_dlp import YoutubeDL
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class YTDLMod(loader.Module):
"""Downloads and sends audio/video from YouTube"""
strings = {
"name": "YTDL",
"_cls_doc": "Downloads and sends audio/video from YouTube",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or they are invalid",
"downloading": "<emoji document_id=5215484787325676090>🕐</emoji> Downloading...",
"done": "<emoji document_id=5854762571659218443>✅</emoji> Done!",
}
strings_ru = {
"_cls_doc": "Скачивает и отправляет аудио/видео с Ютуба",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или они неверны",
"downloading": "<emoji document_id=5215484787325676090>🕐</emoji> Скачиваю...",
"done": "<emoji document_id=5854762571659218443>✅</emoji> Готово!",
}
def _validate_url(self, url: str) -> bool:
"""Validate URL format"""
if not url:
return False
url_pattern = re.compile(
r"^(?:https?://)?(?:www\.|m\.)?(?:youtube\.com|youtu\.be|music\.youtube\.com)/(?:watch\?v=|playlist\?list=|channel/|@|live/|shorts/)?[\w-]+",
re.IGNORECASE,
)
return url_pattern.match(url) is not None
async def get_target(self):
system = platform.system()
machine = platform.machine().lower()
if system == "Windows":
return "Windows"
if system == "Darwin":
return (
"aarch64-apple-darwin" if machine == "arm64" else "x86_64-apple-darwin"
)
if system == "Linux":
return (
"aarch64-unknown-linux-gnu"
if machine in ("aarch64", "arm64")
else "x86_64-unknown-linux-gnu"
)
return "x86_64-unknown-linux-gnu"
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"youtube_cookie",
None,
"Cookie вашего Ютуб-аккаунта (повышает стабильность и помогает скачивать видео с жесткими возрастными ограничениями) | Cookie of your YouTube-account (increases stability and helps downloading video with strict age rating restricrions)",
validator=loader.validators.Hidden(),
),
)
async def client_ready(self, client, db):
deno_path = Path("deno")
deno_which = shutil.which("deno")
# Trying to fix previous shitcode...
if self.get("deno_source") == "file":
self.set("deno_source", str(deno_path.resolve()))
if not deno_which and not deno_path.is_file():
logger.warning("Deno is not installed, attempting installation...")
target = await self.get_target()
if target == "Windows":
logger.critical(
"Windows platform is unsupported by this module. All future commands will fail. Please, unload the module."
)
return
async with aiohttp.ClientSession() as session:
download_link = f"https://github.com/denoland/deno/releases/latest/download/deno-{target}.zip"
async with session.get(download_link) as resp:
if resp.status == 200:
async with aiofiles.open("deno.zip", mode="wb") as f:
async for chunk in resp.content.iter_chunked(8192):
await f.write(chunk)
else:
logger.critical(f"Failed to download Deno: HTTP {resp.status}")
self.set("deno_source", "install_failed")
return
if Path("deno.zip").is_file():
with zipfile.ZipFile("deno.zip", "r") as zip_ref:
zip_ref.extractall()
os.remove("deno.zip")
os.chmod(deno_path, 0o755)
self.set("deno_source", str(deno_path.resolve()))
elif deno_which:
self.set("deno_source", deno_which)
@loader.command(en_doc="Download video", ru_doc="Скачать видео")
async def ytdlvcmd(self, message):
args = utils.get_args(message)
if not args or not self._validate_url(args[0]) or len(args) > 1:
await utils.answer(message, self.strings["invalid_args"])
return
source = self.get("deno_source")
if source == "install_failed" or not Path(source).is_file():
logger.critical(
"Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot."
)
return
await utils.answer(message, self.strings["downloading"])
filename_prefix = f"video_{message.id}"
ydl_opts = {
"quiet": True,
"outtmpl": f"{filename_prefix}.%(ext)s",
"js_runtimes": {"deno": {"path": source}},
"postprocessors": [
{
"key": "FFmpegVideoConvertor",
"preferedformat": "mp4",
}
],
"postprocessor_args": {
"video_convertor": [
"-c:v",
"libx264",
"-pix_fmt",
"yuv420p",
"-preset",
"veryfast",
"-crf",
"23",
"-c:a",
"aac",
],
"merger": ["-movflags", "faststart"],
},
}
if self.get("youtube_cookie"):
ydl_opts["cookiefile"] = self.get("youtube_cookie")
with YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(args[0], download=True)
filename = ydl.prepare_filename(info).split(".")[0] + ".mp4"
await utils.answer(message, self.strings['done'], file=filename, invert_media=True)
os.remove(filename)
@loader.command(en_doc="Download audio", ru_doc="Скачать аудио")
async def ytdlacmd(self, message):
args = utils.get_args(message)
if not args or not self._validate_url(args[0]) or len(args) > 1:
await utils.answer(message, self.strings["invalid_args"])
return
source = self.get("deno_source")
if source == "install_failed" or not Path(source).is_file():
logger.critical(
"Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot."
)
return
await utils.answer(message, self.strings["downloading"])
filename_prefix = f"audio_{message.id}"
ydl_opts = {
"quiet": True,
"outtmpl": f"{filename_prefix}.%(ext)s",
"js_runtimes": {"deno": {"path": source}},
"postprocessors": [
{
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
"preferredquality": "0",
},
{
"key": "FFmpegMetadata",
"add_metadata": True,
},
{
"key": "EmbedThumbnail",
},
],
"writethumbnail": True,
}
if self.get("youtube_cookie"):
ydl_opts["cookiefile"] = self.get("youtube_cookie")
with YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(args[0], download=True)
filename = ydl.prepare_filename(info).split(".")[0] + ".mp3"
await utils.answer(message, self.strings['done'], file=filename)
os.remove(filename)

View File

@@ -13278,74 +13278,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/timezone.py": {
"name": "TimeZoneMod",
"description": "Prints current time in selected timezone (UTC+n and tzdata formats supported)",
"cls_doc": {
"default": "Prints current time in selected timezone (UTC+n and tzdata formats supported)",
"ru": "Выводит текущее время в выбранном часовом поясе (поддерживаются форматы UTC+n и tzdata)"
},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"utc": "(RU) Выводит время по UTC+n | Использование: .utc 4 | (EN) Prints UTC+n time | Usage: .utc 4"
},
{
"tzdata": "(RU) Выводит время по часовому поясу tzdata | Использование: .tzdata Europe/Moscow | (EN) Prints time by tzdata timezone | Usage: .tzdata Europe/Moscow"
}
],
"new_commands": [
{
"name": "utc",
"original_name": "utccmd",
"description": {
"default": "",
"ru": "Выводит время по UTC+n | Использование: .utc 4",
"en": "Prints UTC+n time | Usage: .utc 4"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "tzdata",
"original_name": "tzdatacmd",
"description": {
"default": "",
"ru": "Выводит время по часовому поясу tzdata | Использование: .tzdata Europe/Moscow",
"en": "Prints time by tzdata timezone | Usage: .tzdata Europe/Moscow"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "TimeZone",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or they are invalid",
"_cls_doc": "Prints current time in selected timezone (UTC+n and tzdata formats supported)",
"time_utc": "<emoji document_id=5276412364458059956>🕓</emoji> Current time by UTC+{}: {}",
"time_tzdata": "<emoji document_id=5276412364458059956>🕓</emoji> Current time in {}: {}",
"invalid_args_ru": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или они неверны",
"tzdata_error_ru": "<emoji document_id=5854929766146118183>❌</emoji> Произошла ошибка при получении времени по tzdata: {}\n\nУбедитесь, что часовой пояс указан верно",
"time_utc_ru": "<emoji document_id=5276412364458059956>🕓</emoji> Текущее время по UTC+{}: {}",
"time_tzdata_ru": "<emoji document_id=5276412364458059956>🕓</emoji> Текущее время в {}: {}"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/FakeActions.py": {
"name": "FakeActionsMod",
"description": "Module for simulating various actions in chat",
@@ -14013,103 +13945,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/IrisSimpleMod.py": {
"name": "IrisSimpleMod",
"description": "Module for basic interaction with Iris bot",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"bag": "Check bag | (RU) Проверить мешок | (EN) Check bag"
},
{
"farm": "Farm iris-coins | (RU) Зафармить ирис-коины | (EN) Farm iris-coins"
},
{
"irisstats": "Display user stats | (RU) Вывести анкету | (EN) Display user stats"
}
],
"new_commands": [
{
"name": "bag",
"original_name": "bag",
"description": {
"default": "Check bag",
"ru": "Проверить мешок",
"en": "Check bag"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "farm",
"original_name": "farm",
"description": {
"default": "Farm iris-coins",
"ru": "Зафармить ирис-коины",
"en": "Farm iris-coins"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "irisstats",
"original_name": "irisstats",
"description": {
"default": "Display user stats",
"ru": "Вывести анкету",
"en": "Display user stats"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "IrisSimpleMod",
"checking_bag": "<emoji document_id=5188311512791393083>🌎</emoji> Checking bag...",
"bag_result": "<emoji document_id=5854762571659218443>✅</emoji> Your bag: <code>{}</code>",
"farming": "<emoji document_id=5188311512791393083>🌎</emoji> Farming iris-coins...",
"farm_result": "<emoji document_id=5854762571659218443>✅</emoji> Farm result: <code>{}</code>",
"getting_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Getting user stats...",
"stats_result": "<emoji document_id=5854762571659218443>✅</emoji> User stats: <code>{}</code>",
"bot_stats": "<emoji document_id=5188311512791393083>🌎</emoji> Getting bot stats...",
"bot_stats_result": "<emoji document_id=5854762571659218443>✅</emoji> Bot stats: <code>{}</code>",
"error_no_response": "<emoji document_id=5854929766146118183>❌</emoji> No response from bot. Please try again.",
"error_timeout": "<emoji document_id=5854929766146118183>❌</emoji> Request timeout. Please try again.",
"error_general": "<emoji document_id=5854929766146118183>❌</emoji> An error occurred: {error}",
"checking_bag_ru": "<emoji document_id=5188311512791393083>🌎</emoji> Проверка мешка...",
"bag_result_ru": "<emoji document_id=5854762571659218443>✅</emoji> Ваш мешок: <code>{}</code>",
"farming_ru": "<emoji document_id=5188311512791393083>🌎</emoji> Фарм ирис-коинов...",
"farm_result_ru": "<emoji document_id=5854762571659218443>✅</emoji> Результат фарма: <code>{}</code>",
"getting_stats_ru": "<emoji document_id=5188311512791393083>🌎</emoji> Получение статистики пользователя...",
"stats_result_ru": "<emoji document_id=5854762571659218443>✅</emoji> Статистика пользователя: <code>{}</code>",
"bot_stats_ru": "<emoji document_id=5188311512791393083>🌎</emoji> Получение статистики ботов...",
"bot_stats_result_ru": "<emoji document_id=5854762571659218443>✅</emoji> Статистика ботов: <code>{}</code>",
"error_no_response_ru": "<emoji document_id=5854929766146118183>❌</emoji> Нет ответа от бота. Попробуйте еще раз.",
"error_timeout_ru": "<emoji document_id=5854929766146118183>❌</emoji> Таймаут запроса. Попробуйте еще раз.",
"error_general_ru": "<emoji document_id=5854929766146118183>❌</emoji> Произошла ошибка: {error}"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/sdsaver.py": {
"name": "SDSaverMod",
"description": "The module for automatically saving self-destructing media",
@@ -14585,107 +14420,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/FolderAutoRead.py": {
"name": "FolderAutoReadMod",
"description": "Automatically reads chats in selected folders",
"cls_doc": {
"default": "Automatically reads chats in selected folders every 60 seconds!",
"ru": "Автоматически читает чаты в выбранных папках каждые 60 секунд!"
},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"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 | (RU) Удалить папку из списка отслеживания | (EN) Delete folder from the tracking list | (R) Удаляет папку из списка для отслежнивания | (RU) Удаляет папку из списка для отслежнивания"
},
{
"listfolders": "Prints list of tracked folders | (RU) Список отслеживаемых папок | (EN) List tracked folders | (R) Выводит список отслеживаемых папок | (RU) Выводит список отслеживаемых папок"
}
],
"new_commands": [
{
"name": "addfolder",
"original_name": "addfolder",
"description": {
"default": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName",
"ru": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
"en": "Add folder to the tracking list",
"r": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "delfolder",
"original_name": "delfolder",
"description": {
"default": "Deletes folder from the tracking list",
"ru": "Удаляет папку из списка для отслежнивания",
"en": "Delete folder from the tracking list",
"r": "Удаляет папку из списка для отслежнивания"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "listfolders",
"original_name": "listfolders",
"description": {
"default": "Prints list of tracked folders",
"ru": "Выводит список отслеживаемых папок",
"en": "List tracked folders",
"r": "Выводит список отслеживаемых папок"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "FolderAutoRead",
"not_exists_or_already_added": "<emoji document_id=5278578973595427038>🚫</emoji> <b>This folder does not exists or it is already added for tracking!</b>",
"_cls_doc": "Automatically reads chats in selected folders every 60 seconds!",
"_cmd_doc_addfolder": "Adds folder to the tracking list by it's name. Usage: .addfolder FolderName",
"_cmd_doc_listfolders": "Prints list of tracked folders",
"_cmd_doc_delfolder": "Deletes folder from the tracking list",
"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",
"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>",
"not_exists_or_already_added_ru": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Такой папки не существует, или она уже добавлена для отслеживания!</b>",
"_cmd_doc_ru_addfolder": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
"_cmd_doc_addfolder_ru": "Добавляет папки в список отслеживания по их названию. Использование: .addfolder НазваниеПапки",
"_cmd_doc_ru_listfolders": "Выводит список отслеживаемых папок",
"_cmd_doc_listfolders_ru": "Выводит список отслеживаемых папок",
"_cmd_doc_ru_delfolder": "Удаляет папку из списка для отслежнивания",
"_cmd_doc_delfolder_ru": "Удаляет папку из списка для отслежнивания",
"wrong_args_ru": "<emoji document_id=5278578973595427038>🚫</emoji> <b>Неверные аргументы!</b> Использование: .addfolder/delfolder НазваниеПапки\n\n<i>Совет: Если вы пытаетесь удалить папку из списка отслеживания, проверьте, что она вообще отслеживается, используя .listfolders</i>",
"listfolders_ru": "<emoji document_id=5278227821364275264>📁</emoji> <b>Список отслеживаемых папок:</b>\n",
"delfolder_ru": "<emoji document_id=5276384644739129761>🗑</emoji> <b>Папка успешно удалена из листа отслеживания!</b>",
"addfolder_ru": "<emoji document_id=5278227821364275264>📁</emoji> <b>Папка успешно добавлена в лист отслеживания!</b>"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/MessageMonitor.py": {
"name": "MessageMonitor",
"description": "Monitor messages for trigger words in all chats.",
@@ -14959,51 +14693,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/face.py": {
"name": "face",
"description": "random face",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"rface": "(RU) Рандом kaomoji | (EN) Random kaomoji"
}
],
"new_commands": [
{
"name": "rface",
"original_name": "rfacecmd",
"description": {
"default": "",
"ru": "Рандом kaomoji",
"en": "Random kaomoji"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "face",
"loading": "<emoji document_id=5348399448017871250>🔍</emoji> I'm looking for you kaomoji",
"random_face": "<emoji document_id=5208878706717636743>🗿</emoji> Here is your random one kaomoji\n<code>{}</code>",
"error": "An error has occurred!",
"loading_ru": "<emoji document_id=5348399448017871250>🔍</emoji> Ищю вам kaomoji",
"random_face_ru": "<emoji document_id=5208878706717636743>🗿</emoji> Вот ваш рандомный kaomoji\n<code>{}</code>",
"error_ru": "Произошла ошибка!"
},
"has_on_load": false,
"has_on_unload": true,
"class_cmd_names": {}
},
"archquise/H.Modules/HAFK.py": {
"name": "HAFK",
"description": "",
@@ -15326,79 +15015,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/AniLiberty.py": {
"name": "AniLibertyMod",
"description": "Ищет и возвращает случайное аниме из базы Aniliberty",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"arandom": "(RU) Возвращает случайный релиз из базы | (EN) Returns a random release from the database"
},
{
"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 &lt;3</b>:",
"announce_ru": "<b>Анонс</b>:",
"ongoing_ru": "<b>Онгоинг</b>:",
"type_ru": "<b>Тип</b>:",
"genres_ru": "<b>Жанры</b>:",
"favorite_ru": "<b>Избранное &lt;3</b>:"
},
"has_on_load": false,
"has_on_unload": true,
"class_cmd_names": {}
},
"archquise/H.Modules/soundcloud.py": {
"name": "SoundCloudMod",
"description": "Display the currently playing SoundCloud track as a stylized card.",
@@ -16867,55 +16483,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/WindowsKeys.py": {
"name": "WindowsKeysMod",
"description": "Windows activation keys",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"winkey": "(RU) Меню ключей Windows | (EN) Windows keys menu"
}
],
"new_commands": [
{
"name": "winkey",
"original_name": "winkey",
"description": {
"default": "",
"ru": "Меню ключей Windows",
"en": "Windows keys menu"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "WindowsKeys",
"winkey": "✅ Key: <code>{}</code>\n\n⚠ For KMS activation only",
"error": "❌ Failed to get key",
"select": "🔓 Select version:",
"close": "🎈 Close",
"loading": "⌛ Loading...",
"winkey_ru": "✅ Ключ: <code>{}</code>\n\n⚠ Только для KMS активации",
"error_ru": "❌ Ошибка получения",
"select_ru": "🔓 Выберите версию:",
"close_ru": "🎈 Закрыть",
"loading_ru": "⌛ Загрузка..."
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/TimedEmojiStatus.py": {
"name": "TimedEmojiStatusMod",
"description": "Temporary emoji status with auto-revert using scheduler",
@@ -17683,125 +17250,6 @@
"has_on_unload": true,
"class_cmd_names": {}
},
"archquise/H.Modules/ytdl.py": {
"name": "YTDLMod",
"description": "Downloads and sends audio/video from YouTube",
"cls_doc": {
"default": "Downloads and sends audio/video from YouTube",
"ru": "Скачивает и отправляет аудио/видео с Ютуба"
},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"ytdlv": "(EN) Download video | (RU) Скачать видео"
},
{
"ytdla": "(EN) Download audio | (RU) Скачать аудио"
}
],
"new_commands": [
{
"name": "ytdlv",
"original_name": "ytdlvcmd",
"description": {
"default": "",
"en": "Download video",
"ru": "Скачать видео"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "ytdla",
"original_name": "ytdlacmd",
"description": {
"default": "",
"en": "Download audio",
"ru": "Скачать аудио"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "YTDL",
"_cls_doc": "Downloads and sends audio/video from YouTube",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or they are invalid",
"downloading": "<emoji document_id=5215484787325676090>🕐</emoji> Downloading...",
"done": "<emoji document_id=5854762571659218443>✅</emoji> Done!",
"invalid_args_ru": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или они неверны",
"downloading_ru": "<emoji document_id=5215484787325676090>🕐</emoji> Скачиваю...",
"done_ru": "<emoji document_id=5854762571659218443>✅</emoji> Готово!"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/TempChat.py": {
"name": "TempChatMod",
"description": "Creates a temporary private chat with a message forwarding restriction and adds the specified user to it.",
"cls_doc": {},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"tmpchat": "Create temporary chat. Usage: .tmpchat [@user/reply] [time] | (RU) Создает временный чат. Использование: .tmpchat [@user/reply] [time]"
}
],
"new_commands": [
{
"name": "tmpchat",
"original_name": "tmpchat",
"description": {
"default": "Create temporary chat. Usage: .tmpchat [@user/reply] [time]",
"ru": "Создает временный чат. Использование: .tmpchat [@user/reply] [time]"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "TempChat",
"selfchat": "You can't create a chat with yourself.",
"wrongargs": "<emoji document_id=5980953710157632545>❌</emoji> <b>Wrong arguments. Use </b><code>.tmpchat [@user/reply] [time]</code><b>",
"alreadychatting": "<emoji document_id=5980953710157632545>❌</emoji> <b>You already have an active conversation with this person.</b>",
"invalidtime": "<emoji document_id=5980953710157632545>❌</emoji> <b>Invalid time format. Use combinations like 1h30m.</b>",
"invitemsg": "<emoji document_id=5818967120213445821>🛡</emoji> You've been invited to a temporary private chat!\n\n<emoji document_id=5451646226975955576>⌛️</emoji> Auto-deletes in ",
"joinlink": "🔗 Join link: ",
"chatcreated": "<emoji document_id=5980930633298350051>✅</emoji> The temporary chat has been successfully created!",
"selfchat_ru": "Ты не можешь создать чат сам с собой.",
"wrongargs_ru": "<emoji document_id=5980953710157632545>❌</emoji> <b>Неверные аргументы. Используй </b><code>.tmpchat [@user/reply] [время]</code>",
"alreadychatting_ru": "<emoji document_id=5980953710157632545>❌</emoji> <b>У вас уже есть открытая переписка с этим человеком.</b>",
"invalidtime_ru": "<emoji document_id=5980953710157632545>❌</emoji> <b>Неверный формат времени. Убедитесь, что вы вводите время в формате 1h, 2h30m.</b>",
"invitemsg_ru": "<emoji document_id=5818967120213445821>🛡</emoji> Вы были приглашены во временный приватный чат!\n\n<emoji document_id=5451646226975955576>⌛️</emoji> Авто-удаление через ",
"joinlink_ru": "🔗 Ссылка: ",
"chatcreated_ru": "<emoji document_id=5980930633298350051>✅</emoji> Временный чат успешно создан!"
},
"has_on_load": false,
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/search.py": {
"name": "Search",
"description": "Поисковик",
@@ -18013,79 +17461,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/shortener.py": {
"name": "Shortener",
"description": "Module for using bit.ly API",
"cls_doc": {
"default": "Module for using bit.ly API",
"ru": "Модуль для использования API bit.ly"
},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"shorten": "Shorten URL using bit.ly API | (RU) Сократить ссылку через bit.ly (ссылка с https://) | (EN) Shorten the link via bit.ly (url with https://)"
},
{
"statcl": "Get click statistics for shortened URL | (RU) Посмотреть статистику ссылки через bit.ly (ссылка без https:// | Доступно только на платных аккаунтах) | (EN) View link statistics via bit.ly (link without https:// | Works only on paid accounts)"
}
],
"new_commands": [
{
"name": "shorten",
"original_name": "shortencmd",
"description": {
"default": "Shorten URL using bit.ly API",
"ru": "Сократить ссылку через bit.ly (ссылка с https://)",
"en": "Shorten the link via bit.ly (url with https://)"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
},
{
"name": "statcl",
"original_name": "statclcmd",
"description": {
"default": "Get click statistics for shortened URL",
"ru": "Посмотреть статистику ссылки через bit.ly (ссылка без https:// | Доступно только на платных аккаунтах)",
"en": "View link statistics via bit.ly (link without https:// | Works only on paid accounts)"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "Shortener",
"no_api": "<emoji document_id=5854929766146118183>❌</emoji> You have not specified an API token from the site <a href='https://app.bitly.com/settings/api/'>bit.ly</a>",
"statclcmd": "<emoji document_id=5787384838411522455>📊</emoji> <b>Statistics on clicks for this link:</b> {c}",
"shortencmd": "<emoji document_id=5854762571659218443>✅</emoji> <b>Your shortened link is ready:</b> <code>{c}</code>",
"no_args": "<emoji document_id=5854929766146118183>❌</emoji> Please provide a URL to shorten.",
"invalid_url": "<emoji document_id=5854929766146118183>❌</emoji> Invalid URL format.",
"api_error": "<emoji document_id=5854929766146118183>❌</emoji> API error: {error}",
"_cls_doc": "Module for using bit.ly API",
"no_api_ru": "<emoji document_id=5854929766146118183>❌</emoji> Вы не указали api токен с сайта <a href='https://app.bitly.com/settings/api/'>bit.ly</a>",
"statclcmd_ru": "<emoji document_id=5787384838411522455>📊</emoji> <b>Статистика о переходе по этой ссылке:</b> {c}",
"shortencmd_ru": "<emoji document_id=5854762571659218443>✅</emoji> <b>Ваша сокращённая ссылка готова:</b> <code>{c}</code>",
"no_args_ru": "<emoji document_id=5854929766146118183>❌</emoji> Пожалуйста, укажите URL для сокращения.",
"invalid_url_ru": "<emoji document_id=5854929766146118183>❌</emoji> Неверный формат URL.",
"api_error_ru": "<emoji document_id=5854929766146118183>❌</emoji> Ошибка API: {error}"
},
"has_on_load": false,
"has_on_unload": true,
"class_cmd_names": {}
},
"archquise/H.Modules/Memes.py": {
"name": "MemesMod",
"description": "Random memes",
@@ -18131,53 +17506,6 @@
"has_on_unload": false,
"class_cmd_names": {}
},
"archquise/H.Modules/CodeShare.py": {
"name": "CodeShareMod",
"description": "Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)",
"cls_doc": {
"default": "Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)",
"ru": "Загружает ваш код на kmi.aeza.net (альтернатива Pastebin и GitHub Gist)"
},
"meta": {
"pic": null,
"banner": null,
"developer": "@hikka_mods"
},
"commands": [
{
"codeshare": "(RU) Загрузка кода на сайт | (EN) Upload code to the site"
}
],
"new_commands": [
{
"name": "codeshare",
"original_name": "codesharecmd",
"description": {
"default": "",
"ru": "Загрузка кода на сайт",
"en": "Upload code to the site"
},
"cmd_names": {},
"aliases": [],
"usage": null,
"inline": false,
"is_inline_handler": false,
"decorators": []
}
],
"inline_handlers": [],
"strings": {
"name": "CodeShare",
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or reply with a file, or they are invalid",
"_cls_doc": "Uploads your code at the kmi.aeza.net (Pastebin and GitHub Gist alternative)",
"link_ready": "<emoji document_id=5854762571659218443>✅</emoji> <b>Code uploaded! Link:</b> <code>{}</code>",
"invalid_args_ru": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или реплая с файлом, или они неверны",
"link_ready_ru": "<emoji document_id=5854762571659218443>✅</emoji> <b>Код загружен! Ссылка:</b> <code>{}</code>"
},
"has_on_load": false,
"has_on_unload": true,
"class_cmd_names": {}
},
"archquise/H.Modules/passgen.py": {
"name": "PassgenMod",
"description": "generate random password",
@@ -85195,7 +84523,7 @@
}
},
"meta": {
"total_modules": 1060,
"generated_at": "2026-04-18T01:49:43.246930"
"total_modules": 1050,
"generated_at": "2026-04-19T02:02:03.488953"
}
}