utils.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. from uuid import uuid4
  2. from enum import IntEnum
  3. from datetime import datetime
  4. from collections import namedtuple
  5. from telethon.utils import get_display_name
  6. from telethon.tl.types import (
  7. MessageEntityBold,
  8. MessageEntityItalic,
  9. MessageEntityStrike,
  10. MessageEntityCode,
  11. MessageEntityPre,
  12. MessageEntitySpoiler
  13. )
  14. Command = namedtuple(
  15. 'Command',
  16. 'name argc args args_string'
  17. )
  18. Age = namedtuple(
  19. 'Age',
  20. 'days_until age age_now date_string'
  21. )
  22. class Kind(IntEnum):
  23. CANNOT_APPLY_TO_SELF = 0
  24. CAN_APPLY_TO_SELF = 1
  25. NO_TARGET = 2
  26. class WordKind(IntEnum):
  27. FIRST = 0 # «год» / «день».
  28. SECOND = 1 # «лет» / «дней».
  29. THIRD = 2 # «года» / «дня».
  30. WORDS_TABLE = {
  31. 'год': ('год', 'лет', 'года'),
  32. 'день': ('день', 'дней', 'дня')
  33. }
  34. def parse_command(text):
  35. text = text.strip()
  36. if not text.startswith('/'):
  37. raise ValueError
  38. text = text.split(' ')
  39. if len(text) < 1:
  40. raise ValueError
  41. command = text[0][1:].lower()
  42. if '@' in command:
  43. command = command.split('@')
  44. command = command[0]
  45. args = text[1:]
  46. argc = len(args)
  47. args_string = ' '.join(args)
  48. return Command(
  49. name=command,
  50. argc=argc,
  51. args=args,
  52. args_string=args_string
  53. )
  54. def get_user_name(user):
  55. full_name = get_display_name(user)
  56. if not full_name:
  57. full_name = user.username
  58. if not full_name:
  59. full_name = '?'
  60. return full_name
  61. def get_link_to_user(user):
  62. full_name = get_user_name(user)
  63. if user.username:
  64. return f'[{full_name}](@{user.username})'
  65. return f'[{full_name}](tg://user?id={user.id})'
  66. def is_valid_name(name):
  67. return name.isidentifier()
  68. def make_temporary_filename(ext):
  69. uid = uuid4().hex
  70. return f'tmp_{uid}.{ext}'
  71. def parse_kind(kind):
  72. kind = int(kind)
  73. if kind < 0 or kind > 2:
  74. raise ValueError
  75. return kind
  76. # Bruh?
  77. def get_word_kind(number):
  78. if number == 0 or 5 <= number <= 20:
  79. return WordKind.SECOND
  80. last_digit = number % 10
  81. if last_digit == 0:
  82. return WordKind.SECOND
  83. if last_digit == 1:
  84. return WordKind.FIRST
  85. if 5 <= last_digit <= 9:
  86. return WordKind.SECOND
  87. return WordKind.THIRD
  88. def get_word_for(word, number):
  89. return f'{number} {WORDS_TABLE[word][get_word_kind(number)]}'
  90. def calculate_age(date):
  91. now = datetime.now().date()
  92. birthday_date = date.replace(year=now.year)
  93. if now > birthday_date:
  94. birthday_date = date.replace(year=now.year + 1)
  95. delta = birthday_date - now
  96. age = (birthday_date - date).days // 365
  97. age_now = age - 1
  98. return Age(
  99. days_until=delta.days,
  100. age=age,
  101. age_now=age_now,
  102. date_string=date.strftime('%d.%m.%Y')
  103. )
  104. DELIMITERS = {
  105. MessageEntityBold: '**',
  106. MessageEntityItalic: '__',
  107. MessageEntityStrike: '~~',
  108. MessageEntityCode: '`',
  109. MessageEntityPre: '`',
  110. }
  111. class LookupTable:
  112. def __init__(self):
  113. self._start = {}
  114. self._end = {}
  115. self._spoiler = []
  116. def insert(self, entity):
  117. if type(entity) is MessageEntitySpoiler:
  118. self._spoiler.extend(range(entity.offset, entity.offset + entity.length))
  119. return
  120. delimiter = DELIMITERS.get(type(entity))
  121. if not delimiter:
  122. return
  123. start = entity.offset
  124. end = entity.offset + entity.length
  125. if start in self._start:
  126. self._start[start].append(delimiter)
  127. else:
  128. self._start[start] = [delimiter]
  129. if end in self._end:
  130. self._end[end].insert(0, delimiter)
  131. else:
  132. self._end[end] = [delimiter]
  133. def _lookup(self, position):
  134. if position in self._start:
  135. return ''.join(self._start[position])
  136. elif position in self._end:
  137. return ''.join(self._end[position])
  138. def process(self, text):
  139. text = list(text) + ['']
  140. result = ''
  141. for position, character in zip(range(len(text)), text):
  142. delimiter = self._lookup(position)
  143. if delimiter:
  144. result += delimiter
  145. if position in self._spoiler:
  146. result += '█'
  147. else:
  148. result += character
  149. return result
  150. def unparse(text, entities):
  151. table = LookupTable()
  152. for entity in entities:
  153. table.insert(entity)
  154. return table.process(text)