Merge pull request #56 from thekindlyone/master

Fixed #55 , send fail due to api change.
This commit is contained in:
Taehoon Kim
2016-09-22 22:32:58 +09:00
committed by GitHub
3 changed files with 131 additions and 35 deletions

View File

@@ -38,6 +38,22 @@ Sending a Message
sent = client.send(friend.uid, "Your Message")
if sent:
print("Message sent successfully!")
# IMAGES
client.sendLocalImage(friend.uid,message='<message text>',image='<path/to/image/file>') # send local image
imgurl = "http://i.imgur.com/LDQ2ITV.jpg"
client.sendRemoteImage(friend.uid,message='<message text>', image=imgurl) # send image from image url
Getting user info from user id
==============================
.. code-block:: python
friend1 = client.getUsers('<friend name 1>')[0]
friend2 = client.getUsers('<friend name 2>')[0]
friend1_info = client.getUserInfo(friend1.uid) # returns dict with details
both_info = client.getUserInfo(friend1.uid,friend2.uid) # query both together, returns list of dicts
friend1_name = friend1_info['name']
Getting last messages sent
@@ -52,6 +68,33 @@ Getting last messages sent
print(message.body)
Example Echobot
===============
.. code-block:: python
import fbchat
#subclass fbchat.Client and override required methods
class EchoBot(fbchat.Client):
def __init__(self,email, password, debug=True, user_agent=None):
fbchat.Client.__init__(self,email, password, debug, user_agent)
def on_message(self, mid, author_id, author_name, message, metadata):
self.markAsDelivered(author_id, mid) #mark delivered
self.markAsRead(author_id) #mark read
print("%s said: %s"%(author_id, message))
#if you are not the author, echo
if str(author_id) != str(self.uid):
self.send(author_id,message)
bot = EchoBot("<email>", "<password>")
bot.listen()
Authors
=======

View File

@@ -18,15 +18,14 @@ from random import random, choice
from datetime import datetime
from bs4 import BeautifulSoup as bs
from mimetypes import guess_type
from .utils import *
from .models import *
from .stickers import *
import time
# URLs
LoginURL ="https://m.facebook.com/login.php?login_attempt=1"
SearchURL ="https://www.facebook.com/ajax/typeahead/search.php"
SendURL ="https://www.facebook.com/ajax/mercury/send_messages.php"
SendURL ="https://www.facebook.com/messaging/send/"
ThreadsURL ="https://www.facebook.com/ajax/mercury/threadlist_info.php"
ThreadSyncURL="https://www.facebook.com/ajax/mercury/thread_sync.php"
MessagesURL ="https://www.facebook.com/ajax/mercury/thread_info.php"
@@ -38,7 +37,7 @@ MobileURL ="https://m.facebook.com/"
StickyURL ="https://0-edge-chat.facebook.com/pull"
PingURL ="https://0-channel-proxy-06-ash2.facebook.com/active_ping"
UploadURL ="https://upload.facebook.com/ajax/mercury/upload.php"
UserInfoURL ="https://www.facebook.com/chat/user_info/"
class Client(object):
"""A client for the Facebook Chat (Messenger).
@@ -48,7 +47,7 @@ class Client(object):
"""
def __init__(self, email, password, debug=True, user_agent=None):
def __init__(self, email, password, debug=True, user_agent=None , max_retries=5):
"""A client for the Facebook Chat (Messenger).
:param email: Facebook `email` or `id` or `phone number`
@@ -85,8 +84,17 @@ class Client(object):
self._console("Logging in...")
for i in range(1,max_retries+1):
if not self.login():
raise Exception("id or password is wrong")
self._console("Attempt #{} failed{}".format(i,{True:', retrying'}.get(i<5,'')))
time.sleep(1)
continue
else:
self._console("login successful")
break
else:
raise Exception("login failed. Check id/password")
self.threads = []
@@ -222,38 +230,51 @@ class Client(object):
thread_id = None
user_id = recipient_id
messageAndOTID=generateOfflineThreadingID()
timestamp = now()
date = datetime.now()
data = {
'client' : self.client,
'message_batch[0][action_type]' : 'ma-type:user-generated-message',
'message_batch[0][author]' : 'fbid:' + str(self.uid),
'message_batch[0][specific_to_list][0]' : 'fbid:' + str(recipient_id),
'message_batch[0][specific_to_list][1]' : 'fbid:' + str(self.uid),
'message_batch[0][timestamp]' : timestamp,
'message_batch[0][timestamp_absolute]' : 'Today',
'message_batch[0][timestamp_relative]' : str(date.hour) + ":" + str(date.minute).zfill(2),
'message_batch[0][timestamp_time_passed]' : '0',
'message_batch[0][is_unread]' : False,
'message_batch[0][is_cleared]' : False,
'message_batch[0][is_forward]' : False,
'message_batch[0][is_filtered_content]' : False,
'message_batch[0][is_spoof_warning]' : False,
'message_batch[0][source]' : 'source:chat:web',
'message_batch[0][source_tags][0]' : 'source:chat',
'message_batch[0][body]' : message,
'message_batch[0][html_body]' : False,
'message_batch[0][ui_push_phase]' : 'V3',
'message_batch[0][status]' : '0',
'message_batch[0][message_id]' : generateMessageID(self.client_id),
'message_batch[0][manual_retry_cnt]' : '0',
'message_batch[0][thread_fbid]' : thread_id,
'message_batch[0][has_attachment]' : image_id != None,
'message_batch[0][other_user_fbid]' : user_id
'client': self.client,
'action_type' : 'ma-type:user-generated-message',
'author' : 'fbid:' + str(self.uid),
'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_filtered_content_bh': False,
'is_filtered_content_account': False,
'is_filtered_content_quasar': False,
'is_filtered_content_invalid_app': False,
'is_spoof_warning' : False,
'source' : 'source:chat:web',
'source_tags[0]' : 'source:chat',
'body' : message,
'html_body' : False,
'ui_push_phase' : 'V3',
'status' : '0',
'offline_threading_id':messageAndOTID,
'message_id' : messageAndOTID,
'threading_id':generateMessageID(self.client_id),
'ephemeral_ttl_mode:': '0',
'manual_retry_cnt' : '0',
'signatureID' : getSignatureID(),
'has_attachment' : image_id != None,
'other_user_fbid' : recipient_id,
'specific_to_list[0]' : 'fbid:' + str(recipient_id),
'specific_to_list[1]' : 'fbid:' + str(self.uid),
}
if image_id:
data['message_batch[0][image_ids][0]'] = image_id
data['image_ids[0]'] = image_id
if like:
try:
@@ -261,9 +282,13 @@ class Client(object):
except KeyError:
# if user doesn't enter l or m or s, then use the large one
sticker = LIKES['l']
data["message_batch[0][sticker_id]"] = sticker
data["sticker_id"] = sticker
r = self._post(SendURL, data)
if self.debug:
print(r)
print(data)
return r.ok
def sendRemoteImage(self, recipient_id, message=None, message_type='user', image=''):
@@ -502,7 +527,7 @@ class Client(object):
if 'messageMetadata' in m['delta']:
mid = m['delta']['messageMetadata']['messageId']
message = m['delta']['body']
fbid = m['delta']['messageMetadata']['threadKey']['otherUserFbId']
fbid = m['delta']['messageMetadata']['actorFbId']
name = None
self.on_message(mid, fbid, name, message, m)
else:
@@ -532,6 +557,23 @@ class Client(object):
except requests.exceptions.Timeout:
pass
def getUserInfo(self,*user_ids):
"""Get user info from id. Unordered.
:param user_ids: one or more user id(s) to query
"""
data = {"ids[{}]".format(i):user_id for i,user_id in enumerate(user_ids)}
r = self._post(UserInfoURL, data)
info = get_json(r.text)
full_data= [details for profile,details in info['payload']['profiles'].items()]
if len(full_data)==1:
full_data=full_data[0]
return full_data
def on_message(self, mid, author_id, author_name, message, metadata):
'''

View File

@@ -34,3 +34,14 @@ def generateMessageID(client_id=None):
k = now()
l = int(random() * 4294967295)
return ("<%s:%s-%s@mail.projektitan.com>" % (k, l, client_id));
def getSignatureID():
return hex(int(random() * 2147483648))
def generateOfflineThreadingID() :
ret = now()
value = int(random() * 4294967295);
string = ("0000000000000000000000" + bin(value))[-22:]
msgs = bin(ret) + string
return str(int(msgs,2))