Compare commits

...

9 Commits

Author SHA1 Message Date
Mads Marquart
57954816b2 Version up, thanks to @WeiTang114 2017-10-03 08:29:34 +02:00
Mads Marquart
3e4e1f9bb9 Merge pull request #212 from WeiTang114/gif_support_2
Add Gif support to send(Local/Remote)Image
2017-10-03 08:26:10 +02:00
Mads Marquart
7340918209 Merge pull request #211 from WeiTang114/fetch_pending_thread_2
Enable fetching pending/archived threads
2017-10-03 08:25:58 +02:00
Tang
707df4f941 use mimetype to see if it's a GIF
thanks to @madsmtm's good idea
2017-10-03 03:29:15 +08:00
Tang
8eb6b83411 Update for feedback by @madsmtm
1. Add ThreadLocation Enum in models.
2. avoid using build-in name "type" as parameter name
3. replace ValueError with FBchatUserError

thanks to @madsmtm
2017-10-03 03:05:08 +08:00
Tang
e0aedd617b add param is_gif to doc of functions 2017-10-03 01:40:19 +08:00
Tang
ee81620c14 Add send GIF images support
When uploading and sending GIF images, the keys are explicitly changed
to "gif_id" or "gif_ids" rather than "image_id" or "image_ids".
2017-10-03 01:39:20 +08:00
Tang
2d027af71a Enable fetching pending/archived threads
Add "type" parameter to fetchThreadList().
type can be 'inbox', 'pending' or 'archived'

If set to 'pending', it can fetch messages from unknown users.
It is quite useful to build a service accepting requests from anyone.

For example, in doOneListen(), fetch pending messages once for a while
to handle the messages from strangers.
2017-10-03 01:37:25 +08:00
Mads Marquart
9d5f06b810 Fixed pip setup 2017-09-30 19:17:40 +02:00
4 changed files with 56 additions and 30 deletions

View File

@@ -17,7 +17,7 @@ from .client import *
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year) __copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
__version__ = '1.0.22' __version__ = '1.0.24'
__license__ = 'BSD' __license__ = 'BSD'
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart' __author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
__email__ = 'carpedm20@gmail.com' __email__ = 'carpedm20@gmail.com'

View File

@@ -748,11 +748,12 @@ class Client(object):
return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']])) return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']]))
def fetchThreadList(self, offset=0, limit=20): def fetchThreadList(self, offset=0, limit=20, thread_location=ThreadLocation.INBOX):
"""Get thread list of your facebook account """Get thread list of your facebook account
:param offset: The offset, from where in the list to recieve threads from :param offset: The offset, from where in the list to recieve threads from
:param limit: Max. number of threads to retrieve. Capped at 20 :param limit: Max. number of threads to retrieve. Capped at 20
:param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER
:type offset: int :type offset: int
:type limit: int :type limit: int
:return: :class:`models.Thread` objects :return: :class:`models.Thread` objects
@@ -763,10 +764,15 @@ class Client(object):
if limit > 20 or limit < 1: if limit > 20 or limit < 1:
raise FBchatUserError('`limit` should be between 1 and 20') raise FBchatUserError('`limit` should be between 1 and 20')
if thread_location in ThreadLocation:
loc_str = thread_location.value
else:
raise FBchatUserError('"thread_location" must be a value of ThreadLocation')
data = { data = {
'client' : self.client, 'client' : self.client,
'inbox[offset]' : offset, loc_str + '[offset]' : offset,
'inbox[limit]' : limit, loc_str + '[limit]' : limit,
} }
j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True) j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True)
@@ -774,25 +780,27 @@ class Client(object):
raise FBchatException('Missing payload: {}, with data: {}'.format(j, data)) raise FBchatException('Missing payload: {}, with data: {}'.format(j, data))
participants = {} participants = {}
for p in j['payload']['participants']: if 'participants' in j['payload']:
if p['type'] == 'page': for p in j['payload']['participants']:
participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name']) if p['type'] == 'page':
elif p['type'] == 'user': participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name'])
participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS[p['gender']], photo=p['image_src'], name=p['name']) elif p['type'] == 'user':
else: participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS[p['gender']], photo=p['image_src'], name=p['name'])
raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p)) else:
raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p))
entries = [] entries = []
for k in j['payload']['threads']: if 'threads' in j['payload']:
if k['thread_type'] == 1: for k in j['payload']['threads']:
if k['other_user_fbid'] not in participants: if k['thread_type'] == 1:
raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload'])) if k['other_user_fbid'] not in participants:
participants[k['other_user_fbid']].message_count = k['message_count'] raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload']))
entries.append(participants[k['other_user_fbid']]) participants[k['other_user_fbid']].message_count = k['message_count']
elif k['thread_type'] == 2: entries.append(participants[k['other_user_fbid']])
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'] == 2:
else: 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']))
raise FBchatException('A thread had an unknown thread type: {}'.format(k)) else:
raise FBchatException('A thread had an unknown thread type: {}'.format(k))
return entries return entries
@@ -949,9 +957,12 @@ class Client(object):
) )
}, fix_request=True, as_json=True) }, fix_request=True, as_json=True)
# Return the image_id # Return the image_id
return j['payload']['metadata'][0]['image_id'] if not mimetype == 'image/gif':
return j['payload']['metadata'][0]['image_id']
else:
return j['payload']['metadata'][0]['gif_id']
def sendImage(self, image_id, message=None, thread_id=None, thread_type=ThreadType.USER): def sendImage(self, image_id, message=None, thread_id=None, thread_type=ThreadType.USER, is_gif=False):
""" """
Sends an already uploaded image to a thread. (Used by :func:`Client.sendRemoteImage` and :func:`Client.sendLocalImage`) Sends an already uploaded image to a thread. (Used by :func:`Client.sendRemoteImage` and :func:`Client.sendLocalImage`)
@@ -959,6 +970,7 @@ class Client(object):
:param message: Additional message :param message: Additional message
:param thread_id: User/Group ID to send to. See :ref:`intro_threads` :param thread_id: User/Group ID to send to. See :ref:`intro_threads`
:param thread_type: See :ref:`intro_threads` :param thread_type: See :ref:`intro_threads`
:param is_gif: if sending GIF, True, else False
:type thread_type: models.ThreadType :type thread_type: models.ThreadType
:return: :ref:`Message ID <intro_message_ids>` of the sent image :return: :ref:`Message ID <intro_message_ids>` of the sent image
:raises: FBchatException if request failed :raises: FBchatException if request failed
@@ -972,7 +984,10 @@ class Client(object):
data['specific_to_list[0]'] = 'fbid:' + str(thread_id) data['specific_to_list[0]'] = 'fbid:' + str(thread_id)
data['specific_to_list[1]'] = 'fbid:' + str(self.uid) data['specific_to_list[1]'] = 'fbid:' + str(self.uid)
data['image_ids[0]'] = image_id if not is_gif:
data['image_ids[0]'] = image_id
else:
data['gif_ids[0]'] = image_id
return self._doSendRequest(data) return self._doSendRequest(data)
@@ -990,9 +1005,10 @@ class Client(object):
""" """
thread_id, thread_type = self._getThread(thread_id, thread_type) thread_id, thread_type = self._getThread(thread_id, thread_type)
mimetype = guess_type(image_url)[0] mimetype = guess_type(image_url)[0]
is_gif = (mimetype == 'image/gif')
remote_image = requests.get(image_url).content remote_image = requests.get(image_url).content
image_id = self._uploadImage(image_url, remote_image, mimetype) image_id = self._uploadImage(image_url, remote_image, mimetype)
return self.sendImage(image_id=image_id, message=message, thread_id=thread_id, thread_type=thread_type) return self.sendImage(image_id=image_id, message=message, thread_id=thread_id, thread_type=thread_type, is_gif=is_gif)
def sendLocalImage(self, image_path, message=None, thread_id=None, thread_type=ThreadType.USER): def sendLocalImage(self, image_path, message=None, thread_id=None, thread_type=ThreadType.USER):
""" """
@@ -1008,8 +1024,9 @@ class Client(object):
""" """
thread_id, thread_type = self._getThread(thread_id, thread_type) thread_id, thread_type = self._getThread(thread_id, thread_type)
mimetype = guess_type(image_path)[0] mimetype = guess_type(image_path)[0]
is_gif = (mimetype == 'image/gif')
image_id = self._uploadImage(image_path, open(image_path, 'rb'), mimetype) image_id = self._uploadImage(image_path, open(image_path, 'rb'), mimetype)
return self.sendImage(image_id=image_id, message=message, thread_id=thread_id, thread_type=thread_type) return self.sendImage(image_id=image_id, message=message, thread_id=thread_id, thread_type=thread_type, is_gif=is_gif)
def addUsersToGroup(self, user_ids, thread_id=None): def addUsersToGroup(self, user_ids, thread_id=None):
""" """

View File

@@ -193,6 +193,13 @@ class ThreadType(Enum):
GROUP = 2 GROUP = 2
PAGE = 3 PAGE = 3
class ThreadLocation(Enum):
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
INBOX = 'inbox'
PENDING = 'pending'
ARCHIVED = 'action:archived'
OTHER = 'other'
class TypingStatus(Enum): class TypingStatus(Enum):
"""Used to specify whether the user is typing or has stopped typing""" """Used to specify whether the user is typing or has stopped typing"""
STOPPED = 0 STOPPED = 0

View File

@@ -16,10 +16,12 @@ except ImportError:
with open('README.rst') as f: with open('README.rst') as f:
readme_content = f.read().strip() readme_content = f.read().strip()
try: requirements = [
requirements = [line.rstrip('\n') for line in open(os.path.join('fbchat.egg-info', 'requires.txt'))] 'requests',
except IOError: 'lxml',
requirements = [line.rstrip('\n') for line in open('requirements.txt')] 'beautifulsoup4',
"enum34; python_version == '2.7'"
]
version = None version = None
author = None author = None