From a6a05203a4f12818bdd5c7a48ddb46416682b199 Mon Sep 17 00:00:00 2001 From: PidgeyL Date: Mon, 28 Dec 2015 19:38:22 +0100 Subject: [PATCH 1/5] Add listening --- fbchat/client.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/fbchat/client.py b/fbchat/client.py index 0e93548..7888863 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -32,6 +32,8 @@ DeliveredURL ="https://www.facebook.com/ajax/mercury/delivery_receipts.php" MarkSeenURL ="https://www.facebook.com/ajax/mercury/mark_seen.php" BaseURL ="https://www.facebook.com" MobileURL ="https://m.facebook.com/" +StickyURL ="https://0-edge-chat.facebook.com/pull" +PingURL ="https://0-channel-proxy-06-ash2.facebook.com/active_ping" class Client(object): """A client for the Facebook Chat (Messenger). @@ -346,3 +348,97 @@ class Client(object): r = self._post(MarkSeenURL, {"seen_timestamp": 0}) return r.ok + + def ping(self, sticky): + data={ + 'channel': self.user_channel, + 'clientid': self.client_id, + 'partition': -2, + 'cap': 0, + 'uid': self.uid, + 'sticky': sticky, + 'viewer_uid': self.uid + } + r = self._get(PingURL, data) + return r.ok + + + def _getSticky(self): + ''' + Call pull api to get sticky and pool parameter, + newer api needs these parameter to work. + ''' + data={ "msgs_recv": 0 } + + r = self._get(StickyURL, data) + j = get_json(r.text) + + if 'lb_info' not in j: + raise Exception('Get sticky pool error') + + sticky = j['lb_info']['sticky'] + pool = j['lb_info']['pool'] + return sticky, pool + + + def _pullMessage(self, sticky, pool): + ''' + Call pull api with seq value to get message data. + ''' + data={ + "msgs_recv": 0, + "sticky_token":sticky, + "sticky_pool":pool + } + + r = self._get(StickyURL, data) + j = get_json(r.text) + + self.seq = j.get('seq', '0') + return j + + + def _getMessage(self, content): + ''' + Get message and author name from content. + May contains multiple messages in the content. + ''' + if 'ms' not in content: + return + + for m in content['ms']: + if m.get('type') not in ['m_messaging', 'messaging']: + continue + # look in 'message' + try: + mid = m['message']['mid'] + message=m['message']['body'] + fbid = m['message']['sender_fbid'] + name = m['message']['sender_name'] + yield mid, fbid, name, message, m + except: + pass + + + def listen(self, markAlive=True): + self.listening = True + sticky, pool = self._getSticky() + + if self.debug: + print("Listening...") + + while self.listening: + try: + if markAlive: self.ping(sticky) + try: + content = self._pullMessage(sticky, pool) + except requests.exceptions.RequestException as e: + continue + # iterate through each message in response + for mid, fbid, name, message, meta in self._getMessage(content): + self.on_message(mid, fbid, name, message, meta) + except KeyboardInterrupt: + break + + def on_message(self, mid, author_id, author_name, message, metadata): + print("%s said: %s"%(author_name, message)) From 113c8fb8bc4134e6cd94b423f118b71d713f58ad Mon Sep 17 00:00:00 2001 From: PidgeyL Date: Tue, 29 Dec 2015 16:09:41 +0100 Subject: [PATCH 2/5] automatically mark messages as delivered and read --- fbchat/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fbchat/client.py b/fbchat/client.py index 7888863..c4e1ad5 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -405,7 +405,6 @@ class Client(object): ''' if 'ms' not in content: return - for m in content['ms']: if m.get('type') not in ['m_messaging', 'messaging']: continue @@ -441,4 +440,6 @@ class Client(object): break def on_message(self, mid, author_id, author_name, message, metadata): + self.markAsDelivered(fbid, mid) + self.markAsRead(fbid) print("%s said: %s"%(author_name, message)) From 1c0d7cf3e4d96ed884d6d2704d767b4d905289cc Mon Sep 17 00:00:00 2001 From: PidgeyL Date: Thu, 31 Dec 2015 17:09:41 +0100 Subject: [PATCH 3/5] sanatization, on_typing and on_read --- fbchat/client.py | 58 +++++++++++++++++++++++++++++++++--------------- fbchat/utils.py | 2 +- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index c4e1ad5..aae0bd7 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -201,6 +201,9 @@ class Client(object): :param message: a text that you want to send :param like: size of the like sticker you want to send """ + # sanatize data: + if message: + message=message.encode("unicode-escape").decode("utf-8") timestamp = now() date = datetime.now() data = { @@ -398,7 +401,7 @@ class Client(object): return j - def _getMessage(self, content): + def _parseMessage(self, content): ''' Get message and author name from content. May contains multiple messages in the content. @@ -406,18 +409,31 @@ class Client(object): if 'ms' not in content: return for m in content['ms']: - if m.get('type') not in ['m_messaging', 'messaging']: - continue - # look in 'message' - try: - mid = m['message']['mid'] - message=m['message']['body'] - fbid = m['message']['sender_fbid'] - name = m['message']['sender_name'] - yield mid, fbid, name, message, m - except: - pass - + if m['type'] in ['m_messaging', 'messaging']: + try: + mid = m['message']['mid'] + message=m['message']['body'] + fbid = m['message']['sender_fbid'] + name = m['message']['sender_name'] + self.on_message(mid, fbid, name, message, m) + except: + pass + elif m['type'] in ['typ']: + try: + fbid = m["from"] + self.on_typing(fbid) + except: + pass + elif m['type'] in ['m_read_receipt']: + try: + author = m['author'] + reader = m['reader'] + time = m['time'] + self.on_read(author, reader, time) + except: + pass + else: + print(m) def listen(self, markAlive=True): self.listening = True @@ -431,15 +447,21 @@ class Client(object): if markAlive: self.ping(sticky) try: content = self._pullMessage(sticky, pool) + self._parseMessage(content) except requests.exceptions.RequestException as e: continue - # iterate through each message in response - for mid, fbid, name, message, meta in self._getMessage(content): - self.on_message(mid, fbid, name, message, meta) except KeyboardInterrupt: break + except requests.exceptions.Timeout: + pass def on_message(self, mid, author_id, author_name, message, metadata): - self.markAsDelivered(fbid, mid) - self.markAsRead(fbid) + self.markAsDelivered(author_id, mid) + self.markAsRead(author_id) print("%s said: %s"%(author_name, message)) + + def on_typing(self, author_id): + pass + + def on_read(self, author, reader, time): + pass diff --git a/fbchat/utils.py b/fbchat/utils.py index 10f8c48..1a3285a 100644 --- a/fbchat/utils.py +++ b/fbchat/utils.py @@ -15,7 +15,7 @@ def now(): return int(time()*1000) def get_json(text): - return json.loads(re.sub(r"for.*(.*;.*;.*).*;", '', text.encode('utf-8').decode("unicode-escape"), 1)) + return json.loads(re.sub(r"for.*(.*;.*;.*).*;", '', text.encode('utf-8').decode("unicode-escape"), 1)) def digit_to_char(digit): if digit < 10: From f0daab74f64f1ff3060edcb72096d4f9458ef6cb Mon Sep 17 00:00:00 2001 From: PidgeyL Date: Mon, 4 Jan 2016 09:04:12 +0100 Subject: [PATCH 4/5] undo re-encoding --- fbchat/client.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index aae0bd7..0ea4062 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -201,9 +201,7 @@ class Client(object): :param message: a text that you want to send :param like: size of the like sticker you want to send """ - # sanatize data: - if message: - message=message.encode("unicode-escape").decode("utf-8") + timestamp = now() date = datetime.now() data = { From 47ded77b13d0e0c5db1b952b8960c3e67503429d Mon Sep 17 00:00:00 2001 From: PidgeyL Date: Mon, 4 Jan 2016 09:06:28 +0100 Subject: [PATCH 5/5] update version --- fbchat/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fbchat/__init__.py b/fbchat/__init__.py index 7256c1e..c597015 100644 --- a/fbchat/__init__.py +++ b/fbchat/__init__.py @@ -15,9 +15,9 @@ from .client import * __copyright__ = 'Copyright 2015 by Taehoon Kim' -__version__ = '0.2.3' +__version__ = '0.3.0' __license__ = 'BSD' -__author__ = 'Taehoon Kim' +__author__ = 'Taehoon Kim; Moreels Pieter-Jan' __email__ = 'carpedm20@gmail.com' __source__ = 'https://github.com/carpedm20/fbchat/'