Merge from upstream and solve conflict in fbchat/client.py
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from datetime import datetime
|
||||
from .client import *
|
||||
|
||||
|
||||
"""
|
||||
fbchat
|
||||
~~~~~~
|
||||
|
||||
Facebook Chat (Messenger) for Python
|
||||
|
||||
:copyright: (c) 2015 by Taehoon Kim.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
:copyright: (c) 2015 - 2018 by Taehoon Kim
|
||||
:license: BSD 3-Clause, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .client import *
|
||||
|
||||
__title__ = 'fbchat'
|
||||
__version__ = '1.4.0'
|
||||
__description__ = 'Facebook Chat (Messenger) for Python'
|
||||
|
||||
__copyright__ = 'Copyright 2015 - 2018 by Taehoon Kim'
|
||||
__license__ = 'BSD 3-Clause'
|
||||
|
||||
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
|
||||
__version__ = '1.3.7'
|
||||
__license__ = 'BSD'
|
||||
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
|
||||
__email__ = 'carpedm20@gmail.com'
|
||||
__source__ = 'https://github.com/carpedm20/fbchat/'
|
||||
__description__ = 'Facebook Chat (Messenger) for Python'
|
||||
|
||||
__all__ = [
|
||||
'Client',
|
||||
|
1299
fbchat/client.py
1299
fbchat/client.py
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ def get_customization_info(thread):
|
||||
'emoji': info.get('emoji'),
|
||||
'color': graphql_color_to_enum(info.get('outgoing_bubble_color'))
|
||||
}
|
||||
if thread.get('thread_type') in ('GROUP', 'ROOM') or thread.get('is_group_thread') or thread.get('thread_key', {}).get('thread_fbid'):
|
||||
if thread.get('thread_type') == 'GROUP' or thread.get('is_group_thread') or thread.get('thread_key', {}).get('thread_fbid'):
|
||||
rtn['nicknames'] = {}
|
||||
for k in info.get('participant_customizations', []):
|
||||
rtn['nicknames'][k['participant_id']] = k.get('nickname')
|
||||
@@ -128,6 +128,71 @@ def graphql_to_attachment(a):
|
||||
uid=a.get('legacy_attachment_id')
|
||||
)
|
||||
|
||||
def graphql_to_poll(a):
|
||||
rtn = Poll(
|
||||
title=a.get('title') if a.get('title') else a.get("text"),
|
||||
options=[graphql_to_poll_option(m) for m in a.get('options')]
|
||||
)
|
||||
rtn.uid = int(a["id"])
|
||||
rtn.options_count = a.get("total_count")
|
||||
return rtn
|
||||
|
||||
def graphql_to_poll_option(a):
|
||||
if a.get('viewer_has_voted') is None:
|
||||
vote = None
|
||||
elif isinstance(a['viewer_has_voted'], bool):
|
||||
vote = a['viewer_has_voted']
|
||||
else:
|
||||
vote = a['viewer_has_voted'] == 'true'
|
||||
rtn = PollOption(
|
||||
text=a.get('text'),
|
||||
vote=vote
|
||||
)
|
||||
rtn.uid = int(a["id"])
|
||||
rtn.voters = [m.get('node').get('id') for m in a.get('voters').get('edges')] if isinstance(a.get('voters'), dict) else a.get('voters')
|
||||
rtn.votes_count = a.get('voters').get('count') if isinstance(a.get('voters'), dict) else a.get('total_count')
|
||||
return rtn
|
||||
|
||||
def graphql_to_plan(a):
|
||||
if a.get('event_members'):
|
||||
rtn = Plan(
|
||||
time=a.get('event_time'),
|
||||
title=a.get('title'),
|
||||
location=a.get('location_name')
|
||||
)
|
||||
if a.get('location_id') != 0:
|
||||
rtn.location_id = str(a.get('location_id'))
|
||||
rtn.uid = a.get('oid')
|
||||
rtn.author_id = a.get('creator_id')
|
||||
guests = a.get("event_members")
|
||||
rtn.going = [uid for uid in guests if guests[uid] == "GOING"]
|
||||
rtn.declined = [uid for uid in guests if guests[uid] == "DECLINED"]
|
||||
rtn.invited = [uid for uid in guests if guests[uid] == "INVITED"]
|
||||
return rtn
|
||||
elif a.get('id') is None:
|
||||
rtn = Plan(
|
||||
time=a.get('event_time'),
|
||||
title=a.get('event_title'),
|
||||
location=a.get('event_location_name'),
|
||||
location_id=a.get('event_location_id')
|
||||
)
|
||||
rtn.uid = a.get('event_id')
|
||||
rtn.author_id = a.get('event_creator_id')
|
||||
guests = json.loads(a.get('guest_state_list'))
|
||||
else:
|
||||
rtn = Plan(
|
||||
time=a.get('time'),
|
||||
title=a.get('event_title'),
|
||||
location=a.get('location_name')
|
||||
)
|
||||
rtn.uid = a.get('id')
|
||||
rtn.author_id = a.get('lightweight_event_creator').get('id')
|
||||
guests = a.get('event_reminder_members').get('edges')
|
||||
rtn.going = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "GOING"]
|
||||
rtn.declined = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "DECLINED"]
|
||||
rtn.invited = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "INVITED"]
|
||||
return rtn
|
||||
|
||||
def graphql_to_message(message):
|
||||
if message.get('message_sender') is None:
|
||||
message['message_sender'] = {}
|
||||
@@ -155,6 +220,9 @@ def graphql_to_user(user):
|
||||
if user.get('profile_picture') is None:
|
||||
user['profile_picture'] = {}
|
||||
c_info = get_customization_info(user)
|
||||
plan = None
|
||||
if user.get('event_reminders'):
|
||||
plan = graphql_to_plan(user['event_reminders']['nodes'][0]) if user['event_reminders'].get('nodes') else None
|
||||
return User(
|
||||
user['id'],
|
||||
url=user.get('url'),
|
||||
@@ -169,7 +237,8 @@ def graphql_to_user(user):
|
||||
own_nickname=c_info.get('own_nickname'),
|
||||
photo=user['profile_picture'].get('uri'),
|
||||
name=user.get('name'),
|
||||
message_count=user.get('messages_count')
|
||||
message_count=user.get('messages_count'),
|
||||
plan=plan,
|
||||
)
|
||||
|
||||
def graphql_to_thread(thread):
|
||||
@@ -185,12 +254,22 @@ def graphql_to_thread(thread):
|
||||
if 'last_message' in thread:
|
||||
last_message_timestamp = thread['last_message']['nodes'][0]['timestamp_precise']
|
||||
|
||||
first_name = user.get('short_name')
|
||||
if first_name is None:
|
||||
last_name = None
|
||||
else:
|
||||
last_name = user.get('name').split(first_name, 1).pop().strip()
|
||||
|
||||
plan = None
|
||||
if thread.get('event_reminders'):
|
||||
plan = graphql_to_plan(thread['event_reminders']['nodes'][0]) if thread['event_reminders'].get('nodes') else None
|
||||
|
||||
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).pop().strip(),
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
is_friend=user.get('is_viewer_friend'),
|
||||
gender=GENDERS.get(user.get('gender')),
|
||||
affinity=user.get('affinity'),
|
||||
@@ -200,7 +279,8 @@ def graphql_to_thread(thread):
|
||||
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
|
||||
last_message_timestamp=last_message_timestamp,
|
||||
plan=plan,
|
||||
)
|
||||
else:
|
||||
raise FBchatException('Unknown thread type: {}, with data: {}'.format(thread.get('thread_type'), thread))
|
||||
@@ -212,36 +292,24 @@ def graphql_to_group(group):
|
||||
last_message_timestamp = None
|
||||
if 'last_message' in group:
|
||||
last_message_timestamp = group['last_message']['nodes'][0]['timestamp_precise']
|
||||
plan = None
|
||||
if group.get('event_reminders'):
|
||||
plan = graphql_to_plan(group['event_reminders']['nodes'][0]) if group['event_reminders'].get('nodes') else None
|
||||
return Group(
|
||||
group['thread_key']['thread_fbid'],
|
||||
participants=set([node['messaging_actor']['id'] for node in group['all_participants']['nodes']]),
|
||||
nicknames=c_info.get('nicknames'),
|
||||
color=c_info.get('color'),
|
||||
emoji=c_info.get('emoji'),
|
||||
admins = set([node.get('id') for node in group.get('thread_admins')]),
|
||||
approval_mode = bool(group.get('approval_mode')),
|
||||
approval_requests = set(node["requester"]['id'] for node in group['group_approval_queue']['nodes']),
|
||||
join_link = group['joinable_mode'].get('link'),
|
||||
photo=group['image'].get('uri'),
|
||||
name=group.get('name'),
|
||||
message_count=group.get('messages_count'),
|
||||
last_message_timestamp=last_message_timestamp
|
||||
)
|
||||
|
||||
def graphql_to_room(room):
|
||||
if room.get('image') is None:
|
||||
room['image'] = {}
|
||||
c_info = get_customization_info(room)
|
||||
return Room(
|
||||
room['thread_key']['thread_fbid'],
|
||||
participants=set([node['messaging_actor']['id'] for node in room['all_participants']['nodes']]),
|
||||
nicknames=c_info.get('nicknames'),
|
||||
color=c_info.get('color'),
|
||||
emoji=c_info.get('emoji'),
|
||||
photo=room['image'].get('uri'),
|
||||
name=room.get('name'),
|
||||
message_count=room.get('messages_count'),
|
||||
admins = set([node.get('id') for node in room.get('thread_admins')]),
|
||||
approval_mode = bool(room.get('approval_mode')),
|
||||
approval_requests = set(node.get('id') for node in room['thread_queue_metadata'].get('approval_requests', {}).get('nodes')),
|
||||
join_link = room['joinable_mode'].get('link'),
|
||||
privacy_mode = bool(room.get('privacy_mode')),
|
||||
last_message_timestamp=last_message_timestamp,
|
||||
plan=plan,
|
||||
)
|
||||
|
||||
def graphql_to_page(page):
|
||||
@@ -249,6 +317,9 @@ def graphql_to_page(page):
|
||||
page['profile_picture'] = {}
|
||||
if page.get('city') is None:
|
||||
page['city'] = {}
|
||||
plan = None
|
||||
if page.get('event_reminders'):
|
||||
plan = graphql_to_plan(page['event_reminders']['nodes'][0]) if page['event_reminders'].get('nodes') else None
|
||||
return Page(
|
||||
page['id'],
|
||||
url=page.get('url'),
|
||||
@@ -256,7 +327,8 @@ def graphql_to_page(page):
|
||||
category=page.get('category_type'),
|
||||
photo=page['profile_picture'].get('uri'),
|
||||
name=page.get('name'),
|
||||
message_count=page.get('messages_count')
|
||||
message_count=page.get('messages_count'),
|
||||
plan=plan,
|
||||
)
|
||||
|
||||
def graphql_queries_to_json(*queries):
|
||||
@@ -351,6 +423,40 @@ class GraphQL(object):
|
||||
},
|
||||
outgoing_bubble_color,
|
||||
emoji
|
||||
},
|
||||
thread_admins {
|
||||
id
|
||||
},
|
||||
group_approval_queue {
|
||||
nodes {
|
||||
requester {
|
||||
id
|
||||
}
|
||||
}
|
||||
},
|
||||
approval_mode,
|
||||
joinable_mode {
|
||||
mode,
|
||||
link
|
||||
},
|
||||
event_reminders {
|
||||
nodes {
|
||||
id,
|
||||
lightweight_event_creator {
|
||||
id
|
||||
},
|
||||
time,
|
||||
location_name,
|
||||
event_title,
|
||||
event_reminder_members {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
},
|
||||
guest_list_state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
126
fbchat/models.py
126
fbchat/models.py
@@ -37,7 +37,9 @@ class Thread(object):
|
||||
last_message_timestamp = None
|
||||
#: Number of messages in the thread
|
||||
message_count = None
|
||||
def __init__(self, _type, uid, photo=None, name=None, last_message_timestamp=None, message_count=None):
|
||||
#: Set :class:`Plan`
|
||||
plan = None
|
||||
def __init__(self, _type, uid, photo=None, name=None, last_message_timestamp=None, message_count=None, plan=None):
|
||||
"""Represents a Facebook thread"""
|
||||
self.uid = str(uid)
|
||||
self.type = _type
|
||||
@@ -45,6 +47,7 @@ class Thread(object):
|
||||
self.name = name
|
||||
self.last_message_timestamp = last_message_timestamp
|
||||
self.message_count = message_count
|
||||
self.plan = plan
|
||||
|
||||
def __repr__(self):
|
||||
return self.__unicode__()
|
||||
@@ -99,8 +102,16 @@ class Group(Thread):
|
||||
color = None
|
||||
#: The groups's default emoji
|
||||
emoji = None
|
||||
# Set containing user IDs of thread admins
|
||||
admins = None
|
||||
# True if users need approval to join
|
||||
approval_mode = None
|
||||
# Set containing user IDs requesting to join
|
||||
approval_requests = None
|
||||
# Link for joining group
|
||||
join_link = None
|
||||
|
||||
def __init__(self, uid, participants=None, nicknames=None, color=None, emoji=None, **kwargs):
|
||||
def __init__(self, uid, participants=None, nicknames=None, color=None, emoji=None, admins=None, approval_mode=None, approval_requests=None, join_link=None, privacy_mode=None, **kwargs):
|
||||
"""Represents a Facebook group. Inherits `Thread`"""
|
||||
super(Group, self).__init__(ThreadType.GROUP, uid, **kwargs)
|
||||
if participants is None:
|
||||
@@ -111,24 +122,6 @@ class Group(Thread):
|
||||
self.nicknames = nicknames
|
||||
self.color = color
|
||||
self.emoji = emoji
|
||||
|
||||
|
||||
class Room(Group):
|
||||
# Set containing user IDs of thread admins
|
||||
admins = None
|
||||
# True if users need approval to join
|
||||
approval_mode = None
|
||||
# Set containing user IDs requesting to join
|
||||
approval_requests = None
|
||||
# Link for joining room
|
||||
join_link = None
|
||||
# True is room is not discoverable
|
||||
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`"""
|
||||
super(Room, self).__init__(uid, **kwargs)
|
||||
self.type = ThreadType.ROOM
|
||||
if admins is None:
|
||||
admins = set()
|
||||
self.admins = admins
|
||||
@@ -137,6 +130,16 @@ class Room(Group):
|
||||
approval_requests = set()
|
||||
self.approval_requests = approval_requests
|
||||
self.join_link = join_link
|
||||
|
||||
|
||||
class Room(Group):
|
||||
# True is room is not discoverable
|
||||
privacy_mode = None
|
||||
|
||||
def __init__(self, uid, privacy_mode=None, **kwargs):
|
||||
"""Deprecated. Use :class:`Group` instead"""
|
||||
super(Room, self).__init__(uid, **kwargs)
|
||||
self.type = ThreadType.ROOM
|
||||
self.privacy_mode = privacy_mode
|
||||
|
||||
|
||||
@@ -436,6 +439,87 @@ class Mention(object):
|
||||
def __unicode__(self):
|
||||
return '<Mention {}: offset={} length={}>'.format(self.thread_id, self.offset, self.length)
|
||||
|
||||
class Poll(object):
|
||||
#: ID of the poll
|
||||
uid = None
|
||||
#: Title of the poll
|
||||
title = None
|
||||
#: List of :class:`PollOption`, can be fetched with :func:`fbchat.Client.fetchPollOptions`
|
||||
options = None
|
||||
#: Options count
|
||||
options_count = None
|
||||
|
||||
def __init__(self, title, options):
|
||||
"""Represents a poll"""
|
||||
self.title = title
|
||||
self.options = options
|
||||
|
||||
def __repr__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
def __unicode__(self):
|
||||
return '<Poll ({}): {} options={}>'.format(self.uid, repr(self.title), self.options)
|
||||
|
||||
class PollOption(object):
|
||||
#: ID of the poll option
|
||||
uid = None
|
||||
#: Text of the poll option
|
||||
text = None
|
||||
#: Whether vote when creating or client voted
|
||||
vote = None
|
||||
#: ID of the users who voted for this poll option
|
||||
voters = None
|
||||
#: Votes count
|
||||
votes_count = None
|
||||
|
||||
def __init__(self, text, vote=False):
|
||||
"""Represents a poll option"""
|
||||
self.text = text
|
||||
self.vote = vote
|
||||
|
||||
def __repr__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
def __unicode__(self):
|
||||
return '<PollOption ({}): {} voters={}>'.format(self.uid, repr(self.text), self.voters)
|
||||
|
||||
class Plan(object):
|
||||
#: ID of the plan
|
||||
uid = None
|
||||
#: Plan time (unix time stamp), only precise down to the minute
|
||||
time = None
|
||||
#: Plan title
|
||||
title = None
|
||||
#: Plan location name
|
||||
location = None
|
||||
#: Plan location ID
|
||||
location_id = None
|
||||
#: ID of the plan creator
|
||||
author_id = None
|
||||
#: List of the people IDs who will take part in the plan
|
||||
going = None
|
||||
#: List of the people IDs who won't take part in the plan
|
||||
declined = None
|
||||
#: List of the people IDs who are invited to the plan
|
||||
invited = None
|
||||
|
||||
def __init__(self, time, title, location=None, location_id=None):
|
||||
"""Represents a plan"""
|
||||
self.time = int(time)
|
||||
self.title = title
|
||||
self.location = location or ''
|
||||
self.location_id = location_id or ''
|
||||
self.author_id = None
|
||||
self.going = []
|
||||
self.declined = []
|
||||
self.invited = []
|
||||
|
||||
def __repr__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
def __unicode__(self):
|
||||
return '<Plan ({}): {} time={}, location={}, location_id={}>'.format(self.uid, repr(self.title), self.time, repr(self.location), repr(self.location_id))
|
||||
|
||||
class Enum(enum.Enum):
|
||||
"""Used internally by fbchat to support enumerations"""
|
||||
def __repr__(self):
|
||||
@@ -446,8 +530,8 @@ class ThreadType(Enum):
|
||||
"""Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info"""
|
||||
USER = 1
|
||||
GROUP = 2
|
||||
ROOM = 2
|
||||
PAGE = 3
|
||||
ROOM = 4
|
||||
|
||||
class ThreadLocation(Enum):
|
||||
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
|
||||
|
@@ -5,8 +5,12 @@ import re
|
||||
import json
|
||||
from time import time
|
||||
from random import random
|
||||
from contextlib import contextmanager
|
||||
from mimetypes import guess_type
|
||||
from os.path import basename
|
||||
import warnings
|
||||
import logging
|
||||
import requests
|
||||
from .models import *
|
||||
|
||||
try:
|
||||
@@ -48,16 +52,6 @@ LIKES = {
|
||||
's': EmojiSize.SMALL
|
||||
}
|
||||
|
||||
MessageReactionFix = {
|
||||
'😍': ('0001f60d', '%F0%9F%98%8D'),
|
||||
'😆': ('0001f606', '%F0%9F%98%86'),
|
||||
'😮': ('0001f62e', '%F0%9F%98%AE'),
|
||||
'😢': ('0001f622', '%F0%9F%98%A2'),
|
||||
'😠': ('0001f620', '%F0%9F%98%A0'),
|
||||
'👍': ('0001f44d', '%F0%9F%91%8D'),
|
||||
'👎': ('0001f44e', '%F0%9F%91%8E')
|
||||
}
|
||||
|
||||
|
||||
GENDERS = {
|
||||
# For standard requests
|
||||
@@ -97,6 +91,9 @@ class ReqUrl(object):
|
||||
UNREAD_THREADS = "https://www.facebook.com/ajax/mercury/unread_threads.php"
|
||||
UNSEEN_THREADS = "https://www.facebook.com/mercury/unseen_thread_ids/"
|
||||
THREADS = "https://www.facebook.com/ajax/mercury/threadlist_info.php"
|
||||
MOVE_THREAD = "https://www.facebook.com/ajax/mercury/move_thread.php"
|
||||
ARCHIVED_STATUS = "https://www.facebook.com/ajax/mercury/change_archived_status.php?dpr=1"
|
||||
PINNED_STATUS = "https://www.facebook.com/ajax/mercury/change_pinned_status.php?dpr=1"
|
||||
MESSAGES = "https://www.facebook.com/ajax/mercury/thread_info.php"
|
||||
READ_STATUS = "https://www.facebook.com/ajax/mercury/change_read_status.php"
|
||||
DELIVERED = "https://www.facebook.com/ajax/mercury/delivery_receipts.php"
|
||||
@@ -116,12 +113,33 @@ class ReqUrl(object):
|
||||
THREAD_COLOR = "https://www.facebook.com/messaging/save_thread_color/?source=thread_settings&dpr=1"
|
||||
THREAD_NICKNAME = "https://www.facebook.com/messaging/save_thread_nickname/?source=thread_settings&dpr=1"
|
||||
THREAD_EMOJI = "https://www.facebook.com/messaging/save_thread_emoji/?source=thread_settings&dpr=1"
|
||||
THREAD_IMAGE = "https://www.facebook.com/messaging/set_thread_image/?dpr=1"
|
||||
THREAD_NAME = "https://www.facebook.com/messaging/set_thread_name/?dpr=1"
|
||||
MESSAGE_REACTION = "https://www.facebook.com/webgraphql/mutation"
|
||||
TYPING = "https://www.facebook.com/ajax/messaging/typ.php"
|
||||
GRAPHQL = "https://www.facebook.com/api/graphqlbatch/"
|
||||
ATTACHMENT_PHOTO = "https://www.facebook.com/mercury/attachments/photo/"
|
||||
EVENT_REMINDER = "https://www.facebook.com/ajax/eventreminder/create"
|
||||
PLAN_CREATE = "https://www.facebook.com/ajax/eventreminder/create"
|
||||
PLAN_INFO = "https://www.facebook.com/ajax/eventreminder"
|
||||
PLAN_CHANGE = "https://www.facebook.com/ajax/eventreminder/submit"
|
||||
PLAN_PARTICIPATION = "https://www.facebook.com/ajax/eventreminder/rsvp"
|
||||
MODERN_SETTINGS_MENU = "https://www.facebook.com/bluebar/modern_settings_menu/"
|
||||
REMOVE_FRIEND = "https://m.facebook.com/a/removefriend.php"
|
||||
BLOCK_USER = "https://www.facebook.com/messaging/block_messages/?dpr=1"
|
||||
UNBLOCK_USER = "https://www.facebook.com/messaging/unblock_messages/?dpr=1"
|
||||
SAVE_ADMINS = "https://www.facebook.com/messaging/save_admins/?dpr=1"
|
||||
APPROVAL_MODE = "https://www.facebook.com/messaging/set_approval_mode/?dpr=1"
|
||||
CREATE_GROUP = "https://m.facebook.com/messages/send/?icm=1"
|
||||
DELETE_THREAD = "https://www.facebook.com/ajax/mercury/delete_thread.php?dpr=1"
|
||||
DELETE_MESSAGES = "https://www.facebook.com/ajax/mercury/delete_messages.php?dpr=1"
|
||||
MUTE_THREAD = "https://www.facebook.com/ajax/mercury/change_mute_thread.php?dpr=1"
|
||||
MUTE_REACTIONS = "https://www.facebook.com/ajax/mercury/change_reactions_mute_thread/?dpr=1"
|
||||
MUTE_MENTIONS = "https://www.facebook.com/ajax/mercury/change_mentions_mute_thread/?dpr=1"
|
||||
CREATE_POLL = "https://www.facebook.com/messaging/group_polling/create_poll/?dpr=1"
|
||||
UPDATE_VOTE = "https://www.facebook.com/messaging/group_polling/update_vote/?dpr=1"
|
||||
GET_POLL_OPTIONS = "https://www.facebook.com/ajax/mercury/get_poll_options"
|
||||
SEARCH_MESSAGES = "https://www.facebook.com/ajax/mercury/search_snippets.php?dpr=1"
|
||||
MARK_SPAM = "https://www.facebook.com/ajax/mercury/mark_spam.php?dpr=1"
|
||||
|
||||
pull_channel = 0
|
||||
|
||||
@@ -143,7 +161,7 @@ def strip_to_json(text):
|
||||
try:
|
||||
return text[text.index('{'):]
|
||||
except ValueError:
|
||||
raise FBchatException('No JSON object found: {}, {}'.format(repr(text), text.index('{')))
|
||||
raise FBchatException('No JSON object found: {!r}'.format(text))
|
||||
|
||||
def get_decoded_r(r):
|
||||
return get_decoded(r._content)
|
||||
@@ -210,8 +228,9 @@ def check_request(r, as_json=True):
|
||||
try:
|
||||
j = json.loads(content)
|
||||
except ValueError:
|
||||
raise FBchatFacebookError('Error while parsing JSON: {}'.format(repr(content)))
|
||||
raise FBchatFacebookError('Error while parsing JSON: {!r}'.format(content))
|
||||
check_json(j)
|
||||
log.debug(j)
|
||||
return j
|
||||
else:
|
||||
return content
|
||||
@@ -234,3 +253,47 @@ def get_emojisize_from_tags(tags):
|
||||
except (KeyError, IndexError):
|
||||
log.exception('Could not determine emoji size from {} - {}'.format(tags, tmp))
|
||||
return None
|
||||
|
||||
def require_list(list_):
|
||||
if isinstance(list_, list):
|
||||
return set(list_)
|
||||
else:
|
||||
return set([list_])
|
||||
|
||||
def mimetype_to_key(mimetype):
|
||||
if not mimetype:
|
||||
return "file_id"
|
||||
if mimetype == "image/gif":
|
||||
return "gif_id"
|
||||
x = mimetype.split("/")
|
||||
if x[0] in ["video", "image", "audio"]:
|
||||
return "%s_id" % x[0]
|
||||
return "file_id"
|
||||
|
||||
|
||||
def get_files_from_urls(file_urls):
|
||||
files = []
|
||||
for file_url in file_urls:
|
||||
r = requests.get(file_url)
|
||||
# We could possibly use r.headers.get('Content-Disposition'), see
|
||||
# https://stackoverflow.com/a/37060758
|
||||
files.append((
|
||||
basename(file_url),
|
||||
r.content,
|
||||
r.headers.get('Content-Type') or guess_type(file_url)[0],
|
||||
))
|
||||
return files
|
||||
|
||||
|
||||
@contextmanager
|
||||
def get_files_from_paths(filenames):
|
||||
files = []
|
||||
for filename in filenames:
|
||||
files.append((
|
||||
basename(filename),
|
||||
open(filename, 'rb'),
|
||||
guess_type(filename)[0],
|
||||
))
|
||||
yield files
|
||||
for fn, fp, ft in files:
|
||||
fp.close()
|
||||
|
Reference in New Issue
Block a user