diff --git a/fbchat/client.py b/fbchat/client.py index 71f99d3..2f6b1da 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -754,19 +754,23 @@ class Client(object): return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']])) - def fetchThreadList(self, offset=0, limit=20, thread_location=ThreadLocation.INBOX): + def fetchThreadList(self, offset=0, limit=20, thread_location=ThreadLocation.INBOX, before=None): """Get thread list of your facebook account - :param offset: The offset, from where in the list to recieve threads from + :param offset: Deprecated. Do not use! :param limit: Max. number of threads to retrieve. Capped at 20 :param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER - :type offset: int + :param before: A timestamp (in milliseconds), indicating from which point to retrieve threads :type limit: int + :type before: int :return: :class:`models.Thread` objects :rtype: list :raises: FBchatException if request failed """ + if offset is not None: + log.warning('Using `offset` in `fetchThreadList` is no longer supported, since Facebook migrated to the use of GraphQL in this request. Use `before` instead') + if limit > 20 or limit < 1: raise FBchatUserError('`limit` should be between 1 and 20') @@ -775,52 +779,15 @@ class Client(object): else: raise FBchatUserError('"thread_location" must be a value of ThreadLocation') - data = { - 'client' : self.client, - loc_str + '[offset]' : offset, - loc_str + '[limit]' : limit, - } + j = self.graphql_request(GraphQL(doc_id='1349387578499440', params={ + 'limit': limit, + 'tags': [loc_str], + 'before': before, + 'includeDeliveryReceipts': True, + 'includeSeqID': False + })) - j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True) - if j.get('payload') is None: - raise FBchatException('Missing payload: {}, with data: {}'.format(j, data)) - - participants = {} - if 'participants' in j['payload']: - for p in j['payload']['participants']: - if p['type'] == 'page': - participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name']) - elif p['type'] == 'user': - participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS.get(p['gender']), photo=p['image_src'], name=p['name']) - else: - raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p)) - - entries = [] - if 'threads' in j['payload']: - for k in j['payload']['threads']: - if k['thread_type'] == 1: - if k['other_user_fbid'] not in participants: - raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload'])) - participants[k['other_user_fbid']].message_count = k['message_count'] - entries.append(participants[k['other_user_fbid']]) - elif k['thread_type'] == 2: - entries.append(Group(k['thread_fbid'], participants=set([p.strip('fbid:') for p in k['participants']]), photo=k['image_src'], name=k['name'], message_count=k['message_count'])) - elif k['thread_type'] == 3: - entries.append(Room( - k['thread_fbid'], - participants = set(p.lstrip('fbid:') for p in k['participants']), - photo = k['image_src'], - name = k['name'], - message_count = k['message_count'], - admins = set(p.lstrip('fbid:') for p in k['admin_ids']), - approval_mode = k['approval_mode'], - approval_requests = set(p.lstrip('fbid:') for p in k['approval_queue_ids']), - join_link = k['joinable_mode']['link'] - )) - else: - raise FBchatException('A thread had an unknown thread type: {}'.format(k)) - - return entries + return [graphql_to_thread(node) for node in j['viewer']['message_threads']['nodes']] def fetchUnread(self): """ diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 33c3e6b..f4ee001 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -172,6 +172,35 @@ def graphql_to_user(user): message_count=user.get('messages_count') ) +def graphql_to_thread(thread): + if thread['thread_type'] == 'GROUP': + return graphql_to_group(thread) + elif thread['thread_type'] == 'ONE_TO_ONE': + if thread.get('big_image_src') is None: + thread['big_image_src'] = {} + c_info = get_customization_info(thread) + participants = [node['messaging_actor'] for node in thread['all_participants']['nodes']] + user = next(p for p in participants if p['id'] == thread['thread_key']['other_user_id']) + + return User( + user['id'], + url=user.get('url'), + name=user.get('name'), + first_name=user.get('short_name'), + last_name=user.get('name').split(user.get('short_name'),1)[1].strip(), + is_friend=user.get('is_viewer_friend'), + gender=GENDERS.get(user.get('gender')), + affinity=user.get('affinity'), + nickname=c_info.get('nickname'), + color=c_info.get('color'), + emoji=c_info.get('emoji'), + own_nickname=c_info.get('own_nickname'), + photo=user['big_image_src'].get('uri'), + message_count=thread.get('messages_count') + ) + else: + raise FBchatException('Unknown thread type: {}, with data: {}'.format(thread.get('thread_type'), thread)) + def graphql_to_group(group): if group.get('image') is None: group['image'] = {} diff --git a/tests.py b/tests.py index 08a101b..033a259 100644 --- a/tests.py +++ b/tests.py @@ -123,7 +123,8 @@ class TestFbchat(unittest.TestCase): self.assertTrue(client.sendLocalImage(image_local_url, Message(text='test_send_image_local_to__@you★', mentions=mentions))) def test_fetchThreadList(self): - client.fetchThreadList(offset=0, limit=20) + threads = client.fetchThreadList(limit=2) + self.assertEqual(len(threads), 2) def test_fetchThreadMessages(self): for thread in threads: