settings.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. # Friendly Telegram (telegram userbot)
  2. # Copyright (C) 2018-2021 The Authors
  3. # This program is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU Affero General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. # This program is distributed in the hope that it will be useful,
  8. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. # GNU Affero General Public License for more details.
  11. # You should have received a copy of the GNU Affero General Public License
  12. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. # █ █ ▀ █▄▀ ▄▀█ █▀█ ▀
  14. # █▀█ █ █ █ █▀█ █▀▄ █
  15. # © Copyright 2022
  16. # https://t.me/hikariatama
  17. #
  18. # 🔒 Licensed under the GNU AGPLv3
  19. # 🌐 https://www.gnu.org/licenses/agpl-3.0.html
  20. import os
  21. import telethon
  22. from telethon.tl.types import Message
  23. from telethon.extensions.html import CUSTOM_EMOJIS
  24. from .. import loader, main, translations, utils, version
  25. from ..inline.types import InlineCall
  26. @loader.tds
  27. class CoreMod(loader.Module):
  28. """Control core userbot settings"""
  29. strings = {
  30. "name": "Settings",
  31. "too_many_args": (
  32. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Too many args</b>"
  33. ),
  34. "blacklisted": (
  35. '<emoji document_id="5368324170671202286">👍</emoji> <b>Chat {} blacklisted'
  36. " from userbot</b>"
  37. ),
  38. "unblacklisted": (
  39. '<emoji document_id="5368324170671202286">👍</emoji> <b>Chat {}'
  40. " unblacklisted from userbot</b>"
  41. ),
  42. "user_blacklisted": (
  43. '<emoji document_id="5368324170671202286">👍</emoji> <b>User {} blacklisted'
  44. " from userbot</b>"
  45. ),
  46. "user_unblacklisted": (
  47. '<emoji document_id="5368324170671202286">👍</emoji> <b>User {}'
  48. " unblacklisted from userbot</b>"
  49. ),
  50. "what_prefix": "❓ <b>What should the prefix be set to?</b>",
  51. "prefix_incorrect": (
  52. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Prefix must be one"
  53. " symbol in length</b>"
  54. ),
  55. "prefix_set": (
  56. '<emoji document_id="5368324170671202286">👍</emoji> <b>Command prefix'
  57. " updated. Type</b> <code>{newprefix}setprefix {oldprefix}</code> <b>to"
  58. " change it back</b>"
  59. ),
  60. "alias_created": (
  61. '<emoji document_id="5368324170671202286">👍</emoji> <b>Alias created.'
  62. " Access it with</b> <code>{}</code>"
  63. ),
  64. "aliases": "<b>🔗 Aliases:</b>\n",
  65. "no_command": (
  66. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Command</b>"
  67. " <code>{}</code> <b>does not exist</b>"
  68. ),
  69. "alias_args": (
  70. "<emoji document_id=5436162517686557387>🚫</emoji> <b>You must provide a"
  71. " command and the alias for it</b>"
  72. ),
  73. "delalias_args": (
  74. "<emoji document_id=5436162517686557387>🚫</emoji> <b>You must provide the"
  75. " alias name</b>"
  76. ),
  77. "alias_removed": (
  78. '<emoji document_id="5368324170671202286">👍</emoji> <b>Alias</b>'
  79. " <code>{}</code> <b>removed</b>."
  80. ),
  81. "no_alias": (
  82. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Alias</b>"
  83. " <code>{}</code> <b>does not exist</b>"
  84. ),
  85. "db_cleared": (
  86. '<emoji document_id="5368324170671202286">👍</emoji><b> Database cleared</b>'
  87. ),
  88. "hikka": (
  89. "{}\n\n<emoji document_id=5406931726184225260>🧐</emoji>"
  90. " <b>Version: {}.{}.{}</b>\n<emoji"
  91. " document_id=6318902906900711458>🧱</emoji> <b>Build:"
  92. " </b><i>{}</i>\n\n<emoji document_id=5233346091725888979>⚙️</emoji> <b>Hikka-TL: </b><i>{}</i>\n\n<emoji document_id=5454182070156794055>⌨️</emoji>"
  93. " <b>Developer: t.me/hikariatama</b>"
  94. ),
  95. "check_url": (
  96. "<emoji document_id=5436162517686557387>🚫</emoji> <b>You need to specify"
  97. " valid url containing a langpack</b>"
  98. ),
  99. "lang_saved": "{} <b>Language saved!</b>",
  100. "pack_saved": (
  101. '<emoji document_id="5368324170671202286">👍</emoji> <b>Translate pack'
  102. " saved!</b>"
  103. ),
  104. "incorrect_language": (
  105. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Incorrect language"
  106. " specified</b>"
  107. ),
  108. "lang_removed": (
  109. '<emoji document_id="5368324170671202286">👍</emoji> <b>Translations reset'
  110. " to default ones</b>"
  111. ),
  112. "check_pack": (
  113. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Invalid pack format"
  114. " in url</b>"
  115. ),
  116. "confirm_cleardb": "⚠️ <b>Are you sure, that you want to clear database?</b>",
  117. "cleardb_confirm": "🗑 Clear database",
  118. "cancel": "🚫 Cancel",
  119. "who_to_blacklist": (
  120. "<emoji document_id=5384612769716774600>❓</emoji> <b>Who to blacklist?</b>"
  121. ),
  122. "who_to_unblacklist": (
  123. "<emoji document_id=5384612769716774600>❓</emoji> <b>Who to"
  124. " unblacklist?</b>"
  125. ),
  126. "unstable": (
  127. "\n\n<emoji document_id=5467370583282950466>🙈</emoji> <b>You are using an"
  128. " unstable branch </b><code>{}</code><b>!</b>"
  129. ),
  130. }
  131. strings_ru = {
  132. "too_many_args": (
  133. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Слишком много"
  134. " аргументов</b>"
  135. ),
  136. "blacklisted": (
  137. '<emoji document_id="5368324170671202286">👍</emoji> <b>Чат {} добавлен в'
  138. " черный список юзербота</b>"
  139. ),
  140. "unblacklisted": (
  141. '<emoji document_id="5368324170671202286">👍</emoji> <b>Чат {} удален из'
  142. " черного списка юзербота</b>"
  143. ),
  144. "user_blacklisted": (
  145. '<emoji document_id="5368324170671202286">👍</emoji> <b>Пользователь {}'
  146. " добавлен в черный список юзербота</b>"
  147. ),
  148. "user_unblacklisted": (
  149. '<emoji document_id="5368324170671202286">👍</emoji> <b>Пользователь {}'
  150. " удален из черного списка юзербота</b>"
  151. ),
  152. "what_prefix": "❓ <b>А какой префикс ставить то?</b>",
  153. "prefix_incorrect": (
  154. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Префикс должен"
  155. " состоять только из одного символа</b>"
  156. ),
  157. "prefix_set": (
  158. '<emoji document_id="5368324170671202286">👍</emoji> <b>Префикс обновлен.'
  159. " Чтобы вернуть его, используй</b> <code>{newprefix}setprefix"
  160. " {oldprefix}</code>"
  161. ),
  162. "alias_created": (
  163. '<emoji document_id="5368324170671202286">👍</emoji> <b>Алиас создан.'
  164. " Используй его через</b> <code>{}</code>"
  165. ),
  166. "aliases": "<b>🔗 Алиасы:</b>\n",
  167. "no_command": (
  168. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Команда</b>"
  169. " <code>{}</code> <b>не существует</b>"
  170. ),
  171. "alias_args": (
  172. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Требуется ввести"
  173. " команду и алиас для нее</b>"
  174. ),
  175. "delalias_args": (
  176. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Требуется имя"
  177. " алиаса</b>"
  178. ),
  179. "alias_removed": (
  180. '<emoji document_id="5368324170671202286">👍</emoji> <b>Алиас</b>'
  181. " <code>{}</code> <b>удален</b>."
  182. ),
  183. "no_alias": (
  184. "<emoji document_id=5436162517686557387>🚫</emoji><b> Алиас</b>"
  185. " <code>{}</code> <b>не существует</b>"
  186. ),
  187. "db_cleared": (
  188. '<emoji document_id="5368324170671202286">👍</emoji><b> База очищена</b>'
  189. ),
  190. "hikka": (
  191. "{}\n\n<emoji document_id=5406931726184225260>🧐</emoji>"
  192. " <b>Версия: {}.{}.{}</b>\n<emoji"
  193. " document_id=6318902906900711458>🧱</emoji> <b>Сборка:"
  194. " </b><i>{}</i>\n\n<emoji document_id=5233346091725888979>⚙️</emoji> <b>Hikka-TL: </b><i>{}</i>\n\n<emoji document_id=5454182070156794055>⌨️</emoji>"
  195. " <b>Developer: t.me/hikariatama</b>"
  196. ),
  197. "check_url": (
  198. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Укажи правильную"
  199. " ссылку, ведущую на пак с переводом</b>"
  200. ),
  201. "lang_saved": "{} <b>Язык сохранен!</b>",
  202. "pack_saved": (
  203. '<emoji document_id="5368324170671202286">👍</emoji> <b>Пак перевода'
  204. " сохранен!</b>"
  205. ),
  206. "incorrect_language": (
  207. "<emoji document_id=5436162517686557387>🚫</emoji> <b>Указан неверный"
  208. " язык</b>"
  209. ),
  210. "lang_removed": (
  211. '<emoji document_id="5368324170671202286">👍</emoji> <b>Переводы'
  212. " сброшены</b>"
  213. ),
  214. "check_pack": (
  215. "<emoji document_id=5436162517686557387>🚫</emoji> <b>По ссылке находится"
  216. " неправильный пак</b>"
  217. ),
  218. "_cls_doc": "Управление базовыми настройками юзербота",
  219. "confirm_cleardb": "⚠️ <b>Вы уверены, что хотите сбросить базу данных?</b>",
  220. "cleardb_confirm": "🗑 Очистить базу",
  221. "cancel": "🚫 Отмена",
  222. "who_to_blacklist": (
  223. "<emoji document_id=5384612769716774600>❓</emoji> <b>Кого заблокировать"
  224. " то?</b>"
  225. ),
  226. "who_to_unblacklist": (
  227. "<emoji document_id=5384612769716774600>❓</emoji> <b>Кого разблокировать"
  228. " то?</b>"
  229. ),
  230. "unstable": (
  231. "\n\n<emoji document_id=5467370583282950466>🙈</emoji> <b>Ты используешь"
  232. " нестабильную ветку </b><code>{}</code><b>!</b>"
  233. ),
  234. }
  235. async def blacklistcommon(self, message: Message):
  236. args = utils.get_args(message)
  237. if len(args) > 2:
  238. await utils.answer(message, self.strings("too_many_args"))
  239. return
  240. chatid = None
  241. module = None
  242. if args:
  243. try:
  244. chatid = int(args[0])
  245. except ValueError:
  246. module = args[0]
  247. if len(args) == 2:
  248. module = args[1]
  249. if chatid is None:
  250. chatid = utils.get_chat_id(message)
  251. module = self.allmodules.get_classname(module)
  252. return f"{str(chatid)}.{module}" if module else chatid
  253. @loader.command(ru_doc="Показать версию Hikka")
  254. async def hikkacmd(self, message: Message):
  255. """Get Hikka version"""
  256. await utils.answer(
  257. message,
  258. self.strings("hikka").format(
  259. (
  260. utils.get_platform_emoji()
  261. + (
  262. '<emoji document_id=5192756799647785066>✌️</emoji><emoji'
  263. ' document_id=5193117564015747203>✌️</emoji><emoji'
  264. ' document_id=5195050806105087456>✌️</emoji><emoji'
  265. ' document_id=5195457642587233944>✌️</emoji>'
  266. if "LAVHOST" in os.environ
  267. else ""
  268. )
  269. )
  270. if self._client.hikka_me.premium and CUSTOM_EMOJIS
  271. else "🌘 <b>Hikka userbot</b>",
  272. *version.__version__,
  273. utils.get_commit_url(),
  274. f"{telethon.__version__} #{telethon.tl.alltlobjects.LAYER}",
  275. )
  276. + (
  277. ""
  278. if version.branch == "master"
  279. else self.strings("unstable").format(version.branch)
  280. ),
  281. )
  282. @loader.command(ru_doc="[чат] [модуль] - Отключить бота где-либо")
  283. async def blacklist(self, message: Message):
  284. """[chat_id] [module] - Blacklist the bot from operating somewhere"""
  285. chatid = await self.blacklistcommon(message)
  286. self._db.set(
  287. main.__name__,
  288. "blacklist_chats",
  289. self._db.get(main.__name__, "blacklist_chats", []) + [chatid],
  290. )
  291. await utils.answer(message, self.strings("blacklisted").format(chatid))
  292. @loader.command(ru_doc="[чат] - Включить бота где-либо")
  293. async def unblacklist(self, message: Message):
  294. """<chat_id> - Unblacklist the bot from operating somewhere"""
  295. chatid = await self.blacklistcommon(message)
  296. self._db.set(
  297. main.__name__,
  298. "blacklist_chats",
  299. list(set(self._db.get(main.__name__, "blacklist_chats", [])) - {chatid}),
  300. )
  301. await utils.answer(message, self.strings("unblacklisted").format(chatid))
  302. async def getuser(self, message: Message):
  303. try:
  304. return int(utils.get_args(message)[0])
  305. except (ValueError, IndexError):
  306. reply = await message.get_reply_message()
  307. if reply:
  308. return reply.sender_id
  309. return message.to_id.user_id if message.is_private else False
  310. @loader.command(ru_doc="[пользователь] - Запретить пользователю выполнять команды")
  311. async def blacklistuser(self, message: Message):
  312. """[user_id] - Prevent this user from running any commands"""
  313. user = await self.getuser(message)
  314. if not user:
  315. await utils.answer(message, self.strings("who_to_blacklist"))
  316. return
  317. self._db.set(
  318. main.__name__,
  319. "blacklist_users",
  320. self._db.get(main.__name__, "blacklist_users", []) + [user],
  321. )
  322. await utils.answer(message, self.strings("user_blacklisted").format(user))
  323. @loader.command(ru_doc="[пользователь] - Разрешить пользователю выполнять команды")
  324. async def unblacklistuser(self, message: Message):
  325. """[user_id] - Allow this user to run permitted commands"""
  326. user = await self.getuser(message)
  327. if not user:
  328. await utils.answer(message, self.strings("who_to_unblacklist"))
  329. return
  330. self._db.set(
  331. main.__name__,
  332. "blacklist_users",
  333. list(set(self._db.get(main.__name__, "blacklist_users", [])) - {user}),
  334. )
  335. await utils.answer(
  336. message,
  337. self.strings("user_unblacklisted").format(user),
  338. )
  339. @loader.owner
  340. @loader.command(ru_doc="<префикс> - Установить префикс команд")
  341. async def setprefix(self, message: Message):
  342. """<prefix> - Sets command prefix"""
  343. args = utils.get_args_raw(message)
  344. if not args:
  345. await utils.answer(message, self.strings("what_prefix"))
  346. return
  347. if len(args) != 1:
  348. await utils.answer(message, self.strings("prefix_incorrect"))
  349. return
  350. oldprefix = self.get_prefix()
  351. self._db.set(main.__name__, "command_prefix", args)
  352. await utils.answer(
  353. message,
  354. self.strings("prefix_set").format(
  355. newprefix=utils.escape_html(args[0]),
  356. oldprefix=utils.escape_html(oldprefix),
  357. ),
  358. )
  359. @loader.owner
  360. @loader.command(ru_doc="Показать список алиасов")
  361. async def aliases(self, message: Message):
  362. """Print all your aliases"""
  363. aliases = self.allmodules.aliases
  364. string = self.strings("aliases")
  365. string += "\n".join(
  366. [f"▫️ <code>{i}</code> &lt;- {y}" for i, y in aliases.items()]
  367. )
  368. await utils.answer(message, string)
  369. @loader.owner
  370. @loader.command(ru_doc="Установить алиас для команды")
  371. async def addalias(self, message: Message):
  372. """Set an alias for a command"""
  373. args = utils.get_args(message)
  374. if len(args) != 2:
  375. await utils.answer(message, self.strings("alias_args"))
  376. return
  377. alias, cmd = args
  378. if self.allmodules.add_alias(alias, cmd):
  379. self.set(
  380. "aliases",
  381. {
  382. **self.get("aliases", {}),
  383. alias: cmd,
  384. },
  385. )
  386. await utils.answer(
  387. message,
  388. self.strings("alias_created").format(utils.escape_html(alias)),
  389. )
  390. else:
  391. await utils.answer(
  392. message,
  393. self.strings("no_command").format(utils.escape_html(cmd)),
  394. )
  395. @loader.owner
  396. @loader.command(ru_doc="Удалить алиас для команды")
  397. async def delalias(self, message: Message):
  398. """Remove an alias for a command"""
  399. args = utils.get_args(message)
  400. if len(args) != 1:
  401. await utils.answer(message, self.strings("delalias_args"))
  402. return
  403. alias = args[0]
  404. removed = self.allmodules.remove_alias(alias)
  405. if not removed:
  406. await utils.answer(
  407. message,
  408. self.strings("no_alias").format(utils.escape_html(alias)),
  409. )
  410. return
  411. current = self.get("aliases", {})
  412. del current[alias]
  413. self.set("aliases", current)
  414. await utils.answer(
  415. message,
  416. self.strings("alias_removed").format(utils.escape_html(alias)),
  417. )
  418. @loader.command(ru_doc="[ссылка на пак] - Изменить внешний пак перевода")
  419. async def dllangpackcmd(self, message: Message):
  420. """[link to a langpack | empty to remove] - Change Hikka translate pack (external)"""
  421. args = utils.get_args_raw(message)
  422. if not args:
  423. self._db.set(translations.__name__, "pack", False)
  424. await self.translator.init()
  425. await utils.answer(message, self.strings("lang_removed"))
  426. return
  427. if not utils.check_url(args):
  428. await utils.answer(message, self.strings("check_url"))
  429. return
  430. self._db.set(translations.__name__, "pack", args)
  431. success = await self.translator.init()
  432. await utils.answer(
  433. message, self.strings("pack_saved" if success else "check_pack")
  434. )
  435. @loader.command(ru_doc="[языки] - Изменить стандартный язык")
  436. async def setlang(self, message: Message):
  437. """[languages in the order of priority] - Change default language"""
  438. args = utils.get_args_raw(message)
  439. if not args or any(len(i) != 2 for i in args.split(" ")):
  440. await utils.answer(message, self.strings("incorrect_language"))
  441. return
  442. self._db.set(translations.__name__, "lang", args.lower())
  443. await self.translator.init()
  444. await utils.answer(
  445. message,
  446. self.strings("lang_saved").format(
  447. "".join(
  448. [
  449. utils.get_lang_flag(
  450. lang.lower() if lang.lower() != "en" else "gb"
  451. )
  452. for lang in args.lower().split(" ")
  453. ]
  454. )
  455. ),
  456. )
  457. @loader.owner
  458. @loader.command(ru_doc="Очистить базу данных")
  459. async def cleardb(self, message: Message):
  460. """Clear the entire database, effectively performing a factory reset"""
  461. await self.inline.form(
  462. self.strings("confirm_cleardb"),
  463. message,
  464. reply_markup=[
  465. {
  466. "text": self.strings("cleardb_confirm"),
  467. "callback": self._inline__cleardb,
  468. },
  469. {
  470. "text": self.strings("cancel"),
  471. "action": "close",
  472. },
  473. ],
  474. )
  475. async def _inline__cleardb(self, call: InlineCall):
  476. self._db.clear()
  477. self._db.save()
  478. await utils.answer(call, self.strings("db_cleared"))