Compare commits

..

14 Commits
v1.9.3 ... v1

Author SHA1 Message Date
JabLuszko
4ff7b7e70b Remove add_reaction for onReactionAdded in docs (#579)
Seems like it was leftover from some other function, probably one to handle both Added and Removed :)
2020-10-21 18:00:46 +02:00
Mads Marquart
0761116335 Bump version: 1.9.6 → 1.9.7 2020-06-08 22:20:43 +02:00
Mads Marquart
86d7220126 Merge pull request #586 from qwertyuu/fix-typeerror-v1
Fix AttributeError on login
2020-06-08 22:19:30 +02:00
Raphaël Côté
e175ec791c Update _state.py 2020-05-31 22:38:08 -04:00
Mads Marquart
e54be7583a Merge pull request #547 from Benjamin-Loison/patch-1
Update fetch.py
2020-04-06 12:53:58 +02:00
Benjamin Loison
fdf64597ec Update fetch.py
Variable name mismatched.
2020-04-06 12:46:34 +02:00
Mads Marquart
064707ac23 Add error handling for when the listener has been logged out 2020-01-24 21:19:58 +01:00
Mads Marquart
b9b4d57b25 Bump version: 1.9.5 → 1.9.6 2020-01-21 19:50:57 +01:00
Mads Marquart
b4618739f3 Fix MQTT errors after being offline for too long 2020-01-21 19:39:59 +01:00
Mads Marquart
22c6c82c0e Disable /t_rtc MQTT topic 2020-01-20 14:54:25 +01:00
Mads Marquart
19c875c18a Bump version: 1.9.4 → 1.9.5 2020-01-20 09:32:30 +01:00
Mateusz Soszyński
12bbc0058c Add onPendingMessage (#512) 2020-01-20 09:28:41 +01:00
Mads Marquart
9c81806b95 Bump version: 1.9.3 → 1.9.4 2020-01-14 23:29:58 +01:00
Mads Marquart
45303005b8 Fix onFriendRequest 2020-01-14 23:27:50 +01:00
6 changed files with 82 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 1.9.3 current_version = 1.9.7
commit = True commit = True
tag = True tag = True

View File

@@ -67,5 +67,5 @@ print("thread's type: {}".format(thread.type))
# Print image url for 20 last images from thread. # Print image url for 20 last images from thread.
images = client.fetchThreadImages("<thread id>") images = client.fetchThreadImages("<thread id>")
for image in islice(image, 20): for image in islice(images, 20):
print(image.large_preview_url) print(image.large_preview_url)

View File

@@ -13,7 +13,7 @@ from ._client import Client
from ._util import log # TODO: Remove this (from examples too) from ._util import log # TODO: Remove this (from examples too)
__title__ = "fbchat" __title__ = "fbchat"
__version__ = "1.9.3" __version__ = "1.9.7"
__description__ = "Facebook Chat (Messenger) for Python" __description__ = "Facebook Chat (Messenger) for Python"
__copyright__ = "Copyright 2015 - 2019 by Taehoon Kim" __copyright__ = "Copyright 2015 - 2019 by Taehoon Kim"

View File

@@ -2271,6 +2271,16 @@ class Client(object):
elif delta_class == "ForcedFetch": elif delta_class == "ForcedFetch":
mid = delta.get("messageId") mid = delta.get("messageId")
if mid is None: if mid is None:
if delta["threadKey"] is not None:
# Looks like the whole delta is metadata in this case
thread_id, thread_type = getThreadIdAndThreadType(delta)
self.onPendingMessage(
thread_id=thread_id,
thread_type=thread_type,
metadata=delta,
msg=delta,
)
else:
self.onUnknownMesssageType(msg=delta) self.onUnknownMesssageType(msg=delta)
else: else:
thread_id = str(delta["threadKey"]["threadFbId"]) thread_id = str(delta["threadKey"]["threadFbId"])
@@ -2727,6 +2737,14 @@ class Client(object):
msg=delta, msg=delta,
) )
# New pending message
elif delta_class == "ThreadFolder" and delta.get("folder") == "FOLDER_PENDING":
# Looks like the whole delta is metadata in this case
thread_id, thread_type = getThreadIdAndThreadType(delta)
self.onPendingMessage(
thread_id=thread_id, thread_type=thread_type, metadata=delta, msg=delta
)
# Unknown message type # Unknown message type
else: else:
self.onUnknownMesssageType(msg=delta) self.onUnknownMesssageType(msg=delta)
@@ -2768,9 +2786,15 @@ class Client(object):
msg=m, msg=m,
) )
elif topic == "jewel_requests_add": # Other notifications
elif topic == "/legacy_web":
# Friend request
if m["type"] == "jewel_requests_add":
from_id = m["from"] from_id = m["from"]
# TODO: from_id = str(from_id)
self.onFriendRequest(from_id=from_id, msg=m) self.onFriendRequest(from_id=from_id, msg=m)
else:
self.onUnknownMesssageType(msg=m)
# Chat timestamp / Buddylist overlay # Chat timestamp / Buddylist overlay
elif topic == "/orca_presence": elif topic == "/orca_presence":
@@ -2943,6 +2967,21 @@ class Client(object):
""" """
log.info("{} from {} in {}".format(message_object, thread_id, thread_type.name)) log.info("{} from {} in {}".format(message_object, thread_id, thread_type.name))
def onPendingMessage(
self, thread_id=None, thread_type=None, metadata=None, msg=None
):
"""Called when the client is listening, and somebody that isn't
connected with you on either Facebook or Messenger sends a message.
After that, you need to use fetchThreadList to actually read the message.
Args:
thread_id: Thread ID that the message was sent to. See :ref:`intro_threads`
thread_type (ThreadType): Type of thread that the message was sent to. See :ref:`intro_threads`
metadata: Extra metadata about the message
msg: A full set of the data received
"""
log.info("New pending message from {}".format(thread_id))
def onColorChange( def onColorChange(
self, self,
mid=None, mid=None,
@@ -3392,7 +3431,6 @@ class Client(object):
Args: Args:
mid: Message ID, that user reacted to mid: Message ID, that user reacted to
reaction (MessageReaction): Reaction reaction (MessageReaction): Reaction
add_reaction: Whether user added or removed reaction
author_id: The ID of the person who reacted to the message author_id: The ID of the person who reacted to the message
thread_id: Thread ID that the action was sent to. See :ref:`intro_threads` thread_id: Thread ID that the action was sent to. See :ref:`intro_threads`
thread_type (ThreadType): Type of thread that the action was sent to. See :ref:`intro_threads` thread_type (ThreadType): Type of thread that the action was sent to. See :ref:`intro_threads`

View File

@@ -79,6 +79,8 @@ class Mqtt(object):
log.exception("Failed parsing MQTT data on %s as JSON", message.topic) log.exception("Failed parsing MQTT data on %s as JSON", message.topic)
return return
log.debug("MQTT payload: %s, %s", message.topic, j)
if message.topic == "/t_ms": if message.topic == "/t_ms":
# Update sync_token when received # Update sync_token when received
# This is received in the first message after we've created a messenger # This is received in the first message after we've created a messenger
@@ -86,18 +88,31 @@ class Mqtt(object):
if "syncToken" in j and "firstDeltaSeqId" in j: if "syncToken" in j and "firstDeltaSeqId" in j:
self._sync_token = j["syncToken"] self._sync_token = j["syncToken"]
self._sequence_id = j["firstDeltaSeqId"] self._sequence_id = j["firstDeltaSeqId"]
return
# Update last sequence id when received # Update last sequence id when received
if "lastIssuedSeqId" in j: if "lastIssuedSeqId" in j:
self._sequence_id = j["lastIssuedSeqId"] self._sequence_id = j["lastIssuedSeqId"]
if "errorCode" in j: if "errorCode" in j:
# Known types: ERROR_QUEUE_OVERFLOW | ERROR_QUEUE_NOT_FOUND error = j["errorCode"]
# 'F\xfa\x84\x8c\x85\xf8\xbc-\x88 FB_PAGES_INSUFFICIENT_PERMISSION\x00' # TODO: 'F\xfa\x84\x8c\x85\xf8\xbc-\x88 FB_PAGES_INSUFFICIENT_PERMISSION\x00'
log.error("MQTT error code %s received", j["errorCode"]) if error in ("ERROR_QUEUE_NOT_FOUND", "ERROR_QUEUE_OVERFLOW"):
# TODO: Consider resetting the sync_token and sequence ID here? # ERROR_QUEUE_NOT_FOUND means that the queue was deleted, since too
# much time passed, or that it was simply missing
log.debug("MQTT payload: %s, %s", message.topic, j) # ERROR_QUEUE_OVERFLOW means that the sequence id was too small, so
# the desired events could not be retrieved
log.error(
"The MQTT listener was disconnected for too long,"
" events may have been lost"
)
self._sync_token = None
self._sequence_id = self._fetch_sequence_id(self._state)
self._messenger_queue_publish()
# TODO: Signal to the user that they should reload their data!
return
log.error("MQTT error code %s received", error)
return
# Call the external callback # Call the external callback
self._on_message(message.topic, j) self._on_message(message.topic, j)
@@ -115,11 +130,10 @@ class Mqtt(object):
log.debug("Fetching MQTT sequence ID") log.debug("Fetching MQTT sequence ID")
# Same request as in `Client.fetchThreadList` # Same request as in `Client.fetchThreadList`
(j,) = state._graphql_requests(_graphql.from_doc_id("1349387578499440", params)) (j,) = state._graphql_requests(_graphql.from_doc_id("1349387578499440", params))
try: sequence_id = j["viewer"]["message_threads"]["sync_sequence_id"]
return int(j["viewer"]["message_threads"]["sync_sequence_id"]) if not sequence_id:
except (KeyError, ValueError): raise _exception.FBchatNotLoggedIn("Failed fetching sequence id")
# TODO: Proper exceptions return int(sequence_id)
raise
def _on_connect_handler(self, client, userdata, flags, rc): def _on_connect_handler(self, client, userdata, flags, rc):
if rc == 21: if rc == 21:
@@ -129,6 +143,9 @@ class Mqtt(object):
if rc != 0: if rc != 0:
return # Don't try to send publish if the connection failed return # Don't try to send publish if the connection failed
self._messenger_queue_publish()
def _messenger_queue_publish(self):
# configure receiving messages. # configure receiving messages.
payload = { payload = {
"sync_api_version": 10, "sync_api_version": 10,
@@ -171,6 +188,10 @@ class Mqtt(object):
"/br_sr", "/br_sr",
# Response to /br_sr # Response to /br_sr
"/sr_res", "/sr_res",
# Data about user-to-user calls
# TODO: Investigate the response from this! (A bunch of binary data)
# "/t_rtc",
# TODO: Find out what this does!
# TODO: Investigate the response from this! (A bunch of binary data) # TODO: Investigate the response from this! (A bunch of binary data)
# "/t_p", # "/t_p",
# TODO: Find out what this does! # TODO: Find out what this does!
@@ -186,7 +207,6 @@ class Mqtt(object):
"/messaging_events", "/messaging_events",
"/orca_message_notifications", "/orca_message_notifications",
"/pp", "/pp",
"/t_rtc",
"/webrtc_response", "/webrtc_response",
] ]
@@ -266,6 +286,8 @@ class Mqtt(object):
# This error is wrongly classified # This error is wrongly classified
# See https://github.com/eclipse/paho.mqtt.python/issues/340 # See https://github.com/eclipse/paho.mqtt.python/issues/340
log.warning("Connection error, retrying") log.warning("Connection error, retrying")
elif rc == paho.mqtt.client.MQTT_ERR_CONN_REFUSED:
raise _exception.FBchatNotLoggedIn("MQTT connection refused")
else: else:
err = paho.mqtt.client.error_string(rc) err = paho.mqtt.client.error_string(rc)
log.error("MQTT Error: %s", err) log.error("MQTT Error: %s", err)

View File

@@ -27,6 +27,8 @@ def find_input_fields(html):
def session_factory(user_agent=None): def session_factory(user_agent=None):
session = requests.session() session = requests.session()
session.headers["Referer"] = "https://www.facebook.com" session.headers["Referer"] = "https://www.facebook.com"
session.headers["Accept"] = "text/html"
# TODO: Deprecate setting the user agent manually # TODO: Deprecate setting the user agent manually
session.headers["User-Agent"] = user_agent or random.choice(_util.USER_AGENTS) session.headers["User-Agent"] = user_agent or random.choice(_util.USER_AGENTS)
return session return session