commands.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. from sys import executable
  2. from asyncio import create_subprocess_shell
  3. from asyncio.subprocess import PIPE
  4. from ujson import dumps
  5. from tortoise.exceptions import IntegrityError
  6. from telethon.utils import get_display_name, get_peer_id
  7. from aiofiles.os import remove
  8. from emoji import is_emoji
  9. from actions import (
  10. find_action,
  11. create_action,
  12. delete_action,
  13. add_gif,
  14. add_sticker,
  15. assign_color,
  16. add_admin,
  17. delete_admin,
  18. add_or_update_birthday,
  19. get_birthdays
  20. )
  21. from utils import WORDS_TABLE, make_temporary_filename, parse_kind, get_user_name, get_word_for, calculate_age
  22. class Handler:
  23. def __init__(self, handler, is_restricted=False):
  24. self.handler = handler
  25. self.is_restricted = is_restricted
  26. async def newadmin_handler(bot, event, command):
  27. if command.argc < 1:
  28. await event.reply('Пожалуйста, укажите пользователя!')
  29. return
  30. try:
  31. target = await bot.get_entity(command.args[0])
  32. except ValueError:
  33. await event.reply('Недопустимое имя пользователя!')
  34. return
  35. try:
  36. await add_admin(target)
  37. except IntegrityError:
  38. await event.reply('Данный пользователь уже является администратором!')
  39. return
  40. await event.reply('Готово!~~')
  41. async def deladmin_handler(bot, event, command):
  42. if command.argc < 1:
  43. await event.reply('Пожалуйста, укажите пользователя!')
  44. return
  45. try:
  46. target = await bot.get_entity(command.args[0])
  47. except ValueError:
  48. await event.reply('Недопустимое имя пользователя!')
  49. return
  50. try:
  51. await delete_admin(target)
  52. except IndexError:
  53. await event.reply('Данный пользователь не является администратором!')
  54. return
  55. await event.reply('Готово!~~')
  56. async def newaction_handler(bot, event, command):
  57. if command.argc < 3:
  58. await event.reply('Пожалуйста, укажите тип, имя и шаблон действия!')
  59. return
  60. try:
  61. kind = parse_kind(command.args[0])
  62. except ValueError:
  63. await event.reply('Неверный тип действия!!!')
  64. return
  65. try:
  66. await create_action(command.args[1], ' '.join(command.args[2:]), kind)
  67. except SyntaxError:
  68. await event.reply('Недопустимое имя действия!!!')
  69. return
  70. except IntegrityError:
  71. await event.reply('Действие с таким названием уже существует!')
  72. return
  73. await event.reply('Действие создано!')
  74. async def delaction_handler(bot, event, command):
  75. if command.argc < 1:
  76. await event.reply('Пожалуйста, укажите имя действия!')
  77. return
  78. try:
  79. await delete_action(command.args[0])
  80. except SyntaxError:
  81. await event.reply('Недопустимое имя действия!!!')
  82. return
  83. except NameError:
  84. await event.reply('Действия с таким названием не существует!')
  85. return
  86. await event.reply('Действие удалено!')
  87. async def addgif_handler(bot, event, command):
  88. if command.argc < 1:
  89. await event.reply('Пожалуйста, укажите имя действия!')
  90. return
  91. gif = await event.get_reply_message()
  92. if not gif or not gif.gif:
  93. await event.reply('Пожалуйста, добавьте GIF!')
  94. return
  95. try:
  96. action = await find_action(command.args[0])
  97. await add_gif(action, gif.file.id)
  98. except SyntaxError:
  99. await event.reply('Недопустимое имя действия!!!')
  100. return
  101. except NameError:
  102. await event.reply('Нет такого действия!')
  103. return
  104. await event.reply('Готово!~~')
  105. # Very, very, VERY evil code...
  106. async def make_message_shot(bot, message):
  107. proc = await create_subprocess_shell(
  108. f'{executable} makeshot.py',
  109. stdin=PIPE
  110. )
  111. output_path = make_temporary_filename('png')
  112. avatar_path = make_temporary_filename('png')
  113. if message.sender is None:
  114. await bot.download_profile_photo(message.peer_id.channel_id, file=avatar_path)
  115. full_name = await bot.get_entity(message.peer_id.channel_id)
  116. full_name = full_name.title
  117. else:
  118. await bot.download_profile_photo(message.sender, file=avatar_path)
  119. full_name = get_display_name(message.sender)
  120. data = dumps({
  121. 'output_path': output_path,
  122. 'avatar_path': avatar_path,
  123. 'username': full_name if full_name else message.sender.username,
  124. 'username_color': await assign_color(message.sender.id if message.sender else message.peer_id.channel_id),
  125. 'text': message.text
  126. }).encode('UTF-8')
  127. await proc.communicate(input=data)
  128. await remove(avatar_path)
  129. return output_path
  130. async def save_handler(bot, event, command):
  131. message = await event.get_reply_message()
  132. if not message:
  133. await event.reply('Пожалуйста, укажите сообщение для сохранения!')
  134. return
  135. emoji = '⚡'
  136. if command.argc >= 1:
  137. emoji = command.args[0]
  138. if len(emoji) not in range(1, 6)\
  139. or not all(map(is_emoji, emoji)):
  140. await event.reply('Указан некорректный эмодзи!!!')
  141. return
  142. path = await make_message_shot(bot, message)
  143. try:
  144. file = await add_sticker(bot, path, emoji)
  145. await bot.send_file(
  146. message.peer_id,
  147. file=file,
  148. reply_to=message
  149. )
  150. finally:
  151. await remove(path)
  152. async def bday_handler(bot, event, command):
  153. if command.argc >= 1:
  154. try:
  155. date = datetime.strptime(' '.join(command.args), '%d.%m.%Y')
  156. except ValueError:
  157. await event.reply('Дата не может быть распознана. Пожалуйста, введите свой день рождения в следующем формате: 01.01.1970 (день, месяц, год).')
  158. return
  159. if date >= datetime.now():
  160. await event.reply('День рождения не может быть в будущем...')
  161. return
  162. if await add_or_update_birthday(get_peer_id(event.peer_id), event.sender, date):
  163. await event.reply('День рождения успешно добавлен!!!')
  164. else:
  165. await event.reply('День рождения успешно обновлён!!!')
  166. return
  167. birthdays = await get_birthdays(get_peer_id(event.peer_id))
  168. if not birthdays:
  169. await event.reply('Пока пусто...')
  170. return
  171. birthdays = map(lambda birthday: (birthday.user_id, calculate_age(birthday.date)), birthdays)
  172. birthdays = sorted(birthdays, key=lambda birthday: birthday[1].days_until)
  173. birthdays_list = ''
  174. for user_id, age in birthdays:
  175. birthdays_list += get_user_name(await bot.get_entity(user_id))
  176. birthdays_list += ' — '
  177. birthdays_list += age.date_string
  178. birthdays_list += f' (через {get_word_for("день", age.days_until)} исполнится {get_word_for("год", age.age)}; сейчас {get_word_for("год", age.age_now)})\n'
  179. await event.reply(f'Дни рождения:\n\n{birthdays_list}')
  180. COMMANDS = {
  181. 'newadmin': Handler(newadmin_handler, is_restricted=True),
  182. 'deladmin': Handler(deladmin_handler, is_restricted=True),
  183. 'newaction': Handler(newaction_handler, is_restricted=True),
  184. 'delaction': Handler(delaction_handler, is_restricted=True),
  185. 'addgif': Handler(addgif_handler, is_restricted=True),
  186. 'save': Handler(save_handler),
  187. 'bday': Handler(bday_handler)
  188. }