Sync to maraid/fbchat
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -125,20 +125,12 @@ class Message:
|
|||||||
def react(self, reaction: Optional[str]):
|
def react(self, reaction: Optional[str]):
|
||||||
"""React to the message, or removes reaction.
|
"""React to the message, or removes reaction.
|
||||||
|
|
||||||
Currently, you can use "❤", "😍", "😆", "😮", "😢", "😠", "👍" or "👎". It
|
|
||||||
should be possible to add support for more, but we haven't figured that out yet.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
reaction: Reaction emoji to use, or if ``None``, removes reaction.
|
reaction: Reaction emoji to use, or if ``None``, removes reaction.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> message.react("😍")
|
>>> message.react("😍")
|
||||||
"""
|
"""
|
||||||
if reaction and reaction not in SENDABLE_REACTIONS:
|
|
||||||
raise ValueError(
|
|
||||||
"Invalid reaction! Please use one of: {}".format(SENDABLE_REACTIONS)
|
|
||||||
)
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"action": "ADD_REACTION" if reaction else "REMOVE_REACTION",
|
"action": "ADD_REACTION" if reaction else "REMOVE_REACTION",
|
||||||
"client_mutation_id": "1",
|
"client_mutation_id": "1",
|
||||||
|
@@ -16,8 +16,10 @@ from typing import Optional, Mapping, Callable, Any
|
|||||||
|
|
||||||
|
|
||||||
SERVER_JS_DEFINE_REGEX = re.compile(
|
SERVER_JS_DEFINE_REGEX = re.compile(
|
||||||
r'(?:"ServerJS".{,100}\.handle\({.*"define":)|(?:require\("ServerJSDefine"\)\)?\.handleDefines\()'
|
r'(?:"ServerJS".{,100}\.handle\({.*"define":)'
|
||||||
)
|
r'|(?:ServerJS.{,100}\.handleWithCustomApplyEach\(ScheduledApplyEach,{.*"define":)'
|
||||||
|
r'|(?:require\("ServerJSDefine"\)\)?\.handleDefines\()'
|
||||||
|
r'|(?:"require":\[\["ScheduledServerJS".{,100}"define":)')
|
||||||
SERVER_JS_DEFINE_JSON_DECODER = json.JSONDecoder()
|
SERVER_JS_DEFINE_JSON_DECODER = json.JSONDecoder()
|
||||||
|
|
||||||
|
|
||||||
@@ -36,8 +38,6 @@ def parse_server_js_define(html: str) -> Mapping[str, Any]:
|
|||||||
raise _exception.ParseError("Could not find any ServerJSDefine", data=html)
|
raise _exception.ParseError("Could not find any ServerJSDefine", data=html)
|
||||||
if len(define_splits) < 2:
|
if len(define_splits) < 2:
|
||||||
raise _exception.ParseError("Could not find enough ServerJSDefine", data=html)
|
raise _exception.ParseError("Could not find enough ServerJSDefine", data=html)
|
||||||
if len(define_splits) > 2:
|
|
||||||
raise _exception.ParseError("Found too many ServerJSDefine", data=define_splits)
|
|
||||||
# Parse entries (should be two)
|
# Parse entries (should be two)
|
||||||
for entry in define_splits:
|
for entry in define_splits:
|
||||||
try:
|
try:
|
||||||
@@ -311,6 +311,21 @@ class Session:
|
|||||||
data=data,
|
data=data,
|
||||||
allow_redirects=False,
|
allow_redirects=False,
|
||||||
cookies=login_cookies(_util.now()),
|
cookies=login_cookies(_util.now()),
|
||||||
|
headers={
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36",
|
||||||
|
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||||
|
"accept-language": "en-HU,en;q=0.9,hu-HU;q=0.8,hu;q=0.7,en-US;q=0.6",
|
||||||
|
"cache-control": "max-age=0",
|
||||||
|
"origin": "https://www.messenger.com",
|
||||||
|
"referer": "https://www.messenger.com/login/",
|
||||||
|
"sec-ch-ua": '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
|
||||||
|
"sec-ch-ua-mobile": "?0",
|
||||||
|
"sec-fetch-dest": "document",
|
||||||
|
"sec-fetch-mode": "navigate",
|
||||||
|
"sec-fetch-site": "same-origin",
|
||||||
|
"sec-fetch-user": "?1",
|
||||||
|
"upgrade-insecure-requests": "1"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
_exception.handle_requests_error(e)
|
_exception.handle_requests_error(e)
|
||||||
@@ -411,7 +426,7 @@ class Session:
|
|||||||
|
|
||||||
# Make a request to the main page to retrieve ServerJSDefine entries
|
# Make a request to the main page to retrieve ServerJSDefine entries
|
||||||
try:
|
try:
|
||||||
r = session.get(prefix_url("/"), allow_redirects=False)
|
r = session.get(prefix_url("/"), allow_redirects=True)
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
_exception.handle_requests_error(e)
|
_exception.handle_requests_error(e)
|
||||||
_exception.handle_http_error(r.status_code)
|
_exception.handle_http_error(r.status_code)
|
||||||
@@ -532,3 +547,10 @@ class Session:
|
|||||||
return message_ids[0]
|
return message_ids[0]
|
||||||
except (KeyError, IndexError, TypeError) as e:
|
except (KeyError, IndexError, TypeError) as e:
|
||||||
raise _exception.ParseError("No message IDs could be found", data=j) from e
|
raise _exception.ParseError("No message IDs could be found", data=j) from e
|
||||||
|
|
||||||
|
def _uri_share_data(self, data):
|
||||||
|
data["image_height"] = 960
|
||||||
|
data["image_width"] = 960
|
||||||
|
data["__user"] = self.user.id
|
||||||
|
j = self._post("/message_share_attachment/fromURI/", data)
|
||||||
|
return j["payload"]["share_data"]
|
||||||
|
@@ -105,6 +105,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
|||||||
mentions: Iterable["_models.Mention"] = None,
|
mentions: Iterable["_models.Mention"] = None,
|
||||||
files: Iterable[Tuple[str, str]] = None,
|
files: Iterable[Tuple[str, str]] = None,
|
||||||
reply_to_id: str = None,
|
reply_to_id: str = None,
|
||||||
|
uri: str = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Send a message to the thread.
|
"""Send a message to the thread.
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
|||||||
files: Optional tuples, each containing an uploaded file's ID and mimetype.
|
files: Optional tuples, each containing an uploaded file's ID and mimetype.
|
||||||
See `ThreadABC.send_files` for an example.
|
See `ThreadABC.send_files` for an example.
|
||||||
reply_to_id: Optional message to reply to
|
reply_to_id: Optional message to reply to
|
||||||
|
uri: Uri to formulate a sharable attachment with
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Send a message with a mention to a thread.
|
Send a message with a mention to a thread.
|
||||||
@@ -139,6 +141,9 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
|||||||
if files:
|
if files:
|
||||||
data["has_attachment"] = True
|
data["has_attachment"] = True
|
||||||
|
|
||||||
|
if uri:
|
||||||
|
data.update(self._generate_shareable_attachment(uri))
|
||||||
|
|
||||||
for i, (file_id, mimetype) in enumerate(files or ()):
|
for i, (file_id, mimetype) in enumerate(files or ()):
|
||||||
data["{}s[{}]".format(_util.mimetype_to_key(mimetype), i)] = file_id
|
data["{}s[{}]".format(_util.mimetype_to_key(mimetype), i)] = file_id
|
||||||
|
|
||||||
@@ -236,6 +241,52 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
|||||||
"""
|
"""
|
||||||
return self.send_text(text=None, files=files)
|
return self.send_text(text=None, files=files)
|
||||||
|
|
||||||
|
def send_uri(self, uri: str, **kwargs):
|
||||||
|
"""Send a uri preview to a thread.
|
||||||
|
Args:
|
||||||
|
uri: uri to preview
|
||||||
|
"""
|
||||||
|
if kwargs.get('text') is None:
|
||||||
|
kwargs['text'] = None
|
||||||
|
self.send_text(uri=uri, **kwargs)
|
||||||
|
|
||||||
|
def _generate_shareable_attachment(self, uri):
|
||||||
|
"""Send a uri preview to a thread.
|
||||||
|
Args:
|
||||||
|
uri: uri to preview
|
||||||
|
Returns:
|
||||||
|
:ref:`Message ID <intro_message_ids>` of the sent message
|
||||||
|
Raises:
|
||||||
|
FBchatException: If request failed
|
||||||
|
"""
|
||||||
|
url_data = self.session._uri_share_data({"uri": uri})
|
||||||
|
data = self._to_send_data()
|
||||||
|
data["action_type"] = "ma-type:user-generated-message"
|
||||||
|
data["shareable_attachment[share_type]"] = url_data["share_type"]
|
||||||
|
|
||||||
|
# Most uri params will come back as dict
|
||||||
|
if isinstance(url_data["share_params"], dict):
|
||||||
|
data["has_attachment"] = True
|
||||||
|
for key in url_data["share_params"]:
|
||||||
|
if isinstance(url_data["share_params"][key], dict):
|
||||||
|
for key2 in url_data["share_params"][key]:
|
||||||
|
data[
|
||||||
|
"shareable_attachment[share_params][{}][{}]".format(
|
||||||
|
key, key2
|
||||||
|
)
|
||||||
|
] = url_data["share_params"][key][key2]
|
||||||
|
else:
|
||||||
|
data[
|
||||||
|
"shareable_attachment[share_params][{}]".format(key)
|
||||||
|
] = url_data["share_params"][key]
|
||||||
|
|
||||||
|
# Some (such as facebook profile pages) will just be a list
|
||||||
|
else:
|
||||||
|
data["has_attachment"] = False
|
||||||
|
for index, val in enumerate(url_data["share_params"]):
|
||||||
|
data["shareable_attachment[share_params][{}]".format(index)] = val
|
||||||
|
return data
|
||||||
|
|
||||||
# xmd = {"quick_replies": []}
|
# xmd = {"quick_replies": []}
|
||||||
# for quick_reply in quick_replies:
|
# for quick_reply in quick_replies:
|
||||||
# # TODO: Move this to `_quick_reply.py`
|
# # TODO: Move this to `_quick_reply.py`
|
||||||
|
Reference in New Issue
Block a user