[ADD] Full support of groups service messages
This commit is contained in:
@@ -9,7 +9,7 @@ from telethon.tl.types import MessageMediaDocument, MessageMediaPhoto, MessageMe
|
|||||||
MessageMediaGeo, MessageMediaEmpty, MessageMediaVenue
|
MessageMediaGeo, MessageMediaEmpty, MessageMediaVenue
|
||||||
from telethon.tl.types import DocumentAttributeAnimated, DocumentAttributeAudio, DocumentAttributeFilename,\
|
from telethon.tl.types import DocumentAttributeAnimated, DocumentAttributeAudio, DocumentAttributeFilename,\
|
||||||
DocumentAttributeSticker, DocumentAttributeVideo, DocumentAttributeHasStickers
|
DocumentAttributeSticker, DocumentAttributeVideo, DocumentAttributeHasStickers
|
||||||
from telethon.tl.types import MessageService, MessageActionChannelCreate, MessageActionChannelMigrateFrom,\
|
from telethon.tl.types import Message, MessageService, MessageActionChannelCreate, MessageActionChannelMigrateFrom,\
|
||||||
MessageActionChatCreate, MessageActionChatAddUser, MessageActionChatDeleteUser,\
|
MessageActionChatCreate, MessageActionChatAddUser, MessageActionChatDeleteUser,\
|
||||||
MessageActionChatEditTitle, MessageActionChatJoinedByLink, MessageActionChatMigrateTo,\
|
MessageActionChatEditTitle, MessageActionChatJoinedByLink, MessageActionChatMigrateTo,\
|
||||||
MessageActionPinMessage
|
MessageActionPinMessage
|
||||||
@@ -17,8 +17,8 @@ from telethon.tl.types import UserStatusOnline, UserStatusOffline, UserStatusRec
|
|||||||
from telethon.tl.types import User, Chat, Channel
|
from telethon.tl.types import User, Chat, Channel
|
||||||
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
||||||
from telethon.tl.functions.users import GetFullUserRequest
|
from telethon.tl.functions.users import GetFullUserRequest
|
||||||
from telethon.tl.functions.messages import ReadHistoryRequest, GetFullChatRequest
|
from telethon.tl.functions.messages import ReadHistoryRequest, GetFullChatRequest, GetMessagesRequest
|
||||||
from telethon.tl.functions.channels import ReadHistoryRequest as ReadHistoryChannel, GetParticipantRequest
|
from telethon.tl.functions.channels import ReadHistoryRequest as ReadHistoryChannel, GetParticipantRequest, GetMessagesRequest
|
||||||
from telethon.tl.functions.updates import GetDifferenceRequest
|
from telethon.tl.functions.updates import GetDifferenceRequest
|
||||||
from telethon.tl.functions.contacts import ResolveUsernameRequest
|
from telethon.tl.functions.contacts import ResolveUsernameRequest
|
||||||
|
|
||||||
@@ -62,8 +62,10 @@ class TelegramGateClient(TelegramClient):
|
|||||||
print('new update for ' + self.jid)
|
print('new update for ' + self.jid)
|
||||||
print(type(obj), obj.__dict__)
|
print(type(obj), obj.__dict__)
|
||||||
|
|
||||||
|
# link to self-user #
|
||||||
if not self.me:
|
if not self.me:
|
||||||
self.me = self.get_me()
|
me = self.get_me()
|
||||||
|
self.me = InputPeerUser(me.id, me.access_hash)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Боты
|
Боты
|
||||||
@@ -87,10 +89,8 @@ class TelegramGateClient(TelegramClient):
|
|||||||
|
|
||||||
fwd_from = self._process_forward_msg(obj) if obj.fwd_from else '' # process forward messages
|
fwd_from = self._process_forward_msg(obj) if obj.fwd_from else '' # process forward messages
|
||||||
self.gate_send_message( mfrom='u' + str(obj.user_id), mbody = '[MSG {}] {}{}'.format(obj.id, fwd_from, obj.message) )
|
self.gate_send_message( mfrom='u' + str(obj.user_id), mbody = '[MSG {}] {}{}'.format(obj.id, fwd_from, obj.message) )
|
||||||
|
usr = self._get_user_information(obj.user_id) # get peer information
|
||||||
if obj.user_id in self.xmpp_gate.tg_dialogs[self.jid]['users']: # make as read
|
self.invoke(ReadHistoryRequest( InputPeerUser(usr.id, usr.access_hash), obj.id )) # delivery report
|
||||||
usr = self.xmpp_gate.tg_dialogs[self.jid]['users'][obj.user_id]
|
|
||||||
self.invoke(ReadHistoryRequest( InputPeerUser(usr.id, usr.access_hash), obj.id ))
|
|
||||||
|
|
||||||
# message from normal group #
|
# message from normal group #
|
||||||
if type(obj) in [UpdateShortChatMessage] and not obj.out:
|
if type(obj) in [UpdateShortChatMessage] and not obj.out:
|
||||||
@@ -115,44 +115,53 @@ class TelegramGateClient(TelegramClient):
|
|||||||
if type(obj) in [UpdateNewMessage, UpdateNewChannelMessage, UpdateEditMessage, UpdateEditChannelMessage] and not obj.message.out:
|
if type(obj) in [UpdateNewMessage, UpdateNewChannelMessage, UpdateEditMessage, UpdateEditChannelMessage] and not obj.message.out:
|
||||||
|
|
||||||
cid = None
|
cid = None
|
||||||
mid = obj.message.id
|
msg = ''
|
||||||
msg = obj.message.message
|
|
||||||
fwd_from = ''
|
fwd_from = ''
|
||||||
|
mid = obj.message.id
|
||||||
|
|
||||||
|
|
||||||
# detect message type
|
# detect message type
|
||||||
is_user = type(obj.message.to_id) is PeerUser
|
is_user = type(obj.message.to_id) is PeerUser
|
||||||
is_group = type(obj.message.to_id) is PeerChat
|
is_group = type(obj.message.to_id) is PeerChat
|
||||||
is_supergroup = type(obj.message.to_id) is PeerChannel
|
is_supergroup = type(obj.message.to_id) is PeerChannel
|
||||||
|
|
||||||
# is forwarded?
|
|
||||||
if obj.message.fwd_from:
|
|
||||||
fwd_from = self._process_forward_msg(obj.message)
|
|
||||||
|
|
||||||
# detect from id
|
# detect from id
|
||||||
if is_user:
|
if is_user:
|
||||||
cid = obj.message.from_id
|
cid = obj.message.from_id
|
||||||
usr = self.xmpp_gate.tg_dialogs[self.jid]['users'][cid]
|
peer = InputPeerUser(cid, self.xmpp_gate.tg_dialogs[self.jid]['users'][cid].access_hash) if cid in self.xmpp_gate.tg_dialogs[self.jid]['users'] else None
|
||||||
prefix = 'u'
|
prefix = 'u'
|
||||||
elif is_group:
|
elif is_group:
|
||||||
cid = obj.message.to_id.chat_id
|
cid = obj.message.to_id.chat_id
|
||||||
|
peer = InputPeerChat(cid)
|
||||||
prefix = 'g'
|
prefix = 'g'
|
||||||
elif is_supergroup:
|
elif is_supergroup:
|
||||||
cid = obj.message.to_id.channel_id
|
cid = obj.message.to_id.channel_id
|
||||||
access_hash = self.xmpp_gate.tg_dialogs[self.jid]['supergroups'][cid].access_hash if cid in self.xmpp_gate.tg_dialogs[self.jid]['supergroups'] else None
|
peer = InputPeerChannel(cid, self.xmpp_gate.tg_dialogs[self.jid]['supergroups'][cid].access_hash) if cid in self.xmpp_gate.tg_dialogs[self.jid]['supergroups'] else None
|
||||||
prefix = 's'
|
prefix = 's'
|
||||||
|
|
||||||
|
# our message #
|
||||||
|
if type(obj.message) == MessageService:
|
||||||
|
obj.message.fwd_from, obj.message.post, obj.message.edit_date, obj.message.media = None, None, None, None
|
||||||
|
msg = self._process_info_msg(obj.message, peer)
|
||||||
|
elif type(obj.message) == Message:
|
||||||
|
msg = obj.message.message
|
||||||
|
|
||||||
|
|
||||||
|
# is forwarded?
|
||||||
|
if obj.message.fwd_from:
|
||||||
|
fwd_from = self._process_forward_msg(obj.message)
|
||||||
|
|
||||||
# maybe its channel? #
|
# maybe its channel? #
|
||||||
if obj.message.post:
|
if obj.message.post:
|
||||||
prefix = 'c'
|
prefix = 'c'
|
||||||
|
|
||||||
# maybe its forwarded? #
|
|
||||||
|
|
||||||
# get sender information from chat info #
|
# get sender information from chat info #
|
||||||
if not is_user and not obj.message.post:
|
if not is_user and not obj.message.post:
|
||||||
if obj.message.from_id not in self._groups_users:
|
if obj.message.from_id not in self._groups_users:
|
||||||
|
|
||||||
chat_info = self.invoke(GetFullChatRequest(cid)) if is_group else self.invoke(GetParticipantRequest(InputPeerChannel(cid, access_hash), InputPeerUser(self.me.id, self.me.access_hash)))
|
chat = self.invoke(GetFullChatRequest(cid)) if is_group else self.invoke(GetParticipantRequest(peer, self.me))
|
||||||
for usr in chat_info.users:
|
for usr in chat.users:
|
||||||
self._groups_users[usr.id] = usr
|
self._groups_users[usr.id] = usr
|
||||||
|
|
||||||
nickname = display_tg_name(self._groups_users[obj.message.from_id].first_name, self._groups_users[obj.message.from_id].last_name)
|
nickname = display_tg_name(self._groups_users[obj.message.from_id].first_name, self._groups_users[obj.message.from_id].last_name)
|
||||||
@@ -171,20 +180,14 @@ class TelegramGateClient(TelegramClient):
|
|||||||
self.gate_send_message(prefix + str(cid), mbody = '[MSG {}] {}{}'.format(mid, fwd_from, msg) )
|
self.gate_send_message(prefix + str(cid), mbody = '[MSG {}] {}{}'.format(mid, fwd_from, msg) )
|
||||||
|
|
||||||
# delivery report
|
# delivery report
|
||||||
if is_user and usr.access_hash: # make as read
|
if is_supergroup:
|
||||||
self.invoke(ReadHistoryRequest( InputPeerUser(usr.id, usr.access_hash), mid ))
|
self.invoke(ReadHistoryChannel(peer, mid))
|
||||||
if is_group:
|
else:
|
||||||
self.invoke(ReadHistoryRequest(InputPeerChat(cid), mid))
|
self.invoke(ReadHistoryRequest(peer, mid))
|
||||||
if is_supergroup and access_hash:
|
|
||||||
self.invoke(ReadHistoryChannel(InputPeerChannel(cid, access_hash), mid))
|
|
||||||
|
|
||||||
|
|
||||||
# Status Updates #
|
# Status Updates #
|
||||||
if type(obj) is UpdateUserStatus:
|
if type(obj) is UpdateUserStatus:
|
||||||
|
|
||||||
print(self._status_last)
|
|
||||||
print(time.time())
|
|
||||||
|
|
||||||
# save last update time #
|
# save last update time #
|
||||||
if (obj.user_id in self._status_last) and ( (time.time() - self._status_last[obj.user_id]['time'] < self.user_options['status_update_interval']) or self._status_last[obj.user_id]['status'] == obj.status ):
|
if (obj.user_id in self._status_last) and ( (time.time() - self._status_last[obj.user_id]['time'] < self.user_options['status_update_interval']) or self._status_last[obj.user_id]['status'] == obj.status ):
|
||||||
return
|
return
|
||||||
@@ -256,6 +259,19 @@ class TelegramGateClient(TelegramClient):
|
|||||||
return attrib
|
return attrib
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _get_user_information(self, uid):
|
||||||
|
|
||||||
|
if uid in self.xmpp_gate.tg_dialogs[self.jid]['users']:
|
||||||
|
return self.xmpp_gate.tg_dialogs[self.jid]['users'][uid]
|
||||||
|
|
||||||
|
entity = self.get_entity(uid)
|
||||||
|
if entity.access_hash:
|
||||||
|
self.xmpp_gate.tg_dialogs[self.jid]['users'][uid] = entity
|
||||||
|
return entity
|
||||||
|
else:
|
||||||
|
return {'first_name': 'Unknown', 'last_name': 'user', 'access_hash': -1, 'id': 0}
|
||||||
|
|
||||||
|
|
||||||
def _process_forward_msg(self, message):
|
def _process_forward_msg(self, message):
|
||||||
"""
|
"""
|
||||||
Обрабатывает информацию в пересланном сообщении (от кого оно и/или из какого канала). Требует дополнительно
|
Обрабатывает информацию в пересланном сообщении (от кого оно и/или из какого канала). Требует дополнительно
|
||||||
@@ -267,16 +283,11 @@ class TelegramGateClient(TelegramClient):
|
|||||||
"""
|
"""
|
||||||
if message.fwd_from.from_id: # От пользователя
|
if message.fwd_from.from_id: # От пользователя
|
||||||
|
|
||||||
usr = self.get_entity(message.fwd_from.from_id) if not message.fwd_from.from_id in self.xmpp_gate.tg_dialogs[self.jid]['users'] else self.xmpp_gate.tg_dialogs[self.jid]['users'][message.fwd_from.from_id]
|
usr = self._get_user_information(message.fwd_from.from_id)
|
||||||
print(usr)
|
|
||||||
if usr.access_hash:
|
|
||||||
self.xmpp_gate.tg_dialogs[self.jid]['users'][message.fwd_from.from_id] = usr
|
|
||||||
fwd_from = display_tg_name(usr.first_name, usr.last_name)
|
fwd_from = display_tg_name(usr.first_name, usr.last_name)
|
||||||
else:
|
|
||||||
fwd_from = '<Unknown User>'
|
|
||||||
|
|
||||||
if message.fwd_from.channel_id: # От канала
|
if message.fwd_from.channel_id: # От канала
|
||||||
fwd_from = '<Channel {}>'.format(message.fwd_from.channel_id)
|
fwd_from = 'Channel {}'.format(message.fwd_from.channel_id)
|
||||||
|
|
||||||
# let's construct
|
# let's construct
|
||||||
fwd_reply = '|Forwarded from [{}]|'.format(fwd_from)
|
fwd_reply = '|Forwarded from [{}]|'.format(fwd_from)
|
||||||
@@ -362,120 +373,65 @@ class TelegramGateClient(TelegramClient):
|
|||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
@staticmethod
|
def _process_info_msg(self, message, peer):
|
||||||
def _process_info_msg(message, users):
|
|
||||||
"""
|
"""
|
||||||
Обрабатывает информационные сообщения в групповых чатах. Возвращает готовое для вывода сообщение.
|
Обрабатывает информационные сообщения в групповых чатах. Возвращает готовое для вывода сообщение.
|
||||||
:param message:
|
:param message:
|
||||||
:param users:
|
:param users:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
alt_msg = None
|
|
||||||
nickname = display_tg_name(users[0].first_name, users[0].last_name)
|
|
||||||
uid = users[0].id
|
|
||||||
|
|
||||||
# MessageActionChatEditPhoto
|
msg = ''
|
||||||
|
usr = self._get_user_information(message.from_id)
|
||||||
|
nickname = display_tg_name(usr.first_name, usr.last_name)
|
||||||
|
|
||||||
# Создана супергруппа
|
# supergroup created #
|
||||||
if type(message.action) is MessageActionChannelCreate:
|
if type(message.action) is MessageActionChannelCreate:
|
||||||
# Пока нет смысла - поддержка каналов не реализована
|
|
||||||
pass
|
pass
|
||||||
# Создана группа
|
|
||||||
|
# group created #
|
||||||
elif type(message.action) is MessageActionChatCreate:
|
elif type(message.action) is MessageActionChatCreate:
|
||||||
pass
|
pass
|
||||||
# Добавлен пользователь в чат
|
|
||||||
|
# user added #
|
||||||
elif type(message.action) is MessageActionChatAddUser:
|
elif type(message.action) is MessageActionChatAddUser:
|
||||||
if len(users) == 2: # Кто-то добавил другого пользователя
|
added_users = []
|
||||||
j_name = display_tg_name(users[1].first_name, users[1].last_name)
|
for user_id in message.action.users:
|
||||||
j_uid = users[1].id
|
usr = self._get_user_information(user_id)
|
||||||
alt_msg = 'User [{}] (UID:{}) added [{}] (UID:{})'.format(nickname, uid,
|
added_users.append(display_tg_name(usr.first_name, usr.last_name))
|
||||||
j_name, j_uid)
|
|
||||||
else: # Пользователь вошел сам
|
msg = 'User [{}] has just invited [{}]'.format(nickname, ','.join(added_users))
|
||||||
alt_msg = 'User [{}] (UID:{}) joined'.format(nickname, uid)
|
|
||||||
# Пользователь удален/вышел/забанен
|
# user exit #
|
||||||
elif type(message.action) is MessageActionChatDeleteUser:
|
elif type(message.action) is MessageActionChatDeleteUser:
|
||||||
pass
|
usr = self._get_user_information(message.action.user_id)
|
||||||
# Пользователь вошел по инвайт ссылке
|
msg = 'User [{}] has just left the room'.format(display_tg_name(usr.first_name, usr.last_name))
|
||||||
|
|
||||||
|
# user joined #
|
||||||
elif type(message.action) is MessageActionChatJoinedByLink:
|
elif type(message.action) is MessageActionChatJoinedByLink:
|
||||||
alt_msg = 'User [{}] (UID:{}) joined via invite link'.format(nickname, uid)
|
usr = self._get_user_information(message.action.user_id)
|
||||||
# Изменено название чата
|
msg = 'User [{}] joined the room'.format(display_tg_name(usr.first_name, usr.last_name))
|
||||||
|
|
||||||
|
# chat name modified #
|
||||||
elif type(message.action) is MessageActionChatEditTitle:
|
elif type(message.action) is MessageActionChatEditTitle:
|
||||||
g_title = message.action.title
|
msg = 'User [{}] changed title to [{}]'.format(nickname, message.action.title)
|
||||||
alt_msg = 'User [{}] (UID:{}) changed title to [{}]'.format(nickname, uid, g_title)
|
|
||||||
# Прикреплено сообщение в чате
|
# pinned message
|
||||||
elif type(message.action) is MessageActionPinMessage:
|
elif type(message.action) is MessageActionPinMessage:
|
||||||
# Notify all members реализовано путем указания, что пользователя упомянули,
|
pinned_mid = message.reply_to_msg_id # target message
|
||||||
# то есть флаг mentioned=True. Но для транспорта он не имеет смысла.
|
message_req = self.invoke(GetMessagesRequest(peer, [pinned_mid]))
|
||||||
p_mid = message.reply_to_msg_id # Наркоманы
|
if len(message_req.messages) > 0:
|
||||||
alt_msg = 'User [{}] (UID:{}) pinned message with MID:{}'.format(nickname, uid, p_mid)
|
pinned_message = message_req.messages[0].message
|
||||||
# Группа была преобразована в супергруппу
|
pinned_from = self._get_user_information(message_req.messages[0].from_id)
|
||||||
elif type(message.action) is MessageActionChatMigrateTo:
|
msg = 'User [{}] pinned message: [{}]: {}'.format(nickname, display_tg_name(pinned_from.first_name, pinned_from.last_name), pinned_message)
|
||||||
# Это сложный ивент, который ломает текущую реализацию хендлинга
|
|
||||||
# (ибо в доках, которых нет, не сказано, что так можно было)
|
|
||||||
# Пусть полежит до рефакторинга
|
|
||||||
pass
|
|
||||||
# Супергруппа была технически создана из группы
|
|
||||||
elif type(message.action) is MessageActionChannelMigrateFrom:
|
|
||||||
# ---...---...---
|
|
||||||
# ---...---...---
|
|
||||||
# ---...---...---
|
|
||||||
pass
|
|
||||||
|
|
||||||
return alt_msg
|
# group converted to supergroup
|
||||||
|
elif type(message.action) in [MessageActionChatMigrateTo, MessageActionChannelMigrateFrom]:
|
||||||
|
print('--ACHTUNG!--')
|
||||||
|
print(message)
|
||||||
|
#del(self.xmpp_gate.tg_dialogs[self.jid]['groups'][message.chat_id])
|
||||||
|
|
||||||
def get_cached_message(self, dlg_id, msg_id, user=False, group=False, supergroup=False):
|
return msg
|
||||||
"""
|
|
||||||
Получает из кэша сообщение диалога указанной группы (для работы цитат в последних сообщениях)
|
|
||||||
:param dlg_id:
|
|
||||||
:param msg_id:
|
|
||||||
:param user:
|
|
||||||
:param group:
|
|
||||||
:param supergroup:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if user:
|
|
||||||
obj = self._message_cache_users
|
|
||||||
elif group:
|
|
||||||
obj = self._message_cache_groups
|
|
||||||
elif supergroup:
|
|
||||||
obj = self._message_cache_supergroups
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if dlg_id in obj:
|
|
||||||
if msg_id in obj[dlg_id]:
|
|
||||||
return obj[dlg_id][msg_id]
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_cached_message(self, dlg_id, msg_id, msg, user=False, group=False, supergroup=False):
|
|
||||||
"""
|
|
||||||
Кэширует сообщение из диалога указанной группы (для работы цитат в последних сообщениях)
|
|
||||||
:param dlg_id:
|
|
||||||
:param msg_id:
|
|
||||||
:param msg:
|
|
||||||
:param user:
|
|
||||||
:param group:
|
|
||||||
:param supergroup:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if user:
|
|
||||||
obj = self._message_cache_users
|
|
||||||
elif group:
|
|
||||||
obj = self._message_cache_groups
|
|
||||||
elif supergroup:
|
|
||||||
obj = self._message_cache_supergroups
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
if dlg_id not in obj:
|
|
||||||
obj[dlg_id] = dict()
|
|
||||||
|
|
||||||
obj[dlg_id][msg_id] = msg
|
|
||||||
|
|
||||||
# Удаляем старые сообщения из кэша
|
|
||||||
if len(obj[dlg_id]) > self.xmpp_gate.config['messages_max_max_cache_size']:
|
|
||||||
del obj[dlg_id][sorted(obj[dlg_id].keys())[0]]
|
|
||||||
|
|
||||||
def media_thread_downloader(self):
|
def media_thread_downloader(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user