[SVN] updated to version 0.3.1
[DEP] [BROKE] new dependency: pytz (pip3 install pytz)
[FIX] fixed media downloading with telethon 0.18
[FIX] now using server time zone in status messages instead of UTC
[UPD] now removing chats & supergroups completely after we leaving with !leave command
[ADD] added commands:
!remove — completely remove current user from contact list
!import phone firstname lastname — try to add contact with phone number (untested)
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
sleekxmpp==1.3.2
|
sleekxmpp==1.3.2
|
||||||
Telethon==0.15.5
|
Telethon==0.15.5
|
||||||
|
pytz
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from xmpp_tg.xmpp import XMPPTelegram
|
from xmpp_tg.xmpp import XMPPTelegram
|
||||||
|
|
||||||
__version__ = '0.3.0'
|
__version__ = '0.3.1'
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import os
|
|||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from xmpp_tg.utils import display_tg_name
|
from xmpp_tg.utils import localtime, display_tg_name
|
||||||
|
|
||||||
from .utils import var_dump
|
from .utils import var_dump
|
||||||
import traceback
|
import traceback
|
||||||
@@ -181,7 +181,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
if type(obj.status) is UserStatusOnline:
|
if type(obj.status) is UserStatusOnline:
|
||||||
self._status_updates[str(obj.user_id)] = { 'status': None, 'message': 'Online' }
|
self._status_updates[str(obj.user_id)] = { 'status': None, 'message': 'Online' }
|
||||||
elif type(obj.status) is UserStatusOffline:
|
elif type(obj.status) is UserStatusOffline:
|
||||||
self._status_updates[str(obj.user_id)] = { 'status': 'xa', 'message': obj.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y') }
|
self._status_updates[str(obj.user_id)] = { 'status': 'xa', 'message': localtime(obj.status.was_online).strftime('Last seen at %H:%M %d/%m/%Y') }
|
||||||
elif type(obj.status) is UserStatusRecently:
|
elif type(obj.status) is UserStatusRecently:
|
||||||
self._status_updates[str(obj.user_id)] = { 'status': 'away', 'message': 'Last seen recently' }
|
self._status_updates[str(obj.user_id)] = { 'status': 'away', 'message': 'Last seen recently' }
|
||||||
else:
|
else:
|
||||||
@@ -324,7 +324,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
attr_v = self.get_document_attribute(attributes, DocumentAttributeFilename)
|
attr_v = self.get_document_attribute(attributes, DocumentAttributeFilename)
|
||||||
video_file = '|File:{}'.format(attr_v.file_name)
|
video_file = '|File:{}'.format(attr_v.file_name)
|
||||||
|
|
||||||
if media.caption:
|
if hasattr(media, 'caption'):
|
||||||
caption = media.caption + ' '
|
caption = media.caption + ' '
|
||||||
|
|
||||||
# Тоже свой формат
|
# Тоже свой формат
|
||||||
@@ -335,7 +335,7 @@ class TelegramGateClient(TelegramClient):
|
|||||||
|
|
||||||
self._media_queue.put({'media': media, 'file': g_link['name']})
|
self._media_queue.put({'media': media, 'file': g_link['name']})
|
||||||
|
|
||||||
if media.caption: # Если есть описание - указываем
|
if hasattr(media, 'caption'): # Если есть описание - указываем
|
||||||
msg = '{} {}'.format(media.caption, msg)
|
msg = '{} {}'.format(media.caption, msg)
|
||||||
|
|
||||||
elif type(media) is MessageMediaContact: # Контакт (с номером)
|
elif type(media) is MessageMediaContact: # Контакт (с номером)
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import types
|
import types
|
||||||
|
import time
|
||||||
|
import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def display_tg_name(peer):
|
def display_tg_name(peer):
|
||||||
if hasattr(peer,'title') and hasattr(peer,'broadcast') and peer.broadcast: # channel
|
if hasattr(peer,'title') and hasattr(peer,'broadcast') and peer.broadcast: # channel
|
||||||
return '[C] ' + peer.title
|
return '[C] ' + peer.title
|
||||||
@@ -36,6 +39,14 @@ def get_contact_jid(peer, gatejid):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def localtime(utc_dt):
|
||||||
|
if time.daylight:
|
||||||
|
offsetHour = time.altzone / 3600
|
||||||
|
else:
|
||||||
|
offsetHour = time.timezone / 3600
|
||||||
|
local_tz = pytz.timezone('Etc/GMT%+d' % offsetHour)
|
||||||
|
local_dt = utc_dt.replace(tzinfo = pytz.utc).astimezone(local_tz)
|
||||||
|
return local_tz.normalize(local_dt)
|
||||||
|
|
||||||
def var_dump(obj, depth=7, l=""):
|
def var_dump(obj, depth=7, l=""):
|
||||||
# fall back to repr
|
# fall back to repr
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import sleekxmpp
|
|||||||
from sleekxmpp.componentxmpp import ComponentXMPP
|
from sleekxmpp.componentxmpp import ComponentXMPP
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from telethon.tl.functions.messages import GetDialogsRequest, SendMessageRequest, ImportChatInviteRequest, GetFullChatRequest, AddChatUserRequest, DeleteChatUserRequest, CreateChatRequest
|
from telethon.tl.functions.messages import GetDialogsRequest, SendMessageRequest, ImportChatInviteRequest, GetFullChatRequest, AddChatUserRequest, DeleteChatUserRequest, CreateChatRequest, DeleteHistoryRequest
|
||||||
from telethon.tl.functions.account import UpdateStatusRequest, GetAuthorizationsRequest, UpdateProfileRequest, UpdateUsernameRequest
|
from telethon.tl.functions.account import UpdateStatusRequest, GetAuthorizationsRequest, UpdateProfileRequest, UpdateUsernameRequest
|
||||||
from telethon.tl.functions.contacts import DeleteContactRequest, BlockRequest, UnblockRequest
|
from telethon.tl.functions.contacts import DeleteContactRequest, BlockRequest, UnblockRequest, ImportContactsRequest
|
||||||
from telethon.tl.functions.channels import JoinChannelRequest, LeaveChannelRequest, InviteToChannelRequest, EditBannedRequest, CreateChannelRequest
|
from telethon.tl.functions.channels import JoinChannelRequest, LeaveChannelRequest, InviteToChannelRequest, EditBannedRequest, CreateChannelRequest
|
||||||
|
|
||||||
from telethon.tl.types import InputPeerEmpty, InputPeerUser, InputPeerChat, InputPeerChannel
|
from telethon.tl.types import InputPeerEmpty, InputPeerUser, InputPeerChat, InputPeerChannel, InputPhoneContact
|
||||||
from telethon.tl.types import User, Chat, Channel
|
from telethon.tl.types import User, Chat, Channel
|
||||||
from telethon.tl.types import PeerChannel, PeerChat, PeerUser, Chat, ChatForbidden, Channel, ChannelForbidden
|
from telethon.tl.types import PeerChannel, PeerChat, PeerUser, Chat, ChatForbidden, Channel, ChannelForbidden
|
||||||
from telethon.tl.types import UserStatusOnline, UserStatusRecently, UserStatusOffline
|
from telethon.tl.types import UserStatusOnline, UserStatusRecently, UserStatusOffline
|
||||||
@@ -24,7 +24,7 @@ from telethon.helpers import generate_random_long
|
|||||||
from telethon.errors import SessionPasswordNeededError
|
from telethon.errors import SessionPasswordNeededError
|
||||||
|
|
||||||
from xmpp_tg.mtproto import TelegramGateClient
|
from xmpp_tg.mtproto import TelegramGateClient
|
||||||
from xmpp_tg.utils import var_dump, display_tg_name, get_contact_jid
|
from xmpp_tg.utils import var_dump, display_tg_name, get_contact_jid, localtime
|
||||||
import xmpp_tg.monkey # Патчим баги в библиотеках
|
import xmpp_tg.monkey # Патчим баги в библиотеках
|
||||||
|
|
||||||
class XMPPTelegram(ComponentXMPP):
|
class XMPPTelegram(ComponentXMPP):
|
||||||
@@ -43,7 +43,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
|
|
||||||
self.auto_authorize = True
|
self.auto_authorize = True
|
||||||
# self.auto_subscribe = True
|
# self.auto_subscribe = True
|
||||||
|
|
||||||
self.config = config_dict
|
self.config = config_dict
|
||||||
self.accounts = dict() # personal configuration per JID
|
self.accounts = dict() # personal configuration per JID
|
||||||
self.tg_connections = dict()
|
self.tg_connections = dict()
|
||||||
@@ -77,7 +77,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
|
|
||||||
vcard = self.plugin['xep_0054'].make_vcard()
|
vcard = self.plugin['xep_0054'].make_vcard()
|
||||||
vcard['FN'] = self.config['title']
|
vcard['FN'] = self.config['title']
|
||||||
vcard['DESC'] = 'Send /help for information'
|
vcard['DESC'] = 'Send !help for information'
|
||||||
self.plugin['xep_0054'].publish_vcard(jid=self.boundjid.bare, vcard=vcard)
|
self.plugin['xep_0054'].publish_vcard(jid=self.boundjid.bare, vcard=vcard)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
@@ -268,6 +268,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
'!reload_dialogs - Reloads dialogs list from Telegram\n\n'
|
'!reload_dialogs - Reloads dialogs list from Telegram\n\n'
|
||||||
'!add - Find and add Telegram contact. Any formats accepted (nickname or t.me link)\n\n'
|
'!add - Find and add Telegram contact. Any formats accepted (nickname or t.me link)\n\n'
|
||||||
'!join - Join Telegram conference via invite link \n\n'
|
'!join - Join Telegram conference via invite link \n\n'
|
||||||
|
'!import phone firstname lastname - Add Telegram contact with phone number \n\n'
|
||||||
'!group GroupName @InviteContact - Create a normal group\n'
|
'!group GroupName @InviteContact - Create a normal group\n'
|
||||||
'!supergroup SupergroupName - Create a supergroup\n'
|
'!supergroup SupergroupName - Create a supergroup\n'
|
||||||
'!channel ChannelName - Create a channel\n\n'
|
'!channel ChannelName - Create a channel\n\n'
|
||||||
@@ -394,6 +395,15 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
elif parsed[0] == '!about' and len(parsed) >= 2: # create new channel
|
elif parsed[0] == '!about' and len(parsed) >= 2: # create new channel
|
||||||
about = iq['body'][7:]
|
about = iq['body'][7:]
|
||||||
self.tg_connections[jid].invoke(UpdateProfileRequest(about = about))
|
self.tg_connections[jid].invoke(UpdateProfileRequest(about = about))
|
||||||
|
|
||||||
|
elif parsed[0] == '!import' and len(parsed) >= 3: # create new channel
|
||||||
|
phone = parsed[1]
|
||||||
|
firstname = parsed[2]
|
||||||
|
lastname = parsed[3] if len(parsed) > 3 else None
|
||||||
|
|
||||||
|
contact = InputPhoneContact(client_id=generate_random_long(), phone=phone, first_name=firstname, last_name=lastname)
|
||||||
|
self.tg_connections[jid].invoke(ImportContactsRequest([contact]))
|
||||||
|
self.tg_process_dialogs(jid)
|
||||||
|
|
||||||
else: # --------------------------------------------------
|
else: # --------------------------------------------------
|
||||||
self.gate_reply_message(iq, 'Unknown command. Try !help for list all commands.')
|
self.gate_reply_message(iq, 'Unknown command. Try !help for list all commands.')
|
||||||
@@ -407,6 +417,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
'!help - Displays this text\n'
|
'!help - Displays this text\n'
|
||||||
'!block - Blacklists current user\n'
|
'!block - Blacklists current user\n'
|
||||||
'!unblock - Unblacklists current user\n'
|
'!unblock - Unblacklists current user\n'
|
||||||
|
'!remove - Removes history and contact from your contact list\n'
|
||||||
)
|
)
|
||||||
elif parsed[0] == '!block':
|
elif parsed[0] == '!block':
|
||||||
tg_id = int(iq['to'].node[1:])
|
tg_id = int(iq['to'].node[1:])
|
||||||
@@ -420,6 +431,16 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
self.tg_connections[jid].invoke(UnblockRequest( InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash) ) )
|
self.tg_connections[jid].invoke(UnblockRequest( InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash) ) )
|
||||||
self.gate_reply_message(iq, 'User %s unblacklisted!' % nickname)
|
self.gate_reply_message(iq, 'User %s unblacklisted!' % nickname)
|
||||||
|
|
||||||
|
elif parsed[0] == '!remove':
|
||||||
|
tg_id = int(iq['to'].node[1:])
|
||||||
|
peer = InputPeerUser(tg_id, self.tg_dialogs[jid]['users'][tg_id].access_hash)
|
||||||
|
c_jid = get_contact_jid(self.tg_dialogs[jid]['users'][tg_id], self.boundjid.bare)
|
||||||
|
self.tg_connections[jid].invoke( DeleteContactRequest(peer) )
|
||||||
|
self.tg_connections[jid].invoke( DeleteHistoryRequest( peer, max_id = 0, just_clear = None ) )
|
||||||
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
||||||
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
||||||
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribe')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def process_chat_group_command(self, iq):
|
def process_chat_group_command(self, iq):
|
||||||
@@ -436,13 +457,16 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
elif parsed[0] == '!leave':
|
elif parsed[0] == '!leave':
|
||||||
tg_id = int(iq['to'].node[1:])
|
tg_id = int(iq['to'].node[1:])
|
||||||
if tg_id in self.tg_dialogs[jid]['supergroups']:
|
if tg_id in self.tg_dialogs[jid]['supergroups']:
|
||||||
self.tg_connections[jid].invoke(LeaveChannelRequest( InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash) ) )
|
peer = InputPeerChannel(tg_id, self.tg_dialogs[jid]['supergroups'][tg_id].access_hash)
|
||||||
|
self.tg_connections[jid].invoke( LeaveChannelRequest(peer) )
|
||||||
|
self.tg_connections[jid].invoke( DeleteHistoryRequest( peer, max_id = 0, just_clear = None ) )
|
||||||
c_jid = get_contact_jid(self.tg_dialogs[jid]['supergroups'][tg_id], self.boundjid.bare)
|
c_jid = get_contact_jid(self.tg_dialogs[jid]['supergroups'][tg_id], self.boundjid.bare)
|
||||||
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
||||||
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
||||||
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribe')
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribe')
|
||||||
if tg_id in self.tg_dialogs[jid]['groups']:
|
if tg_id in self.tg_dialogs[jid]['groups']:
|
||||||
self.tg_connections[jid].invoke( DeleteChatUserRequest(tg_id, self.tg_connections[jid].me) )
|
self.tg_connections[jid].invoke( DeleteChatUserRequest(tg_id, self.tg_connections[jid].me) )
|
||||||
|
self.tg_connections[jid].invoke( DeleteHistoryRequest( InputPeerChat(tg_id), max_id = 0, just_clear = None ) )
|
||||||
c_jid = get_contact_jid(self.tg_dialogs[jid]['groups'][tg_id], self.boundjid.bare)
|
c_jid = get_contact_jid(self.tg_dialogs[jid]['groups'][tg_id], self.boundjid.bare)
|
||||||
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unavailable')
|
||||||
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
self.send_presence(pto = jid, pfrom = c_jid, ptype = 'unsubscribed')
|
||||||
@@ -603,7 +627,7 @@ class XMPPTelegram(ComponentXMPP):
|
|||||||
elif type(usr.status) is UserStatusRecently:
|
elif type(usr.status) is UserStatusRecently:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, pshow='away', pstatus='Last seen recently')
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='away', pstatus='Last seen recently')
|
||||||
elif type(usr.status) is UserStatusOffline:
|
elif type(usr.status) is UserStatusOffline:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, pshow='xa', pstatus=usr.status.was_online.strftime('Last seen at %H:%M %d/%m/%Y') )
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='xa', pstatus=localtime(usr.status.was_online).strftime('Last seen at %H:%M %d/%m/%Y') )
|
||||||
else:
|
else:
|
||||||
self.send_presence(pto=jid, pfrom=u_jid, pshow='dnd', pstatus='Last seen a long time ago')
|
self.send_presence(pto=jid, pfrom=u_jid, pshow='dnd', pstatus='Last seen a long time ago')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user