Merge branch 'master' into logging
This commit is contained in:
131
fbchat/client.py
131
fbchat/client.py
@@ -41,6 +41,9 @@ StickyURL ="https://0-edge-chat.facebook.com/pull"
|
|||||||
PingURL ="https://0-channel-proxy-06-ash2.facebook.com/active_ping"
|
PingURL ="https://0-channel-proxy-06-ash2.facebook.com/active_ping"
|
||||||
UploadURL ="https://upload.facebook.com/ajax/mercury/upload.php"
|
UploadURL ="https://upload.facebook.com/ajax/mercury/upload.php"
|
||||||
UserInfoURL ="https://www.facebook.com/chat/user_info/"
|
UserInfoURL ="https://www.facebook.com/chat/user_info/"
|
||||||
|
ConnectURL ="https://www.facebook.com/ajax/add_friend/action.php?dpr=1"
|
||||||
|
RemoveUserURL="https://www.facebook.com/chat/remove_participants/"
|
||||||
|
LogoutURL ="https://www.facebook.com/logout.php"
|
||||||
|
|
||||||
# Log settings
|
# Log settings
|
||||||
log = logging.getLogger("client")
|
log = logging.getLogger("client")
|
||||||
@@ -193,6 +196,7 @@ class Client(object):
|
|||||||
r = self._get(BaseURL)
|
r = self._get(BaseURL)
|
||||||
soup = bs(r.text, "lxml")
|
soup = bs(r.text, "lxml")
|
||||||
self.fb_dtsg = soup.find("input", {'name':'fb_dtsg'})['value']
|
self.fb_dtsg = soup.find("input", {'name':'fb_dtsg'})['value']
|
||||||
|
self.fb_h = soup.find("input", {'name':'h'})['value']
|
||||||
self._setttstamp()
|
self._setttstamp()
|
||||||
# Set default payload
|
# Set default payload
|
||||||
self.payloadDefault['__rev'] = int(r.text.split('"revision":',1)[1].split(",",1)[0])
|
self.payloadDefault['__rev'] = int(r.text.split('"revision":',1)[1].split(",",1)[0])
|
||||||
@@ -221,6 +225,19 @@ class Client(object):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def logout(self, timeout=30):
|
||||||
|
data = {}
|
||||||
|
data['ref'] = "mb"
|
||||||
|
data['h'] = self.fb_h
|
||||||
|
payload=self._generatePayload(data)
|
||||||
|
r = self._session.get(LogoutURL, headers=self._header, params=payload, timeout=timeout)
|
||||||
|
# reset value
|
||||||
|
self.payloadDefault={}
|
||||||
|
self._session = requests.session()
|
||||||
|
self.req_counter = 1
|
||||||
|
self.seq = "0"
|
||||||
|
return r
|
||||||
|
|
||||||
def listen(self):
|
def listen(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -298,7 +315,8 @@ class Client(object):
|
|||||||
'manual_retry_cnt' : '0',
|
'manual_retry_cnt' : '0',
|
||||||
'signatureID' : getSignatureID(),
|
'signatureID' : getSignatureID(),
|
||||||
'has_attachment' : image_id != None,
|
'has_attachment' : image_id != None,
|
||||||
'other_user_fbid' : recipient_id,
|
'other_user_fbid' : user_id,
|
||||||
|
'thread_fbid': thread_id,
|
||||||
'specific_to_list[0]' : 'fbid:' + str(recipient_id),
|
'specific_to_list[0]' : 'fbid:' + str(recipient_id),
|
||||||
'specific_to_list[1]' : 'fbid:' + str(self.uid),
|
'specific_to_list[1]' : 'fbid:' + str(self.uid),
|
||||||
|
|
||||||
@@ -356,24 +374,32 @@ class Client(object):
|
|||||||
:param image: a tuple of (file name, data, mime type) to upload to facebook
|
:param image: a tuple of (file name, data, mime type) to upload to facebook
|
||||||
"""
|
"""
|
||||||
r = self._postFile(UploadURL, image)
|
r = self._postFile(UploadURL, image)
|
||||||
|
if isinstance(r._content, str) is False:
|
||||||
|
r._content = r._content.decode("utf-8")
|
||||||
# Strip the start and parse out the returned image_id
|
# Strip the start and parse out the returned image_id
|
||||||
return json.loads(r._content[9:])['payload']['metadata'][0]['image_id']
|
return json.loads(r._content[9:])['payload']['metadata'][0]['image_id']
|
||||||
|
|
||||||
def getThreadInfo(self, userID, start, end=None):
|
def getThreadInfo(self, userID, start, end=None, thread_type='user'):
|
||||||
"""Get the info of one Thread
|
"""Get the info of one Thread
|
||||||
|
|
||||||
:param userID: ID of the user you want the messages from
|
:param userID: ID of the user you want the messages from
|
||||||
:param start: the start index of a thread
|
:param start: the start index of a thread
|
||||||
:param end: (optional) the last index of a thread
|
:param end: (optional) the last index of a thread
|
||||||
|
:param thread_type: (optional) change from 'user' for group threads
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not end: end = start + 20
|
if not end: end = start + 20
|
||||||
if end <= start: end = start + end
|
if end <= start: end = start + end
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
data['messages[user_ids][%s][offset]'%userID] = start
|
if thread_type == 'user':
|
||||||
data['messages[user_ids][%s][limit]'%userID] = end
|
key = 'user_ids'
|
||||||
data['messages[user_ids][%s][timestamp]'%userID] = now()
|
else:
|
||||||
|
key = 'thread_fbids'
|
||||||
|
|
||||||
|
data['messages[{}][{}][offset]'.format(key, userID)] = start
|
||||||
|
data['messages[{}][{}][limit]'.format(key, userID)] = end
|
||||||
|
data['messages[{}][{}][timestamp]'.format(key, userID)] = now()
|
||||||
|
|
||||||
r = self._post(MessagesURL, query=data)
|
r = self._post(MessagesURL, query=data)
|
||||||
if not r.ok or len(r.text) == 0:
|
if not r.ok or len(r.text) == 0:
|
||||||
@@ -474,6 +500,19 @@ class Client(object):
|
|||||||
r = self._post(MarkSeenURL, {"seen_timestamp": 0})
|
r = self._post(MarkSeenURL, {"seen_timestamp": 0})
|
||||||
return r.ok
|
return r.ok
|
||||||
|
|
||||||
|
def friend_connect(self, friend_id):
|
||||||
|
data = {
|
||||||
|
"to_friend": friend_id,
|
||||||
|
"action": "confirm"
|
||||||
|
}
|
||||||
|
|
||||||
|
r = self._post(ConnectURL, data)
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
print(r)
|
||||||
|
print(data)
|
||||||
|
return r.ok
|
||||||
|
|
||||||
|
|
||||||
def ping(self, sticky):
|
def ping(self, sticky):
|
||||||
data = {
|
data = {
|
||||||
@@ -495,7 +534,11 @@ class Client(object):
|
|||||||
newer api needs these parameter to work.
|
newer api needs these parameter to work.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
data = {"msgs_recv": 0}
|
data = {
|
||||||
|
"msgs_recv": 0,
|
||||||
|
"channel": self.user_channel,
|
||||||
|
"clientid": self.client_id
|
||||||
|
}
|
||||||
|
|
||||||
r = self._get(StickyURL, data)
|
r = self._get(StickyURL, data)
|
||||||
j = get_json(r.text)
|
j = get_json(r.text)
|
||||||
@@ -566,6 +609,9 @@ class Client(object):
|
|||||||
fbid = m['delta']['messageMetadata']['actorFbId']
|
fbid = m['delta']['messageMetadata']['actorFbId']
|
||||||
name = None
|
name = None
|
||||||
self.on_message(mid, fbid, name, message, m)
|
self.on_message(mid, fbid, name, message, m)
|
||||||
|
elif m['type'] in ['jewel_requests_add']:
|
||||||
|
from_id = m['from']
|
||||||
|
self.on_friend_request(from_id)
|
||||||
else:
|
else:
|
||||||
log.debug("Unknwon type {}".format(m))
|
log.debug("Unknwon type {}".format(m))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -606,6 +652,70 @@ class Client(object):
|
|||||||
return full_data
|
return full_data
|
||||||
|
|
||||||
|
|
||||||
|
def remove_user_from_chat(self, threadID, userID):
|
||||||
|
"""Remove user (userID) from group chat (threadID)
|
||||||
|
|
||||||
|
:param threadID: group chat id
|
||||||
|
:param userID: user id to remove from chat
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"uid" : userID,
|
||||||
|
"tid" : threadID
|
||||||
|
}
|
||||||
|
|
||||||
|
r = self._post(RemoveUserURL, data)
|
||||||
|
|
||||||
|
self._console(r)
|
||||||
|
self._console(data)
|
||||||
|
|
||||||
|
return r.ok
|
||||||
|
|
||||||
|
|
||||||
|
def changeThreadTitle(self, threadID, newTitle):
|
||||||
|
"""Change title of a group conversation
|
||||||
|
|
||||||
|
:param threadID: group chat id
|
||||||
|
:param newTitle: new group chat title
|
||||||
|
"""
|
||||||
|
|
||||||
|
messageAndOTID = generateOfflineThreadingID()
|
||||||
|
timestamp = now()
|
||||||
|
date = datetime.now()
|
||||||
|
data = {
|
||||||
|
'client' : self.client,
|
||||||
|
'action_type' : 'ma-type:log-message',
|
||||||
|
'author' : 'fbid:' + str(self.uid),
|
||||||
|
'thread_id' : '',
|
||||||
|
'author_email' : '',
|
||||||
|
'coordinates' : '',
|
||||||
|
'timestamp' : timestamp,
|
||||||
|
'timestamp_absolute' : 'Today',
|
||||||
|
'timestamp_relative' : str(date.hour) + ":" + str(date.minute).zfill(2),
|
||||||
|
'timestamp_time_passed' : '0',
|
||||||
|
'is_unread' : False,
|
||||||
|
'is_cleared' : False,
|
||||||
|
'is_forward' : False,
|
||||||
|
'is_filtered_content' : False,
|
||||||
|
'is_spoof_warning' : False,
|
||||||
|
'source' : 'source:chat:web',
|
||||||
|
'source_tags[0]' : 'source:chat',
|
||||||
|
'status' : '0',
|
||||||
|
'offline_threading_id' : messageAndOTID,
|
||||||
|
'message_id' : messageAndOTID,
|
||||||
|
'threading_id': generateMessageID(self.client_id),
|
||||||
|
'manual_retry_cnt' : '0',
|
||||||
|
'thread_fbid' : threadID,
|
||||||
|
'log_message_data[name]' : newTitle,
|
||||||
|
'log_message_type' : 'log:thread-name'
|
||||||
|
}
|
||||||
|
|
||||||
|
r = self._post(SendURL, data)
|
||||||
|
|
||||||
|
self._console(r)
|
||||||
|
self._console(data)
|
||||||
|
|
||||||
|
return r.ok
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -618,6 +728,13 @@ class Client(object):
|
|||||||
log.info("%s said: %s"%(author_name, message))
|
log.info("%s said: %s"%(author_name, message))
|
||||||
|
|
||||||
|
|
||||||
|
def on_friend_request(self, from_id):
|
||||||
|
'''
|
||||||
|
subclass Client and override this method to add custom behavior on event
|
||||||
|
'''
|
||||||
|
print("friend request from %s"%from_id)
|
||||||
|
|
||||||
|
|
||||||
def on_typing(self, author_id):
|
def on_typing(self, author_id):
|
||||||
'''
|
'''
|
||||||
subclass Client and override this method to add custom behavior on event
|
subclass Client and override this method to add custom behavior on event
|
||||||
|
Reference in New Issue
Block a user