class bindings(object): def __init__(self, bot): self.bot = bot self.receiver = Receiver(host="localhost", port=self.bot.config.bindings_token) self.sender = Sender(host="localhost", port=self.bot.config.bindings_token) logging.getLogger("pytg").setLevel(logging.WARNING) def get_me(self): msg = self.sender.get_self() return User(msg.peer_id, msg.first_name, None, msg.username) def convert_message(self, msg): id = msg['id'] if msg.receiver.type == 'user': conversation = Conversation(msg.sender.peer_id) conversation.title = msg.sender.first_name else: if msg.receiver.type == 'channel': conversation = Conversation(- int('100' + str(msg.receiver.peer_id))) else: conversation = Conversation(- int(msg.receiver.peer_id)) conversation.title = msg.receiver.title if msg.sender.type == 'user': sender = User(int(msg.sender.peer_id)) if 'first_name' in msg.sender: sender.first_name = msg.sender.first_name if 'last_name' in msg.sender: sender.last_name = msg.sender.last_name if 'username' in msg.sender: sender.username = msg.sender.username else: if msg.sender.type == 'channel': sender = Conversation(- int('100' + str(msg.sender.peer_id))) else: sender = Conversation(- int(msg.sender.peer_id)) sender.first_name = msg.sender.title date = msg.date # Gets the type of the message if 'text' in msg: type = 'text' content = msg.text extra = None elif 'media' in msg: type = msg.media.type content = msg.id if 'caption' in msg.media: extra = msg.media.caption else: extra = None elif msg.event == 'service': type = 'service' if msg.action.type == 'chat_del_user': content = 'left_user' extra = msg.action.user.peer_id elif msg.action.type == 'chat_add_user': content = 'join_user' extra = msg.action.user.peer_id elif msg.action.type == 'chat_add_user_link': content = 'join_user' extra = msg.sender.peer_id else: type = None content = None extra = None else: type = None content = None extra = None # Generates another message object for the original message if the reply. if 'reply_id' in msg: reply_msg = self.sender.message_get(msg.reply_id) reply = self.convert_message(reply_msg) else: reply = None return Message(id, conversation, sender, content, type, date, reply, extra) def receiver_worker(self): try: logging.debug('Starting receiver worker...') while self.bot.started: self.receiver.start() self.receiver.message(self.main_loop()) except KeyboardInterrupt: pass def send_message(self, message): if not message.extra: message.extra = {} if message.type != 'text' and message.content.startswith('http'): message.content = download(message.content) elif message.type != 'text' and not message.content.startswith('/'): message.content = self.sender.load_file(message.content) if not message.extra or not 'caption' in message.extra: message.extra['caption'] = None if message.type == 'text': self.sender.send_typing(self.peer(message.conversation.id), 1) if 'format' in message.extra and message.extra['format'] == 'Markdown': message.content = remove_markdown(message.content) elif 'format' in message.extra and message.extra['format'] == 'HTML': message.content = self.convert_links(message.content) try: if 'format' in message.extra and message.extra['format'] == 'HTML': self.sender.raw('[html] msg %s %s' % (self.peer(message.conversation.id), self.escape(message.content)), enable_preview=False) else: self.sender.send_msg(self.peer(message.conversation.id), message.content, enable_preview=False) except Exception as e: logging.exception(e) elif message.type == 'photo': self.sender.send_typing(self.peer(message.conversation.id), 1) # 7 try: if message.reply: self.sender.reply_photo(message.reply, message.content, message.extra['caption']) else: self.sender.send_photo(self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'audio': self.sender.send_typing(self.peer(message.conversation.id), 1) # 6 try: if message.reply: self.sender.reply_audio(message.reply, message.content) else: self.sender.send_audio(self.peer(message.conversation.id), message.content) except Exception as e: logging.exception(e) elif message.type == 'document': self.sender.send_typing(self.peer(message.conversation.id), 1) # 8 try: if message.reply: self.sender.reply_document(message.reply, message.content, message.extra['caption']) else: self.sender.send_document(self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'sticker': if message.reply: self.sender.reply_file(message.reply, message.content) else: self.sender.send_file(self.peer(message.conversation.id), message.content) elif message.type == 'video': self.sender.send_typing(self.peer(message.conversation.id), 1) # 4 try: if message.reply: self.sender.reply_video(message.reply, message.content, message.extra['caption']) else: self.sender.send_video(self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'voice': self.sender.send_typing(self.peer(message.conversation.id), 5) try: if message.reply: self.sender.reply_audio(message.reply, message.content) else: self.sender.send_audio(self.peer(message.conversation.id), message.content) except Exception as e: logging.exception(e) elif message.type == 'location': self.sender.send_typing(self.peer(message.conversation.id), 1) # 9 if message.reply: self.sender.reply_location(message.reply, message.content['latitude'], message.content['longitude']) else: self.sender.send_location(self.peer(message.conversation.id), message.content['latitude'], message.content['longitude']) else: print('UNKNOWN MESSAGE TYPE: ' + message.type) logging.debug("UNKNOWN MESSAGE TYPE") @coroutine def main_loop(self): while self.bot.started: msg = (yield) if (msg.event == 'message' and msg.own == False) or msg.event == 'service': message = self.convert_message(msg) self.bot.inbox.put(message) try: if message.conversation.id > 0: self.sender.mark_read(self.peer(message.sender.id)) else: self.sender.mark_read(self.peer(message.conversation.id)) except Exception as e: logging.error(e) def peer(self, chat_id): if chat_id > 0: peer = 'user#id' + str(chat_id) else: if str(chat_id)[1:].startswith('100'): peer = 'channel#id' + str(chat_id)[4:] else: peer = 'chat#id' + str(chat_id)[1:] return peer def user_id(self, username): if username.startswith('@'): command = 'resolve_username ' + username[1:] resolve = self.sender.raw(command) dict = DictObject(json.loads(resolve)) else: dict = self.sender.user_info(username) if 'peer_id' in dict: return dict.peer_id else: return False def get_id(self, user): if isinstance(user, int): return user if user.isdigit(): id = int(user) else: id = int(self.user_id(user)) return id def escape(self, string): if string is None: return None CHARS_UNESCAPED = ["\\", "\n", "\r", "\t", "\b", "\a", "'"] CHARS_ESCAPED = ["\\\\", "\\n", "\\r", "\\t", "\\b", "\\a", "\\'"] for i in range(0, 7): string = string.replace(CHARS_UNESCAPED[i], CHARS_ESCAPED[i]) return string.join(["'", "'"]) # wrap with single quotes. def convert_links(self, string): for link in BeautifulSoup(string, 'lxml').findAll("a"): string = string.replace(str(link), link.get("href")) return string # THESE METHODS DO DIRECT ACTIONS # def get_file(self, file_id): pass def invite_conversation_member(self, conversation_id, user_id): self.sender.chat_add_user(self.peer(conversation_id), self.peer(user_id)) def kick_conversation_member(self, conversation_id, user_id): self.sender.chat_del_user(self.peer(conversation_id), self.peer(user_id)) def unban_conversation_member(self, conversation_id, user_id): pass def conversation_info(self, conversation_id): self.api_request('sendContact', params)
class bindings(object): def __init__(self, bot): self.bot = bot self.receiver = Receiver(host="localhost", port=self.bot.config.bindings_token) self.sender = Sender(host="localhost", port=self.bot.config.bindings_token) logging.getLogger("pytg").setLevel(logging.WARNING) def get_me(self): try: msg = self.sender.get_self() return User(msg.peer_id, msg.first_name, None, msg.username) except: return None def convert_message(self, msg): id = msg['id'] if msg.receiver.type == 'user': conversation = Conversation(msg.sender.peer_id) conversation.title = msg.sender.first_name else: if msg.receiver.type == 'channel': conversation = Conversation(-int('100' + str(msg.receiver.peer_id))) else: conversation = Conversation(-int(msg.receiver.peer_id)) conversation.title = msg.receiver.title if msg.sender.type == 'user': sender = User(int(msg.sender.peer_id)) if 'first_name' in msg.sender: sender.first_name = msg.sender.first_name if 'last_name' in msg.sender: sender.last_name = msg.sender.last_name if 'username' in msg.sender: sender.username = msg.sender.username else: if msg.sender.type == 'channel': sender = Conversation(-int('100' + str(msg.sender.peer_id))) else: sender = Conversation(-int(msg.sender.peer_id)) sender.first_name = msg.sender.title date = msg.date # Gets the type of the message if 'text' in msg: type = 'text' content = msg.text extra = None elif 'media' in msg: type = msg.media.type content = msg.id if 'caption' in msg.media: extra = msg.media.caption else: extra = None elif msg.event == 'service': type = 'notification' if msg.action.type == 'chat_del_user': content = 'left_chat_member' extra = msg.action.user.peer_id elif msg.action.type == 'chat_add_user': content = 'new_chat_member' extra = msg.action.user.peer_id elif msg.action.type == 'chat_add_user_link': content = 'new_chat_member' extra = msg.sender.peer_id else: type = None content = None extra = None else: type = None content = None extra = None # Generates another message object for the original message if the reply. if 'reply_id' in msg: reply_msg = self.sender.message_get(msg.reply_id) reply = self.convert_message(reply_msg) else: reply = None return Message(id, conversation, sender, content, type, date, reply, extra) def receiver_worker(self): try: logging.debug('Starting receiver worker...') while self.bot.started: self.receiver.start() self.receiver.message(self.main_loop()) except KeyboardInterrupt: pass def send_message(self, message): if not message.extra: message.extra = {} if message.type != 'text' and message.content.startswith('http'): message.content = download(message.content) elif message.type != 'text' and not message.content.startswith('/'): message.content = self.sender.load_file(message.content) if not message.extra or not 'caption' in message.extra: message.extra['caption'] = None if message.type == 'text': self.sender.send_typing(self.peer(message.conversation.id), 1) if 'format' in message.extra and message.extra[ 'format'] == 'Markdown': message.content = remove_markdown(message.content) elif 'format' in message.extra and message.extra[ 'format'] == 'HTML': message.content = self.convert_links(message.content) try: if 'format' in message.extra and message.extra[ 'format'] == 'HTML': self.sender.raw('[html] msg %s %s' % (self.peer(message.conversation.id), self.escape(message.content)), enable_preview=False) else: self.sender.send_msg(self.peer(message.conversation.id), message.content, enable_preview=False) except Exception as e: logging.exception(e) elif message.type == 'photo': self.sender.send_typing(self.peer(message.conversation.id), 1) # 7 try: if message.reply: self.sender.reply_photo(message.reply, message.content, message.extra['caption']) else: self.sender.send_photo(self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'audio': self.sender.send_typing(self.peer(message.conversation.id), 1) # 6 try: if message.reply: self.sender.reply_audio(message.reply, message.content) else: self.sender.send_audio(self.peer(message.conversation.id), message.content) except Exception as e: logging.exception(e) elif message.type == 'document': self.sender.send_typing(self.peer(message.conversation.id), 1) # 8 try: if message.reply: self.sender.reply_document(message.reply, message.content, message.extra['caption']) else: self.sender.send_document( self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'sticker': if message.reply: self.sender.reply_file(message.reply, message.content) else: self.sender.send_file(self.peer(message.conversation.id), message.content) elif message.type == 'video': self.sender.send_typing(self.peer(message.conversation.id), 1) # 4 try: if message.reply: self.sender.reply_video(message.reply, message.content, message.extra['caption']) else: self.sender.send_video(self.peer(message.conversation.id), message.content, message.extra['caption']) except Exception as e: logging.exception(e) elif message.type == 'voice': self.sender.send_typing(self.peer(message.conversation.id), 5) try: if message.reply: self.sender.reply_audio(message.reply, message.content) else: self.sender.send_audio(self.peer(message.conversation.id), message.content) except Exception as e: logging.exception(e) elif message.type == 'location': self.sender.send_typing(self.peer(message.conversation.id), 1) # 9 if message.reply: self.sender.reply_location(message.reply, message.content['latitude'], message.content['longitude']) else: self.sender.send_location(self.peer(message.conversation.id), message.content['latitude'], message.content['longitude']) else: print('UNKNOWN MESSAGE TYPE: ' + message.type) logging.debug("UNKNOWN MESSAGE TYPE") @coroutine def main_loop(self): while self.bot.started: msg = (yield) if (msg.event == 'message' and msg.own == False) or msg.event == 'service': message = self.convert_message(msg) self.bot.inbox.put(message) try: if message.conversation.id > 0: self.sender.mark_read(self.peer(message.sender.id)) else: self.sender.mark_read( self.peer(message.conversation.id)) except Exception as e: logging.error(e) def peer(self, chat_id): if chat_id > 0: peer = 'user#id' + str(chat_id) else: if str(chat_id)[1:].startswith('100'): peer = 'channel#id' + str(chat_id)[4:] else: peer = 'chat#id' + str(chat_id)[1:] return peer def user_id(self, username): if username.startswith('@'): command = 'resolve_username ' + username[1:] resolve = self.sender.raw(command) dict = DictObject(json.loads(resolve)) else: dict = self.sender.user_info(username) if 'peer_id' in dict: return dict.peer_id else: return False def get_id(self, user): if isinstance(user, int): return user if user.isdigit(): id = int(user) else: id = int(self.user_id(user)) return id def escape(self, string): if string is None: return None CHARS_UNESCAPED = ["\\", "\n", "\r", "\t", "\b", "\a", "'"] CHARS_ESCAPED = ["\\\\", "\\n", "\\r", "\\t", "\\b", "\\a", "\\'"] for i in range(0, 7): string = string.replace(CHARS_UNESCAPED[i], CHARS_ESCAPED[i]) return string.join(["'", "'"]) # wrap with single quotes. def convert_links(self, string): for link in BeautifulSoup(string, 'lxml').findAll("a"): string = string.replace(str(link), link.get("href")) return string # THESE METHODS DO DIRECT ACTIONS # def get_file(self, file_id): pass def invite_conversation_member(self, conversation_id, user_id): self.sender.chat_add_user(self.peer(conversation_id), self.peer(user_id)) def kick_conversation_member(self, conversation_id, user_id): self.sender.chat_del_user(self.peer(conversation_id), self.peer(user_id)) def unban_conversation_member(self, conversation_id, user_id): pass def conversation_info(self, conversation_id): self.api_request('sendContact', params)
class PyTelegram(object): def __init__(self): tgcli_port = 4458 self.setlog() if not self.start(tgcli_port): sys.exit(1) self.receiver = Receiver(host="localhost", port=tgcli_port) self.sender = Sender(host="localhost", port=tgcli_port) def setlog(self): basepath = os.path.dirname(os.path.realpath(__file__)) logdir = os.path.join(basepath, "./log") if not os.path.exists(logdir): os.mkdir(logdir) self.logname = os.path.join(basepath, "./log/%s.log" % time.strftime("%Y%m%d%H")) LOG_FORMAT = '[%(asctime)s] : %(levelname)s %(filename)s - %(funcName)s(%(lineno)d) - %(message)s' logging.basicConfig( format=LOG_FORMAT, level=0, handlers=[logging.FileHandler(self.logname, 'a', 'utf-8')]) def need_proxy(self): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 1)) selfip = s.getsockname()[0] except Exception as e: logging.error(e) return False if selfip.startswith("192.168.") or selfip.startswith("10.")\ or selfip.startswith("172.1") or selfip.startswith("10.64."): logging.debug("need proxy") return True else: logging.debug("no need proxy") return False def start(self, tgcli_port): try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) check = s.connect_ex(('127.0.0.1', tgcli_port)) s.close() except Exception as e: logging.error(e) check = 1 if check == 0: return True if self.need_proxy(): cmd = """nohup proxychains telegram-cli --json --tcp-port %d >> %s 2>&1 &"""\ % (tgcli_port, self.logname) else: cmd = """nohup telegram-cli --json --tcp-port %d >> %s 2>&1 &"""\ % (tgcli_port, self.logname) logging.debug(cmd) ret = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) ret.wait() logging.debug("ret wait") reterr = ret.stderr.read() logging.debug("ret err") retout = ret.stdout.read() logging.debug("ret out") if reterr: logging.error(reterr.decode("utf8")) return False logging.info(retout) return True def parse_recive(self, msg_dict): logging.debug(msg_dict) def receive_loop(self): @coroutine def receive_coroutine_loop(): while 1: msg = (yield) self.parse_recive(msg) self.receiver.start() self.receiver.message(receive_coroutine_loop()) def get_channel_list(self, limit=0, offset=0): if limit == 0 and offset == 0: channels = self.sender.channel_list() else: channels = self.sender.channel_list(limit, offset) return channels def get_dialog_list(self, limit=0, offset=0): if limit == 0 and offset == 0: dialogs = self.sender.dialog_list() else: dialogs = self.sender.dialog_list(limit, offset) return dialogs def channel_get_members(self, name): members = self.sender.channel_get_members(name) return members def chat_get_members(self, name): chat_info_dict = self.sender.chat_info(name) meminfo_list = chat_info_dict["members"] return meminfo_list def get_history(self, peer, limit=0, offset=0): if limit == 0: ret = self.sender.history(peer, retry_connect=10, result_timeout=100) elif offset == 0: ret = self.sender.history(peer, limit, retry_connect=10) else: ret = self.sender.history(peer, limit, offset, retry_connect=10) #logging.debug(ret) ret.reverse() history_dict = collections.OrderedDict() for chat_info in ret: try: if chat_info["event"] != "message": continue chatid = chat_info["id"] history_dict[chatid] = chat_info logging.debug(chat_info) except Exception as e: logging.error(e) return history_dict def create_group(self, groupname, userlist): try: ret = self.sender.create_group_chat(groupname, userlist[0]) logging.debug(ret) except Exception as e: logging.error(e) return False if len(userlist) == 1: return True for username in userlist[1:]: try: ret = self.sender.chat_add_user(groupname, username, 0) logging.debug(ret) except Exception as e: logging.error(e) return True