utils.py 4.3 KB

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