Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4dd15b05ef | ||
|
d7cdb644c4 | ||
|
bfcf4950b3 | ||
|
6612c97f05 | ||
|
b92cf62726 | ||
|
a53ba33a81 | ||
|
c04d38cf63 | ||
|
a051adcbc0 | ||
|
900a9cdf72 | ||
|
611b329934 | ||
|
2642788bc1 | ||
|
8268445f0b | ||
|
c12dcd9263 | ||
|
3142524809 | ||
|
4c9d3bd9d7 | ||
|
ba103066b8 | ||
|
0b0d6179a2 | ||
|
e8806d4ef8 | ||
|
c96e5f174c | ||
|
315242e069 | ||
|
a94fa5fbe3 | ||
|
90203afdd0 | ||
|
2c0d098852 | ||
|
e4290cd465 | ||
|
46b85dec5c | ||
|
bbc34bd009 | ||
|
c495317e65 | ||
|
a946050228 | ||
|
83789dcefa |
@@ -17,7 +17,7 @@ from .client import *
|
||||
|
||||
|
||||
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
|
||||
__version__ = '1.1.3'
|
||||
__version__ = '1.3.3'
|
||||
__license__ = 'BSD'
|
||||
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
|
||||
__email__ = 'carpedm20@gmail.com'
|
||||
|
117
fbchat/client.py
117
fbchat/client.py
@@ -754,19 +754,23 @@ class Client(object):
|
||||
|
||||
return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']]))
|
||||
|
||||
def fetchThreadList(self, offset=0, limit=20, thread_location=ThreadLocation.INBOX):
|
||||
def fetchThreadList(self, offset=None, limit=20, thread_location=ThreadLocation.INBOX, before=None):
|
||||
"""Get thread list of your facebook account
|
||||
|
||||
:param offset: The offset, from where in the list to recieve threads from
|
||||
:param offset: Deprecated. Do not use!
|
||||
:param limit: Max. number of threads to retrieve. Capped at 20
|
||||
:param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER
|
||||
:type offset: int
|
||||
:param before: A timestamp (in milliseconds), indicating from which point to retrieve threads
|
||||
:type limit: int
|
||||
:type before: int
|
||||
:return: :class:`models.Thread` objects
|
||||
:rtype: list
|
||||
:raises: FBchatException if request failed
|
||||
"""
|
||||
|
||||
if offset is not None:
|
||||
log.warning('Using `offset` in `fetchThreadList` is no longer supported, since Facebook migrated to the use of GraphQL in this request. Use `before` instead')
|
||||
|
||||
if limit > 20 or limit < 1:
|
||||
raise FBchatUserError('`limit` should be between 1 and 20')
|
||||
|
||||
@@ -775,52 +779,15 @@ class Client(object):
|
||||
else:
|
||||
raise FBchatUserError('"thread_location" must be a value of ThreadLocation')
|
||||
|
||||
data = {
|
||||
'client' : self.client,
|
||||
loc_str + '[offset]' : offset,
|
||||
loc_str + '[limit]' : limit,
|
||||
}
|
||||
j = self.graphql_request(GraphQL(doc_id='1349387578499440', params={
|
||||
'limit': limit,
|
||||
'tags': [loc_str],
|
||||
'before': before,
|
||||
'includeDeliveryReceipts': True,
|
||||
'includeSeqID': False
|
||||
}))
|
||||
|
||||
j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True)
|
||||
if j.get('payload') is None:
|
||||
raise FBchatException('Missing payload: {}, with data: {}'.format(j, data))
|
||||
|
||||
participants = {}
|
||||
if 'participants' in j['payload']:
|
||||
for p in j['payload']['participants']:
|
||||
if p['type'] == 'page':
|
||||
participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name'])
|
||||
elif p['type'] == 'user':
|
||||
participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS.get(p['gender']), photo=p['image_src'], name=p['name'])
|
||||
else:
|
||||
raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p))
|
||||
|
||||
entries = []
|
||||
if 'threads' in j['payload']:
|
||||
for k in j['payload']['threads']:
|
||||
if k['thread_type'] == 1:
|
||||
if k['other_user_fbid'] not in participants:
|
||||
raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload']))
|
||||
participants[k['other_user_fbid']].message_count = k['message_count']
|
||||
entries.append(participants[k['other_user_fbid']])
|
||||
elif k['thread_type'] == 2:
|
||||
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'] == 3:
|
||||
entries.append(Room(
|
||||
k['thread_fbid'],
|
||||
participants = set(p.lstrip('fbid:') for p in k['participants']),
|
||||
photo = k['image_src'],
|
||||
name = k['name'],
|
||||
message_count = k['message_count'],
|
||||
admins = set(p.lstrip('fbid:') for p in k['admin_ids']),
|
||||
approval_mode = k['approval_mode'],
|
||||
approval_requests = set(p.lstrip('fbid:') for p in k['approval_queue_ids']),
|
||||
join_link = k['joinable_mode']['link']
|
||||
))
|
||||
else:
|
||||
raise FBchatException('A thread had an unknown thread type: {}'.format(k))
|
||||
|
||||
return entries
|
||||
return [graphql_to_thread(node) for node in j['viewer']['message_threads']['nodes']]
|
||||
|
||||
def fetchUnread(self):
|
||||
"""
|
||||
@@ -987,7 +954,7 @@ class Client(object):
|
||||
Deprecated. Use :func:`fbchat.Client.send` instead
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||
data = self._getSendData(message=message, thread_id=thread_id, thread_type=thread_type)
|
||||
data = self._getSendData(message=self._oldMessage(message), thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
data['action_type'] = 'ma-type:user-generated-message'
|
||||
data['has_attachment'] = True
|
||||
@@ -1248,7 +1215,7 @@ class Client(object):
|
||||
:type thread_type: models.ThreadType
|
||||
:raises: FBchatException if request failed
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, None)
|
||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||
|
||||
data = {
|
||||
"typ": status.value,
|
||||
@@ -1482,21 +1449,20 @@ class Client(object):
|
||||
try:
|
||||
for a in delta['attachments']:
|
||||
mercury = a['mercury']
|
||||
if mercury.get('attach_type'):
|
||||
if mercury.get('blob_attachment'):
|
||||
image_metadata = a.get('imageMetadata', {})
|
||||
attach_type = mercury['attach_type']
|
||||
if attach_type != 'share':
|
||||
attachment = graphql_to_attachment(mercury.get('blob_attachment', {}))
|
||||
else:
|
||||
# TODO: Add more data here for shared stuff (URLs, events and so on)
|
||||
pass
|
||||
attach_type = mercury['blob_attachment']['__typename']
|
||||
attachment = graphql_to_attachment(mercury.get('blob_attachment', {}))
|
||||
|
||||
if attach_type == ['file', 'video']:
|
||||
if attach_type == ['MessageFile', 'MessageVideo', 'MessageAudio']:
|
||||
# TODO: Add more data here for audio files
|
||||
attachment.size = int(a['fileSize'])
|
||||
attachments.append(attachment)
|
||||
if a['mercury'].get('sticker_attachment'):
|
||||
elif mercury.get('sticker_attachment'):
|
||||
sticker = graphql_to_sticker(a['mercury']['sticker_attachment'])
|
||||
elif mercury.get('extensible_attachment'):
|
||||
# TODO: Add more data here for shared stuff (URLs, events and so on)
|
||||
pass
|
||||
except Exception:
|
||||
log.exception('An exception occured while reading attachments: {}'.format(delta['attachments']))
|
||||
|
||||
@@ -1527,10 +1493,15 @@ class Client(object):
|
||||
self.onInbox(unseen=m["unseen"], unread=m["unread"], recent_unread=m["recent_unread"], msg=m)
|
||||
|
||||
# Typing
|
||||
# elif mtype == "typ":
|
||||
# author_id = str(m.get("from"))
|
||||
# typing_status = TypingStatus(m.get("st"))
|
||||
# self.onTyping(author_id=author_id, typing_status=typing_status)
|
||||
elif mtype == "typ":
|
||||
author_id = str(m.get("from"))
|
||||
thread_id = str(m.get("to"))
|
||||
if thread_id == self.uid:
|
||||
thread_type = ThreadType.USER
|
||||
else:
|
||||
thread_type = ThreadType.GROUP
|
||||
typing_status = TypingStatus(m.get("st"))
|
||||
self.onTyping(author_id=author_id, status=typing_status, thread_id=thread_id, thread_type=thread_type, msg=m)
|
||||
|
||||
# Delivered
|
||||
|
||||
@@ -1539,9 +1510,9 @@ class Client(object):
|
||||
#
|
||||
# self.onSeen(m.get('realtime_viewer_fbid'), m.get('reader'), m.get('time'))
|
||||
|
||||
# elif mtype in ['jewel_requests_add']:
|
||||
# from_id = m['from']
|
||||
# self.on_friend_request(from_id)
|
||||
elif mtype in ['jewel_requests_add']:
|
||||
from_id = m['from']
|
||||
self.onFriendRequest(from_id=from_id, msg=m)
|
||||
|
||||
# Happens on every login
|
||||
elif mtype == "qprimer":
|
||||
@@ -1850,6 +1821,20 @@ class Client(object):
|
||||
"""
|
||||
log.info('Inbox event: {}, {}, {}'.format(unseen, unread, recent_unread))
|
||||
|
||||
def onTyping(self, author_id=None, status=None, thread_id=None, thread_type=None, msg=None):
|
||||
"""
|
||||
Called when the client is listening, and somebody starts or stops typing into a chat
|
||||
|
||||
:param author_id: The ID of the person who sent the action
|
||||
:param status: The typing status
|
||||
:param thread_id: Thread ID that the action was sent to. See :ref:`intro_threads`
|
||||
:param thread_type: Type of thread that the action was sent to. See :ref:`intro_threads`
|
||||
:param msg: A full set of the data recieved
|
||||
:type typing_status: models.TypingStatus
|
||||
:type thread_type: models.ThreadType
|
||||
"""
|
||||
pass
|
||||
|
||||
def onQprimer(self, ts=None, msg=None):
|
||||
"""
|
||||
Called when the client just started listening
|
||||
|
@@ -109,6 +109,13 @@ def graphql_to_attachment(a):
|
||||
large_image=a.get('large_image'),
|
||||
uid=a.get('legacy_attachment_id')
|
||||
)
|
||||
elif _type == 'MessageAudio':
|
||||
return AudioAttachment(
|
||||
filename=a.get('filename'),
|
||||
url=a.get('playable_url'),
|
||||
duration=a.get('playable_duration_in_ms'),
|
||||
audio_type=a.get('audio_type')
|
||||
)
|
||||
elif _type == 'MessageFile':
|
||||
return FileAttachment(
|
||||
url=a.get('url'),
|
||||
@@ -165,10 +172,42 @@ def graphql_to_user(user):
|
||||
message_count=user.get('messages_count')
|
||||
)
|
||||
|
||||
def graphql_to_thread(thread):
|
||||
if thread['thread_type'] == 'GROUP':
|
||||
return graphql_to_group(thread)
|
||||
elif thread['thread_type'] == 'ONE_TO_ONE':
|
||||
if thread.get('big_image_src') is None:
|
||||
thread['big_image_src'] = {}
|
||||
c_info = get_customization_info(thread)
|
||||
participants = [node['messaging_actor'] for node in thread['all_participants']['nodes']]
|
||||
user = next(p for p in participants if p['id'] == thread['thread_key']['other_user_id'])
|
||||
last_message_timestamp = thread['last_message']['nodes'][0]['timestamp_precise']
|
||||
|
||||
return User(
|
||||
user['id'],
|
||||
url=user.get('url'),
|
||||
name=user.get('name'),
|
||||
first_name=user.get('short_name'),
|
||||
last_name=user.get('name').split(user.get('short_name'),1)[1].strip(),
|
||||
is_friend=user.get('is_viewer_friend'),
|
||||
gender=GENDERS.get(user.get('gender')),
|
||||
affinity=user.get('affinity'),
|
||||
nickname=c_info.get('nickname'),
|
||||
color=c_info.get('color'),
|
||||
emoji=c_info.get('emoji'),
|
||||
own_nickname=c_info.get('own_nickname'),
|
||||
photo=user['big_image_src'].get('uri'),
|
||||
message_count=thread.get('messages_count'),
|
||||
last_message_timestamp=last_message_timestamp
|
||||
)
|
||||
else:
|
||||
raise FBchatException('Unknown thread type: {}, with data: {}'.format(thread.get('thread_type'), thread))
|
||||
|
||||
def graphql_to_group(group):
|
||||
if group.get('image') is None:
|
||||
group['image'] = {}
|
||||
c_info = get_customization_info(group)
|
||||
last_message_timestamp = group['last_message']['nodes'][0]['timestamp_precise']
|
||||
return Group(
|
||||
group['thread_key']['thread_fbid'],
|
||||
participants=set([node['messaging_actor']['id'] for node in group['all_participants']['nodes']]),
|
||||
@@ -177,7 +216,8 @@ def graphql_to_group(group):
|
||||
emoji=c_info.get('emoji'),
|
||||
photo=group['image'].get('uri'),
|
||||
name=group.get('name'),
|
||||
message_count=group.get('messages_count')
|
||||
message_count=group.get('messages_count'),
|
||||
last_message_timestamp=last_message_timestamp
|
||||
)
|
||||
|
||||
def graphql_to_room(room):
|
||||
|
171
fbchat/models.py
171
fbchat/models.py
@@ -9,11 +9,11 @@ class FBchatException(Exception):
|
||||
|
||||
class FBchatFacebookError(FBchatException):
|
||||
#: The error code that Facebook returned
|
||||
fb_error_code = str
|
||||
fb_error_code = None
|
||||
#: The error message that Facebook returned (In the user's own language)
|
||||
fb_error_message = str
|
||||
fb_error_message = None
|
||||
#: The status code that was sent in the http response (eg. 404) (Usually only set if not successful, aka. not 200)
|
||||
request_status_code = int
|
||||
request_status_code = None
|
||||
def __init__(self, message, fb_error_code=None, fb_error_message=None, request_status_code=None):
|
||||
super(FBchatFacebookError, self).__init__(message)
|
||||
"""Thrown by fbchat when Facebook returns an error"""
|
||||
@@ -26,17 +26,17 @@ class FBchatUserError(FBchatException):
|
||||
|
||||
class Thread(object):
|
||||
#: The unique identifier of the thread. Can be used a `thread_id`. See :ref:`intro_threads` for more info
|
||||
uid = str
|
||||
uid = None
|
||||
#: Specifies the type of thread. Can be used a `thread_type`. See :ref:`intro_threads` for more info
|
||||
type = None
|
||||
#: The thread's picture
|
||||
photo = str
|
||||
#: A url to the thread's picture
|
||||
photo = None
|
||||
#: The name of the thread
|
||||
name = str
|
||||
name = None
|
||||
#: Timestamp of last message
|
||||
last_message_timestamp = str
|
||||
last_message_timestamp = None
|
||||
#: Number of messages in the thread
|
||||
message_count = int
|
||||
message_count = None
|
||||
def __init__(self, _type, uid, photo=None, name=None, last_message_timestamp=None, message_count=None):
|
||||
"""Represents a Facebook thread"""
|
||||
self.uid = str(uid)
|
||||
@@ -55,25 +55,25 @@ class Thread(object):
|
||||
|
||||
class User(Thread):
|
||||
#: The profile url
|
||||
url = str
|
||||
url = None
|
||||
#: The users first name
|
||||
first_name = str
|
||||
first_name = None
|
||||
#: The users last name
|
||||
last_name = str
|
||||
last_name = None
|
||||
#: Whether the user and the client are friends
|
||||
is_friend = bool
|
||||
is_friend = None
|
||||
#: The user's gender
|
||||
gender = str
|
||||
gender = None
|
||||
#: From 0 to 1. How close the client is to the user
|
||||
affinity = float
|
||||
affinity = None
|
||||
#: The user's nickname
|
||||
nickname = str
|
||||
nickname = None
|
||||
#: The clients nickname, as seen by the user
|
||||
own_nickname = str
|
||||
own_nickname = None
|
||||
#: A :class:`ThreadColor`. The message color
|
||||
color = None
|
||||
#: The default emoji
|
||||
emoji = str
|
||||
emoji = None
|
||||
|
||||
def __init__(self, uid, url=None, first_name=None, last_name=None, is_friend=None, gender=None, affinity=None, nickname=None, own_nickname=None, color=None, emoji=None, **kwargs):
|
||||
"""Represents a Facebook user. Inherits `Thread`"""
|
||||
@@ -92,13 +92,13 @@ class User(Thread):
|
||||
|
||||
class Group(Thread):
|
||||
#: Unique list (set) of the group thread's participant user IDs
|
||||
participants = set
|
||||
#: Dict, containing user nicknames mapped to their IDs
|
||||
nicknames = dict
|
||||
participants = None
|
||||
#: A dict, containing user nicknames mapped to their IDs
|
||||
nicknames = None
|
||||
#: A :class:`ThreadColor`. The groups's message color
|
||||
color = None
|
||||
#: The groups's default emoji
|
||||
emoji = str
|
||||
emoji = None
|
||||
|
||||
def __init__(self, uid, participants=None, nicknames=None, color=None, emoji=None, **kwargs):
|
||||
"""Represents a Facebook group. Inherits `Thread`"""
|
||||
@@ -115,15 +115,15 @@ class Group(Thread):
|
||||
|
||||
class Room(Group):
|
||||
# Set containing user IDs of thread admins
|
||||
admins = set
|
||||
admins = None
|
||||
# True if users need approval to join
|
||||
approval_mode = bool
|
||||
approval_mode = None
|
||||
# Set containing user IDs requesting to join
|
||||
approval_requests = set
|
||||
approval_requests = None
|
||||
# Link for joining room
|
||||
join_link = str
|
||||
join_link = None
|
||||
# True is room is not discoverable
|
||||
privacy_mode = bool
|
||||
privacy_mode = None
|
||||
|
||||
def __init__(self, uid, admins=None, approval_mode=None, approval_requests=None, join_link=None, privacy_mode=None, **kwargs):
|
||||
"""Represents a Facebook room. Inherits `Group`"""
|
||||
@@ -142,15 +142,15 @@ class Room(Group):
|
||||
|
||||
class Page(Thread):
|
||||
#: The page's custom url
|
||||
url = str
|
||||
url = None
|
||||
#: The name of the page's location city
|
||||
city = str
|
||||
city = None
|
||||
#: Amount of likes the page has
|
||||
likes = int
|
||||
likes = None
|
||||
#: Some extra information about the page
|
||||
sub_title = str
|
||||
sub_title = None
|
||||
#: The page's category
|
||||
category = str
|
||||
category = None
|
||||
|
||||
def __init__(self, uid, url=None, city=None, likes=None, sub_title=None, category=None, **kwargs):
|
||||
"""Represents a Facebook page. Inherits `Thread`"""
|
||||
@@ -166,7 +166,7 @@ class Message(object):
|
||||
#: The actual message
|
||||
text = None
|
||||
#: A list of :class:`Mention` objects
|
||||
mentions = []
|
||||
mentions = None
|
||||
#: A :class:`EmojiSize`. Size of a sent emoji
|
||||
emoji_size = None
|
||||
#: The message ID
|
||||
@@ -178,13 +178,13 @@ class Message(object):
|
||||
#: Whether the message is read
|
||||
is_read = None
|
||||
#: A dict with user's IDs as keys, and their :class:`MessageReaction` as values
|
||||
reactions = {}
|
||||
reactions = None
|
||||
#: The actual message
|
||||
text = None
|
||||
#: A :class:`Sticker`
|
||||
sticker = None
|
||||
#: A list of attachments
|
||||
attachments = []
|
||||
attachments = None
|
||||
|
||||
def __init__(self, text=None, mentions=None, emoji_size=None, sticker=None, attachments=None):
|
||||
"""Represents a Facebook message"""
|
||||
@@ -207,7 +207,7 @@ class Message(object):
|
||||
|
||||
class Attachment(object):
|
||||
#: The attachment ID
|
||||
uid = str
|
||||
uid = None
|
||||
|
||||
def __init__(self, uid=None):
|
||||
"""Represents a Facebook attachment"""
|
||||
@@ -251,13 +251,13 @@ class ShareAttachment(Attachment):
|
||||
|
||||
class FileAttachment(Attachment):
|
||||
#: Url where you can download the file
|
||||
url = str
|
||||
url = None
|
||||
#: Size of the file in bytes
|
||||
size = int
|
||||
size = None
|
||||
#: Name of the file
|
||||
name = str
|
||||
name = None
|
||||
#: Whether Facebook determines that this file may be harmful
|
||||
is_malicious = bool
|
||||
is_malicious = None
|
||||
|
||||
def __init__(self, url=None, size=None, name=None, is_malicious=None, **kwargs):
|
||||
"""Represents a file that has been sent as a Facebook attachment"""
|
||||
@@ -267,45 +267,58 @@ class FileAttachment(Attachment):
|
||||
self.name = name
|
||||
self.is_malicious = is_malicious
|
||||
|
||||
class AudioAttachment(FileAttachment):
|
||||
def __init__(self, **kwargs):
|
||||
"""Represents an audio file that has been sent as a Facebook attachment - *Currently Incomplete!*"""
|
||||
super(StickerAttachment, self).__init__(**kwargs)
|
||||
class AudioAttachment(Attachment):
|
||||
#: Name of the file
|
||||
filename = None
|
||||
#: Url of the audio file
|
||||
url = None
|
||||
#: Duration of the audioclip in milliseconds
|
||||
duration = None
|
||||
#: Audio type
|
||||
audio_type = None
|
||||
|
||||
def __init__(self, filename=None, url=None, duration=None, audio_type=None, **kwargs):
|
||||
"""Represents an audio file that has been sent as a Facebook attachment"""
|
||||
super(AudioAttachment, self).__init__(**kwargs)
|
||||
self.filename = filename
|
||||
self.url = url
|
||||
self.duration = duration
|
||||
self.audio_type = audio_type
|
||||
|
||||
class ImageAttachment(Attachment):
|
||||
#: The extension of the original image (eg. 'png')
|
||||
original_extension = str
|
||||
original_extension = None
|
||||
#: Width of original image
|
||||
width = int
|
||||
width = None
|
||||
#: Height of original image
|
||||
height = int
|
||||
height = None
|
||||
|
||||
#: Whether the image is animated
|
||||
is_animated = bool
|
||||
is_animated = None
|
||||
|
||||
#: URL to a thumbnail of the image
|
||||
thumbnail_url = str
|
||||
thumbnail_url = None
|
||||
|
||||
#: URL to a medium preview of the image
|
||||
preview_url = str
|
||||
preview_url = None
|
||||
#: Width of the medium preview image
|
||||
preview_width = int
|
||||
preview_width = None
|
||||
#: Height of the medium preview image
|
||||
preview_height = int
|
||||
preview_height = None
|
||||
|
||||
#: URL to a large preview of the image
|
||||
large_preview_url = str
|
||||
large_preview_url = None
|
||||
#: Width of the large preview image
|
||||
large_preview_width = int
|
||||
large_preview_width = None
|
||||
#: Height of the large preview image
|
||||
large_preview_height = int
|
||||
large_preview_height = None
|
||||
|
||||
#: URL to an animated preview of the image (eg. for gifs)
|
||||
animated_preview_url = str
|
||||
animated_preview_url = None
|
||||
#: Width of the animated preview image
|
||||
animated_preview_width = int
|
||||
animated_preview_width = None
|
||||
#: Height of the animated preview image
|
||||
animated_preview_height = int
|
||||
animated_preview_height = None
|
||||
|
||||
def __init__(self, original_extension=None, width=None, height=None, is_animated=None, thumbnail_url=None, preview=None, large_preview=None, animated_preview=None, **kwargs):
|
||||
"""
|
||||
@@ -344,36 +357,36 @@ class ImageAttachment(Attachment):
|
||||
|
||||
class VideoAttachment(Attachment):
|
||||
#: Size of the original video in bytes
|
||||
size = int
|
||||
size = None
|
||||
#: Width of original video
|
||||
width = int
|
||||
width = None
|
||||
#: Height of original video
|
||||
height = int
|
||||
height = None
|
||||
#: Length of video in milliseconds
|
||||
duration = int
|
||||
duration = None
|
||||
#: URL to very compressed preview video
|
||||
preview_url = str
|
||||
preview_url = None
|
||||
|
||||
#: URL to a small preview image of the video
|
||||
small_image_url = str
|
||||
small_image_url = None
|
||||
#: Width of the small preview image
|
||||
small_image_width = int
|
||||
small_image_width = None
|
||||
#: Height of the small preview image
|
||||
small_image_height = int
|
||||
small_image_height = None
|
||||
|
||||
#: URL to a medium preview image of the video
|
||||
medium_image_url = str
|
||||
medium_image_url = None
|
||||
#: Width of the medium preview image
|
||||
medium_image_width = int
|
||||
medium_image_width = None
|
||||
#: Height of the medium preview image
|
||||
medium_image_height = int
|
||||
medium_image_height = None
|
||||
|
||||
#: URL to a large preview image of the video
|
||||
large_image_url = str
|
||||
large_image_url = None
|
||||
#: Width of the large preview image
|
||||
large_image_width = int
|
||||
large_image_width = None
|
||||
#: Height of the large preview image
|
||||
large_image_height = int
|
||||
large_image_height = None
|
||||
|
||||
def __init__(self, size=None, width=None, height=None, duration=None, preview_url=None, small_image=None, medium_image=None, large_image=None, **kwargs):
|
||||
"""Represents a video that has been sent as a Facebook attachment"""
|
||||
@@ -405,11 +418,11 @@ class VideoAttachment(Attachment):
|
||||
|
||||
class Mention(object):
|
||||
#: The thread ID the mention is pointing at
|
||||
thread_id = str
|
||||
thread_id = None
|
||||
#: The character where the mention starts
|
||||
offset = int
|
||||
offset = None
|
||||
#: The length of the mention
|
||||
length = int
|
||||
length = None
|
||||
|
||||
def __init__(self, thread_id, offset=0, length=10):
|
||||
"""Represents a @mention"""
|
||||
@@ -438,10 +451,10 @@ class ThreadType(Enum):
|
||||
|
||||
class ThreadLocation(Enum):
|
||||
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
|
||||
INBOX = 'inbox'
|
||||
PENDING = 'pending'
|
||||
ARCHIVED = 'action:archived'
|
||||
OTHER = 'other'
|
||||
INBOX = 'INBOX'
|
||||
PENDING = 'PENDING'
|
||||
ARCHIVED = 'ARCHIVED'
|
||||
OTHER = 'OTHER'
|
||||
|
||||
class TypingStatus(Enum):
|
||||
"""Used to specify whether the user is typing or has stopped typing"""
|
||||
|
2
setup.py
2
setup.py
@@ -54,10 +54,8 @@ setup(
|
||||
classifiers=[
|
||||
'Development Status :: 2 - Pre-Alpha',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
|
3
tests.py
3
tests.py
@@ -123,7 +123,8 @@ class TestFbchat(unittest.TestCase):
|
||||
self.assertTrue(client.sendLocalImage(image_local_url, Message(text='test_send_image_local_to__@you★', mentions=mentions)))
|
||||
|
||||
def test_fetchThreadList(self):
|
||||
client.fetchThreadList(offset=0, limit=20)
|
||||
threads = client.fetchThreadList(limit=2)
|
||||
self.assertEqual(len(threads), 2)
|
||||
|
||||
def test_fetchThreadMessages(self):
|
||||
for thread in threads:
|
||||
|
Reference in New Issue
Block a user