More documentation work, changed addUsersToGroup
back to taking a list of user IDs
Created new README, and finished `intro`
This commit is contained in:
122
README.rst
122
README.rst
@@ -1,118 +1,26 @@
|
||||
======
|
||||
fbchat
|
||||
======
|
||||
fbchat: Facebook Chat (Messenger) for Python
|
||||
============================================
|
||||
|
||||
.. image:: docs/_static/license.svg
|
||||
:target: LICENSE.txt
|
||||
:alt: License: BSD
|
||||
|
||||
Facebook Chat (`Messenger <https://www.messenger.com/>`__) for Python. This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`__.
|
||||
.. image:: docs/_static/python-versions.svg
|
||||
:target: https://pypi.python.org/pypi/fbchat
|
||||
:alt: Supported python versions: 2.7, 3.4, 3.5 and 3.6
|
||||
|
||||
**No XMPP or API key is needed**. Just use your EMAIL and PASSWORD.
|
||||
Facebook Chat (`Messenger <https://www.facebook.com/messages/>`__) for Python.
|
||||
This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`__.
|
||||
|
||||
**No XMPP or API key is needed**. Just use your email and password.
|
||||
|
||||
Installation
|
||||
============
|
||||
Go to `ReadTheDocs <https://fbchat.readthedocs.com>`__ to see the full documentation,
|
||||
or jump right into the code by viewing the `examples`_
|
||||
|
||||
Simple:
|
||||
Installation:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install fbchat
|
||||
|
||||
|
||||
Example Login
|
||||
=============
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import fbchat
|
||||
|
||||
client = fbchat.Client('YOUR_EMAIL', 'YOUR_PASSWORD')
|
||||
|
||||
Sending a Message
|
||||
=================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
friends = client.getUsers("FRIEND'S NAME") # return a list of names
|
||||
friend = friends[0]
|
||||
sent = client.send(friend.uid, "Your Message")
|
||||
if sent:
|
||||
print("Message sent successfully!")
|
||||
# IMAGES
|
||||
client.sendLocalImage(friend.uid,message='<message text>',image='<path/to/image/file>') # send local image
|
||||
imgurl = "http://i.imgur.com/LDQ2ITV.jpg"
|
||||
client.sendRemoteImage(friend.uid,message='<message text>', image=imgurl) # send image from image url
|
||||
|
||||
|
||||
Getting user info from user id
|
||||
==============================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
friend1 = client.getUsers('<friend name 1>')[0]
|
||||
friend2 = client.getUsers('<friend name 2>')[0]
|
||||
friend1_info = client.getUserInfo(friend1.uid) # returns dict with details
|
||||
both_info = client.getUserInfo(friend1.uid,friend2.uid) # query both together, returns list of dicts
|
||||
friend1_name = friend1_info['name']
|
||||
|
||||
|
||||
Getting last messages sent
|
||||
==========================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
last_messages = client.getThreadInfo(friend.uid, last_n=20)
|
||||
last_messages.reverse() # messages come in reversed order
|
||||
|
||||
for message in last_messages:
|
||||
print(message.body)
|
||||
|
||||
|
||||
Example Echobot
|
||||
===============
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import fbchat
|
||||
#subclass fbchat.Client and override required methods
|
||||
class EchoBot(fbchat.Client):
|
||||
|
||||
def __init__(self,email, password, debug=True, user_agent=None):
|
||||
fbchat.Client.__init__(self,email, password, debug, user_agent)
|
||||
|
||||
def on_message(self, mid, author_id, author_name, message, metadata):
|
||||
self.markAsDelivered(author_id, mid) #mark delivered
|
||||
self.markAsRead(author_id) #mark read
|
||||
|
||||
print("%s said: %s"%(author_id, message))
|
||||
|
||||
#if you are not the author, echo
|
||||
if str(author_id) != str(self.uid):
|
||||
self.send(author_id,message)
|
||||
|
||||
bot = EchoBot("<email>", "<password>")
|
||||
bot.listen()
|
||||
|
||||
|
||||
Saving session
|
||||
==========================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
session_cookies = client.setSession()
|
||||
# save session_cookies
|
||||
|
||||
|
||||
Loading session
|
||||
==========================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
client = fbchat.Client(None, None, session_cookies=session_cookies)
|
||||
# OR
|
||||
client.setSession(session_cookies)
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Taehoon Kim / `@carpedm20 <http://carpedm20.github.io/about/>`__
|
||||
© Copyright 2015 - 2017 by Taehoon Kim / `@carpedm20 <http://carpedm20.github.io/about/>`__
|
||||
|
BIN
docs/_static/find-group-id.png
vendored
Normal file
BIN
docs/_static/find-group-id.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
10
docs/api.rst
10
docs/api.rst
@@ -13,10 +13,13 @@ If you are looking for information on a specific function, class, or method, thi
|
||||
Client
|
||||
------
|
||||
|
||||
.. todo::
|
||||
Write introduction text about `Client`, and add documentation for all events
|
||||
This is the main class of `fbchat`, which contains all the methods you use to interract with Facebook.
|
||||
You can extend this class, and overwrite the events, to provide custom event handling (mainly used while listening)
|
||||
|
||||
.. autoclass:: Client(email, password, user_agent=None, max_retries=5, session_cookies=None, logging_level=logging.INFO, set_default_events=True)
|
||||
.. todo::
|
||||
Add documentation for all events
|
||||
|
||||
.. autoclass:: Client(email, password, user_agent=None, max_retries=5, session_cookies=None, logging_level=logging.INFO)
|
||||
:members:
|
||||
|
||||
.. automethod:: sendRemoteImage(image_url, message=None, thread_id=None, thread_type=ThreadType.USER)
|
||||
@@ -33,6 +36,7 @@ A good tip is to write ``from fbchat.models import *`` at the start of your sour
|
||||
|
||||
.. automodule:: fbchat.models
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
.. _api_utils:
|
||||
|
@@ -7,22 +7,20 @@ Examples
|
||||
These are a few examples on how to use `fbchat`. Remember to swap out `<email>` and `<password>` for your email and password
|
||||
|
||||
|
||||
Sending messages
|
||||
----------------
|
||||
Interacting with Threads
|
||||
------------------------
|
||||
|
||||
This will send one of each message type to the specified thread
|
||||
This will interract with the thread in every way `fbchat` supports
|
||||
|
||||
.. literalinclude:: ../examples/send.py
|
||||
:language: python
|
||||
.. literalinclude:: ../examples/interract.py
|
||||
|
||||
|
||||
Getting information
|
||||
-------------------
|
||||
Fetching Information
|
||||
--------------------
|
||||
|
||||
This will show the different ways of fetching information about users and threads
|
||||
|
||||
.. literalinclude:: ../examples/get.py
|
||||
:language: python
|
||||
.. literalinclude:: ../examples/fetch.py
|
||||
|
||||
|
||||
Echobot
|
||||
@@ -31,22 +29,20 @@ Echobot
|
||||
This will reply to any message with the same message
|
||||
|
||||
.. literalinclude:: ../examples/echobot.py
|
||||
:language: python
|
||||
|
||||
|
||||
Remove bot
|
||||
Remove Bot
|
||||
----------
|
||||
|
||||
This will remove a user from a group if they write the message `Remove me!`
|
||||
|
||||
.. literalinclude:: ../examples/removebot.py
|
||||
:language: python
|
||||
|
||||
|
||||
"Keep it"-bot
|
||||
-------------
|
||||
"Prevent changes"-Bot
|
||||
---------------------
|
||||
|
||||
This will prevent chat color, emoji, nicknames and chat name from being changed. It will also prevent people from being added and removed
|
||||
This will prevent chat color, emoji, nicknames and chat name from being changed.
|
||||
It will also prevent people from being added and removed
|
||||
|
||||
.. literalinclude:: ../examples/keepbot.py
|
||||
:language: python
|
||||
|
@@ -1,4 +1,5 @@
|
||||
.. highlight:: python
|
||||
.. module:: fbchat
|
||||
.. fbchat documentation master file, created by
|
||||
sphinx-quickstart on Thu May 25 15:43:01 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
@@ -16,26 +17,36 @@ Release v\ |version|. (:ref:`install`)
|
||||
|
||||
.. image:: /_static/license.svg
|
||||
:target: https://github.com/carpedm20/fbchat/blob/master/LICENSE.txt
|
||||
:alt: License: BSD
|
||||
|
||||
.. generated with: https://img.shields.io/badge/python-2.7%2C%203.4%2C%203.5%2C%203.6-blue.svg
|
||||
|
||||
.. image:: /_static/python-versions.svg
|
||||
:target: https://pypi.python.org/pypi/fbchat
|
||||
:alt: Supported python versions: 2.7, 3.4, 3.5 and 3.6
|
||||
|
||||
Facebook Chat (`Messenger <https://www.facebook.com/messages/>`__) for Python. This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`__.
|
||||
Facebook Chat (`Messenger <https://www.facebook.com/messages/>`_) for Python.
|
||||
This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`_.
|
||||
|
||||
**No XMPP or API key is needed**. Just use your email and password.
|
||||
|
||||
Currently `fbchat` support Python 2.7, 3.4, 3.5 and 3.6:
|
||||
|
||||
`fbchat` works by emulating the browser. This means doing the exact same GET/POST requests and tricking Facebook into thinking we're accessing the website normally.
|
||||
Because we're doing it this way, this API requires the credentials of a Facebook account.
|
||||
`fbchat` works by emulating the browser.
|
||||
This means doing the exact same GET/POST requests and tricking Facebook into thinking it's accessing the website normally.
|
||||
Therefore, this API requires the credentials of a Facebook account.
|
||||
|
||||
.. warning::
|
||||
We are not responsible if your account gets banned for spammy activities such as sending lots of messages to people you don't know, sending messages very quickly, sending spammy looking URLs, logging in and out very quickly... Be responsible Facebook citizens.
|
||||
We are not responsible if your account gets banned for spammy activities,
|
||||
such as sending lots of messages to people you don't know, sending messages very quickly,
|
||||
sending spammy looking URLs, logging in and out very quickly... Be responsible Facebook citizens.
|
||||
|
||||
.. note::
|
||||
Facebook now has an `official API <https://developers.facebook.com/docs/messenger-platform>`_ for chat bots, so if you're familiar with node.js, this might be what you're looking for.
|
||||
Facebook now has an `official API <https://developers.facebook.com/docs/messenger-platform>`_ for chat bots,
|
||||
so if you're familiar with node.js, this might be what you're looking for.
|
||||
|
||||
If you're already familiar with the basics of how Facebook works internally, go to :ref:`examples` to see example usage of `fbchat`
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
246
docs/intro.rst
246
docs/intro.rst
@@ -1,20 +1,138 @@
|
||||
.. highlight:: python
|
||||
.. module:: fbchat
|
||||
.. _intro:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. todo::
|
||||
Make a general introduction to `fbchat`
|
||||
`fbchat` uses your email and password to communicate with the Facebook server.
|
||||
That means that you should always store your password in a seperate file, in case e.g. someone looks over your shoulder while you're writing code.
|
||||
You should also make sure that the file's access control is appropriately restrictive
|
||||
|
||||
|
||||
.. _intro_logging_in:
|
||||
|
||||
Logging in
|
||||
Logging In
|
||||
----------
|
||||
|
||||
.. todo::
|
||||
Write something about logging in, logging out, checking login, 2FA and the event `on2FACode`, here
|
||||
Simply create an instance of :class:`Client`. If you have two factor authentication enabled, type the code in the terminal prompt
|
||||
(If you want to supply the code in another fasion, overwrite :func:`Client.on2FACode`)::
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
client = Client('<email>', '<password>')
|
||||
|
||||
Replace ``<email>`` and ``<password>`` with your email and password respectively
|
||||
|
||||
.. note::
|
||||
For ease of use then most of the code snippets in this document will assume you've already completed the login process
|
||||
Though the second line, ``from fbchat.models import *``, is not strictly neccesary here, later code snippets will assume you've done this
|
||||
|
||||
If you want to change how verbose `fbchat` is, change the logging level (in :class:`Client`)
|
||||
|
||||
Throughout your code, if you want to check whether you are still logged in, use :func:`Client.isLoggedIn`.
|
||||
An example would be to login again if you've been logged out, using :func:`Client.login`::
|
||||
|
||||
if not client.isLoggedIn():
|
||||
client.login('<email>', '<password>')
|
||||
|
||||
When you're done using the client, and want to securely logout, use :func:`Client.logout`::
|
||||
|
||||
client.logout()
|
||||
|
||||
|
||||
.. _intro_threads:
|
||||
|
||||
Threads
|
||||
-------
|
||||
|
||||
A thread can refer to two things: A Messenger group chat or a single Facebook user
|
||||
|
||||
:class:`models.ThreadType` is an enumerator with two values: ``USER`` and ``GROUP``.
|
||||
These will specify whether the thread is a single user chat or a group chat.
|
||||
This is required for many of `fbchat`'s functions, since Facebook differetiates between these two internally
|
||||
|
||||
Searching for group chats and finding their ID is not yet possible with `fbchat`,
|
||||
but searching for users is possible via. :func:`Client.getUsers`. See :ref:`intro_fetching`
|
||||
|
||||
You can get your own user ID by using :any:`Client.uid`
|
||||
|
||||
Getting the ID of a group chat is fairly trivial though, since you only need to navigate to `<https://www.facebook.com/messages/>`_,
|
||||
click on the group you want to find the ID of, and then read the id from the address bar.
|
||||
The URL will look something like this: ``https://www.facebook.com/messages/t/1234567890``, where ``1234567890`` would be the ID of the group.
|
||||
An image to illustrate this is shown below:
|
||||
|
||||
.. image:: /_static/find-group-id.png
|
||||
:alt: An image illustrating how to find the ID of a group
|
||||
|
||||
The same method can be applied to some user accounts, though if they've set a custom URL, then you'll just see that URL instead
|
||||
|
||||
Here's an snippet showing the usage of thread IDs and thread types, where ``<user id>`` and ``<group id>``
|
||||
corresponds to the ID of a single user, and the ID of a group respectively::
|
||||
|
||||
client.sendMessage('<message>', thread_id='<user id>', thread_type=ThreadType.USER)
|
||||
client.sendMessage('<message>', thread_id='<group id>', thread_type=ThreadType.GROUP)
|
||||
|
||||
Some functions (e.g. :func:`Client.changeThreadColor`) don't require a thread type, so in these cases you just provide the thread ID::
|
||||
|
||||
client.changeThreadColor(ThreadColor.BILOBA_FLOWER, thread_id='<user id>')
|
||||
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, thread_id='<group id>')
|
||||
|
||||
|
||||
.. _intro_message_ids:
|
||||
|
||||
Message IDs
|
||||
-----------
|
||||
|
||||
Every message you send on Facebook has a unique ID, and every action you do in a thread,
|
||||
like changing a nickname or adding a person, has a unique ID too.
|
||||
|
||||
Some of `fbchat`'s functions require these ID's, like :func:`Client.reactToMessage`,
|
||||
and some of then provide this ID, like :func:`Client.sendMessage`.
|
||||
This snippet shows how to send a message, and then use the returned ID to react to that message with a 😍 emoji::
|
||||
|
||||
message_id = client.sendMessage('message', thread_id=thread_id, thread_type=thread_type)
|
||||
client.reactToMessage(message_id, MessageReaction.LOVE)
|
||||
|
||||
|
||||
.. _intro_interacting:
|
||||
|
||||
Interacting with Threads
|
||||
------------------------
|
||||
|
||||
`fbchat` provides multiple functions for interacting with threads
|
||||
|
||||
Most functionality works on all threads, though some things,
|
||||
like adding users to and removing users from a group chat, logically only works on group chats
|
||||
|
||||
The simplest way of using `fbchat` is to send a message.
|
||||
The following snippet will, as you've probably already figured out, send the message `test message` to your account::
|
||||
|
||||
message_id = client.sendMessage('test message', thread_id=client.uid, thread_type=ThreadType.USER)
|
||||
|
||||
You can see a full example showing all the possible thread interactions with `fbchat` by going to :ref:`examples`
|
||||
|
||||
|
||||
.. _intro_fetching:
|
||||
|
||||
Fetching Information
|
||||
--------------------
|
||||
|
||||
You can use `fbchat` to fetch basic information like user names, profile pictures, thread names and user IDs
|
||||
|
||||
You can retrieve a user's ID with :func:`Client.getUsers`.
|
||||
The following snippet will search for users by their name, take the first (and most likely) user, and then get their user ID from the result::
|
||||
|
||||
users = client.getUsers('<name of user>')
|
||||
user = users[0]
|
||||
print("User's ID: {}".format(user.uid))
|
||||
print("User's name: {}".format(user.name))
|
||||
print("User's profile picture url: {}".format(user.photo))
|
||||
print("User's main url: {}".format(user.url))
|
||||
|
||||
Since this uses Facebook's search functions, you don't have to specify the whole name, first names will usually be enough
|
||||
|
||||
You can see a full example showing all the possible ways to fetch information with `fbchat` by going to :ref:`examples`
|
||||
|
||||
|
||||
.. _intro_sessions:
|
||||
@@ -22,65 +140,81 @@ Logging in
|
||||
Sessions
|
||||
--------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of sessions
|
||||
`fbchat` provides functions to retrieve and set the session cookies.
|
||||
This will enable you to store the session cookies in a seperate file, so that you don't have to login each time you start your script.
|
||||
Use :func:`Client.getSession` to retrieve the cookies::
|
||||
|
||||
session_cookies = client.getSession()
|
||||
|
||||
.. _intro_sending:
|
||||
Then you can use :func:`Client.setSession`::
|
||||
|
||||
Sending messages
|
||||
----------------
|
||||
client.setSession(session_cookies)
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of how you send information
|
||||
Or you can set the ``session_cookies`` on your initial login.
|
||||
(If the session cookies are invalid, your email and password will be used to login instead)::
|
||||
|
||||
.. literalinclude:: ../examples/send.py
|
||||
:language: python
|
||||
client = Client('<email>', '<password>', session_cookies=session_cookies)
|
||||
|
||||
|
||||
.. _intro_fetching:
|
||||
|
||||
Fetching information
|
||||
--------------------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of fetching information
|
||||
|
||||
.. literalinclude:: ../examples/get.py
|
||||
:language: python
|
||||
|
||||
|
||||
.. _intro_thread_id:
|
||||
|
||||
Thread ids
|
||||
----------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of thread ids
|
||||
|
||||
|
||||
.. _intro_thread_type:
|
||||
|
||||
Thread types
|
||||
------------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of thread types
|
||||
|
||||
|
||||
.. _intro_message_ids:
|
||||
|
||||
Message ids
|
||||
-----------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of message ids
|
||||
.. warning::
|
||||
You session cookies can be just as valueable as you password, so store them with equal care
|
||||
|
||||
|
||||
.. _intro_events:
|
||||
|
||||
Events
|
||||
------
|
||||
Listening & Events
|
||||
------------------
|
||||
|
||||
.. todo::
|
||||
Make an introduction to and show example usage of the event system
|
||||
To use the listening functions `fbchat` offers (like :func:`Client.listen`),
|
||||
you have to define what should be executed when certain events happen.
|
||||
By default, (most) events will just be a `logging.info` statement,
|
||||
meaning it will simply print information to the console when an event happens
|
||||
|
||||
.. note::
|
||||
You can identify the event methods by their `on` prefix, e.g. `onMessage`
|
||||
|
||||
The event actions can be changed by subclassing the :class:`Client`, and then overwriting the event methods::
|
||||
|
||||
class CustomClient(Client):
|
||||
def onMessage(self, mid, author_id, message, thread_id, thread_type, ts, metadata, msg, **kwargs):
|
||||
# Do something with the message here
|
||||
pass
|
||||
|
||||
client = CustomClient('<email>', '<password>')
|
||||
|
||||
**Notice:** The following snippet is as equally valid as the previous one::
|
||||
|
||||
class CustomClient(Client):
|
||||
def onMessage(self, message, author_id, thread_id, thread_type, **kwargs):
|
||||
# Do something with the message here
|
||||
pass
|
||||
|
||||
client = CustomClient('<email>', '<password>')
|
||||
|
||||
The change was in the parameters that our `onMessage` method took: ``message`` and ``author_id`` got swapped,
|
||||
and ``mid``, ``ts``, ``metadata`` and ``msg`` got removed, but the function still works, since we included ``**kwargs``
|
||||
|
||||
.. note::
|
||||
Therefore, for both backwards and forwards compatability,
|
||||
the API actually requires that you include ``**kwargs`` as your final argument.
|
||||
|
||||
View the :ref:`examples` to see some more examples illustrating the event system
|
||||
|
||||
|
||||
.. _intro_submitting:
|
||||
|
||||
Submitting Issues
|
||||
-----------------
|
||||
|
||||
If you're having trouble with some of the snippets shown here, or you think some of the functionality is broken,
|
||||
please feel free to submit an issue on `Github <https://github.com/carpedm20/fbchat>`_.
|
||||
One side note is that you should first login with ``logging_level`` set to ``logging.DEBUG``::
|
||||
|
||||
from fbchat import Client
|
||||
import logging
|
||||
client = Client('<email>', '<password>', logging_level=logging.DEBUG)
|
||||
|
||||
Then you can submit the relevant parts of this log, and detailed steps on how to reproduce
|
||||
|
||||
.. warning::
|
||||
Always remove your credentials from any debug information you may provide us.
|
||||
Preferably, use a test account, in case you miss anything
|
||||
|
@@ -1,10 +1,11 @@
|
||||
.. highlight:: sh
|
||||
.. module:: fbchat
|
||||
.. _testing:
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
To use these tests copy ``tests/data.json`` to ``tests/my_data.json`` or type the information manually in the terminal prompts.
|
||||
To use the tests, copy ``tests/data.json`` to ``tests/my_data.json`` or type the information manually in the terminal prompts.
|
||||
|
||||
- email: Your (or a test user's) email / phone number
|
||||
- password: Your (or a test user's) password
|
||||
|
@@ -1,19 +1,23 @@
|
||||
.. highlight:: python
|
||||
.. module:: fbchat
|
||||
.. _todo:
|
||||
|
||||
Todo
|
||||
====
|
||||
|
||||
This page will be periodically updated to show missing features and documentation
|
||||
|
||||
Functionality
|
||||
-------------
|
||||
|
||||
- Implement Client.changeThreadEmoji
|
||||
- Implement Client.changeNickname
|
||||
Missing Functionality
|
||||
---------------------
|
||||
|
||||
- Implement Client.searchForThread
|
||||
- This will use the graphql request API
|
||||
- Implement Client.searchForMessage
|
||||
- This will use the graphql request API
|
||||
- Implement chatting with pages
|
||||
- This might require a new :class:`models.ThreadType`, something like ``ThreadType.PAGE``
|
||||
- Rework `User`, `Thread` and `Message` models, and rework fething methods, to make the whole process more streamlined
|
||||
|
||||
|
||||
Documentation
|
||||
|
50
examples/fetch.py
Normal file
50
examples/fetch.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
|
||||
client = Client("<email>", "<password>")
|
||||
|
||||
# Fetches a list of all users you're currently chatting with, as `User` objects
|
||||
users = client.getAllUsers()
|
||||
|
||||
print('user IDs: {}'.format(user.uid for user in users))
|
||||
print("user's names: {}".format(user.name for user in users))
|
||||
|
||||
|
||||
# If we have a user id, we can use `getUserInfo` to fetch a `User` object
|
||||
user = client.getUserInfo('<user id>')
|
||||
# We can also query both mutiple users together, which returns list of `User` objects
|
||||
users = client.getUserInfo('<1st user id>', '<2nd user id>', '<3rd user id>')
|
||||
|
||||
print('User INFO: {}'.format(user))
|
||||
print("User's INFO: {}".format(users))
|
||||
|
||||
|
||||
# `getUsers` 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:
|
||||
user = client.getUsers('<name of user>')[0]
|
||||
|
||||
print('user ID: {}'.format(user.uid))
|
||||
print("user's name: {}".format(user.name))
|
||||
|
||||
|
||||
# Fetches a list of all threads you're currently chatting with
|
||||
threads = client.getThreadList()
|
||||
# Fetches the next 10 threads
|
||||
threads += client.getThreadList(start=20, length=10)
|
||||
|
||||
print("Thread's INFO: {}".format(threads))
|
||||
|
||||
|
||||
# Gets the last 10 messages sent to the thread
|
||||
messages = client.getThreadInfo(last_n=10, thread_id='<thread id>', thread_type=ThreadType)
|
||||
# Since the message come in reversed order, reverse them
|
||||
messages.reverse()
|
||||
|
||||
# Prints the content of all the messages
|
||||
for message in messages:
|
||||
print(message.body)
|
||||
|
||||
|
||||
# Here should be an example of `getUnread`
|
@@ -1,8 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
|
||||
client = Client("<email>", "<password>")
|
||||
|
||||
# This should show example usage of getAllUsers, getUsers, getUserInfo, getThreadInfo, getThreadList and getUnread
|
55
examples/interract.py
Normal file
55
examples/interract.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
|
||||
client = Client("<email>", "<password>")
|
||||
|
||||
thread_id = '1234567890'
|
||||
thread_type = ThreadType.GROUP
|
||||
|
||||
# Will send a message to the thread
|
||||
client.sendMessage('<message>', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will send the default `like` emoji
|
||||
client.sendEmoji(emoji=None, size=EmojiSize.LARGE, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will send the emoji `👍`
|
||||
client.sendEmoji(emoji='👍', size=EmojiSize.LARGE, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will send the image located at `<image path>`
|
||||
client.sendLocalImage('<image path>', message='This is a local image', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will download the image at the url `<image url>`, and then send it
|
||||
client.sendRemoteImage('<image url>', message='This is a remote image', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
|
||||
# Only do these actions if the thread is a group
|
||||
if thread_type == ThreadType.GROUP:
|
||||
# Will remove the user with ID `<user id>` from the thread
|
||||
client.removeUserFromGroup('<user id>', thread_id=thread_id)
|
||||
|
||||
# Will add the user with ID `<user id>` to the thread
|
||||
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
|
||||
client.addUsersToGroup(['<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>`
|
||||
client.changeNickname('<new nickname>', '<user id>', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will change the title of the thread to `<title>`
|
||||
client.changeThreadTitle('<title>', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will set the typing status of the thread to `TYPING`
|
||||
client.setTypingStatus(TypingStatus.TYPING, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# Will change the thread color to `MESSENGER_BLUE`
|
||||
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, thread_id=thread_id)
|
||||
|
||||
# Will change the thread emoji to `👍`
|
||||
client.changeThreadEmoji('👍', thread_id=thread_id)
|
||||
|
||||
# Will react to a message with a 😍 emoji
|
||||
client.reactToMessage('<message id>', MessageReaction.LOVE)
|
@@ -9,12 +9,12 @@ old_thread_id = '1234567890'
|
||||
# Change these to match your liking
|
||||
old_color = ThreadColor.MESSENGER_BLUE
|
||||
old_emoji = '👍'
|
||||
old_title = 'Old school'
|
||||
old_title = 'Old group chat name'
|
||||
old_nicknames = {
|
||||
'12345678901': 'Old School user nr. 1',
|
||||
'12345678902': 'Old School user nr. 2',
|
||||
'12345678903': 'Old School user nr. 3',
|
||||
'12345678904': 'Old School user nr. 4'
|
||||
'12345678901': "User nr. 1's nickname",
|
||||
'12345678902': "User nr. 2's nickname",
|
||||
'12345678903': "User nr. 3's nickname",
|
||||
'12345678904': "User nr. 4's nickname"
|
||||
}
|
||||
|
||||
class KeepBot(Client):
|
||||
|
@@ -1,25 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
|
||||
client = Client("<email>", "<password>")
|
||||
|
||||
# Change these to match your thread
|
||||
thread_id = '1234567890'
|
||||
thread_type = ThreadType.GROUP # Or ThreadType.USER
|
||||
|
||||
# This will send a message to the thread
|
||||
client.sendMessage('Hey there', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# This will send the default emoji
|
||||
client.sendEmoji(emoji=None, size=EmojiSize.LARGE, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# This will send the emoji `👍`
|
||||
client.sendEmoji(emoji='👍', size=EmojiSize.LARGE, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# This will send the image called `image.png`
|
||||
client.sendLocalImage('image.png', message='This is a local image', thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
# This will send the image at the url `https://example.com/image.png`
|
||||
client.sendRemoteImage('https://example.com/image.png', message='This is a remote image', thread_id=thread_id, thread_type=thread_type)
|
173
fbchat/client.py
173
fbchat/client.py
@@ -28,12 +28,46 @@ handler = logging.StreamHandler()
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
|
||||
#: This function needs the logger
|
||||
def check_request(r, check_json=True):
|
||||
if not r.ok:
|
||||
log.warning('Error when sending request: Got {} response'.format(r.status_code))
|
||||
return None
|
||||
|
||||
content = get_decoded(r)
|
||||
|
||||
if content is None or len(content) == 0:
|
||||
log.warning('Error when sending request: Got empty response')
|
||||
return None
|
||||
|
||||
if check_json:
|
||||
j = json.loads(strip_to_json(content))
|
||||
if 'error' in j:
|
||||
# 'errorDescription' is in the users own language!
|
||||
log.warning('Error #{} when sending request: {}'.format(j['error'], j['errorDescription']))
|
||||
return None
|
||||
return j
|
||||
else:
|
||||
return r
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""A client for the Facebook Chat (Messenger).
|
||||
|
||||
See https://fbchat.readthedocs.io for complete documentation of the API.
|
||||
"""
|
||||
|
||||
listening = False
|
||||
"""Whether the client is listening. Used when creating an external event loop to determine when to stop listening"""
|
||||
uid = None
|
||||
"""
|
||||
The id of the client.
|
||||
Can be used a `thread_id`. See :ref:`intro_threads` for more info.
|
||||
|
||||
Note: Modifying this results in undefined behaviour
|
||||
"""
|
||||
|
||||
def __init__(self, email, password, debug=False, info_log=False, user_agent=None, max_retries=5,
|
||||
session_cookies=None, logging_level=logging.INFO):
|
||||
"""Initializes and logs in the client
|
||||
@@ -56,7 +90,6 @@ class Client(object):
|
||||
self.seq = "0"
|
||||
self.payloadDefault = {}
|
||||
self.client = 'mercury'
|
||||
self.listening = False
|
||||
self.default_thread_id = None
|
||||
self.default_thread_type = None
|
||||
self.threads = []
|
||||
@@ -359,19 +392,6 @@ class Client(object):
|
||||
r = self._cleanPost(ReqUrl.CHECKPOINT, data)
|
||||
return r
|
||||
|
||||
def _checkRequest(self, r):
|
||||
if not r.ok:
|
||||
log.warning('Error when sending request: Got {} response'.format(r.status_code))
|
||||
return None
|
||||
|
||||
j = get_json(r)
|
||||
if 'error' in j:
|
||||
# 'errorDescription' is in the users own language!
|
||||
log.warning('Error #{} when sending request: {}'.format(j['error'], j['errorDescription']))
|
||||
return None
|
||||
|
||||
return j
|
||||
|
||||
def isLoggedIn(self):
|
||||
"""
|
||||
Sends a request to Facebook to check the login status
|
||||
@@ -469,8 +489,8 @@ class Client(object):
|
||||
def setDefaultThread(self, thread_id, thread_type):
|
||||
"""Sets default thread to send messages to
|
||||
|
||||
:param thread_id: User/Group ID to default to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to default to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
"""
|
||||
self.default_thread_id = thread_id
|
||||
@@ -497,7 +517,7 @@ class Client(object):
|
||||
return given_thread_id, given_thread_type
|
||||
|
||||
"""
|
||||
GET METHODS
|
||||
FETCH METHODS
|
||||
"""
|
||||
|
||||
def getAllUsers(self):
|
||||
@@ -559,8 +579,11 @@ class Client(object):
|
||||
def getUserInfo(self, *user_ids):
|
||||
"""Get user info from id. Unordered.
|
||||
|
||||
.. todo::
|
||||
Make this return a list of User objects
|
||||
|
||||
:param user_ids: One or more user ID(s) to query
|
||||
:return: A raw dataset containing user information
|
||||
:return: (list of) raw user data
|
||||
"""
|
||||
|
||||
def fbidStrip(_fbid):
|
||||
@@ -587,8 +610,8 @@ class Client(object):
|
||||
"""Get the last messages in a thread
|
||||
|
||||
:param last_n: Number of messages to retrieve
|
||||
:param thread_id: User/Group ID to retrieve from. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to retrieve from. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type last_n: int
|
||||
:type thread_type: models.ThreadType
|
||||
:return: Dictionaries, containing message data
|
||||
@@ -679,19 +702,15 @@ class Client(object):
|
||||
# 'last_action_timestamp': 0
|
||||
}
|
||||
|
||||
r = self._post(ReqUrl.THREAD_SYNC, form)
|
||||
if not r.ok or len(r.text) == 0:
|
||||
return None
|
||||
j = check_request(self._post(ReqUrl.THREAD_SYNC, form))
|
||||
|
||||
j = get_json(r)
|
||||
result = {
|
||||
return {
|
||||
"message_counts": j['payload']['message_counts'],
|
||||
"unseen_threads": j['payload']['unseen_thread_ids']
|
||||
}
|
||||
return result
|
||||
|
||||
"""
|
||||
END GET METHODS
|
||||
END FETCH METHODS
|
||||
"""
|
||||
|
||||
"""
|
||||
@@ -741,10 +760,10 @@ class Client(object):
|
||||
return data
|
||||
|
||||
def _doSendRequest(self, data):
|
||||
"""Sends the data to `SendURL`, and returns the message id"""
|
||||
"""Sends the data to `SendURL`, and returns the message id or None on failure"""
|
||||
r = self._post(ReqUrl.SEND, data)
|
||||
|
||||
j = self._checkRequest(r)
|
||||
j = check_request(r)
|
||||
|
||||
if j is None:
|
||||
return None
|
||||
@@ -782,10 +801,10 @@ class Client(object):
|
||||
Sends a message to a thread
|
||||
|
||||
:param message: Message to send
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent message
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent message or `None` on failure
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||
data = self._getSendData(thread_id, thread_type)
|
||||
@@ -802,13 +821,13 @@ class Client(object):
|
||||
"""
|
||||
Sends an emoji to a thread
|
||||
|
||||
:param emoji: The chosen emoji to send. If not specified, the thread's default emoji is sent
|
||||
:param emoji: The chosen emoji to send. If not specified, the default `like` emoji is sent
|
||||
:param size: If not specified, a small emoji is sent
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type size: models.EmojiSize
|
||||
:type thread_type: models.ThreadType
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent emoji
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent emoji or `None` on failure
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||
data = self._getSendData(thread_id, thread_type)
|
||||
@@ -844,14 +863,14 @@ class Client(object):
|
||||
|
||||
def sendImage(self, image_id, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||
"""
|
||||
Sends an already uploaded image to a thread. (Used by :any:`Client.sendRemoteImage` and :any:`Client.sendLocalImage`)
|
||||
Sends an already uploaded image to a thread. (Used by :func:`Client.sendRemoteImage` and :func:`Client.sendLocalImage`)
|
||||
|
||||
:param image_id: ID of an image that's already uploaded to Facebook
|
||||
:param message: Additional message
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image or `None` on failure
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||
data = self._getSendData(thread_id, thread_type)
|
||||
@@ -873,10 +892,10 @@ class Client(object):
|
||||
|
||||
:param image_url: URL of an image to upload and send
|
||||
:param message: Additional message
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image or `None` on failure
|
||||
"""
|
||||
if recipient_id is not None:
|
||||
deprecation('sendRemoteImage(recipient_id)', deprecated_in='0.10.2', removed_in='0.15.0', details='Use sendRemoteImage(thread_id) instead')
|
||||
@@ -902,10 +921,10 @@ class Client(object):
|
||||
|
||||
:param image_path: URL of an image to upload and send
|
||||
:param message: Additional message
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image or `None` on failure
|
||||
"""
|
||||
if recipient_id is not None:
|
||||
deprecation('sendLocalImage(recipient_id)', deprecated_in='0.10.2', removed_in='0.15.0', details='Use sendLocalImage(thread_id) instead')
|
||||
@@ -922,14 +941,14 @@ class Client(object):
|
||||
image_id = self._uploadImage(image_path, open(image_path, 'rb'), mimetype)
|
||||
return self.sendImage(image_id=image_id, message=message, thread_id=thread_id, thread_type=thread_type)
|
||||
|
||||
def addUsersToGroup(self, *user_ids, thread_id=None):
|
||||
def addUsersToGroup(self, user_ids, thread_id=None):
|
||||
"""
|
||||
Adds users to a group.
|
||||
|
||||
:param user_ids: User ids to add
|
||||
:param thread_id: Group ID to add people to. See :ref:`intro_thread_id`
|
||||
:type user_ids: list of positional arguments
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent "message"
|
||||
:param user_ids: One or more user ids to add
|
||||
:param thread_id: Group ID to add people to. See :ref:`intro_threads`
|
||||
:type user_ids: list
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the executed action or `None` on failure
|
||||
"""
|
||||
thread_id, thread_type = self._getThread(thread_id, None)
|
||||
data = self._getSendData(thread_id, ThreadType.GROUP)
|
||||
@@ -937,9 +956,14 @@ class Client(object):
|
||||
data['action_type'] = 'ma-type:log-message'
|
||||
data['log_message_type'] = 'log:subscribe'
|
||||
|
||||
if type(user_ids) is not list:
|
||||
user_ids = [user_ids]
|
||||
|
||||
# Make list of users unique
|
||||
user_ids = set(user_ids)
|
||||
|
||||
print(user_ids)
|
||||
|
||||
for i, user_id in enumerate(user_ids):
|
||||
if user_id == self.uid:
|
||||
log.warning('Error when adding users: Cannot add self to group chat')
|
||||
@@ -955,8 +979,9 @@ class Client(object):
|
||||
Removes users from a group.
|
||||
|
||||
:param user_id: User ID to remove
|
||||
:param thread_id: Group ID to remove people from. See :ref:`intro_thread_id`
|
||||
:return: :ref:`Message ID <intro_message_ids>` of the sent "message"
|
||||
:param thread_id: Group ID to remove people from. See :ref:`intro_threads`
|
||||
:return: True if the action was successful
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
thread_id, thread_type = self._getThread(thread_id, None)
|
||||
@@ -966,7 +991,7 @@ class Client(object):
|
||||
"tid": thread_id
|
||||
}
|
||||
|
||||
j = self._checkRequest(self._post(ReqUrl.REMOVE_USER, data))
|
||||
j = check_request(self._post(ReqUrl.REMOVE_USER, data))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -982,11 +1007,12 @@ class Client(object):
|
||||
|
||||
def changeThreadTitle(self, title, thread_id=None, thread_type=ThreadType.USER):
|
||||
"""
|
||||
Changes title of a thread
|
||||
Changes title of a thread.
|
||||
If this is executed on a user thread, this will change the nickname of that user, effectively changing the title
|
||||
|
||||
:param title: New group chat title
|
||||
:param thread_id: Group ID to change title of. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: Group ID to change title of. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: True if the action was successful
|
||||
:rtype: bool
|
||||
@@ -1018,8 +1044,8 @@ class Client(object):
|
||||
|
||||
:param nickname: New nickname
|
||||
:param user_id: User that will have their nickname changed
|
||||
:param thread_id: User/Group ID to change color of. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to change color of. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type thread_type: models.ThreadType
|
||||
:return: True if the action was successful
|
||||
:rtype: bool
|
||||
@@ -1032,7 +1058,7 @@ class Client(object):
|
||||
'thread_or_other_fbid': thread_id
|
||||
}
|
||||
|
||||
j = self._checkRequest(self._post(ReqUrl.THREAD_NICKNAME, data))
|
||||
j = check_request(self._post(ReqUrl.THREAD_NICKNAME, data))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -1041,7 +1067,7 @@ class Client(object):
|
||||
Changes thread color
|
||||
|
||||
:param color: New thread color
|
||||
:param thread_id: User/Group ID to change color of. See :ref:`intro_thread_id`
|
||||
:param thread_id: User/Group ID to change color of. See :ref:`intro_threads`
|
||||
:type color: models.ThreadColor
|
||||
:return: True if the action was successful
|
||||
:rtype: bool
|
||||
@@ -1053,7 +1079,7 @@ class Client(object):
|
||||
'thread_or_other_fbid': thread_id
|
||||
}
|
||||
|
||||
j = self._checkRequest(self._post(ReqUrl.THREAD_COLOR, data))
|
||||
j = check_request(self._post(ReqUrl.THREAD_COLOR, data))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -1064,7 +1090,7 @@ class Client(object):
|
||||
Trivia: While changing the emoji, the Facebook web client actually sends multiple different requests, though only this one is required to make the change
|
||||
|
||||
:param color: New thread emoji
|
||||
:param thread_id: User/Group ID to change emoji of. See :ref:`intro_thread_id`
|
||||
:param thread_id: User/Group ID to change emoji of. See :ref:`intro_threads`
|
||||
:return: True if the action was successful
|
||||
:rtype: bool
|
||||
"""
|
||||
@@ -1075,7 +1101,7 @@ class Client(object):
|
||||
'thread_or_other_fbid': thread_id
|
||||
}
|
||||
|
||||
j = self._checkRequest(self._post(ReqUrl.THREAD_EMOJI, data))
|
||||
j = check_request(self._post(ReqUrl.THREAD_EMOJI, data))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -1110,7 +1136,7 @@ class Client(object):
|
||||
.replace('u%27', '%27')\
|
||||
.replace('%5CU{}'.format(MessageReactionFix[reaction.value][0]), MessageReactionFix[reaction.value][1])
|
||||
|
||||
j = self._checkRequest(self._post('{}/?{}'.format(ReqUrl.MESSAGE_REACTION, url_part)))
|
||||
j = check_request(self._post('{}/?{}'.format(ReqUrl.MESSAGE_REACTION, url_part)))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -1119,8 +1145,8 @@ class Client(object):
|
||||
Sets users typing status in a thread
|
||||
|
||||
:param status: Specify the typing status
|
||||
:param thread_id: User/Group ID to change status in. See :ref:`intro_thread_id`
|
||||
:param thread_type: See :ref:`intro_thread_type`
|
||||
:param thread_id: User/Group ID to change status in. See :ref:`intro_threads`
|
||||
:param thread_type: See :ref:`intro_threads`
|
||||
:type status: models.TypingStatus
|
||||
:type thread_type: models.ThreadType
|
||||
:return: True if the action was successful
|
||||
@@ -1135,7 +1161,7 @@ class Client(object):
|
||||
"source": "mercury-chat"
|
||||
}
|
||||
|
||||
j = self._checkRequest(self._post(ReqUrl.TYPING, data))
|
||||
j = check_request(self._post(ReqUrl.TYPING, data))
|
||||
|
||||
return False if j is None else True
|
||||
|
||||
@@ -1195,11 +1221,7 @@ class Client(object):
|
||||
r = self._post(ReqUrl.CONNECT, data)
|
||||
return r.ok
|
||||
|
||||
def ping(self, sticky):
|
||||
"""
|
||||
.. todo::
|
||||
Documenting this
|
||||
"""
|
||||
def _ping(self, sticky):
|
||||
data = {
|
||||
'channel': self.user_channel,
|
||||
'clientid': self.client_id,
|
||||
@@ -1209,8 +1231,7 @@ class Client(object):
|
||||
'sticky': sticky,
|
||||
'viewer_uid': self.uid
|
||||
}
|
||||
r = self._get(ReqUrl.PING, data)
|
||||
return r.ok
|
||||
return False if check_request(self._get(ReqUrl.PING, data), check_json=False) is None else True
|
||||
|
||||
def _getSticky(self):
|
||||
"""Call pull api to get sticky and pool parameter,
|
||||
@@ -1435,7 +1456,7 @@ class Client(object):
|
||||
:rtype: bool
|
||||
"""
|
||||
try:
|
||||
if markAlive: self.ping(self.sticky)
|
||||
if markAlive: self._ping(self.sticky)
|
||||
try:
|
||||
content = self._pullMessage(self.sticky, self.pool)
|
||||
if content: self._parseMessage(content)
|
||||
|
@@ -6,7 +6,7 @@ import enum
|
||||
class User(object):
|
||||
"""Represents a Facebook User"""
|
||||
|
||||
#: The unique identifier of the user. Can be used a `thread_id`. See :ref:`intro_thread_id` for more info
|
||||
#: The unique identifier of the user. Can be used a `thread_id`. See :ref:`intro_threads` for more info
|
||||
uid = None
|
||||
#: Currently always set to `user`. Might change in the future
|
||||
type = 'user'
|
||||
@@ -75,10 +75,12 @@ class User(object):
|
||||
}
|
||||
|
||||
class Thread(object):
|
||||
def __init__(self, **entries):
|
||||
"""Represents a thread. Currently just acts as a dict"""
|
||||
def __init__(self, **entries):
|
||||
self.__dict__.update(entries)
|
||||
|
||||
class Message(object):
|
||||
"""Represents a message. Currently just acts as a dict"""
|
||||
def __init__(self, **entries):
|
||||
self.__dict__.update(entries)
|
||||
|
||||
@@ -89,7 +91,7 @@ class Enum(enum.Enum):
|
||||
return '{}.{}'.format(type(self).__name__, self.name)
|
||||
|
||||
class ThreadType(Enum):
|
||||
"""Used to specify what type of Facebook thread is being used. See :ref:`intro_thread_type` for more info"""
|
||||
"""Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info"""
|
||||
USER = 1
|
||||
GROUP = 2
|
||||
|
||||
|
9
tests.py
9
tests.py
@@ -15,6 +15,13 @@ import py_compile
|
||||
|
||||
logging_level = logging.ERROR
|
||||
|
||||
"""
|
||||
|
||||
Testing script for `fbchat`.
|
||||
Full documentation on https://fbchat.readthedocs.io/
|
||||
|
||||
"""
|
||||
|
||||
class CustomClient(Client):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.got_qprimer = False
|
||||
@@ -168,8 +175,8 @@ class TestFbchat(unittest.TestCase):
|
||||
def test_setTypingStatus(self):
|
||||
self.assertTrue(client.sendMessage('Hi', thread_id=user_uid, thread_type=ThreadType.USER))
|
||||
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=user_uid, thread_type=ThreadType.USER))
|
||||
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
||||
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=user_uid, thread_type=ThreadType.USER))
|
||||
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
||||
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user