From 58bf9e1ceeac74995b2a10f52f3101dcbe64f3b5 Mon Sep 17 00:00:00 2001 From: tcmal Date: Sat, 31 Mar 2018 19:48:03 +0100 Subject: [PATCH 1/5] Use a datetime object for Message.timestamp --- fbchat/graphql.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 323a0467..94a9de52 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -5,6 +5,7 @@ import re from .models import * from .utils import * +from datetime import datetime # Shameless copy from https://stackoverflow.com/a/8730674 FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL @@ -141,7 +142,11 @@ def graphql_to_message(message): ) rtn.uid = str(message.get('message_id')) rtn.author = str(message.get('message_sender').get('id')) - rtn.timestamp = message.get('timestamp_precise') + + # timestamp is a string of an int in milliseconds, so divide by 1000 and convert it + timestamp_raw = int(message.get('timestamp_precise')) + rtn.timestamp = datetime.fromtimestamp(timestamp_raw / 1000) + if message.get('unread') is not None: rtn.is_read = not message['unread'] rtn.reactions = {str(r['user']['id']):MessageReaction(r['reaction']) for r in message.get('message_reactions')} From 33c6c433652319ec7f7c8f3a89e07c4eb573701b Mon Sep 17 00:00:00 2001 From: tcmal Date: Sat, 31 Mar 2018 20:29:46 +0100 Subject: [PATCH 2/5] Use datetime for fetchThreadMessages(before) --- fbchat/client.py | 10 ++++++---- fbchat/graphql.py | 4 ++-- fbchat/utils.py | 7 +++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 46981550..c54b59f7 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -10,8 +10,8 @@ from .utils import * from .models import * from .graphql import * -import time - +from datetime import datetime +import calendar class Client(object): @@ -735,14 +735,16 @@ def fetchThreadMessages(self, thread_id=None, limit=20, before=None): :param limit: Max. number of messages to retrieve :param before: A timestamp, indicating from which point to retrieve messages :type limit: int - :type before: int + :type before: datetime :return: :class:`models.Message` objects :rtype: list :raises: FBchatException if request failed """ - thread_id, thread_type = self._getThread(thread_id, None) + if before is not None: + before = int(unix_time_millis(before)) + j = self.graphql_request(GraphQL(doc_id='1386147188135407', params={ 'id': thread_id, 'message_limit': limit, diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 94a9de52..596588f5 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -144,8 +144,8 @@ def graphql_to_message(message): rtn.author = str(message.get('message_sender').get('id')) # timestamp is a string of an int in milliseconds, so divide by 1000 and convert it - timestamp_raw = int(message.get('timestamp_precise')) - rtn.timestamp = datetime.fromtimestamp(timestamp_raw / 1000) + timestamp_raw = float(message.get('timestamp_precise')) / 1000 + rtn.timestamp = datetime.fromtimestamp(timestamp_raw) if message.get('unread') is not None: rtn.is_read = not message['unread'] diff --git a/fbchat/utils.py b/fbchat/utils.py index 87eef262..46252535 100644 --- a/fbchat/utils.py +++ b/fbchat/utils.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import re import json +from datetime import datetime from time import time from random import random import warnings @@ -29,6 +30,9 @@ handler = logging.StreamHandler() log.addHandler(handler) +# Unix epoch +epoch = datetime.utcfromtimestamp(0) + #: Default list of user agents USER_AGENTS = [ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", @@ -233,3 +237,6 @@ def get_emojisize_from_tags(tags): except (KeyError, IndexError): log.exception('Could not determine emoji size from {} - {}'.format(tags, tmp)) return None + +def unix_time_millis(dt): + return (dt - epoch).total_seconds() * 1000.0 From b6b77cae25924f109e4b2a43a80c30009c105240 Mon Sep 17 00:00:00 2001 From: tcmal Date: Sat, 31 Mar 2018 20:41:55 +0100 Subject: [PATCH 3/5] Move Converting millis to datetime to a helper function & make last_message_timestamp a datetime --- fbchat/graphql.py | 8 +++----- fbchat/utils.py | 5 +++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 596588f5..d6d5fe4c 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -143,9 +143,7 @@ def graphql_to_message(message): rtn.uid = str(message.get('message_id')) rtn.author = str(message.get('message_sender').get('id')) - # timestamp is a string of an int in milliseconds, so divide by 1000 and convert it - timestamp_raw = float(message.get('timestamp_precise')) / 1000 - rtn.timestamp = datetime.fromtimestamp(timestamp_raw) + rtn.timestamp = millis_to_datetime(message.get('timestamp_precise')) if message.get('unread') is not None: rtn.is_read = not message['unread'] @@ -188,7 +186,7 @@ def graphql_to_thread(thread): user = next(p for p in participants if p['id'] == thread['thread_key']['other_user_id']) last_message_timestamp = None if 'last_message' in thread: - last_message_timestamp = thread['last_message']['nodes'][0]['timestamp_precise'] + last_message_timestamp = millis_to_datetime(thread['last_message']['nodes'][0]['timestamp_precise']) return User( user['id'], @@ -216,7 +214,7 @@ def graphql_to_group(group): c_info = get_customization_info(group) last_message_timestamp = None if 'last_message' in group: - last_message_timestamp = group['last_message']['nodes'][0]['timestamp_precise'] + last_message_timestamp = millis_to_datetime(group['last_message']['nodes'][0]['timestamp_precise']) return Group( group['thread_key']['thread_fbid'], participants=set([node['messaging_actor']['id'] for node in group['all_participants']['nodes']]), diff --git a/fbchat/utils.py b/fbchat/utils.py index 46252535..d71c013b 100644 --- a/fbchat/utils.py +++ b/fbchat/utils.py @@ -240,3 +240,8 @@ def get_emojisize_from_tags(tags): def unix_time_millis(dt): return (dt - epoch).total_seconds() * 1000.0 + +def millis_to_datetime(t): + if isinstance(t, str): + t = float(t) + return datetime.fromtimestamp(t / 1000.0) From 31847f9e1f35e2f02a772412f63e8773debdb795 Mon Sep 17 00:00:00 2001 From: tcmal Date: Sat, 31 Mar 2018 20:46:50 +0100 Subject: [PATCH 4/5] fetchThreadList(before) is now a datetime --- fbchat/client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fbchat/client.py b/fbchat/client.py index c54b59f7..40b40ddf 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -766,7 +766,7 @@ def fetchThreadList(self, offset=None, limit=20, thread_location=ThreadLocation. :param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER :param before: A timestamp (in milliseconds), indicating from which point to retrieve threads :type limit: int - :type before: int + :type before: datetime :return: :class:`models.Thread` objects :rtype: list :raises: FBchatException if request failed @@ -783,6 +783,9 @@ def fetchThreadList(self, offset=None, limit=20, thread_location=ThreadLocation. else: raise FBchatUserError('"thread_location" must be a value of ThreadLocation') + if before is not None: + before = unix_time_millis(before) + j = self.graphql_request(GraphQL(doc_id='1349387578499440', params={ 'limit': limit, 'tags': [loc_str], From 53bf4652c5adb746d26b462fbaebac7db5f3a052 Mon Sep 17 00:00:00 2001 From: tcmal Date: Mon, 2 Apr 2018 14:24:17 +0100 Subject: [PATCH 5/5] Fix imports in client.py --- fbchat/client.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 40b40ddf..8e995148 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -10,9 +10,7 @@ from .utils import * from .models import * from .graphql import * -from datetime import datetime -import calendar - +import time class Client(object): """A client for the Facebook Chat (Messenger).