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