Guest User

Untitled

a guest
Jan 25th, 2018
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.76 KB | None | 0 0
  1. # Copyright (c) 2017 Stanislav Bobokalo
  2.  
  3. # Permission is hereby granted, free of charge, to any person obtaining a copy
  4. # of this software and associated documentation files (the "Software"), to deal
  5. # in the Software without restriction, including without limitation the rights
  6. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. # copies of the Software, and to permit persons to whom the Software is
  8. # furnished to do so, subject to the following conditions:
  9.  
  10. # The above copyright notice and this permission notice shall be included in all
  11. # copies or substantial portions of the Software.
  12.  
  13. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. # SOFTWARE.
  20.  
  21. from telethon import TelegramClient
  22. from telethon.errors import SessionPasswordNeededError
  23. from telethon.tl.functions.messages import GetHistoryRequest
  24. from telethon.tl.functions.channels import DeleteMessagesRequest
  25. from telethon.tl.types import Channel
  26. import shelve
  27. from os import listdir
  28. from time import sleep
  29.  
  30. # Просто утилиты
  31.  
  32. def chunks(l, n):
  33. """Разбивает список l на чанки размером n. Возвращает генератор"""
  34. for i in range(0, len(l), n):
  35. yield l[i:i + n]
  36.  
  37.  
  38. def print_header(text):
  39. """Просто для красивого вывода"""
  40. print('====================')
  41. print('= {} ='.format(text))
  42. print('====================')
  43.  
  44. ###########################################
  45.  
  46. API_ID = 666666
  47. API_HASH = 'xxxxxxxxxxxxxxxxxxxxxxx'
  48. PHONE = '+xxxxxxxxx'
  49. NUMBER_OF_CHUNKS = 1 # Сколько чанков подгрузить за выполнение скрипта
  50. CHUNK_SIZE = 1000 # Сколько сообщений нужно просканировать за чанк
  51. FROM_ID = 123456 # ID пользователя, сообщения которого нужно удалить
  52.  
  53. class DeleterClient(TelegramClient):
  54. def __init__(self, session_user_id, user_phone, api_id, api_hash):
  55. super().__init__(session_user_id, api_id, api_hash)
  56.  
  57. self.messages_to_delete = set()
  58. self.chunk_size = CHUNK_SIZE # Сколько сообщений нужно просканировать за чанк
  59.  
  60. # Проверка соеденения с сервером. Проверка данных приложения
  61. print('Connecting to Telegram servers...')
  62. if not self.connect():
  63. print('Initial connection failed. Retrying...')
  64. if not self.connect():
  65. print('Could not connect to Telegram servers.')
  66. return
  67.  
  68. # Проверка авторизирован ли юзер под сессией
  69. if not self.is_user_authorized():
  70. print('First run. Sending code request...')
  71. self.send_code_request(user_phone)
  72.  
  73. self_user = None
  74. while self_user is None:
  75. code = input('Enter the code you just received: ')
  76. try:
  77. self_user = self.sign_in(user_phone, code)
  78.  
  79. # Two-step verification may be enabled
  80. except SessionPasswordNeededError:
  81. pw = input('Two step verification is enabled. Please enter your password: ')
  82. self_user = self.sign_in(password=pw)
  83.  
  84. limit = input('Enter limit of chats (empty for all): ')
  85. # Добавляем количество отображаемых групп
  86. if limit:
  87. self.limit = int(limit)
  88. else:
  89. self.limit = None
  90.  
  91. # Создание пустого хранилища для сдвигов сканирования
  92. if 'parsed_chunks.db' not in listdir('.'):
  93. self._init_shelve(*self.get_dialogs(self.limit))
  94.  
  95. def run(self):
  96. # Запрос выбора чата для сканирования
  97. peer = self.choose_peer()
  98. # ID пользователя чьи сообщения удалить
  99. from_id = FROM_ID
  100. # Основная функция выкачки сообщений и фильтрация от нужного юзера
  101. self.filter_messages_from_chunk(peer, from_id)
  102. # Основная функция удаления сообщений юзера из чата
  103. r = self.delete_messages_from_peer(peer)
  104. return r
  105.  
  106. def choose_peer(self):
  107. dialogs, entities = self.get_dialogs(limit=self.limit)
  108. s = ''
  109.  
  110. entities = [entity for entity in entities if isinstance(entity, Channel)] # Удаляем все супергруп и каналов
  111. entities = [entity for entity in entities if entity.megagroup] # А теперь и каналы
  112.  
  113. for i, entity in enumerate(entities):
  114. s += '{}. {}\t | {}\n'.format(i, entity.title, entity.id)
  115.  
  116. print(s)
  117. num = input('Choose group: ')
  118. print('Chosen: ' + entities[int(num)].title)
  119.  
  120. return entities[int(num)]
  121.  
  122. def delete_messages_from_peer(self, peer):
  123. messages_to_delete = list(self.messages_to_delete)
  124. print_header('УДАЛЕНИЕ {} СВОИХ СООБЩЕНИЙ В ЧАТЕ {}'.format(len(messages_to_delete), peer.title))
  125. for chunk_data in chunks(messages_to_delete, 100):
  126. # Поскольку удалить больше чем 100 сообщеий мы не можем - разделяем на маленькие кусочки
  127. r = self(DeleteMessagesRequest(peer, chunk_data))
  128. if r.pts_count:
  129. print('Удалено сообщений: {}'.format(r.pts_count))
  130. sleep(1)
  131. return True
  132.  
  133. def filter_messages_from_chunk(self, peer, from_id):
  134. number_of_chunks = NUMBER_OF_CHUNKS
  135. messages = []
  136.  
  137. for n in range(number_of_chunks):
  138. msgs, status = self.get_chunk(peer, n)
  139. messages.extend(msgs)
  140. if not status:
  141. break
  142.  
  143. # Генератор который фильтрует сообщения от нужного пользователя
  144. filter_generator = (msg.id for msg in messages if msg.from_id == from_id)
  145. self.messages_to_delete.update(filter_generator)
  146.  
  147. def get_chunk(self, peer, chunk_number, limit=100, offset_date=None, offset_id=0, max_id=0, min_id=0):
  148. add_offset = self._shelve_read(peer.id)
  149. print_header('ВЫКАЧКА ЧАНКА #{}'.format(chunk_number))
  150. local_offset = 0
  151. messages = []
  152.  
  153. while True and local_offset < self.chunk_size:
  154. sleep(1)
  155. # Поскольку лимит на выкачку сообщений 100 - выкачиваем по 100 и делаем шаг равный выкачанному ранее
  156. result = self(GetHistoryRequest(
  157. peer,
  158. limit=limit,
  159. offset_date=offset_date,
  160. offset_id=offset_id,
  161. max_id=max_id,
  162. min_id=min_id,
  163. add_offset=add_offset
  164. ))
  165.  
  166. if result.messages:
  167. print('Скачано сообщений: {}. Сдвиг: {}.'.format(len(result.messages), add_offset))
  168. messages.extend(result.messages)
  169. add_offset += len(result.messages)
  170. local_offset += len(result.messages)
  171. # Записываем значение смещения для данной группы
  172. self._shelve_write(peer.id, add_offset)
  173. else:
  174. print_header('ПОЛУЧЕНО 0 СООБЩЕНИЙ. ВЫКАЧКА ЧАНКА #{} ОСТАНОВЛЕНА, '
  175. 'СКОРЕЕ ВСЕГО ДОШЛО ДО КОНЦА ЧАТА'.format(chunk_number))
  176. return messages, False
  177.  
  178. return messages, True
  179.  
  180. @staticmethod
  181. def _shelve_write(k, v):
  182. with shelve.open('parsed_chunks.db') as db:
  183. db[str(k)] = v
  184.  
  185. @staticmethod
  186. def _shelve_read(k):
  187. with shelve.open('parsed_chunks.db') as db:
  188. return db[str(k)]
  189.  
  190. def _init_shelve(self, dialogs, entities):
  191. for entity in entities:
  192. self._shelve_write(entity.id, 0)
  193.  
  194. client = DeleterClient('Deleter', PHONE, API_ID, API_HASH) # 1 аргумент - название сессии, второй - телефон,
  195. # третий - айди приложения, четвертый - хэш приложения
  196. client.run()
Add Comment
Please, Sign In to add comment