Format strings using black
This commit is contained in:
50
docs/conf.py
50
docs/conf.py
@@ -20,7 +20,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
sys.path.insert(0, os.path.abspath(".."))
|
||||||
|
|
||||||
import fbchat
|
import fbchat
|
||||||
import tests
|
import tests
|
||||||
@@ -37,27 +37,27 @@ from fbchat import __copyright__, __author__, __version__, __description__
|
|||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
'sphinx.ext.intersphinx',
|
"sphinx.ext.intersphinx",
|
||||||
'sphinx.ext.todo',
|
"sphinx.ext.todo",
|
||||||
'sphinx.ext.viewcode',
|
"sphinx.ext.viewcode",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
# You can specify multiple suffix as a list of string:
|
# You can specify multiple suffix as a list of string:
|
||||||
#
|
#
|
||||||
# source_suffix = ['.rst', '.md']
|
# source_suffix = ['.rst', '.md']
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = 'fbchat'
|
project = "fbchat"
|
||||||
title = 'fbchat Documentation'
|
title = "fbchat Documentation"
|
||||||
copyright = __copyright__
|
copyright = __copyright__
|
||||||
author = __author__
|
author = __author__
|
||||||
description = __description__
|
description = __description__
|
||||||
@@ -81,10 +81,10 @@ language = None
|
|||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
# This patterns also effect to html_static_path and html_extra_path
|
# This patterns also effect to html_static_path and html_extra_path
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'sphinx'
|
pygments_style = "sphinx"
|
||||||
|
|
||||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
todo_include_todos = True
|
todo_include_todos = True
|
||||||
@@ -96,7 +96,7 @@ todo_include_todos = True
|
|||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
|
|
||||||
html_theme = 'alabaster'
|
html_theme = "alabaster"
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
@@ -107,13 +107,13 @@ html_theme = 'alabaster'
|
|||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTMLHelp output ------------------------------------------
|
# -- Options for HTMLHelp output ------------------------------------------
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = project + 'doc'
|
htmlhelp_basename = project + "doc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
@@ -136,7 +136,7 @@ latex_elements = {
|
|||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [(master_doc, project + '.tex', title, author, 'manual')]
|
latex_documents = [(master_doc, project + ".tex", title, author, "manual")]
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ---------------------------------------
|
# -- Options for manual page output ---------------------------------------
|
||||||
@@ -152,27 +152,27 @@ man_pages = [(master_doc, project, title, [author], 1)]
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
(master_doc, project, title, author, project, description, 'Miscellaneous')
|
(master_doc, project, title, author, project, description, "Miscellaneous")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
intersphinx_mapping = {'https://docs.python.org/3/': None}
|
intersphinx_mapping = {"https://docs.python.org/3/": None}
|
||||||
|
|
||||||
|
|
||||||
add_function_parentheses = False
|
add_function_parentheses = False
|
||||||
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
'show_powered_by': False,
|
"show_powered_by": False,
|
||||||
'github_user': 'carpedm20',
|
"github_user": "carpedm20",
|
||||||
'github_repo': project,
|
"github_repo": project,
|
||||||
'github_banner': True,
|
"github_banner": True,
|
||||||
'show_related': False,
|
"show_related": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
html_sidebars = {'**': ['sidebar.html', 'searchbox.html']}
|
html_sidebars = {"**": ["sidebar.html", "searchbox.html"]}
|
||||||
|
|
||||||
html_show_sphinx = False
|
html_show_sphinx = False
|
||||||
html_show_sourcelink = False
|
html_show_sourcelink = False
|
||||||
autoclass_content = 'init'
|
autoclass_content = "init"
|
||||||
html_short_title = description
|
html_short_title = description
|
||||||
|
@@ -3,10 +3,10 @@
|
|||||||
from fbchat import Client
|
from fbchat import Client
|
||||||
from fbchat.models import *
|
from fbchat.models import *
|
||||||
|
|
||||||
client = Client('<email>', '<password>')
|
client = Client("<email>", "<password>")
|
||||||
|
|
||||||
print('Own id: {}'.format(client.uid))
|
print("Own id: {}".format(client.uid))
|
||||||
|
|
||||||
client.send(Message(text='Hi me!'), thread_id=client.uid, thread_type=ThreadType.USER)
|
client.send(Message(text="Hi me!"), thread_id=client.uid, thread_type=ThreadType.USER)
|
||||||
|
|
||||||
client.logout()
|
client.logout()
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
from fbchat import Client
|
from fbchat import Client
|
||||||
from fbchat.models import *
|
from fbchat.models import *
|
||||||
|
|
||||||
client = Client('<email>', '<password>')
|
client = Client("<email>", "<password>")
|
||||||
|
|
||||||
# Fetches a list of all users you're currently chatting with, as `User` objects
|
# Fetches a list of all users you're currently chatting with, as `User` objects
|
||||||
users = client.fetchAllUsers()
|
users = client.fetchAllUsers()
|
||||||
@@ -13,9 +13,9 @@ print("users' names: {}".format([user.name for user in users]))
|
|||||||
|
|
||||||
|
|
||||||
# If we have a user id, we can use `fetchUserInfo` to fetch a `User` object
|
# If we have a user id, we can use `fetchUserInfo` to fetch a `User` object
|
||||||
user = client.fetchUserInfo('<user id>')['<user id>']
|
user = client.fetchUserInfo("<user id>")["<user id>"]
|
||||||
# We can also query both mutiple users together, which returns list of `User` objects
|
# We can also query both mutiple users together, which returns list of `User` objects
|
||||||
users = client.fetchUserInfo('<1st user id>', '<2nd user id>', '<3rd user id>')
|
users = client.fetchUserInfo("<1st user id>", "<2nd user id>", "<3rd user id>")
|
||||||
|
|
||||||
print("user's name: {}".format(user.name))
|
print("user's name: {}".format(user.name))
|
||||||
print("users' names: {}".format([users[k].name for k in users]))
|
print("users' names: {}".format([users[k].name for k in users]))
|
||||||
@@ -23,9 +23,9 @@ print("users' names: {}".format([users[k].name for k in users]))
|
|||||||
|
|
||||||
# `searchForUsers` searches for the user and gives us a list of the results,
|
# `searchForUsers` searches for the user and gives us a list of the results,
|
||||||
# and then we just take the first one, aka. the most likely one:
|
# and then we just take the first one, aka. the most likely one:
|
||||||
user = client.searchForUsers('<name of user>')[0]
|
user = client.searchForUsers("<name of user>")[0]
|
||||||
|
|
||||||
print('user ID: {}'.format(user.uid))
|
print("user ID: {}".format(user.uid))
|
||||||
print("user's name: {}".format(user.name))
|
print("user's name: {}".format(user.name))
|
||||||
print("user's photo: {}".format(user.photo))
|
print("user's photo: {}".format(user.photo))
|
||||||
print("Is user client's friend: {}".format(user.is_friend))
|
print("Is user client's friend: {}".format(user.is_friend))
|
||||||
@@ -40,7 +40,7 @@ print("Threads: {}".format(threads))
|
|||||||
|
|
||||||
|
|
||||||
# Gets the last 10 messages sent to the thread
|
# Gets the last 10 messages sent to the thread
|
||||||
messages = client.fetchThreadMessages(thread_id='<thread id>', limit=10)
|
messages = client.fetchThreadMessages(thread_id="<thread id>", limit=10)
|
||||||
# Since the message come in reversed order, reverse them
|
# Since the message come in reversed order, reverse them
|
||||||
messages.reverse()
|
messages.reverse()
|
||||||
|
|
||||||
@@ -50,13 +50,13 @@ for message in messages:
|
|||||||
|
|
||||||
|
|
||||||
# If we have a thread id, we can use `fetchThreadInfo` to fetch a `Thread` object
|
# If we have a thread id, we can use `fetchThreadInfo` to fetch a `Thread` object
|
||||||
thread = client.fetchThreadInfo('<thread id>')['<thread id>']
|
thread = client.fetchThreadInfo("<thread id>")["<thread id>"]
|
||||||
print("thread's name: {}".format(thread.name))
|
print("thread's name: {}".format(thread.name))
|
||||||
print("thread's type: {}".format(thread.type))
|
print("thread's type: {}".format(thread.type))
|
||||||
|
|
||||||
|
|
||||||
# `searchForThreads` searches works like `searchForUsers`, but gives us a list of threads instead
|
# `searchForThreads` searches works like `searchForUsers`, but gives us a list of threads instead
|
||||||
thread = client.searchForThreads('<name of thread>')[0]
|
thread = client.searchForThreads("<name of thread>")[0]
|
||||||
print("thread's name: {}".format(thread.name))
|
print("thread's name: {}".format(thread.name))
|
||||||
print("thread's type: {}".format(thread.type))
|
print("thread's type: {}".format(thread.type))
|
||||||
|
|
||||||
|
@@ -5,11 +5,11 @@ from fbchat.models import *
|
|||||||
|
|
||||||
client = Client("<email>", "<password>")
|
client = Client("<email>", "<password>")
|
||||||
|
|
||||||
thread_id = '1234567890'
|
thread_id = "1234567890"
|
||||||
thread_type = ThreadType.GROUP
|
thread_type = ThreadType.GROUP
|
||||||
|
|
||||||
# Will send a message to the thread
|
# Will send a message to the thread
|
||||||
client.send(Message(text='<message>'), thread_id=thread_id, thread_type=thread_type)
|
client.send(Message(text="<message>"), thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
# Will send the default `like` emoji
|
# Will send the default `like` emoji
|
||||||
client.send(
|
client.send(
|
||||||
@@ -18,14 +18,14 @@ client.send(
|
|||||||
|
|
||||||
# Will send the emoji `👍`
|
# Will send the emoji `👍`
|
||||||
client.send(
|
client.send(
|
||||||
Message(text='👍', emoji_size=EmojiSize.LARGE),
|
Message(text="👍", emoji_size=EmojiSize.LARGE),
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
thread_type=thread_type,
|
thread_type=thread_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Will send the sticker with ID `767334476626295`
|
# Will send the sticker with ID `767334476626295`
|
||||||
client.send(
|
client.send(
|
||||||
Message(sticker=Sticker('767334476626295')),
|
Message(sticker=Sticker("767334476626295")),
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
thread_type=thread_type,
|
thread_type=thread_type,
|
||||||
)
|
)
|
||||||
@@ -33,7 +33,7 @@ client.send(
|
|||||||
# Will send a message with a mention
|
# Will send a message with a mention
|
||||||
client.send(
|
client.send(
|
||||||
Message(
|
Message(
|
||||||
text='This is a @mention', mentions=[Mention(thread_id, offset=10, length=8)]
|
text="This is a @mention", mentions=[Mention(thread_id, offset=10, length=8)]
|
||||||
),
|
),
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
thread_type=thread_type,
|
thread_type=thread_type,
|
||||||
@@ -41,16 +41,16 @@ client.send(
|
|||||||
|
|
||||||
# Will send the image located at `<image path>`
|
# Will send the image located at `<image path>`
|
||||||
client.sendLocalImage(
|
client.sendLocalImage(
|
||||||
'<image path>',
|
"<image path>",
|
||||||
message=Message(text='This is a local image'),
|
message=Message(text="This is a local image"),
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
thread_type=thread_type,
|
thread_type=thread_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Will download the image at the url `<image url>`, and then send it
|
# Will download the image at the url `<image url>`, and then send it
|
||||||
client.sendRemoteImage(
|
client.sendRemoteImage(
|
||||||
'<image url>',
|
"<image url>",
|
||||||
message=Message(text='This is a remote image'),
|
message=Message(text="This is a remote image"),
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
thread_type=thread_type,
|
thread_type=thread_type,
|
||||||
)
|
)
|
||||||
@@ -59,24 +59,24 @@ client.sendRemoteImage(
|
|||||||
# Only do these actions if the thread is a group
|
# Only do these actions if the thread is a group
|
||||||
if thread_type == ThreadType.GROUP:
|
if thread_type == ThreadType.GROUP:
|
||||||
# Will remove the user with ID `<user id>` from the thread
|
# Will remove the user with ID `<user id>` from the thread
|
||||||
client.removeUserFromGroup('<user id>', thread_id=thread_id)
|
client.removeUserFromGroup("<user id>", thread_id=thread_id)
|
||||||
|
|
||||||
# Will add the user with ID `<user id>` to the thread
|
# Will add the user with ID `<user id>` to the thread
|
||||||
client.addUsersToGroup('<user id>', thread_id=thread_id)
|
client.addUsersToGroup("<user id>", thread_id=thread_id)
|
||||||
|
|
||||||
# Will add the users with IDs `<1st user id>`, `<2nd user id>` and `<3th user id>` to the thread
|
# Will add the users with IDs `<1st user id>`, `<2nd user id>` and `<3th user id>` to the thread
|
||||||
client.addUsersToGroup(
|
client.addUsersToGroup(
|
||||||
['<1st user id>', '<2nd user id>', '<3rd user id>'], thread_id=thread_id
|
["<1st user id>", "<2nd user id>", "<3rd user id>"], thread_id=thread_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Will change the nickname of the user `<user_id>` to `<new nickname>`
|
# Will change the nickname of the user `<user_id>` to `<new nickname>`
|
||||||
client.changeNickname(
|
client.changeNickname(
|
||||||
'<new nickname>', '<user id>', thread_id=thread_id, thread_type=thread_type
|
"<new nickname>", "<user id>", thread_id=thread_id, thread_type=thread_type
|
||||||
)
|
)
|
||||||
|
|
||||||
# Will change the title of the thread to `<title>`
|
# Will change the title of the thread to `<title>`
|
||||||
client.changeThreadTitle('<title>', thread_id=thread_id, thread_type=thread_type)
|
client.changeThreadTitle("<title>", thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
# Will set the typing status of the thread to `TYPING`
|
# Will set the typing status of the thread to `TYPING`
|
||||||
client.setTypingStatus(
|
client.setTypingStatus(
|
||||||
@@ -87,7 +87,7 @@ client.setTypingStatus(
|
|||||||
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, thread_id=thread_id)
|
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, thread_id=thread_id)
|
||||||
|
|
||||||
# Will change the thread emoji to `👍`
|
# Will change the thread emoji to `👍`
|
||||||
client.changeThreadEmoji('👍', thread_id=thread_id)
|
client.changeThreadEmoji("👍", thread_id=thread_id)
|
||||||
|
|
||||||
# Will react to a message with a 😍 emoji
|
# Will react to a message with a 😍 emoji
|
||||||
client.reactToMessage('<message id>', MessageReaction.LOVE)
|
client.reactToMessage("<message id>", MessageReaction.LOVE)
|
||||||
|
@@ -4,17 +4,17 @@ from fbchat import log, Client
|
|||||||
from fbchat.models import *
|
from fbchat.models import *
|
||||||
|
|
||||||
# Change this to your group id
|
# Change this to your group id
|
||||||
old_thread_id = '1234567890'
|
old_thread_id = "1234567890"
|
||||||
|
|
||||||
# Change these to match your liking
|
# Change these to match your liking
|
||||||
old_color = ThreadColor.MESSENGER_BLUE
|
old_color = ThreadColor.MESSENGER_BLUE
|
||||||
old_emoji = '👍'
|
old_emoji = "👍"
|
||||||
old_title = 'Old group chat name'
|
old_title = "Old group chat name"
|
||||||
old_nicknames = {
|
old_nicknames = {
|
||||||
'12345678901': "User nr. 1's nickname",
|
"12345678901": "User nr. 1's nickname",
|
||||||
'12345678902': "User nr. 2's nickname",
|
"12345678902": "User nr. 2's nickname",
|
||||||
'12345678903': "User nr. 3's nickname",
|
"12345678903": "User nr. 3's nickname",
|
||||||
'12345678904': "User nr. 4's nickname",
|
"12345678904": "User nr. 4's nickname",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -7,8 +7,8 @@ from fbchat.models import *
|
|||||||
class RemoveBot(Client):
|
class RemoveBot(Client):
|
||||||
def onMessage(self, author_id, message_object, thread_id, thread_type, **kwargs):
|
def onMessage(self, author_id, message_object, thread_id, thread_type, **kwargs):
|
||||||
# We can only kick people from group chats, so no need to try if it's a user chat
|
# We can only kick people from group chats, so no need to try if it's a user chat
|
||||||
if message_object.text == 'Remove me!' and thread_type == ThreadType.GROUP:
|
if message_object.text == "Remove me!" and thread_type == ThreadType.GROUP:
|
||||||
log.info('{} will be removed from {}'.format(author_id, thread_id))
|
log.info("{} will be removed from {}".format(author_id, thread_id))
|
||||||
self.removeUserFromGroup(author_id, thread_id=thread_id)
|
self.removeUserFromGroup(author_id, thread_id=thread_id)
|
||||||
else:
|
else:
|
||||||
# Sends the data to the inherited onMessage, so that we can still see when a message is recieved
|
# Sends the data to the inherited onMessage, so that we can still see when a message is recieved
|
||||||
|
@@ -9,14 +9,14 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from .client import *
|
from .client import *
|
||||||
|
|
||||||
__title__ = 'fbchat'
|
__title__ = "fbchat"
|
||||||
__version__ = '1.6.1'
|
__version__ = "1.6.1"
|
||||||
__description__ = 'Facebook Chat (Messenger) for Python'
|
__description__ = "Facebook Chat (Messenger) for Python"
|
||||||
|
|
||||||
__copyright__ = 'Copyright 2015 - 2019 by Taehoon Kim'
|
__copyright__ = "Copyright 2015 - 2019 by Taehoon Kim"
|
||||||
__license__ = 'BSD 3-Clause'
|
__license__ = "BSD 3-Clause"
|
||||||
|
|
||||||
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
|
__author__ = "Taehoon Kim; Moreels Pieter-Jan; Mads Marquart"
|
||||||
__email__ = 'carpedm20@gmail.com'
|
__email__ = "carpedm20@gmail.com"
|
||||||
|
|
||||||
__all__ = ['Client']
|
__all__ = ["Client"]
|
||||||
|
686
fbchat/client.py
686
fbchat/client.py
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ from .utils import *
|
|||||||
|
|
||||||
# Shameless copy from https://stackoverflow.com/a/8730674
|
# Shameless copy from https://stackoverflow.com/a/8730674
|
||||||
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
|
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
|
||||||
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
|
WHITESPACE = re.compile(r"[ \t\n\r]*", FLAGS)
|
||||||
|
|
||||||
|
|
||||||
class ConcatJSONDecoder(json.JSONDecoder):
|
class ConcatJSONDecoder(json.JSONDecoder):
|
||||||
@@ -33,220 +33,220 @@ def graphql_color_to_enum(color):
|
|||||||
if not color:
|
if not color:
|
||||||
return ThreadColor.MESSENGER_BLUE
|
return ThreadColor.MESSENGER_BLUE
|
||||||
color = color[2:] # Strip the alpha value
|
color = color[2:] # Strip the alpha value
|
||||||
color_value = '#{}'.format(color.lower())
|
color_value = "#{}".format(color.lower())
|
||||||
return enum_extend_if_invalid(ThreadColor, color_value)
|
return enum_extend_if_invalid(ThreadColor, color_value)
|
||||||
|
|
||||||
|
|
||||||
def get_customization_info(thread):
|
def get_customization_info(thread):
|
||||||
if thread is None or thread.get('customization_info') is None:
|
if thread is None or thread.get("customization_info") is None:
|
||||||
return {}
|
return {}
|
||||||
info = thread['customization_info']
|
info = thread["customization_info"]
|
||||||
|
|
||||||
rtn = {
|
rtn = {
|
||||||
'emoji': info.get('emoji'),
|
"emoji": info.get("emoji"),
|
||||||
'color': graphql_color_to_enum(info.get('outgoing_bubble_color')),
|
"color": graphql_color_to_enum(info.get("outgoing_bubble_color")),
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
thread.get('thread_type') == 'GROUP'
|
thread.get("thread_type") == "GROUP"
|
||||||
or thread.get('is_group_thread')
|
or thread.get("is_group_thread")
|
||||||
or thread.get('thread_key', {}).get('thread_fbid')
|
or thread.get("thread_key", {}).get("thread_fbid")
|
||||||
):
|
):
|
||||||
rtn['nicknames'] = {}
|
rtn["nicknames"] = {}
|
||||||
for k in info.get('participant_customizations', []):
|
for k in info.get("participant_customizations", []):
|
||||||
rtn['nicknames'][k['participant_id']] = k.get('nickname')
|
rtn["nicknames"][k["participant_id"]] = k.get("nickname")
|
||||||
elif info.get('participant_customizations'):
|
elif info.get("participant_customizations"):
|
||||||
uid = thread.get('thread_key', {}).get('other_user_id') or thread.get('id')
|
uid = thread.get("thread_key", {}).get("other_user_id") or thread.get("id")
|
||||||
pc = info['participant_customizations']
|
pc = info["participant_customizations"]
|
||||||
if len(pc) > 0:
|
if len(pc) > 0:
|
||||||
if pc[0].get('participant_id') == uid:
|
if pc[0].get("participant_id") == uid:
|
||||||
rtn['nickname'] = pc[0].get('nickname')
|
rtn["nickname"] = pc[0].get("nickname")
|
||||||
else:
|
else:
|
||||||
rtn['own_nickname'] = pc[0].get('nickname')
|
rtn["own_nickname"] = pc[0].get("nickname")
|
||||||
if len(pc) > 1:
|
if len(pc) > 1:
|
||||||
if pc[1].get('participant_id') == uid:
|
if pc[1].get("participant_id") == uid:
|
||||||
rtn['nickname'] = pc[1].get('nickname')
|
rtn["nickname"] = pc[1].get("nickname")
|
||||||
else:
|
else:
|
||||||
rtn['own_nickname'] = pc[1].get('nickname')
|
rtn["own_nickname"] = pc[1].get("nickname")
|
||||||
return rtn
|
return rtn
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_sticker(s):
|
def graphql_to_sticker(s):
|
||||||
if not s:
|
if not s:
|
||||||
return None
|
return None
|
||||||
sticker = Sticker(uid=s['id'])
|
sticker = Sticker(uid=s["id"])
|
||||||
if s.get('pack'):
|
if s.get("pack"):
|
||||||
sticker.pack = s['pack'].get('id')
|
sticker.pack = s["pack"].get("id")
|
||||||
if s.get('sprite_image'):
|
if s.get("sprite_image"):
|
||||||
sticker.is_animated = True
|
sticker.is_animated = True
|
||||||
sticker.medium_sprite_image = s['sprite_image'].get('uri')
|
sticker.medium_sprite_image = s["sprite_image"].get("uri")
|
||||||
sticker.large_sprite_image = s['sprite_image_2x'].get('uri')
|
sticker.large_sprite_image = s["sprite_image_2x"].get("uri")
|
||||||
sticker.frames_per_row = s.get('frames_per_row')
|
sticker.frames_per_row = s.get("frames_per_row")
|
||||||
sticker.frames_per_col = s.get('frames_per_column')
|
sticker.frames_per_col = s.get("frames_per_column")
|
||||||
sticker.frame_rate = s.get('frame_rate')
|
sticker.frame_rate = s.get("frame_rate")
|
||||||
sticker.url = s.get('url')
|
sticker.url = s.get("url")
|
||||||
sticker.width = s.get('width')
|
sticker.width = s.get("width")
|
||||||
sticker.height = s.get('height')
|
sticker.height = s.get("height")
|
||||||
if s.get('label'):
|
if s.get("label"):
|
||||||
sticker.label = s['label']
|
sticker.label = s["label"]
|
||||||
return sticker
|
return sticker
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_attachment(a):
|
def graphql_to_attachment(a):
|
||||||
_type = a['__typename']
|
_type = a["__typename"]
|
||||||
if _type in ['MessageImage', 'MessageAnimatedImage']:
|
if _type in ["MessageImage", "MessageAnimatedImage"]:
|
||||||
return ImageAttachment(
|
return ImageAttachment(
|
||||||
original_extension=a.get('original_extension')
|
original_extension=a.get("original_extension")
|
||||||
or (a['filename'].split('-')[0] if a.get('filename') else None),
|
or (a["filename"].split("-")[0] if a.get("filename") else None),
|
||||||
width=a.get('original_dimensions', {}).get('width'),
|
width=a.get("original_dimensions", {}).get("width"),
|
||||||
height=a.get('original_dimensions', {}).get('height'),
|
height=a.get("original_dimensions", {}).get("height"),
|
||||||
is_animated=_type == 'MessageAnimatedImage',
|
is_animated=_type == "MessageAnimatedImage",
|
||||||
thumbnail_url=a.get('thumbnail', {}).get('uri'),
|
thumbnail_url=a.get("thumbnail", {}).get("uri"),
|
||||||
preview=a.get('preview') or a.get('preview_image'),
|
preview=a.get("preview") or a.get("preview_image"),
|
||||||
large_preview=a.get('large_preview'),
|
large_preview=a.get("large_preview"),
|
||||||
animated_preview=a.get('animated_image'),
|
animated_preview=a.get("animated_image"),
|
||||||
uid=a.get('legacy_attachment_id'),
|
uid=a.get("legacy_attachment_id"),
|
||||||
)
|
)
|
||||||
elif _type == 'MessageVideo':
|
elif _type == "MessageVideo":
|
||||||
return VideoAttachment(
|
return VideoAttachment(
|
||||||
width=a.get('original_dimensions', {}).get('width'),
|
width=a.get("original_dimensions", {}).get("width"),
|
||||||
height=a.get('original_dimensions', {}).get('height'),
|
height=a.get("original_dimensions", {}).get("height"),
|
||||||
duration=a.get('playable_duration_in_ms'),
|
duration=a.get("playable_duration_in_ms"),
|
||||||
preview_url=a.get('playable_url'),
|
preview_url=a.get("playable_url"),
|
||||||
small_image=a.get('chat_image'),
|
small_image=a.get("chat_image"),
|
||||||
medium_image=a.get('inbox_image'),
|
medium_image=a.get("inbox_image"),
|
||||||
large_image=a.get('large_image'),
|
large_image=a.get("large_image"),
|
||||||
uid=a.get('legacy_attachment_id'),
|
uid=a.get("legacy_attachment_id"),
|
||||||
)
|
)
|
||||||
elif _type == 'MessageAudio':
|
elif _type == "MessageAudio":
|
||||||
return AudioAttachment(
|
return AudioAttachment(
|
||||||
filename=a.get('filename'),
|
filename=a.get("filename"),
|
||||||
url=a.get('playable_url'),
|
url=a.get("playable_url"),
|
||||||
duration=a.get('playable_duration_in_ms'),
|
duration=a.get("playable_duration_in_ms"),
|
||||||
audio_type=a.get('audio_type'),
|
audio_type=a.get("audio_type"),
|
||||||
)
|
)
|
||||||
elif _type == 'MessageFile':
|
elif _type == "MessageFile":
|
||||||
return FileAttachment(
|
return FileAttachment(
|
||||||
url=a.get('url'),
|
url=a.get("url"),
|
||||||
name=a.get('filename'),
|
name=a.get("filename"),
|
||||||
is_malicious=a.get('is_malicious'),
|
is_malicious=a.get("is_malicious"),
|
||||||
uid=a.get('message_file_fbid'),
|
uid=a.get("message_file_fbid"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return Attachment(uid=a.get('legacy_attachment_id'))
|
return Attachment(uid=a.get("legacy_attachment_id"))
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_extensible_attachment(a):
|
def graphql_to_extensible_attachment(a):
|
||||||
story = a.get('story_attachment')
|
story = a.get("story_attachment")
|
||||||
if story:
|
if story:
|
||||||
target = story.get('target')
|
target = story.get("target")
|
||||||
if target:
|
if target:
|
||||||
_type = target['__typename']
|
_type = target["__typename"]
|
||||||
if _type == 'MessageLocation':
|
if _type == "MessageLocation":
|
||||||
latitude, longitude = get_url_parameter(
|
latitude, longitude = get_url_parameter(
|
||||||
get_url_parameter(story['url'], 'u'), 'where1'
|
get_url_parameter(story["url"], "u"), "where1"
|
||||||
).split(", ")
|
).split(", ")
|
||||||
rtn = LocationAttachment(
|
rtn = LocationAttachment(
|
||||||
uid=int(story['deduplication_key']),
|
uid=int(story["deduplication_key"]),
|
||||||
latitude=float(latitude),
|
latitude=float(latitude),
|
||||||
longitude=float(longitude),
|
longitude=float(longitude),
|
||||||
)
|
)
|
||||||
if story['media']:
|
if story["media"]:
|
||||||
rtn.image_url = story['media']['image']['uri']
|
rtn.image_url = story["media"]["image"]["uri"]
|
||||||
rtn.image_width = story['media']['image']['width']
|
rtn.image_width = story["media"]["image"]["width"]
|
||||||
rtn.image_height = story['media']['image']['height']
|
rtn.image_height = story["media"]["image"]["height"]
|
||||||
rtn.url = story['url']
|
rtn.url = story["url"]
|
||||||
return rtn
|
return rtn
|
||||||
elif _type == 'MessageLiveLocation':
|
elif _type == "MessageLiveLocation":
|
||||||
rtn = LiveLocationAttachment(
|
rtn = LiveLocationAttachment(
|
||||||
uid=int(story['target']['live_location_id']),
|
uid=int(story["target"]["live_location_id"]),
|
||||||
latitude=story['target']['coordinate']['latitude']
|
latitude=story["target"]["coordinate"]["latitude"]
|
||||||
if story['target'].get('coordinate')
|
if story["target"].get("coordinate")
|
||||||
else None,
|
else None,
|
||||||
longitude=story['target']['coordinate']['longitude']
|
longitude=story["target"]["coordinate"]["longitude"]
|
||||||
if story['target'].get('coordinate')
|
if story["target"].get("coordinate")
|
||||||
else None,
|
else None,
|
||||||
name=story['title_with_entities']['text'],
|
name=story["title_with_entities"]["text"],
|
||||||
expiration_time=story['target']['expiration_time']
|
expiration_time=story["target"]["expiration_time"]
|
||||||
if story['target'].get('expiration_time')
|
if story["target"].get("expiration_time")
|
||||||
else None,
|
else None,
|
||||||
is_expired=story['target']['is_expired'],
|
is_expired=story["target"]["is_expired"],
|
||||||
)
|
)
|
||||||
if story['media']:
|
if story["media"]:
|
||||||
rtn.image_url = story['media']['image']['uri']
|
rtn.image_url = story["media"]["image"]["uri"]
|
||||||
rtn.image_width = story['media']['image']['width']
|
rtn.image_width = story["media"]["image"]["width"]
|
||||||
rtn.image_height = story['media']['image']['height']
|
rtn.image_height = story["media"]["image"]["height"]
|
||||||
rtn.url = story['url']
|
rtn.url = story["url"]
|
||||||
return rtn
|
return rtn
|
||||||
elif _type in ['ExternalUrl', 'Story']:
|
elif _type in ["ExternalUrl", "Story"]:
|
||||||
return ShareAttachment(
|
return ShareAttachment(
|
||||||
uid=a.get('legacy_attachment_id'),
|
uid=a.get("legacy_attachment_id"),
|
||||||
author=story['target']['actors'][0]['id']
|
author=story["target"]["actors"][0]["id"]
|
||||||
if story['target'].get('actors')
|
if story["target"].get("actors")
|
||||||
else None,
|
else None,
|
||||||
url=story['url'],
|
url=story["url"],
|
||||||
original_url=get_url_parameter(story['url'], 'u')
|
original_url=get_url_parameter(story["url"], "u")
|
||||||
if "/l.php?u=" in story['url']
|
if "/l.php?u=" in story["url"]
|
||||||
else story['url'],
|
else story["url"],
|
||||||
title=story['title_with_entities'].get('text'),
|
title=story["title_with_entities"].get("text"),
|
||||||
description=story['description'].get('text')
|
description=story["description"].get("text")
|
||||||
if story.get('description')
|
if story.get("description")
|
||||||
else None,
|
else None,
|
||||||
source=story['source']['text'],
|
source=story["source"]["text"],
|
||||||
image_url=story['media']['image']['uri']
|
image_url=story["media"]["image"]["uri"]
|
||||||
if story.get('media')
|
if story.get("media")
|
||||||
else None,
|
else None,
|
||||||
original_image_url=(
|
original_image_url=(
|
||||||
get_url_parameter(story['media']['image']['uri'], 'url')
|
get_url_parameter(story["media"]["image"]["uri"], "url")
|
||||||
if "/safe_image.php" in story['media']['image']['uri']
|
if "/safe_image.php" in story["media"]["image"]["uri"]
|
||||||
else story['media']['image']['uri']
|
else story["media"]["image"]["uri"]
|
||||||
)
|
)
|
||||||
if story.get('media')
|
if story.get("media")
|
||||||
else None,
|
else None,
|
||||||
image_width=story['media']['image']['width']
|
image_width=story["media"]["image"]["width"]
|
||||||
if story.get('media')
|
if story.get("media")
|
||||||
else None,
|
else None,
|
||||||
image_height=story['media']['image']['height']
|
image_height=story["media"]["image"]["height"]
|
||||||
if story.get('media')
|
if story.get("media")
|
||||||
else None,
|
else None,
|
||||||
attachments=[
|
attachments=[
|
||||||
graphql_to_subattachment(attachment)
|
graphql_to_subattachment(attachment)
|
||||||
for attachment in story.get('subattachments')
|
for attachment in story.get("subattachments")
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return UnsentMessage(uid=a.get('legacy_attachment_id'))
|
return UnsentMessage(uid=a.get("legacy_attachment_id"))
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_subattachment(a):
|
def graphql_to_subattachment(a):
|
||||||
_type = a['target']['__typename']
|
_type = a["target"]["__typename"]
|
||||||
if _type == 'Video':
|
if _type == "Video":
|
||||||
return VideoAttachment(
|
return VideoAttachment(
|
||||||
duration=a['media'].get('playable_duration_in_ms'),
|
duration=a["media"].get("playable_duration_in_ms"),
|
||||||
preview_url=a['media'].get('playable_url'),
|
preview_url=a["media"].get("playable_url"),
|
||||||
medium_image=a['media'].get('image'),
|
medium_image=a["media"].get("image"),
|
||||||
uid=a['target'].get('video_id'),
|
uid=a["target"].get("video_id"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_live_location(a):
|
def graphql_to_live_location(a):
|
||||||
return LiveLocationAttachment(
|
return LiveLocationAttachment(
|
||||||
uid=a['id'],
|
uid=a["id"],
|
||||||
latitude=a['coordinate']['latitude'] / (10 ** 8)
|
latitude=a["coordinate"]["latitude"] / (10 ** 8)
|
||||||
if not a.get('stopReason')
|
if not a.get("stopReason")
|
||||||
else None,
|
else None,
|
||||||
longitude=a['coordinate']['longitude'] / (10 ** 8)
|
longitude=a["coordinate"]["longitude"] / (10 ** 8)
|
||||||
if not a.get('stopReason')
|
if not a.get("stopReason")
|
||||||
else None,
|
else None,
|
||||||
name=a.get('locationTitle'),
|
name=a.get("locationTitle"),
|
||||||
expiration_time=a['expirationTime'],
|
expiration_time=a["expirationTime"],
|
||||||
is_expired=bool(a.get('stopReason')),
|
is_expired=bool(a.get("stopReason")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_poll(a):
|
def graphql_to_poll(a):
|
||||||
rtn = Poll(
|
rtn = Poll(
|
||||||
title=a.get('title') if a.get('title') else a.get('text'),
|
title=a.get("title") if a.get("title") else a.get("text"),
|
||||||
options=[graphql_to_poll_option(m) for m in a.get('options')],
|
options=[graphql_to_poll_option(m) for m in a.get("options")],
|
||||||
)
|
)
|
||||||
rtn.uid = int(a["id"])
|
rtn.uid = int(a["id"])
|
||||||
rtn.options_count = a.get("total_count")
|
rtn.options_count = a.get("total_count")
|
||||||
@@ -254,90 +254,90 @@ def graphql_to_poll(a):
|
|||||||
|
|
||||||
|
|
||||||
def graphql_to_poll_option(a):
|
def graphql_to_poll_option(a):
|
||||||
if a.get('viewer_has_voted') is None:
|
if a.get("viewer_has_voted") is None:
|
||||||
vote = None
|
vote = None
|
||||||
elif isinstance(a['viewer_has_voted'], bool):
|
elif isinstance(a["viewer_has_voted"], bool):
|
||||||
vote = a['viewer_has_voted']
|
vote = a["viewer_has_voted"]
|
||||||
else:
|
else:
|
||||||
vote = a['viewer_has_voted'] == 'true'
|
vote = a["viewer_has_voted"] == "true"
|
||||||
rtn = PollOption(text=a.get('text'), vote=vote)
|
rtn = PollOption(text=a.get("text"), vote=vote)
|
||||||
rtn.uid = int(a["id"])
|
rtn.uid = int(a["id"])
|
||||||
rtn.voters = (
|
rtn.voters = (
|
||||||
[m.get('node').get('id') for m in a.get('voters').get('edges')]
|
[m.get("node").get("id") for m in a.get("voters").get("edges")]
|
||||||
if isinstance(a.get('voters'), dict)
|
if isinstance(a.get("voters"), dict)
|
||||||
else a.get('voters')
|
else a.get("voters")
|
||||||
)
|
)
|
||||||
rtn.votes_count = (
|
rtn.votes_count = (
|
||||||
a.get('voters').get('count')
|
a.get("voters").get("count")
|
||||||
if isinstance(a.get('voters'), dict)
|
if isinstance(a.get("voters"), dict)
|
||||||
else a.get('total_count')
|
else a.get("total_count")
|
||||||
)
|
)
|
||||||
return rtn
|
return rtn
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_plan(a):
|
def graphql_to_plan(a):
|
||||||
if a.get('event_members'):
|
if a.get("event_members"):
|
||||||
rtn = Plan(
|
rtn = Plan(
|
||||||
time=a.get('event_time'),
|
time=a.get("event_time"),
|
||||||
title=a.get('title'),
|
title=a.get("title"),
|
||||||
location=a.get('location_name'),
|
location=a.get("location_name"),
|
||||||
)
|
)
|
||||||
if a.get('location_id') != 0:
|
if a.get("location_id") != 0:
|
||||||
rtn.location_id = str(a.get('location_id'))
|
rtn.location_id = str(a.get("location_id"))
|
||||||
rtn.uid = a.get('oid')
|
rtn.uid = a.get("oid")
|
||||||
rtn.author_id = a.get('creator_id')
|
rtn.author_id = a.get("creator_id")
|
||||||
guests = a.get("event_members")
|
guests = a.get("event_members")
|
||||||
rtn.going = [uid for uid in guests if guests[uid] == "GOING"]
|
rtn.going = [uid for uid in guests if guests[uid] == "GOING"]
|
||||||
rtn.declined = [uid for uid in guests if guests[uid] == "DECLINED"]
|
rtn.declined = [uid for uid in guests if guests[uid] == "DECLINED"]
|
||||||
rtn.invited = [uid for uid in guests if guests[uid] == "INVITED"]
|
rtn.invited = [uid for uid in guests if guests[uid] == "INVITED"]
|
||||||
return rtn
|
return rtn
|
||||||
elif a.get('id') is None:
|
elif a.get("id") is None:
|
||||||
rtn = Plan(
|
rtn = Plan(
|
||||||
time=a.get('event_time'),
|
time=a.get("event_time"),
|
||||||
title=a.get('event_title'),
|
title=a.get("event_title"),
|
||||||
location=a.get('event_location_name'),
|
location=a.get("event_location_name"),
|
||||||
location_id=a.get('event_location_id'),
|
location_id=a.get("event_location_id"),
|
||||||
)
|
)
|
||||||
rtn.uid = a.get('event_id')
|
rtn.uid = a.get("event_id")
|
||||||
rtn.author_id = a.get('event_creator_id')
|
rtn.author_id = a.get("event_creator_id")
|
||||||
guests = json.loads(a.get('guest_state_list'))
|
guests = json.loads(a.get("guest_state_list"))
|
||||||
else:
|
else:
|
||||||
rtn = Plan(
|
rtn = Plan(
|
||||||
time=a.get('time'),
|
time=a.get("time"),
|
||||||
title=a.get('event_title'),
|
title=a.get("event_title"),
|
||||||
location=a.get('location_name'),
|
location=a.get("location_name"),
|
||||||
)
|
)
|
||||||
rtn.uid = a.get('id')
|
rtn.uid = a.get("id")
|
||||||
rtn.author_id = a.get('lightweight_event_creator').get('id')
|
rtn.author_id = a.get("lightweight_event_creator").get("id")
|
||||||
guests = a.get('event_reminder_members').get('edges')
|
guests = a.get("event_reminder_members").get("edges")
|
||||||
rtn.going = [
|
rtn.going = [
|
||||||
m.get('node').get('id') for m in guests if m.get('guest_list_state') == "GOING"
|
m.get("node").get("id") for m in guests if m.get("guest_list_state") == "GOING"
|
||||||
]
|
]
|
||||||
rtn.declined = [
|
rtn.declined = [
|
||||||
m.get('node').get('id')
|
m.get("node").get("id")
|
||||||
for m in guests
|
for m in guests
|
||||||
if m.get('guest_list_state') == "DECLINED"
|
if m.get("guest_list_state") == "DECLINED"
|
||||||
]
|
]
|
||||||
rtn.invited = [
|
rtn.invited = [
|
||||||
m.get('node').get('id')
|
m.get("node").get("id")
|
||||||
for m in guests
|
for m in guests
|
||||||
if m.get('guest_list_state') == "INVITED"
|
if m.get("guest_list_state") == "INVITED"
|
||||||
]
|
]
|
||||||
return rtn
|
return rtn
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_quick_reply(q, is_response=False):
|
def graphql_to_quick_reply(q, is_response=False):
|
||||||
data = dict()
|
data = dict()
|
||||||
_type = q.get('content_type').lower()
|
_type = q.get("content_type").lower()
|
||||||
if q.get('payload'):
|
if q.get("payload"):
|
||||||
data["payload"] = q["payload"]
|
data["payload"] = q["payload"]
|
||||||
if q.get('data'):
|
if q.get("data"):
|
||||||
data["data"] = q["data"]
|
data["data"] = q["data"]
|
||||||
if q.get('image_url') and _type is not QuickReplyLocation._type:
|
if q.get("image_url") and _type is not QuickReplyLocation._type:
|
||||||
data["image_url"] = q["image_url"]
|
data["image_url"] = q["image_url"]
|
||||||
data["is_response"] = is_response
|
data["is_response"] = is_response
|
||||||
if _type == QuickReplyText._type:
|
if _type == QuickReplyText._type:
|
||||||
if q.get('title') is not None:
|
if q.get("title") is not None:
|
||||||
data["title"] = q["title"]
|
data["title"] = q["title"]
|
||||||
rtn = QuickReplyText(**data)
|
rtn = QuickReplyText(**data)
|
||||||
elif _type == QuickReplyLocation._type:
|
elif _type == QuickReplyLocation._type:
|
||||||
@@ -350,48 +350,48 @@ def graphql_to_quick_reply(q, is_response=False):
|
|||||||
|
|
||||||
|
|
||||||
def graphql_to_message(message):
|
def graphql_to_message(message):
|
||||||
if message.get('message_sender') is None:
|
if message.get("message_sender") is None:
|
||||||
message['message_sender'] = {}
|
message["message_sender"] = {}
|
||||||
if message.get('message') is None:
|
if message.get("message") is None:
|
||||||
message['message'] = {}
|
message["message"] = {}
|
||||||
rtn = Message(
|
rtn = Message(
|
||||||
text=message.get('message').get('text'),
|
text=message.get("message").get("text"),
|
||||||
mentions=[
|
mentions=[
|
||||||
Mention(
|
Mention(
|
||||||
m.get('entity', {}).get('id'),
|
m.get("entity", {}).get("id"),
|
||||||
offset=m.get('offset'),
|
offset=m.get("offset"),
|
||||||
length=m.get('length'),
|
length=m.get("length"),
|
||||||
)
|
)
|
||||||
for m in message.get('message').get('ranges', [])
|
for m in message.get("message").get("ranges", [])
|
||||||
],
|
],
|
||||||
emoji_size=get_emojisize_from_tags(message.get('tags_list')),
|
emoji_size=get_emojisize_from_tags(message.get("tags_list")),
|
||||||
sticker=graphql_to_sticker(message.get('sticker')),
|
sticker=graphql_to_sticker(message.get("sticker")),
|
||||||
)
|
)
|
||||||
rtn.uid = str(message.get('message_id'))
|
rtn.uid = str(message.get("message_id"))
|
||||||
rtn.author = str(message.get('message_sender').get('id'))
|
rtn.author = str(message.get("message_sender").get("id"))
|
||||||
rtn.timestamp = message.get('timestamp_precise')
|
rtn.timestamp = message.get("timestamp_precise")
|
||||||
rtn.unsent = False
|
rtn.unsent = False
|
||||||
if message.get('unread') is not None:
|
if message.get("unread") is not None:
|
||||||
rtn.is_read = not message['unread']
|
rtn.is_read = not message["unread"]
|
||||||
rtn.reactions = {
|
rtn.reactions = {
|
||||||
str(r['user']['id']): enum_extend_if_invalid(MessageReaction, r['reaction'])
|
str(r["user"]["id"]): enum_extend_if_invalid(MessageReaction, r["reaction"])
|
||||||
for r in message.get('message_reactions')
|
for r in message.get("message_reactions")
|
||||||
}
|
}
|
||||||
if message.get('blob_attachments') is not None:
|
if message.get("blob_attachments") is not None:
|
||||||
rtn.attachments = [
|
rtn.attachments = [
|
||||||
graphql_to_attachment(attachment)
|
graphql_to_attachment(attachment)
|
||||||
for attachment in message['blob_attachments']
|
for attachment in message["blob_attachments"]
|
||||||
]
|
]
|
||||||
if message.get('platform_xmd_encoded'):
|
if message.get("platform_xmd_encoded"):
|
||||||
quick_replies = json.loads(message['platform_xmd_encoded']).get('quick_replies')
|
quick_replies = json.loads(message["platform_xmd_encoded"]).get("quick_replies")
|
||||||
if isinstance(quick_replies, list):
|
if isinstance(quick_replies, list):
|
||||||
rtn.quick_replies = [graphql_to_quick_reply(q) for q in quick_replies]
|
rtn.quick_replies = [graphql_to_quick_reply(q) for q in quick_replies]
|
||||||
elif isinstance(quick_replies, dict):
|
elif isinstance(quick_replies, dict):
|
||||||
rtn.quick_replies = [
|
rtn.quick_replies = [
|
||||||
graphql_to_quick_reply(quick_replies, is_response=True)
|
graphql_to_quick_reply(quick_replies, is_response=True)
|
||||||
]
|
]
|
||||||
if message.get('extensible_attachment') is not None:
|
if message.get("extensible_attachment") is not None:
|
||||||
attachment = graphql_to_extensible_attachment(message['extensible_attachment'])
|
attachment = graphql_to_extensible_attachment(message["extensible_attachment"])
|
||||||
if isinstance(attachment, UnsentMessage):
|
if isinstance(attachment, UnsentMessage):
|
||||||
rtn.unsent = True
|
rtn.unsent = True
|
||||||
elif attachment:
|
elif attachment:
|
||||||
@@ -400,157 +400,157 @@ def graphql_to_message(message):
|
|||||||
|
|
||||||
|
|
||||||
def graphql_to_user(user):
|
def graphql_to_user(user):
|
||||||
if user.get('profile_picture') is None:
|
if user.get("profile_picture") is None:
|
||||||
user['profile_picture'] = {}
|
user["profile_picture"] = {}
|
||||||
c_info = get_customization_info(user)
|
c_info = get_customization_info(user)
|
||||||
plan = None
|
plan = None
|
||||||
if user.get('event_reminders'):
|
if user.get("event_reminders"):
|
||||||
plan = (
|
plan = (
|
||||||
graphql_to_plan(user['event_reminders']['nodes'][0])
|
graphql_to_plan(user["event_reminders"]["nodes"][0])
|
||||||
if user['event_reminders'].get('nodes')
|
if user["event_reminders"].get("nodes")
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
return User(
|
return User(
|
||||||
user['id'],
|
user["id"],
|
||||||
url=user.get('url'),
|
url=user.get("url"),
|
||||||
first_name=user.get('first_name'),
|
first_name=user.get("first_name"),
|
||||||
last_name=user.get('last_name'),
|
last_name=user.get("last_name"),
|
||||||
is_friend=user.get('is_viewer_friend'),
|
is_friend=user.get("is_viewer_friend"),
|
||||||
gender=GENDERS.get(user.get('gender')),
|
gender=GENDERS.get(user.get("gender")),
|
||||||
affinity=user.get('affinity'),
|
affinity=user.get("affinity"),
|
||||||
nickname=c_info.get('nickname'),
|
nickname=c_info.get("nickname"),
|
||||||
color=c_info.get('color'),
|
color=c_info.get("color"),
|
||||||
emoji=c_info.get('emoji'),
|
emoji=c_info.get("emoji"),
|
||||||
own_nickname=c_info.get('own_nickname'),
|
own_nickname=c_info.get("own_nickname"),
|
||||||
photo=user['profile_picture'].get('uri'),
|
photo=user["profile_picture"].get("uri"),
|
||||||
name=user.get('name'),
|
name=user.get("name"),
|
||||||
message_count=user.get('messages_count'),
|
message_count=user.get("messages_count"),
|
||||||
plan=plan,
|
plan=plan,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_thread(thread):
|
def graphql_to_thread(thread):
|
||||||
if thread['thread_type'] == 'GROUP':
|
if thread["thread_type"] == "GROUP":
|
||||||
return graphql_to_group(thread)
|
return graphql_to_group(thread)
|
||||||
elif thread['thread_type'] == 'ONE_TO_ONE':
|
elif thread["thread_type"] == "ONE_TO_ONE":
|
||||||
if thread.get('big_image_src') is None:
|
if thread.get("big_image_src") is None:
|
||||||
thread['big_image_src'] = {}
|
thread["big_image_src"] = {}
|
||||||
c_info = get_customization_info(thread)
|
c_info = get_customization_info(thread)
|
||||||
participants = [
|
participants = [
|
||||||
node['messaging_actor'] for node in thread['all_participants']['nodes']
|
node["messaging_actor"] for node in thread["all_participants"]["nodes"]
|
||||||
]
|
]
|
||||||
user = next(
|
user = next(
|
||||||
p for p in participants if p['id'] == thread['thread_key']['other_user_id']
|
p for p in participants if p["id"] == thread["thread_key"]["other_user_id"]
|
||||||
)
|
)
|
||||||
last_message_timestamp = None
|
last_message_timestamp = None
|
||||||
if 'last_message' in thread:
|
if "last_message" in thread:
|
||||||
last_message_timestamp = thread['last_message']['nodes'][0][
|
last_message_timestamp = thread["last_message"]["nodes"][0][
|
||||||
'timestamp_precise'
|
"timestamp_precise"
|
||||||
]
|
]
|
||||||
|
|
||||||
first_name = user.get('short_name')
|
first_name = user.get("short_name")
|
||||||
if first_name is None:
|
if first_name is None:
|
||||||
last_name = None
|
last_name = None
|
||||||
else:
|
else:
|
||||||
last_name = user.get('name').split(first_name, 1).pop().strip()
|
last_name = user.get("name").split(first_name, 1).pop().strip()
|
||||||
|
|
||||||
plan = None
|
plan = None
|
||||||
if thread.get('event_reminders'):
|
if thread.get("event_reminders"):
|
||||||
plan = (
|
plan = (
|
||||||
graphql_to_plan(thread['event_reminders']['nodes'][0])
|
graphql_to_plan(thread["event_reminders"]["nodes"][0])
|
||||||
if thread['event_reminders'].get('nodes')
|
if thread["event_reminders"].get("nodes")
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
return User(
|
return User(
|
||||||
user['id'],
|
user["id"],
|
||||||
url=user.get('url'),
|
url=user.get("url"),
|
||||||
name=user.get('name'),
|
name=user.get("name"),
|
||||||
first_name=first_name,
|
first_name=first_name,
|
||||||
last_name=last_name,
|
last_name=last_name,
|
||||||
is_friend=user.get('is_viewer_friend'),
|
is_friend=user.get("is_viewer_friend"),
|
||||||
gender=GENDERS.get(user.get('gender')),
|
gender=GENDERS.get(user.get("gender")),
|
||||||
affinity=user.get('affinity'),
|
affinity=user.get("affinity"),
|
||||||
nickname=c_info.get('nickname'),
|
nickname=c_info.get("nickname"),
|
||||||
color=c_info.get('color'),
|
color=c_info.get("color"),
|
||||||
emoji=c_info.get('emoji'),
|
emoji=c_info.get("emoji"),
|
||||||
own_nickname=c_info.get('own_nickname'),
|
own_nickname=c_info.get("own_nickname"),
|
||||||
photo=user['big_image_src'].get('uri'),
|
photo=user["big_image_src"].get("uri"),
|
||||||
message_count=thread.get('messages_count'),
|
message_count=thread.get("messages_count"),
|
||||||
last_message_timestamp=last_message_timestamp,
|
last_message_timestamp=last_message_timestamp,
|
||||||
plan=plan,
|
plan=plan,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise FBchatException(
|
raise FBchatException(
|
||||||
'Unknown thread type: {}, with data: {}'.format(
|
"Unknown thread type: {}, with data: {}".format(
|
||||||
thread.get('thread_type'), thread
|
thread.get("thread_type"), thread
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_group(group):
|
def graphql_to_group(group):
|
||||||
if group.get('image') is None:
|
if group.get("image") is None:
|
||||||
group['image'] = {}
|
group["image"] = {}
|
||||||
c_info = get_customization_info(group)
|
c_info = get_customization_info(group)
|
||||||
last_message_timestamp = None
|
last_message_timestamp = None
|
||||||
if 'last_message' in group:
|
if "last_message" in group:
|
||||||
last_message_timestamp = group['last_message']['nodes'][0]['timestamp_precise']
|
last_message_timestamp = group["last_message"]["nodes"][0]["timestamp_precise"]
|
||||||
plan = None
|
plan = None
|
||||||
if group.get('event_reminders'):
|
if group.get("event_reminders"):
|
||||||
plan = (
|
plan = (
|
||||||
graphql_to_plan(group['event_reminders']['nodes'][0])
|
graphql_to_plan(group["event_reminders"]["nodes"][0])
|
||||||
if group['event_reminders'].get('nodes')
|
if group["event_reminders"].get("nodes")
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
return Group(
|
return Group(
|
||||||
group['thread_key']['thread_fbid'],
|
group["thread_key"]["thread_fbid"],
|
||||||
participants=set(
|
participants=set(
|
||||||
[
|
[
|
||||||
node['messaging_actor']['id']
|
node["messaging_actor"]["id"]
|
||||||
for node in group['all_participants']['nodes']
|
for node in group["all_participants"]["nodes"]
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
nicknames=c_info.get('nicknames'),
|
nicknames=c_info.get("nicknames"),
|
||||||
color=c_info.get('color'),
|
color=c_info.get("color"),
|
||||||
emoji=c_info.get('emoji'),
|
emoji=c_info.get("emoji"),
|
||||||
admins=set([node.get('id') for node in group.get('thread_admins')]),
|
admins=set([node.get("id") for node in group.get("thread_admins")]),
|
||||||
approval_mode=bool(group.get('approval_mode'))
|
approval_mode=bool(group.get("approval_mode"))
|
||||||
if group.get('approval_mode') is not None
|
if group.get("approval_mode") is not None
|
||||||
else None,
|
else None,
|
||||||
approval_requests=set(
|
approval_requests=set(
|
||||||
node["requester"]['id'] for node in group['group_approval_queue']['nodes']
|
node["requester"]["id"] for node in group["group_approval_queue"]["nodes"]
|
||||||
)
|
)
|
||||||
if group.get('group_approval_queue')
|
if group.get("group_approval_queue")
|
||||||
else None,
|
else None,
|
||||||
join_link=group['joinable_mode'].get('link'),
|
join_link=group["joinable_mode"].get("link"),
|
||||||
photo=group['image'].get('uri'),
|
photo=group["image"].get("uri"),
|
||||||
name=group.get('name'),
|
name=group.get("name"),
|
||||||
message_count=group.get('messages_count'),
|
message_count=group.get("messages_count"),
|
||||||
last_message_timestamp=last_message_timestamp,
|
last_message_timestamp=last_message_timestamp,
|
||||||
plan=plan,
|
plan=plan,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def graphql_to_page(page):
|
def graphql_to_page(page):
|
||||||
if page.get('profile_picture') is None:
|
if page.get("profile_picture") is None:
|
||||||
page['profile_picture'] = {}
|
page["profile_picture"] = {}
|
||||||
if page.get('city') is None:
|
if page.get("city") is None:
|
||||||
page['city'] = {}
|
page["city"] = {}
|
||||||
plan = None
|
plan = None
|
||||||
if page.get('event_reminders'):
|
if page.get("event_reminders"):
|
||||||
plan = (
|
plan = (
|
||||||
graphql_to_plan(page['event_reminders']['nodes'][0])
|
graphql_to_plan(page["event_reminders"]["nodes"][0])
|
||||||
if page['event_reminders'].get('nodes')
|
if page["event_reminders"].get("nodes")
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
return Page(
|
return Page(
|
||||||
page['id'],
|
page["id"],
|
||||||
url=page.get('url'),
|
url=page.get("url"),
|
||||||
city=page.get('city').get('name'),
|
city=page.get("city").get("name"),
|
||||||
category=page.get('category_type'),
|
category=page.get("category_type"),
|
||||||
photo=page['profile_picture'].get('uri'),
|
photo=page["profile_picture"].get("uri"),
|
||||||
name=page.get('name'),
|
name=page.get("name"),
|
||||||
message_count=page.get('messages_count'),
|
message_count=page.get("messages_count"),
|
||||||
plan=plan,
|
plan=plan,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -561,7 +561,7 @@ def graphql_queries_to_json(*queries):
|
|||||||
"""
|
"""
|
||||||
rtn = {}
|
rtn = {}
|
||||||
for i, query in enumerate(queries):
|
for i, query in enumerate(queries):
|
||||||
rtn['q{}'.format(i)] = query.value
|
rtn["q{}".format(i)] = query.value
|
||||||
return json.dumps(rtn)
|
return json.dumps(rtn)
|
||||||
|
|
||||||
|
|
||||||
@@ -570,20 +570,20 @@ def graphql_response_to_json(content):
|
|||||||
try:
|
try:
|
||||||
j = json.loads(content, cls=ConcatJSONDecoder)
|
j = json.loads(content, cls=ConcatJSONDecoder)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise FBchatException('Error while parsing JSON: {}'.format(repr(content)))
|
raise FBchatException("Error while parsing JSON: {}".format(repr(content)))
|
||||||
|
|
||||||
rtn = [None] * (len(j))
|
rtn = [None] * (len(j))
|
||||||
for x in j:
|
for x in j:
|
||||||
if 'error_results' in x:
|
if "error_results" in x:
|
||||||
del rtn[-1]
|
del rtn[-1]
|
||||||
continue
|
continue
|
||||||
check_json(x)
|
check_json(x)
|
||||||
[(key, value)] = x.items()
|
[(key, value)] = x.items()
|
||||||
check_json(value)
|
check_json(value)
|
||||||
if 'response' in value:
|
if "response" in value:
|
||||||
rtn[int(key[1:])] = value['response']
|
rtn[int(key[1:])] = value["response"]
|
||||||
else:
|
else:
|
||||||
rtn[int(key[1:])] = value['data']
|
rtn[int(key[1:])] = value["data"]
|
||||||
|
|
||||||
log.debug(rtn)
|
log.debug(rtn)
|
||||||
|
|
||||||
@@ -595,11 +595,11 @@ class GraphQL(object):
|
|||||||
if params is None:
|
if params is None:
|
||||||
params = {}
|
params = {}
|
||||||
if query is not None:
|
if query is not None:
|
||||||
self.value = {'priority': 0, 'q': query, 'query_params': params}
|
self.value = {"priority": 0, "q": query, "query_params": params}
|
||||||
elif doc_id is not None:
|
elif doc_id is not None:
|
||||||
self.value = {'doc_id': doc_id, 'query_params': params}
|
self.value = {"doc_id": doc_id, "query_params": params}
|
||||||
else:
|
else:
|
||||||
raise FBchatUserError('A query or doc_id must be specified')
|
raise FBchatUserError("A query or doc_id must be specified")
|
||||||
|
|
||||||
FRAGMENT_USER = """
|
FRAGMENT_USER = """
|
||||||
QueryFragment User: User {
|
QueryFragment User: User {
|
||||||
|
120
fbchat/models.py
120
fbchat/models.py
@@ -74,7 +74,7 @@ class Thread(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<{} {} ({})>'.format(self.type.name, self.name, self.uid)
|
return "<{} {} ({})>".format(self.type.name, self.name, self.uid)
|
||||||
|
|
||||||
|
|
||||||
class User(Thread):
|
class User(Thread):
|
||||||
@@ -282,7 +282,7 @@ class Message(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<Message ({}): {}, mentions={} emoji_size={} attachments={}>'.format(
|
return "<Message ({}): {}, mentions={} emoji_size={} attachments={}>".format(
|
||||||
self.uid, repr(self.text), self.mentions, self.emoji_size, self.attachments
|
self.uid, repr(self.text), self.mentions, self.emoji_size, self.attachments
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -305,7 +305,7 @@ class Message(object):
|
|||||||
offset = 0
|
offset = 0
|
||||||
f = Formatter()
|
f = Formatter()
|
||||||
field_names = [field_name[1] for field_name in f.parse(text)]
|
field_names = [field_name[1] for field_name in f.parse(text)]
|
||||||
automatic = '' in field_names
|
automatic = "" in field_names
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
for (literal_text, field_name, format_spec, conversion) in f.parse(text):
|
for (literal_text, field_name, format_spec, conversion) in f.parse(text):
|
||||||
@@ -315,7 +315,7 @@ class Message(object):
|
|||||||
if field_name is None:
|
if field_name is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if field_name == '':
|
if field_name == "":
|
||||||
field_name = str(i)
|
field_name = str(i)
|
||||||
i += 1
|
i += 1
|
||||||
elif automatic and field_name.isdigit():
|
elif automatic and field_name.isdigit():
|
||||||
@@ -584,21 +584,21 @@ class ImageAttachment(Attachment):
|
|||||||
|
|
||||||
if preview is None:
|
if preview is None:
|
||||||
preview = {}
|
preview = {}
|
||||||
self.preview_url = preview.get('uri')
|
self.preview_url = preview.get("uri")
|
||||||
self.preview_width = preview.get('width')
|
self.preview_width = preview.get("width")
|
||||||
self.preview_height = preview.get('height')
|
self.preview_height = preview.get("height")
|
||||||
|
|
||||||
if large_preview is None:
|
if large_preview is None:
|
||||||
large_preview = {}
|
large_preview = {}
|
||||||
self.large_preview_url = large_preview.get('uri')
|
self.large_preview_url = large_preview.get("uri")
|
||||||
self.large_preview_width = large_preview.get('width')
|
self.large_preview_width = large_preview.get("width")
|
||||||
self.large_preview_height = large_preview.get('height')
|
self.large_preview_height = large_preview.get("height")
|
||||||
|
|
||||||
if animated_preview is None:
|
if animated_preview is None:
|
||||||
animated_preview = {}
|
animated_preview = {}
|
||||||
self.animated_preview_url = animated_preview.get('uri')
|
self.animated_preview_url = animated_preview.get("uri")
|
||||||
self.animated_preview_width = animated_preview.get('width')
|
self.animated_preview_width = animated_preview.get("width")
|
||||||
self.animated_preview_height = animated_preview.get('height')
|
self.animated_preview_height = animated_preview.get("height")
|
||||||
|
|
||||||
|
|
||||||
class VideoAttachment(Attachment):
|
class VideoAttachment(Attachment):
|
||||||
@@ -656,21 +656,21 @@ class VideoAttachment(Attachment):
|
|||||||
|
|
||||||
if small_image is None:
|
if small_image is None:
|
||||||
small_image = {}
|
small_image = {}
|
||||||
self.small_image_url = small_image.get('uri')
|
self.small_image_url = small_image.get("uri")
|
||||||
self.small_image_width = small_image.get('width')
|
self.small_image_width = small_image.get("width")
|
||||||
self.small_image_height = small_image.get('height')
|
self.small_image_height = small_image.get("height")
|
||||||
|
|
||||||
if medium_image is None:
|
if medium_image is None:
|
||||||
medium_image = {}
|
medium_image = {}
|
||||||
self.medium_image_url = medium_image.get('uri')
|
self.medium_image_url = medium_image.get("uri")
|
||||||
self.medium_image_width = medium_image.get('width')
|
self.medium_image_width = medium_image.get("width")
|
||||||
self.medium_image_height = medium_image.get('height')
|
self.medium_image_height = medium_image.get("height")
|
||||||
|
|
||||||
if large_image is None:
|
if large_image is None:
|
||||||
large_image = {}
|
large_image = {}
|
||||||
self.large_image_url = large_image.get('uri')
|
self.large_image_url = large_image.get("uri")
|
||||||
self.large_image_width = large_image.get('width')
|
self.large_image_width = large_image.get("width")
|
||||||
self.large_image_height = large_image.get('height')
|
self.large_image_height = large_image.get("height")
|
||||||
|
|
||||||
|
|
||||||
class Mention(object):
|
class Mention(object):
|
||||||
@@ -691,7 +691,7 @@ class Mention(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<Mention {}: offset={} length={}>'.format(
|
return "<Mention {}: offset={} length={}>".format(
|
||||||
self.thread_id, self.offset, self.length
|
self.thread_id, self.offset, self.length
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -716,7 +716,7 @@ class QuickReply(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<{}: payload={!r}>'.format(self.__class__.__name__, self.payload)
|
return "<{}: payload={!r}>".format(self.__class__.__name__, self.payload)
|
||||||
|
|
||||||
|
|
||||||
class QuickReplyText(QuickReply):
|
class QuickReplyText(QuickReply):
|
||||||
@@ -787,7 +787,7 @@ class Poll(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<Poll ({}): {} options={}>'.format(
|
return "<Poll ({}): {} options={}>".format(
|
||||||
self.uid, repr(self.title), self.options
|
self.uid, repr(self.title), self.options
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -813,7 +813,7 @@ class PollOption(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<PollOption ({}): {} voters={}>'.format(
|
return "<PollOption ({}): {} voters={}>".format(
|
||||||
self.uid, repr(self.text), self.voters
|
self.uid, repr(self.text), self.voters
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -842,8 +842,8 @@ class Plan(object):
|
|||||||
"""Represents a plan"""
|
"""Represents a plan"""
|
||||||
self.time = int(time)
|
self.time = int(time)
|
||||||
self.title = title
|
self.title = title
|
||||||
self.location = location or ''
|
self.location = location or ""
|
||||||
self.location_id = location_id or ''
|
self.location_id = location_id or ""
|
||||||
self.author_id = None
|
self.author_id = None
|
||||||
self.going = []
|
self.going = []
|
||||||
self.declined = []
|
self.declined = []
|
||||||
@@ -853,7 +853,7 @@ class Plan(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<Plan ({}): {} time={}, location={}, location_id={}>'.format(
|
return "<Plan ({}): {} time={}, location={}, location_id={}>".format(
|
||||||
self.uid,
|
self.uid,
|
||||||
repr(self.title),
|
repr(self.title),
|
||||||
self.time,
|
self.time,
|
||||||
@@ -879,7 +879,7 @@ class ActiveStatus(object):
|
|||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<ActiveStatus: active={} last_active={} in_game={}>'.format(
|
return "<ActiveStatus: active={} last_active={} in_game={}>".format(
|
||||||
self.active, self.last_active, self.in_game
|
self.active, self.last_active, self.in_game
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -889,7 +889,7 @@ class Enum(aenum.Enum):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# For documentation:
|
# For documentation:
|
||||||
return '{}.{}'.format(type(self).__name__, self.name)
|
return "{}.{}".format(type(self).__name__, self.name)
|
||||||
|
|
||||||
|
|
||||||
class ThreadType(Enum):
|
class ThreadType(Enum):
|
||||||
@@ -904,10 +904,10 @@ class ThreadType(Enum):
|
|||||||
class ThreadLocation(Enum):
|
class ThreadLocation(Enum):
|
||||||
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
|
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
|
||||||
|
|
||||||
INBOX = 'INBOX'
|
INBOX = "INBOX"
|
||||||
PENDING = 'PENDING'
|
PENDING = "PENDING"
|
||||||
ARCHIVED = 'ARCHIVED'
|
ARCHIVED = "ARCHIVED"
|
||||||
OTHER = 'OTHER'
|
OTHER = "OTHER"
|
||||||
|
|
||||||
|
|
||||||
class TypingStatus(Enum):
|
class TypingStatus(Enum):
|
||||||
@@ -920,38 +920,38 @@ class TypingStatus(Enum):
|
|||||||
class EmojiSize(Enum):
|
class EmojiSize(Enum):
|
||||||
"""Used to specify the size of a sent emoji"""
|
"""Used to specify the size of a sent emoji"""
|
||||||
|
|
||||||
LARGE = '369239383222810'
|
LARGE = "369239383222810"
|
||||||
MEDIUM = '369239343222814'
|
MEDIUM = "369239343222814"
|
||||||
SMALL = '369239263222822'
|
SMALL = "369239263222822"
|
||||||
|
|
||||||
|
|
||||||
class ThreadColor(Enum):
|
class ThreadColor(Enum):
|
||||||
"""Used to specify a thread colors"""
|
"""Used to specify a thread colors"""
|
||||||
|
|
||||||
MESSENGER_BLUE = '#0084ff'
|
MESSENGER_BLUE = "#0084ff"
|
||||||
VIKING = '#44bec7'
|
VIKING = "#44bec7"
|
||||||
GOLDEN_POPPY = '#ffc300'
|
GOLDEN_POPPY = "#ffc300"
|
||||||
RADICAL_RED = '#fa3c4c'
|
RADICAL_RED = "#fa3c4c"
|
||||||
SHOCKING = '#d696bb'
|
SHOCKING = "#d696bb"
|
||||||
PICTON_BLUE = '#6699cc'
|
PICTON_BLUE = "#6699cc"
|
||||||
FREE_SPEECH_GREEN = '#13cf13'
|
FREE_SPEECH_GREEN = "#13cf13"
|
||||||
PUMPKIN = '#ff7e29'
|
PUMPKIN = "#ff7e29"
|
||||||
LIGHT_CORAL = '#e68585'
|
LIGHT_CORAL = "#e68585"
|
||||||
MEDIUM_SLATE_BLUE = '#7646ff'
|
MEDIUM_SLATE_BLUE = "#7646ff"
|
||||||
DEEP_SKY_BLUE = '#20cef5'
|
DEEP_SKY_BLUE = "#20cef5"
|
||||||
FERN = '#67b868'
|
FERN = "#67b868"
|
||||||
CAMEO = '#d4a88c'
|
CAMEO = "#d4a88c"
|
||||||
BRILLIANT_ROSE = '#ff5ca1'
|
BRILLIANT_ROSE = "#ff5ca1"
|
||||||
BILOBA_FLOWER = '#a695c7'
|
BILOBA_FLOWER = "#a695c7"
|
||||||
|
|
||||||
|
|
||||||
class MessageReaction(Enum):
|
class MessageReaction(Enum):
|
||||||
"""Used to specify a message reaction"""
|
"""Used to specify a message reaction"""
|
||||||
|
|
||||||
LOVE = '😍'
|
LOVE = "😍"
|
||||||
SMILE = '😆'
|
SMILE = "😆"
|
||||||
WOW = '😮'
|
WOW = "😮"
|
||||||
SAD = '😢'
|
SAD = "😢"
|
||||||
ANGRY = '😠'
|
ANGRY = "😠"
|
||||||
YES = '👍'
|
YES = "👍"
|
||||||
NO = '👎'
|
NO = "👎"
|
||||||
|
104
fbchat/utils.py
104
fbchat/utils.py
@@ -48,37 +48,37 @@ USER_AGENTS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
LIKES = {
|
LIKES = {
|
||||||
'large': EmojiSize.LARGE,
|
"large": EmojiSize.LARGE,
|
||||||
'medium': EmojiSize.MEDIUM,
|
"medium": EmojiSize.MEDIUM,
|
||||||
'small': EmojiSize.SMALL,
|
"small": EmojiSize.SMALL,
|
||||||
'l': EmojiSize.LARGE,
|
"l": EmojiSize.LARGE,
|
||||||
'm': EmojiSize.MEDIUM,
|
"m": EmojiSize.MEDIUM,
|
||||||
's': EmojiSize.SMALL,
|
"s": EmojiSize.SMALL,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GENDERS = {
|
GENDERS = {
|
||||||
# For standard requests
|
# For standard requests
|
||||||
0: 'unknown',
|
0: "unknown",
|
||||||
1: 'female_singular',
|
1: "female_singular",
|
||||||
2: 'male_singular',
|
2: "male_singular",
|
||||||
3: 'female_singular_guess',
|
3: "female_singular_guess",
|
||||||
4: 'male_singular_guess',
|
4: "male_singular_guess",
|
||||||
5: 'mixed',
|
5: "mixed",
|
||||||
6: 'neuter_singular',
|
6: "neuter_singular",
|
||||||
7: 'unknown_singular',
|
7: "unknown_singular",
|
||||||
8: 'female_plural',
|
8: "female_plural",
|
||||||
9: 'male_plural',
|
9: "male_plural",
|
||||||
10: 'neuter_plural',
|
10: "neuter_plural",
|
||||||
11: 'unknown_plural',
|
11: "unknown_plural",
|
||||||
# For graphql requests
|
# For graphql requests
|
||||||
'UNKNOWN': 'unknown',
|
"UNKNOWN": "unknown",
|
||||||
'FEMALE': 'female_singular',
|
"FEMALE": "female_singular",
|
||||||
'MALE': 'male_singular',
|
"MALE": "male_singular",
|
||||||
# '': 'female_singular_guess',
|
# '': 'female_singular_guess',
|
||||||
# '': 'male_singular_guess',
|
# '': 'male_singular_guess',
|
||||||
# '': 'mixed',
|
# '': 'mixed',
|
||||||
'NEUTER': 'neuter_singular',
|
"NEUTER": "neuter_singular",
|
||||||
# '': 'unknown_singular',
|
# '': 'unknown_singular',
|
||||||
# '': 'female_plural',
|
# '': 'female_plural',
|
||||||
# '': 'male_plural',
|
# '': 'male_plural',
|
||||||
@@ -168,7 +168,7 @@ class ReqUrl(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
facebookEncoding = 'UTF-8'
|
facebookEncoding = "UTF-8"
|
||||||
|
|
||||||
|
|
||||||
def now():
|
def now():
|
||||||
@@ -177,9 +177,9 @@ def now():
|
|||||||
|
|
||||||
def strip_to_json(text):
|
def strip_to_json(text):
|
||||||
try:
|
try:
|
||||||
return text[text.index('{') :]
|
return text[text.index("{") :]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise FBchatException('No JSON object found: {!r}'.format(text))
|
raise FBchatException("No JSON object found: {!r}".format(text))
|
||||||
|
|
||||||
|
|
||||||
def get_decoded_r(r):
|
def get_decoded_r(r):
|
||||||
@@ -201,12 +201,12 @@ def get_json(r):
|
|||||||
def digitToChar(digit):
|
def digitToChar(digit):
|
||||||
if digit < 10:
|
if digit < 10:
|
||||||
return str(digit)
|
return str(digit)
|
||||||
return chr(ord('a') + digit - 10)
|
return chr(ord("a") + digit - 10)
|
||||||
|
|
||||||
|
|
||||||
def str_base(number, base):
|
def str_base(number, base):
|
||||||
if number < 0:
|
if number < 0:
|
||||||
return '-' + str_base(-number, base)
|
return "-" + str_base(-number, base)
|
||||||
(d, m) = divmod(number, base)
|
(d, m) = divmod(number, base)
|
||||||
if d > 0:
|
if d > 0:
|
||||||
return str_base(d, base) + digitToChar(m)
|
return str_base(d, base) + digitToChar(m)
|
||||||
@@ -226,55 +226,55 @@ def getSignatureID():
|
|||||||
def generateOfflineThreadingID():
|
def generateOfflineThreadingID():
|
||||||
ret = now()
|
ret = now()
|
||||||
value = int(random() * 4294967295)
|
value = int(random() * 4294967295)
|
||||||
string = ("0000000000000000000000" + format(value, 'b'))[-22:]
|
string = ("0000000000000000000000" + format(value, "b"))[-22:]
|
||||||
msgs = format(ret, 'b') + string
|
msgs = format(ret, "b") + string
|
||||||
return str(int(msgs, 2))
|
return str(int(msgs, 2))
|
||||||
|
|
||||||
|
|
||||||
def check_json(j):
|
def check_json(j):
|
||||||
if j.get('error') is None:
|
if j.get("error") is None:
|
||||||
return
|
return
|
||||||
if 'errorDescription' in j:
|
if "errorDescription" in j:
|
||||||
# 'errorDescription' is in the users own language!
|
# 'errorDescription' is in the users own language!
|
||||||
raise FBchatFacebookError(
|
raise FBchatFacebookError(
|
||||||
'Error #{} when sending request: {}'.format(
|
"Error #{} when sending request: {}".format(
|
||||||
j['error'], j['errorDescription']
|
j["error"], j["errorDescription"]
|
||||||
),
|
),
|
||||||
fb_error_code=j['error'],
|
fb_error_code=j["error"],
|
||||||
fb_error_message=j['errorDescription'],
|
fb_error_message=j["errorDescription"],
|
||||||
)
|
)
|
||||||
elif 'debug_info' in j['error'] and 'code' in j['error']:
|
elif "debug_info" in j["error"] and "code" in j["error"]:
|
||||||
raise FBchatFacebookError(
|
raise FBchatFacebookError(
|
||||||
'Error #{} when sending request: {}'.format(
|
"Error #{} when sending request: {}".format(
|
||||||
j['error']['code'], repr(j['error']['debug_info'])
|
j["error"]["code"], repr(j["error"]["debug_info"])
|
||||||
),
|
),
|
||||||
fb_error_code=j['error']['code'],
|
fb_error_code=j["error"]["code"],
|
||||||
fb_error_message=j['error']['debug_info'],
|
fb_error_message=j["error"]["debug_info"],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise FBchatFacebookError(
|
raise FBchatFacebookError(
|
||||||
'Error {} when sending request'.format(j['error']), fb_error_code=j['error']
|
"Error {} when sending request".format(j["error"]), fb_error_code=j["error"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_request(r, as_json=True):
|
def check_request(r, as_json=True):
|
||||||
if not r.ok:
|
if not r.ok:
|
||||||
raise FBchatFacebookError(
|
raise FBchatFacebookError(
|
||||||
'Error when sending request: Got {} response'.format(r.status_code),
|
"Error when sending request: Got {} response".format(r.status_code),
|
||||||
request_status_code=r.status_code,
|
request_status_code=r.status_code,
|
||||||
)
|
)
|
||||||
|
|
||||||
content = get_decoded_r(r)
|
content = get_decoded_r(r)
|
||||||
|
|
||||||
if content is None or len(content) == 0:
|
if content is None or len(content) == 0:
|
||||||
raise FBchatFacebookError('Error when sending request: Got empty response')
|
raise FBchatFacebookError("Error when sending request: Got empty response")
|
||||||
|
|
||||||
if as_json:
|
if as_json:
|
||||||
content = strip_to_json(content)
|
content = strip_to_json(content)
|
||||||
try:
|
try:
|
||||||
j = json.loads(content)
|
j = json.loads(content)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise FBchatFacebookError('Error while parsing JSON: {!r}'.format(content))
|
raise FBchatFacebookError("Error while parsing JSON: {!r}".format(content))
|
||||||
check_json(j)
|
check_json(j)
|
||||||
log.debug(j)
|
log.debug(j)
|
||||||
return j
|
return j
|
||||||
@@ -283,12 +283,12 @@ def check_request(r, as_json=True):
|
|||||||
|
|
||||||
|
|
||||||
def get_jsmods_require(j, index):
|
def get_jsmods_require(j, index):
|
||||||
if j.get('jsmods') and j['jsmods'].get('require'):
|
if j.get("jsmods") and j["jsmods"].get("require"):
|
||||||
try:
|
try:
|
||||||
return j['jsmods']['require'][0][index][0]
|
return j["jsmods"]["require"][0][index][0]
|
||||||
except (KeyError, IndexError) as e:
|
except (KeyError, IndexError) as e:
|
||||||
log.warning(
|
log.warning(
|
||||||
'Error when getting jsmods_require: {}. Facebook might have changed protocol'.format(
|
"Error when getting jsmods_require: {}. Facebook might have changed protocol".format(
|
||||||
j
|
j
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -298,13 +298,13 @@ def get_jsmods_require(j, index):
|
|||||||
def get_emojisize_from_tags(tags):
|
def get_emojisize_from_tags(tags):
|
||||||
if tags is None:
|
if tags is None:
|
||||||
return None
|
return None
|
||||||
tmp = [tag for tag in tags if tag.startswith('hot_emoji_size:')]
|
tmp = [tag for tag in tags if tag.startswith("hot_emoji_size:")]
|
||||||
if len(tmp) > 0:
|
if len(tmp) > 0:
|
||||||
try:
|
try:
|
||||||
return LIKES[tmp[0].split(':')[1]]
|
return LIKES[tmp[0].split(":")[1]]
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
log.exception(
|
log.exception(
|
||||||
'Could not determine emoji size from {} - {}'.format(tags, tmp)
|
"Could not determine emoji size from {} - {}".format(tags, tmp)
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ def get_files_from_urls(file_urls):
|
|||||||
(
|
(
|
||||||
basename(file_url),
|
basename(file_url),
|
||||||
r.content,
|
r.content,
|
||||||
r.headers.get('Content-Type') or guess_type(file_url)[0],
|
r.headers.get("Content-Type") or guess_type(file_url)[0],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return files
|
return files
|
||||||
@@ -348,7 +348,7 @@ def get_files_from_paths(filenames):
|
|||||||
files = []
|
files = []
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
files.append(
|
files.append(
|
||||||
(basename(filename), open(filename, 'rb'), guess_type(filename)[0])
|
(basename(filename), open(filename, "rb"), guess_type(filename)[0])
|
||||||
)
|
)
|
||||||
yield files
|
yield files
|
||||||
for fn, fp, ft in files:
|
for fn, fp, ft in files:
|
||||||
|
@@ -115,14 +115,14 @@ def compare(client, thread):
|
|||||||
def message_with_mentions(request, client, client2, group):
|
def message_with_mentions(request, client, client2, group):
|
||||||
text = "Hi there ["
|
text = "Hi there ["
|
||||||
mentions = []
|
mentions = []
|
||||||
if 'me' in request.param:
|
if "me" in request.param:
|
||||||
mentions.append(Mention(thread_id=client.uid, offset=len(text), length=2))
|
mentions.append(Mention(thread_id=client.uid, offset=len(text), length=2))
|
||||||
text += "me, "
|
text += "me, "
|
||||||
if 'other' in request.param:
|
if "other" in request.param:
|
||||||
mentions.append(Mention(thread_id=client2.uid, offset=len(text), length=5))
|
mentions.append(Mention(thread_id=client2.uid, offset=len(text), length=5))
|
||||||
text += "other, "
|
text += "other, "
|
||||||
# Unused, because Facebook don't properly support sending mentions with groups as targets
|
# Unused, because Facebook don't properly support sending mentions with groups as targets
|
||||||
if 'group' in request.param:
|
if "group" in request.param:
|
||||||
mentions.append(Mention(thread_id=group["id"], offset=len(text), length=5))
|
mentions.append(Mention(thread_id=group["id"], offset=len(text), length=5))
|
||||||
text += "group, "
|
text += "group, "
|
||||||
text += "nothing]"
|
text += "nothing]"
|
||||||
|
@@ -120,6 +120,6 @@ def test_send_remote_files(client, catch_event, compare):
|
|||||||
assert len(x.res["message_object"].attachments) == len(files)
|
assert len(x.res["message_object"].attachments) == len(files)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('wave_first', [True, False])
|
@pytest.mark.parametrize("wave_first", [True, False])
|
||||||
def test_wave(client, wave_first):
|
def test_wave(client, wave_first):
|
||||||
client.wave(wave_first)
|
client.wave(wave_first)
|
||||||
|
@@ -9,4 +9,4 @@ def test_catch_event(client2, catch_event):
|
|||||||
mid = "test"
|
mid = "test"
|
||||||
with catch_event("onMessage") as x:
|
with catch_event("onMessage") as x:
|
||||||
client2.onMessage(mid=mid)
|
client2.onMessage(mid=mid)
|
||||||
assert x.res['mid'] == mid
|
assert x.res["mid"] == mid
|
||||||
|
@@ -135,7 +135,7 @@ def test_typing_status(client, catch_event, compare, status):
|
|||||||
assert compare(x, status=status)
|
assert compare(x, status=status)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('require_admin_approval', [True, False])
|
@pytest.mark.parametrize("require_admin_approval", [True, False])
|
||||||
def test_change_approval_mode(client1, group, catch_event, require_admin_approval):
|
def test_change_approval_mode(client1, group, catch_event, require_admin_approval):
|
||||||
with catch_event("onApprovalModeChange") as x:
|
with catch_event("onApprovalModeChange") as x:
|
||||||
client1.changeGroupApprovalMode(require_admin_approval, group["id"])
|
client1.changeGroupApprovalMode(require_admin_approval, group["id"])
|
||||||
|
@@ -106,7 +106,7 @@ def load_client(n, cache):
|
|||||||
client = Client(
|
client = Client(
|
||||||
load_variable("client{}_email".format(n), cache),
|
load_variable("client{}_email".format(n), cache),
|
||||||
load_variable("client{}_password".format(n), cache),
|
load_variable("client{}_password".format(n), cache),
|
||||||
user_agent='Mozilla/5.0 (Windows NT 6.3; WOW64; ; NCT50_AAP285C84A1328) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36',
|
user_agent="Mozilla/5.0 (Windows NT 6.3; WOW64; ; NCT50_AAP285C84A1328) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
|
||||||
session_cookies=cache.get("client{}_session".format(n), None),
|
session_cookies=cache.get("client{}_session".format(n), None),
|
||||||
max_tries=1,
|
max_tries=1,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user