12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232 |
- # █ █ ▀ █▄▀ ▄▀█ █▀█ ▀
- # █▀█ █ █ █ █▀█ █▀▄ █
- # © Copyright 2022
- # https://t.me/hikariatama
- #
- # 🔒 Licensed under the GNU AGPLv3
- # 🌐 https://www.gnu.org/licenses/agpl-3.0.html
- import logging
- import atexit
- import random
- import sys
- import os
- import telethon
- from telethon.tl.types import Message
- from telethon.tl.functions.messages import (
- GetDialogFiltersRequest,
- UpdateDialogFilterRequest,
- )
- from telethon.tl.functions.channels import JoinChannelRequest
- from telethon.utils import get_display_name
- from .. import loader, main, utils
- from ..inline.types import InlineCall
- logger = logging.getLogger(__name__)
- ALL_INVOKES = [
- "clear_entity_cache",
- "clear_fulluser_cache",
- "clear_fullchannel_cache",
- "clear_perms_cache",
- "clear_cache",
- "reload_core",
- "inspect_cache",
- "inspect_modules",
- ]
- def restart(*argv):
- os.execl(
- sys.executable,
- sys.executable,
- "-m",
- os.path.relpath(utils.get_base_dir()),
- *argv,
- )
- @loader.tds
- class HikkaSettingsMod(loader.Module):
- """Advanced settings for Hikka Userbot"""
- strings = {
- "name": "HikkaSettings",
- "watchers": (
- "<emoji document_id=5424885441100782420>👀</emoji>"
- " <b>Watchers:</b>\n\n<b>{}</b>"
- ),
- "no_args": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>No arguments"
- " specified</b>"
- ),
- "invoke404": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Internal debug method"
- " </b><code>{}</code><b> not found, ergo can't be invoked</b>"
- ),
- "module404": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Module</b>"
- " <code>{}</code> <b>not found</b>"
- ),
- "invoke": (
- "<emoji document_id=5215519585150706301>👍</emoji> <b>Invoked internal debug"
- " method </b><code>{}</code>\n\n<emoji"
- " document_id=5784891605601225888>🔵</emoji> <b>Result: \n{}</b>"
- ),
- "invoking": (
- "<emoji document_id=5213452215527677338>⏳</emoji> <b>Invoking internal"
- " debug method </b><code>{}</code><b> of </b><code>{}</code><b>...</b>"
- ),
- "mod404": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Watcher {} not"
- " found</b>"
- ),
- "disabled": (
- "<emoji document_id=5424885441100782420>👀</emoji> <b>Watcher {} is now"
- " <u>disabled</u></b>"
- ),
- "enabled": (
- "<emoji document_id=5424885441100782420>👀</emoji> <b>Watcher {} is now"
- " <u>enabled</u></b>"
- ),
- "args": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>You need to specify"
- " watcher name</b>"
- ),
- "user_nn": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick for this user"
- " is now {}</b>"
- ),
- "no_cmd": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Please, specify"
- " command to toggle NoNick for</b>"
- ),
- "cmd_nn": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick for"
- " </b><code>{}</code><b> is now {}</b>"
- ),
- "cmd404": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Command not found</b>"
- ),
- "inline_settings": "⚙️ <b>Here you can configure your Hikka settings</b>",
- "confirm_update": (
- "🧭 <b>Please, confirm that you want to update. Your userbot will be"
- " restarted</b>"
- ),
- "confirm_restart": "🔄 <b>Please, confirm that you want to restart</b>",
- "suggest_fs": "✅ Suggest FS for modules",
- "do_not_suggest_fs": "🚫 Suggest FS for modules",
- "use_fs": "✅ Always use FS for modules",
- "do_not_use_fs": "🚫 Always use FS for modules",
- "btn_restart": "🔄 Restart",
- "btn_update": "🧭 Update",
- "close_menu": "😌 Close menu",
- "custom_emojis": "✅ Custom emojis",
- "no_custom_emojis": "🚫 Custom emojis",
- "suggest_subscribe": "✅ Suggest subscribe to channel",
- "do_not_suggest_subscribe": "🚫 Suggest subscribe to channel",
- "private_not_allowed": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>This command must be"
- " executed in chat</b>"
- ),
- "nonick_warning": (
- "Warning! You enabled NoNick with default prefix! "
- "You may get muted in Hikka chats. Change prefix or "
- "disable NoNick!"
- ),
- "reply_required": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Reply to a message"
- " of user, which needs to be added to NoNick</b>"
- ),
- "deauth_confirm": (
- "⚠️ <b>This action will fully remove Hikka from this account and can't be"
- " reverted!</b>\n\n<i>- Hikka chats will be removed\n- Session will be"
- " terminated and removed\n- Hikka inline bot will be removed</i>"
- ),
- "deauth_confirm_step2": (
- "⚠️ <b>Are you really sure you want to delete Hikka?</b>"
- ),
- "deauth_yes": "I'm sure",
- "deauth_no_1": "I'm not sure",
- "deauth_no_2": "I'm uncertain",
- "deauth_no_3": "I'm struggling to answer",
- "deauth_cancel": "🚫 Cancel",
- "deauth_confirm_btn": "😢 Delete",
- "uninstall": "😢 <b>Uninstalling Hikka...</b>",
- "uninstalled": (
- "😢 <b>Hikka uninstalled. Web interface is still active, you can add another"
- " account</b>"
- ),
- "logs_cleared": "🗑 <b>Logs cleared</b>",
- "cmd_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick is enabled"
- " for these commands:</b>\n\n{}"
- ),
- "user_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick is enabled"
- " for these users:</b>\n\n{}"
- ),
- "chat_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick is enabled"
- " for these chats:</b>\n\n{}"
- ),
- "nothing": (
- "<emoji document_id=5427052514094619126>🤷♀️</emoji> <b>Nothing to"
- " show...</b>"
- ),
- "privacy_leak": (
- "⚠️ <b>This command gives access to your Hikka web interface. It's not"
- " recommended to run it in public group chats. Consider using it in <a"
- " href='tg://openmessage?user_id={}'>Saved messages</a>. Type"
- " </b><code>{}proxypass force_insecure</code><b> to ignore this warning</b>"
- ),
- "privacy_leak_nowarn": (
- "⚠️ <b>This command gives access to your Hikka web interface. It's not"
- " recommended to run it in public group chats. Consider using it in <a"
- " href='tg://openmessage?user_id={}'>Saved messages</a>.</b>"
- ),
- "opening_tunnel": "🔁 <b>Opening tunnel to Hikka web interface...</b>",
- "tunnel_opened": "🎉 <b>Tunnel opened. This link is valid for about 1 hour</b>",
- "web_btn": "🌍 Web interface",
- "btn_yes": "🚸 Open anyway",
- "btn_no": "🔻 Cancel",
- "lavhost_web": (
- "✌️ <b>This link leads to your Hikka web interface on lavHost</b>\n\n<i>💡"
- " You'll need to authorize using lavHost credentials, specified on"
- " registration</i>"
- ),
- "disable_stats": "✅ Anonymous stats allowed",
- "enable_stats": "🚫 Anonymous stats disabled",
- }
- strings_ru = {
- "watchers": (
- "<emoji document_id=5424885441100782420>👀</emoji>"
- " <b>Смотрители:</b>\n\n<b>{}</b>"
- ),
- "mod404": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Смотритель {} не"
- " найден</b>"
- ),
- "disabled": (
- "<emoji document_id=5424885441100782420>👀</emoji> <b>Смотритель {} теперь"
- " <u>выключен</u></b>"
- ),
- "enabled": (
- "<emoji document_id=5424885441100782420>👀</emoji> <b>Смотритель {} теперь"
- " <u>включен</u></b>"
- ),
- "args": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Укажи имя"
- " смотрителя</b>"
- ),
- "user_nn": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Состояние NoNick для"
- " этого пользователя: {}</b>"
- ),
- "no_cmd": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Укажи команду, для"
- " которой надо включить\\выключить NoNick</b>"
- ),
- "cmd_nn": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Состояние NoNick для"
- " </b><code>{}</code><b>: {}</b>"
- ),
- "cmd404": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>Команда не найдена</b>"
- ),
- "inline_settings": "⚙️ <b>Здесь можно управлять настройками Hikka</b>",
- "confirm_update": "🧭 <b>Подтвердите обновление. Юзербот будет перезагружен</b>",
- "confirm_restart": "🔄 <b>Подтвердите перезагрузку</b>",
- "suggest_fs": "✅ Предлагать сохранение модулей",
- "do_not_suggest_fs": "🚫 Предлагать сохранение модулей",
- "use_fs": "✅ Всегда сохранять модули",
- "do_not_use_fs": "🚫 Всегда сохранять модули",
- "btn_restart": "🔄 Перезагрузка",
- "btn_update": "🧭 Обновление",
- "close_menu": "😌 Закрыть меню",
- "custom_emojis": "✅ Кастомные эмодзи",
- "no_custom_emojis": "🚫 Кастомные эмодзи",
- "suggest_subscribe": "✅ Предлагать подписку на канал",
- "do_not_suggest_subscribe": "🚫 Предлагать подписку на канал",
- "private_not_allowed": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Эту команду нужно"
- " выполнять в чате</b>"
- ),
- "_cls_doc": "Дополнительные настройки Hikka",
- "nonick_warning": (
- "Внимание! Ты включил NoNick со стандартным префиксом! "
- "Тебя могут замьютить в чатах Hikka. Измени префикс или "
- "отключи глобальный NoNick!"
- ),
- "reply_required": (
- "<emoji document_id=5447207618793708263>🚫</emoji> <b>Ответь на сообщение"
- " пользователя, для которого нужно включить NoNick</b>"
- ),
- "deauth_confirm": (
- "⚠️ <b>Это действие полностью удалит Hikka с этого аккаунта! Его нельзя"
- " отменить</b>\n\n<i>- Все чаты, связанные с Hikka будут удалены\n- Сессия"
- " Hikka будет сброшена\n- Инлайн бот Hikka будет удален</i>"
- ),
- "deauth_confirm_step2": "⚠️ <b>Ты точно уверен, что хочешь удалить Hikka?</b>",
- "deauth_yes": "Я уверен",
- "deauth_no_1": "Я не уверен",
- "deauth_no_2": "Не точно",
- "deauth_no_3": "Нет",
- "deauth_cancel": "🚫 Отмена",
- "deauth_confirm_btn": "😢 Удалить",
- "uninstall": "😢 <b>Удаляю Hikka...</b>",
- "uninstalled": (
- "😢 <b>Hikka удалена. Веб-интерфейс все еще активен, можно добавить другие"
- " аккаунты!</b>"
- ),
- "logs_cleared": "🗑 <b>Логи очищены</b>",
- "cmd_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick включен для"
- " этих команд:</b>\n\n{}"
- ),
- "user_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick включен для"
- " этих пользователей:</b>\n\n{}"
- ),
- "chat_nn_list": (
- "<emoji document_id=5469791106591890404>🪄</emoji> <b>NoNick включен для"
- " этих чатов:</b>\n\n{}"
- ),
- "nothing": (
- "<emoji document_id=5427052514094619126>🤷♀️</emoji> <b>Нечего"
- " показывать...</b>"
- ),
- "privacy_leak": (
- "⚠️ <b>Эта команда дает доступ к веб-интерфейсу Hikka. Ее выполнение в"
- " публичных чатах является угрозой безопасности. Предпочтительно выполнять"
- " ее в <a href='tg://openmessage?user_id={}'>Избранных сообщениях</a>."
- " Выполни </b><code>{}proxypass force_insecure</code><b> чтобы отключить"
- " это предупреждение</b>"
- ),
- "privacy_leak_nowarn": (
- "⚠️ <b>Эта команда дает доступ к веб-интерфейсу Hikka. Ее выполнение в"
- " публичных чатах является угрозой безопасности. Предпочтительно выполнять"
- " ее в <a href='tg://openmessage?user_id={}'>Избранных сообщениях</a>.</b>"
- ),
- "opening_tunnel": "🔁 <b>Открываю тоннель к веб-интерфейсу Hikka...</b>",
- "tunnel_opened": (
- "🎉 <b>Тоннель открыт. Эта ссылка будет активна не более часа</b>"
- ),
- "web_btn": "🌍 Веб-интерфейс",
- "btn_yes": "🚸 Все равно открыть",
- "btn_no": "🔻 Закрыть",
- "lavhost_web": (
- "✌️ <b>По этой ссылке ты попадешь в веб-интерфейс Hikka на"
- " lavHost</b>\n\n<i>💡 Тебе нужно будет авторизоваться, используя данные,"
- " указанные при настройке lavHost</i>"
- ),
- "disable_stats": "✅ Анонимная стата разрешена",
- "enable_stats": "🚫 Анонимная стата запрещена",
- }
- def get_watchers(self) -> tuple:
- return [
- str(watcher.__self__.__class__.strings["name"])
- for watcher in self.allmodules.watchers
- if watcher.__self__.__class__.strings is not None
- ], self._db.get(main.__name__, "disabled_watchers", {})
- async def _uninstall(self, call: InlineCall):
- await call.edit(self.strings("uninstall"))
- async with self._client.conversation("@BotFather") as conv:
- for msg in [
- "/deletebot",
- f"@{self.inline.bot_username}",
- "Yes, I am totally sure.",
- ]:
- m = await conv.send_message(msg)
- r = await conv.get_response()
- logger.debug(">> %s", m.raw_text)
- logger.debug("<< %s", r.raw_text)
- await m.delete()
- await r.delete()
- async for dialog in self._client.iter_dialogs(
- None,
- ignore_migrated=True,
- ):
- if (
- dialog.name
- in {
- "hikka-logs",
- "hikka-onload",
- "hikka-assets",
- "hikka-backups",
- "hikka-acc-switcher",
- "silent-tags",
- }
- and dialog.is_channel
- and (
- dialog.entity.participants_count == 1
- or dialog.entity.participants_count == 2
- and dialog.name in {"hikka-logs", "silent-tags"}
- )
- or (
- self._client.loader.inline.init_complete
- and dialog.entity.id == self._client.loader.inline.bot_id
- )
- ):
- await self._client.delete_dialog(dialog.entity)
- folders = await self._client(GetDialogFiltersRequest())
- if any(folder.title == "hikka" for folder in folders):
- folder_id = max(
- folders,
- key=lambda x: x.id,
- ).id
- await self._client(UpdateDialogFilterRequest(id=folder_id))
- for handler in logging.getLogger().handlers:
- handler.setLevel(logging.CRITICAL)
- await self._client.log_out()
- await call.edit(self.strings("uninstalled"))
- if "LAVHOST" in os.environ:
- os.system("lavhost restart")
- return
- atexit.register(restart, *sys.argv[1:])
- sys.exit(0)
- async def _uninstall_confirm_step_2(self, call: InlineCall):
- await call.edit(
- self.strings("deauth_confirm_step2"),
- utils.chunks(
- list(
- sorted(
- [
- {
- "text": self.strings("deauth_yes"),
- "callback": self._uninstall,
- },
- *[
- {
- "text": self.strings(f"deauth_no_{i}"),
- "action": "close",
- }
- for i in range(1, 4)
- ],
- ],
- key=lambda _: random.random(),
- )
- ),
- 2,
- )
- + [
- [
- {
- "text": self.strings("deauth_cancel"),
- "action": "close",
- }
- ]
- ],
- )
- @loader.owner
- @loader.command(ru_doc="Удалить Hikka")
- async def uninstall_hikka(self, message: Message):
- """Uninstall Hikka"""
- await self.inline.form(
- self.strings("deauth_confirm"),
- message,
- [
- {
- "text": self.strings("deauth_confirm_btn"),
- "callback": self._uninstall_confirm_step_2,
- },
- {"text": self.strings("deauth_cancel"), "action": "close"},
- ],
- )
- @loader.command(ru_doc="Очистить логи")
- async def clearlogs(self, message: Message):
- """Clear logs"""
- for handler in logging.getLogger().handlers:
- handler.buffer = []
- handler.handledbuffer = []
- handler.tg_buff = ""
- await utils.answer(message, self.strings("logs_cleared"))
- @loader.command(ru_doc="Показать активные смотрители")
- async def watchers(self, message: Message):
- """List current watchers"""
- watchers, disabled_watchers = self.get_watchers()
- watchers = [
- f"♻️ {watcher}"
- for watcher in watchers
- if watcher not in list(disabled_watchers.keys())
- ]
- watchers += [f"💢 {k} {v}" for k, v in disabled_watchers.items()]
- await utils.answer(
- message, self.strings("watchers").format("\n".join(watchers))
- )
- @loader.command(ru_doc="<module> - Включить/выключить смотрителя в текущем чате")
- async def watcherbl(self, message: Message):
- """<module> - Toggle watcher in current chat"""
- args = utils.get_args_raw(message)
- if not args:
- await utils.answer(message, self.strings("args"))
- return
- watchers, disabled_watchers = self.get_watchers()
- if args.lower() not in map(lambda x: x.lower(), watchers):
- await utils.answer(message, self.strings("mod404").format(args))
- return
- args = next((x.lower() == args.lower() for x in watchers), False)
- current_bl = [
- v for k, v in disabled_watchers.items() if k.lower() == args.lower()
- ]
- current_bl = current_bl[0] if current_bl else []
- chat = utils.get_chat_id(message)
- if chat not in current_bl:
- if args in disabled_watchers:
- for k in disabled_watchers:
- if k.lower() == args.lower():
- disabled_watchers[k].append(chat)
- break
- else:
- disabled_watchers[args] = [chat]
- await utils.answer(
- message,
- self.strings("disabled").format(args) + " <b>in current chat</b>",
- )
- else:
- for k in disabled_watchers.copy():
- if k.lower() == args.lower():
- disabled_watchers[k].remove(chat)
- if not disabled_watchers[k]:
- del disabled_watchers[k]
- break
- await utils.answer(
- message,
- self.strings("enabled").format(args) + " <b>in current chat</b>",
- )
- self._db.set(main.__name__, "disabled_watchers", disabled_watchers)
- @loader.command(
- ru_doc=(
- "<модуль> - Управление глобальными правилами смотрителя\n"
- "Аргументы:\n"
- "[-c - только в чатах]\n"
- "[-p - только в лс]\n"
- "[-o - только исходящие]\n"
- "[-i - только входящие]"
- )
- )
- async def watchercmd(self, message: Message):
- """<module> - Toggle global watcher rules
- Args:
- [-c - only in chats]
- [-p - only in pm]
- [-o - only out]
- [-i - only incoming]"""
- args = utils.get_args_raw(message)
- if not args:
- return await utils.answer(message, self.strings("args"))
- chats, pm, out, incoming = False, False, False, False
- if "-c" in args:
- args = args.replace("-c", "").replace(" ", " ").strip()
- chats = True
- if "-p" in args:
- args = args.replace("-p", "").replace(" ", " ").strip()
- pm = True
- if "-o" in args:
- args = args.replace("-o", "").replace(" ", " ").strip()
- out = True
- if "-i" in args:
- args = args.replace("-i", "").replace(" ", " ").strip()
- incoming = True
- if chats and pm:
- pm = False
- if out and incoming:
- incoming = False
- watchers, disabled_watchers = self.get_watchers()
- if args.lower() not in [watcher.lower() for watcher in watchers]:
- return await utils.answer(message, self.strings("mod404").format(args))
- args = [watcher for watcher in watchers if watcher.lower() == args.lower()][0]
- if chats or pm or out or incoming:
- disabled_watchers[args] = [
- *(["only_chats"] if chats else []),
- *(["only_pm"] if pm else []),
- *(["out"] if out else []),
- *(["in"] if incoming else []),
- ]
- self._db.set(main.__name__, "disabled_watchers", disabled_watchers)
- await utils.answer(
- message,
- self.strings("enabled").format(args)
- + f" (<code>{disabled_watchers[args]}</code>)",
- )
- return
- if args in disabled_watchers and "*" in disabled_watchers[args]:
- await utils.answer(message, self.strings("enabled").format(args))
- del disabled_watchers[args]
- self._db.set(main.__name__, "disabled_watchers", disabled_watchers)
- return
- disabled_watchers[args] = ["*"]
- self._db.set(main.__name__, "disabled_watchers", disabled_watchers)
- await utils.answer(message, self.strings("disabled").format(args))
- @loader.command(ru_doc="Включить NoNick для определенного пользователя")
- async def nonickuser(self, message: Message):
- """Allow no nickname for certain user"""
- reply = await message.get_reply_message()
- if not reply:
- await utils.answer(message, self.strings("reply_required"))
- return
- u = reply.sender_id
- if not isinstance(u, int):
- u = u.user_id
- nn = self._db.get(main.__name__, "nonickusers", [])
- if u not in nn:
- nn += [u]
- nn = list(set(nn)) # skipcq: PTC-W0018
- await utils.answer(message, self.strings("user_nn").format("on"))
- else:
- nn = list(set(nn) - {u})
- await utils.answer(message, self.strings("user_nn").format("off"))
- self._db.set(main.__name__, "nonickusers", nn)
- @loader.command(ru_doc="Включить NoNick для определенного чата")
- async def nonickchat(self, message: Message):
- """Allow no nickname in certain chat"""
- if message.is_private:
- await utils.answer(message, self.strings("private_not_allowed"))
- return
- chat = utils.get_chat_id(message)
- nn = self._db.get(main.__name__, "nonickchats", [])
- if chat not in nn:
- nn += [chat]
- nn = list(set(nn)) # skipcq: PTC-W0018
- await utils.answer(
- message,
- self.strings("cmd_nn").format(
- utils.escape_html((await message.get_chat()).title),
- "on",
- ),
- )
- else:
- nn = list(set(nn) - {chat})
- await utils.answer(
- message,
- self.strings("cmd_nn").format(
- utils.escape_html((await message.get_chat()).title),
- "off",
- ),
- )
- self._db.set(main.__name__, "nonickchats", nn)
- @loader.command(ru_doc="Включить NoNick для определенной команды")
- async def nonickcmdcmd(self, message: Message):
- """Allow certain command to be executed without nickname"""
- args = utils.get_args_raw(message)
- if not args:
- await utils.answer(message, self.strings("no_cmd"))
- return
- if args not in self.allmodules.commands:
- await utils.answer(message, self.strings("cmd404"))
- return
- nn = self._db.get(main.__name__, "nonickcmds", [])
- if args not in nn:
- nn += [args]
- nn = list(set(nn))
- await utils.answer(
- message,
- self.strings("cmd_nn").format(
- self.get_prefix() + args,
- "on",
- ),
- )
- else:
- nn = list(set(nn) - {args})
- await utils.answer(
- message,
- self.strings("cmd_nn").format(
- self.get_prefix() + args,
- "off",
- ),
- )
- self._db.set(main.__name__, "nonickcmds", nn)
- @loader.command(ru_doc="Показать список активных NoNick команд")
- async def nonickcmds(self, message: Message):
- """Returns the list of NoNick commands"""
- if not self._db.get(main.__name__, "nonickcmds", []):
- await utils.answer(message, self.strings("nothing"))
- return
- await utils.answer(
- message,
- self.strings("cmd_nn_list").format(
- "\n".join(
- [
- f"▫️ <code>{self.get_prefix()}{cmd}</code>"
- for cmd in self._db.get(main.__name__, "nonickcmds", [])
- ]
- )
- ),
- )
- @loader.command(ru_doc="Показать список активных NoNick пользователей")
- async def nonickusers(self, message: Message):
- """Returns the list of NoNick users"""
- users = []
- for user_id in self._db.get(main.__name__, "nonickusers", []).copy():
- try:
- user = await self._client.get_entity(user_id)
- except Exception:
- self._db.set(
- main.__name__,
- "nonickusers",
- list(
- (
- set(self._db.get(main.__name__, "nonickusers", []))
- - {user_id}
- )
- ),
- )
- logger.warning("User %s removed from nonickusers list", user_id)
- continue
- users += [
- '▫️ <b><a href="tg://user?id={}">{}</a></b>'.format(
- user_id,
- utils.escape_html(get_display_name(user)),
- )
- ]
- if not users:
- await utils.answer(message, self.strings("nothing"))
- return
- await utils.answer(
- message,
- self.strings("user_nn_list").format("\n".join(users)),
- )
- @loader.command(ru_doc="Показать список активных NoNick чатов")
- async def nonickchats(self, message: Message):
- """Returns the list of NoNick chats"""
- chats = []
- for chat in self._db.get(main.__name__, "nonickchats", []):
- try:
- chat_entity = await self._client.get_entity(int(chat))
- except Exception:
- self._db.set(
- main.__name__,
- "nonickchats",
- list(
- (set(self._db.get(main.__name__, "nonickchats", [])) - {chat})
- ),
- )
- logger.warning("Chat %s removed from nonickchats list", chat)
- continue
- chats += [
- '▫️ <b><a href="{}">{}</a></b>'.format(
- utils.get_entity_url(chat_entity),
- utils.escape_html(get_display_name(chat_entity)),
- )
- ]
- if not chats:
- await utils.answer(message, self.strings("nothing"))
- return
- await utils.answer(
- message,
- self.strings("user_nn_list").format("\n".join(chats)),
- )
- async def inline__setting(self, call: InlineCall, key: str, state: bool = False):
- if callable(key):
- key()
- telethon.extensions.html.CUSTOM_EMOJIS = not main.get_config_key(
- "disable_custom_emojis"
- )
- else:
- self._db.set(main.__name__, key, state)
- if key == "no_nickname" and state and self.get_prefix() == ".":
- await call.answer(
- self.strings("nonick_warning"),
- show_alert=True,
- )
- else:
- await call.answer("Configuration value saved!")
- await call.edit(
- self.strings("inline_settings"),
- reply_markup=self._get_settings_markup(),
- )
- async def inline__update(
- self,
- call: InlineCall,
- confirm_required: bool = False,
- ):
- if confirm_required:
- await call.edit(
- self.strings("confirm_update"),
- reply_markup=[
- {"text": "🪂 Update", "callback": self.inline__update},
- {"text": "🚫 Cancel", "action": "close"},
- ],
- )
- return
- await call.answer("You userbot is being updated...", show_alert=True)
- await call.delete()
- m = await self._client.send_message("me", f"{self.get_prefix()}update --force")
- await self.allmodules.commands["update"](m)
- async def inline__restart(
- self,
- call: InlineCall,
- confirm_required: bool = False,
- ):
- if confirm_required:
- await call.edit(
- self.strings("confirm_restart"),
- reply_markup=[
- {"text": "🔄 Restart", "callback": self.inline__restart},
- {"text": "🚫 Cancel", "action": "close"},
- ],
- )
- return
- await call.answer("You userbot is being restarted...", show_alert=True)
- await call.delete()
- await self.allmodules.commands["restart"](
- await self._client.send_message("me", f"{self.get_prefix()}restart --force")
- )
- def _get_settings_markup(self) -> list:
- return [
- [
- (
- {
- "text": "✅ NoNick",
- "callback": self.inline__setting,
- "args": (
- "no_nickname",
- False,
- ),
- }
- if self._db.get(main.__name__, "no_nickname", False)
- else {
- "text": "🚫 NoNick",
- "callback": self.inline__setting,
- "args": (
- "no_nickname",
- True,
- ),
- }
- ),
- (
- {
- "text": "✅ Grep",
- "callback": self.inline__setting,
- "args": (
- "grep",
- False,
- ),
- }
- if self._db.get(main.__name__, "grep", False)
- else {
- "text": "🚫 Grep",
- "callback": self.inline__setting,
- "args": (
- "grep",
- True,
- ),
- }
- ),
- (
- {
- "text": "✅ InlineLogs",
- "callback": self.inline__setting,
- "args": (
- "inlinelogs",
- False,
- ),
- }
- if self._db.get(main.__name__, "inlinelogs", True)
- else {
- "text": "🚫 InlineLogs",
- "callback": self.inline__setting,
- "args": (
- "inlinelogs",
- True,
- ),
- }
- ),
- ],
- [
- {
- "text": self.strings("do_not_suggest_fs"),
- "callback": self.inline__setting,
- "args": (
- "disable_modules_fs",
- False,
- ),
- }
- if self._db.get(main.__name__, "disable_modules_fs", False)
- else {
- "text": self.strings("suggest_fs"),
- "callback": self.inline__setting,
- "args": (
- "disable_modules_fs",
- True,
- ),
- }
- ],
- [
- (
- {
- "text": self.strings("use_fs"),
- "callback": self.inline__setting,
- "args": (
- "permanent_modules_fs",
- False,
- ),
- }
- if self._db.get(main.__name__, "permanent_modules_fs", False)
- else {
- "text": self.strings("do_not_use_fs"),
- "callback": self.inline__setting,
- "args": (
- "permanent_modules_fs",
- True,
- ),
- }
- ),
- ],
- [
- (
- {
- "text": self.strings("suggest_subscribe"),
- "callback": self.inline__setting,
- "args": (
- "suggest_subscribe",
- False,
- ),
- }
- if self._db.get(main.__name__, "suggest_subscribe", True)
- else {
- "text": self.strings("do_not_suggest_subscribe"),
- "callback": self.inline__setting,
- "args": (
- "suggest_subscribe",
- True,
- ),
- }
- ),
- ],
- [
- (
- {
- "text": self.strings("no_custom_emojis"),
- "callback": self.inline__setting,
- "args": (
- lambda: main.save_config_key(
- "disable_custom_emojis", False
- ),
- ),
- }
- if main.get_config_key("disable_custom_emojis")
- else {
- "text": self.strings("custom_emojis"),
- "callback": self.inline__setting,
- "args": (
- lambda: main.save_config_key("disable_custom_emojis", True),
- ),
- }
- ),
- ],
- [
- (
- {
- "text": self.strings("disable_stats"),
- "callback": self.inline__setting,
- "args": ("stats", False),
- }
- if self._db.get(main.__name__, "stats", True)
- else {
- "text": self.strings("enable_stats"),
- "callback": self.inline__setting,
- "args": (
- "stats",
- True,
- ),
- }
- ),
- ],
- [
- {
- "text": self.strings("btn_restart"),
- "callback": self.inline__restart,
- "args": (True,),
- },
- {
- "text": self.strings("btn_update"),
- "callback": self.inline__update,
- "args": (True,),
- },
- ],
- [{"text": self.strings("close_menu"), "action": "close"}],
- ]
- @loader.owner
- @loader.command(ru_doc="Показать настройки")
- async def settings(self, message: Message):
- """Show settings menu"""
- await self.inline.form(
- self.strings("inline_settings"),
- message=message,
- reply_markup=self._get_settings_markup(),
- )
- @loader.owner
- @loader.command(ru_doc="Открыть тоннель к веб-интерфейсу Hikka")
- async def weburl(self, message: Message, force: bool = False):
- """Opens web tunnel to your Hikka web interface"""
- if "LAVHOST" in os.environ:
- form = await self.inline.form(
- self.strings("lavhost_web"),
- message=message,
- reply_markup={
- "text": self.strings("web_btn"),
- "url": await main.hikka.web.get_url(proxy_pass=False),
- },
- gif="https://t.me/hikari_assets/28",
- )
- return
- if (
- not force
- and not message.is_private
- and "force_insecure" not in message.raw_text.lower()
- ):
- try:
- if not await self.inline.form(
- self.strings("privacy_leak_nowarn").format(self._client.tg_id),
- message=message,
- reply_markup=[
- {
- "text": self.strings("btn_yes"),
- "callback": self.weburl,
- "args": (True,),
- },
- {"text": self.strings("btn_no"), "action": "close"},
- ],
- gif="https://i.gifer.com/embedded/download/Z5tS.gif",
- ):
- raise Exception
- except Exception:
- await utils.answer(
- message,
- self.strings("privacy_leak").format(
- self._client.tg_id,
- self.get_prefix(),
- ),
- )
- return
- if force:
- form = message
- await form.edit(
- self.strings("opening_tunnel"),
- reply_markup={"text": "🕔 Wait...", "data": "empty"},
- gif=(
- "https://i.gifer.com/origin/e4/e43e1b221fd960003dc27d2f2f1b8ce1.gif"
- ),
- )
- else:
- form = await self.inline.form(
- self.strings("opening_tunnel"),
- message=message,
- reply_markup={"text": "🕔 Wait...", "data": "empty"},
- gif=(
- "https://i.gifer.com/origin/e4/e43e1b221fd960003dc27d2f2f1b8ce1.gif"
- ),
- )
- url = await main.hikka.web.get_url(proxy_pass=True)
- await form.edit(
- self.strings("tunnel_opened"),
- reply_markup={"text": self.strings("web_btn"), "url": url},
- gif="https://t.me/hikari_assets/48",
- )
- @loader.loop(interval=1, autostart=True)
- async def loop(self):
- obj = self.allmodules.get_approved_channel
- if not obj:
- return
- channel, event = obj
- try:
- await self._client(JoinChannelRequest(channel))
- except Exception:
- logger.exception("Failed to join channel")
- event.status = False
- event.set()
- else:
- event.status = True
- event.set()
- def _get_all_IDM(self, module: str):
- return {
- getattr(getattr(self.lookup(module), name), "name", name): getattr(
- self.lookup(module), name
- )
- for name in dir(self.lookup(module))
- if getattr(getattr(self.lookup(module), name), "is_debug_method", False)
- }
- @loader.command()
- async def invoke(self, message: Message):
- """<module or `core` for built-in methods> <method> - Only for debugging purposes. DO NOT USE IF YOU'RE NOT A DEVELOPER
- """
- args = utils.get_args_raw(message)
- if not args or len(args.split()) < 2:
- await utils.answer(message, self.strings("no_args"))
- return
- module = args.split()[0]
- method = args.split(maxsplit=1)[1]
- if module != "core" and not self.lookup(module):
- await utils.answer(message, self.strings("module404").format(module))
- return
- if (
- module == "core"
- and method not in ALL_INVOKES
- or module != "core"
- and method not in self._get_all_IDM(module)
- ):
- await utils.answer(message, self.strings("invoke404").format(method))
- return
- message = await utils.answer(
- message, self.strings("invoking").format(method, module)
- )
- result = ""
- if module == "core":
- if method == "clear_entity_cache":
- result = (
- f"Dropped {len(self._client._hikka_entity_cache)} cache records"
- )
- self._client._hikka_entity_cache = {}
- elif method == "clear_fulluser_cache":
- result = (
- f"Dropped {len(self._client._hikka_fulluser_cache)} cache records"
- )
- self._client._hikka_fulluser_cache = {}
- elif method == "clear_fullchannel_cache":
- result = (
- f"Dropped {len(self._client._hikka_fullchannel_cache)} cache"
- " records"
- )
- self._client._hikka_fullchannel_cache = {}
- elif method == "clear_perms_cache":
- result = f"Dropped {len(self._client._hikka_perms_cache)} cache records"
- self._client._hikka_perms_cache = {}
- elif method == "clear_cache":
- result = (
- f"Dropped {len(self._client._hikka_entity_cache)} entity cache"
- " records\nDropped"
- f" {len(self._client._hikka_fulluser_cache)} fulluser cache"
- " records\nDropped"
- f" {len(self._client._hikka_fullchannel_cache)} fullchannel cache"
- " records"
- )
- self._client._hikka_entity_cache = {}
- self._client._hikka_fulluser_cache = {}
- self._client._hikka_fullchannel_cache = {}
- elif method == "reload_core":
- core_quantity = await self.lookup("loader").reload_core()
- result = f"Reloaded {core_quantity} core modules"
- elif method == "inspect_cache":
- result = (
- "Entity cache:"
- f" {len(self._client._hikka_entity_cache)} records\nFulluser cache:"
- f" {len(self._client._hikka_fulluser_cache)} records\nFullchannel"
- f" cache: {len(self._client._hikka_fullchannel_cache)} records"
- )
- elif method == "inspect_modules":
- result = (
- "Loaded modules: {}\nLoaded core modules: {}\nLoaded user"
- " modules: {}"
- ).format(
- len(self.allmodules.modules),
- sum(
- module.__origin__.startswith("<core")
- for module in self.allmodules.modules
- ),
- sum(
- not module.__origin__.startswith("<core")
- for module in self.allmodules.modules
- ),
- )
- else:
- result = await self._get_all_IDM(module)[method](message)
- await utils.answer(
- message,
- self.strings("invoke").format(method, utils.escape_html(result)),
- )
|