commands.py 7.8 KB

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