utils.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. from uuid import uuid4
  2. from enum import IntEnum
  3. from datetime import datetime
  4. from ipaddress import ip_address
  5. from collections import namedtuple
  6. from aiofiles.os import mkdir
  7. from aiofiles.os import path
  8. from telethon.utils import get_display_name
  9. from telethon.tl.types import (
  10. MessageEntityBold,
  11. MessageEntityItalic,
  12. MessageEntityStrike,
  13. MessageEntityCode,
  14. MessageEntityPre,
  15. MessageEntitySpoiler,
  16. MessageEntityUnderline,
  17. MessageEntityUrl,
  18. MessageEntityMention,
  19. MessageEntityBotCommand
  20. )
  21. Command = namedtuple(
  22. 'Command',
  23. 'name argc args args_string'
  24. )
  25. Age = namedtuple(
  26. 'Age',
  27. 'days_until age age_now date_string'
  28. )
  29. class Kind(IntEnum):
  30. CANNOT_APPLY_TO_SELF = 0
  31. CAN_APPLY_TO_SELF = 1
  32. NO_TARGET = 2
  33. NO_TARGET_MAYBE = 3
  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. CACHE_DIR = './cache'
  72. async def make_cache_filename(id, ext):
  73. if not await path.isdir(CACHE_DIR):
  74. await mkdir(CACHE_DIR)
  75. return f'{CACHE_DIR}/{id}.{ext}'
  76. def parse_kind(kind):
  77. kind = int(kind)
  78. if kind < 0 or kind > 3:
  79. raise ValueError
  80. return kind
  81. def calculate_age(date):
  82. now = datetime.now().date()
  83. birthday_date = date.replace(year=now.year)
  84. if now > birthday_date:
  85. birthday_date = date.replace(year=now.year + 1)
  86. delta = birthday_date - now
  87. age = (birthday_date - date).days // 365
  88. age_now = age - 1
  89. return Age(
  90. days_until=delta.days,
  91. age=age,
  92. age_now=age_now,
  93. date_string=date.strftime('%d.%m.%Y')
  94. )
  95. DELIMITERS = {
  96. MessageEntityBold: '**',
  97. MessageEntityItalic: '__',
  98. MessageEntityStrike: '~~',
  99. MessageEntityCode: '`',
  100. MessageEntityPre: '`',
  101. MessageEntityUnderline: '\ue000',
  102. MessageEntitySpoiler: '\ue001',
  103. MessageEntityUrl: '\ue002',
  104. MessageEntityMention: '\ue003',
  105. MessageEntityBotCommand: '\ue003'
  106. }
  107. class LookupTable:
  108. def __init__(self):
  109. self._start = {}
  110. self._end = {}
  111. def insert(self, entity):
  112. delimiter = DELIMITERS.get(type(entity))
  113. if not delimiter:
  114. return
  115. start = entity.offset
  116. end = entity.offset + entity.length
  117. if start in self._start:
  118. self._start[start].append(delimiter)
  119. else:
  120. self._start[start] = [delimiter]
  121. if end in self._end:
  122. self._end[end].insert(0, delimiter)
  123. else:
  124. self._end[end] = [delimiter]
  125. def _lookup(self, position):
  126. if position in self._start:
  127. return ''.join(self._start[position])
  128. elif position in self._end:
  129. return ''.join(self._end[position])
  130. def process(self, text):
  131. text = list(text) + ['']
  132. result = ''
  133. for position, character in zip(range(len(text)), text):
  134. delimiter = self._lookup(position)
  135. if delimiter:
  136. result += delimiter
  137. result += character
  138. return result
  139. def unparse(text, entities):
  140. table = LookupTable()
  141. for entity in entities:
  142. table.insert(entity)
  143. return table.process(text)
  144. def is_valid_ip(ip):
  145. try:
  146. ip_address(ip)
  147. except:
  148. return False
  149. return True