[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:
annelin
2018-07-01 21:29:34 +00:00
parent 0f648e6bd4
commit e66bda9cd8
5 changed files with 49 additions and 14 deletions

View File

@@ -1,3 +1,3 @@
sleekxmpp==1.3.2 sleekxmpp==1.3.2
Telethon==0.15.5 Telethon==0.15.5
pytz

View File

@@ -1,3 +1,3 @@
from xmpp_tg.xmpp import XMPPTelegram from xmpp_tg.xmpp import XMPPTelegram
__version__ = '0.3.0' __version__ = '0.3.1'

View File

@@ -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: # Контакт (с номером)

View File

@@ -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

View File

@@ -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):
@@ -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'
@@ -395,6 +396,15 @@ class XMPPTelegram(ComponentXMPP):
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')