Merge remote-tracking branch 'refs/remotes/origin/master' into ratelimits
# Conflicts: # mastodon/Mastodon.py
This commit is contained in:
commit
ab58894041
S'han modificat 2 arxius amb 213 adicions i 80 eliminacions
117
docs/index.rst
117
docs/index.rst
|
@ -1,5 +1,7 @@
|
||||||
Mastodon.py
|
Mastodon.py
|
||||||
===========
|
===========
|
||||||
|
.. py:module:: mastodon
|
||||||
|
.. py:class: Mastodon
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -37,14 +39,114 @@ as a single python module. By default, it talks to the
|
||||||
`Mastodon flagship instance`_, but it can be set to talk to any
|
`Mastodon flagship instance`_, but it can be set to talk to any
|
||||||
node running Mastodon.
|
node running Mastodon.
|
||||||
|
|
||||||
|
A note about IDs
|
||||||
|
----------------
|
||||||
|
Mastodons API uses IDs in several places: User IDs, Toot IDs, ...
|
||||||
|
|
||||||
|
While debugging, it might be tempting to copy-paste in IDs from the
|
||||||
|
web interface into your code. This will not work, as the IDs on the web
|
||||||
|
interface and in the URLs are not the same as the IDs used internally
|
||||||
|
in the API, so don't do that.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
-------------
|
||||||
Unless otherwise specified, all data is returned as python
|
Unless otherwise specified, all data is returned as python
|
||||||
dictionaries, matching the JSON format used by the API.
|
dictionaries, matching the JSON format used by the API.
|
||||||
For complete documentation on what every function returns,
|
|
||||||
check the `Mastodon API docs`_, or just play around a bit - the
|
|
||||||
format of the data is generally very easy to understand.
|
|
||||||
|
|
||||||
.. py:module:: mastodon
|
User dicts
|
||||||
.. py:class: Mastodon
|
~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.account(<numerical id>)
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'display_name': The user's display name
|
||||||
|
'acct': The user's account name as username@domain (@domain omitted for local users)
|
||||||
|
'following_count': How many people they follow
|
||||||
|
'url': Their URL; usually 'https://mastodon.social/users/<acct>'
|
||||||
|
'statuses_count': How many statuses they have
|
||||||
|
'followers_count': How many followers they have
|
||||||
|
'avatar': URL for their avatar
|
||||||
|
'note': Their bio
|
||||||
|
'header': URL for their header image
|
||||||
|
'id': Same as <numerical id>
|
||||||
|
'username': The username (what you @ them with)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toot dicts
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.toot("Hello from Python")
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'sensitive': Denotes whether the toot is marked sensitive
|
||||||
|
'created_at': Creation time
|
||||||
|
'mentions': A list of account dicts mentioned in the toot
|
||||||
|
'uri': Descriptor for the toot
|
||||||
|
EG 'tag:mastodon.social,2016-11-25:objectId=<id>:objectType=Status'
|
||||||
|
'tags': A list of hashtag dicts used in the toot
|
||||||
|
'in_reply_to_id': Numerical id of the toot this toot is in response to
|
||||||
|
'id': Numerical id of this toot
|
||||||
|
'reblogs_count': Number of reblogs
|
||||||
|
'favourites_count': Number of favourites
|
||||||
|
'reblog': Denotes whether the toot is a reblog
|
||||||
|
'url': URL of the toot
|
||||||
|
'content': Content of the toot, as HTML: '<p>Hello from Python</p>'
|
||||||
|
'favourited': Denotes whether the logged in user has favourited this toot
|
||||||
|
'account': Account dict for the logged in account
|
||||||
|
}
|
||||||
|
|
||||||
|
Relationship dicts
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.account_follow(<numerical id>)
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'followed_by': Boolean denoting whether they follow you back
|
||||||
|
'following': Boolean denoting whether you follow them
|
||||||
|
'id': Numerical id (same one as <numerical id>)
|
||||||
|
'blocking': Boolean denoting whether you are blocking them
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification dicts
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.notifications()[0]
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'id': id of the notification.
|
||||||
|
'type': "mention", "reblog", "favourite" or "follow".
|
||||||
|
'status': In case of "mention", the mentioning status.
|
||||||
|
In case of reblog / favourite, the reblogged / favourited status.
|
||||||
|
'account': User dict of the user from whom the notification originates.
|
||||||
|
}
|
||||||
|
|
||||||
|
Context dicts
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.status_context(<numerical id>)
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'descendants': A list of toot dicts
|
||||||
|
'ancestors': A list of toot dicts
|
||||||
|
}
|
||||||
|
|
||||||
|
Media dicts
|
||||||
|
~~~~~~~~~~~
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mastodon.media_post("image.jpg", "image/jpeg")
|
||||||
|
# Returns the following dictionary:
|
||||||
|
{
|
||||||
|
'text_url': The display text for the media (what shows up in toots)
|
||||||
|
'preview_url': The URL for the media preview
|
||||||
|
'type': Media type, EG 'image'
|
||||||
|
'url': The URL for the media
|
||||||
|
}
|
||||||
|
|
||||||
App registration and user authentication
|
App registration and user authentication
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -91,7 +193,6 @@ This function allows you to get information about a users notifications.
|
||||||
|
|
||||||
.. automethod:: Mastodon.notifications
|
.. automethod:: Mastodon.notifications
|
||||||
|
|
||||||
|
|
||||||
Reading data: Accounts
|
Reading data: Accounts
|
||||||
----------------------
|
----------------------
|
||||||
These functions allow you to get information about accounts and
|
These functions allow you to get information about accounts and
|
||||||
|
@ -103,7 +204,6 @@ their relationships.
|
||||||
.. automethod:: Mastodon.account_following
|
.. automethod:: Mastodon.account_following
|
||||||
.. automethod:: Mastodon.account_followers
|
.. automethod:: Mastodon.account_followers
|
||||||
.. automethod:: Mastodon.account_relationships
|
.. automethod:: Mastodon.account_relationships
|
||||||
.. automethod:: Mastodon.account_suggestions
|
|
||||||
.. automethod:: Mastodon.account_search
|
.. automethod:: Mastodon.account_search
|
||||||
|
|
||||||
Writing data: Statuses
|
Writing data: Statuses
|
||||||
|
@ -113,11 +213,11 @@ interact with already posted statuses.
|
||||||
|
|
||||||
.. automethod:: Mastodon.status_post
|
.. automethod:: Mastodon.status_post
|
||||||
.. automethod:: Mastodon.toot
|
.. automethod:: Mastodon.toot
|
||||||
.. automethod:: Mastodon.status_delete
|
|
||||||
.. automethod:: Mastodon.status_reblog
|
.. automethod:: Mastodon.status_reblog
|
||||||
.. automethod:: Mastodon.status_unreblog
|
.. automethod:: Mastodon.status_unreblog
|
||||||
.. automethod:: Mastodon.status_favourite
|
.. automethod:: Mastodon.status_favourite
|
||||||
.. automethod:: Mastodon.status_unfavourite
|
.. automethod:: Mastodon.status_unfavourite
|
||||||
|
.. automethod:: Mastodon.status_delete
|
||||||
|
|
||||||
Writing data: Accounts
|
Writing data: Accounts
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -137,6 +237,7 @@ to attach media to statuses.
|
||||||
|
|
||||||
.. automethod:: Mastodon.media_post
|
.. automethod:: Mastodon.media_post
|
||||||
|
|
||||||
|
|
||||||
.. _Mastodon: https://github.com/Gargron/mastodon
|
.. _Mastodon: https://github.com/Gargron/mastodon
|
||||||
.. _Mastodon flagship instance: http://mastodon.social/
|
.. _Mastodon flagship instance: http://mastodon.social/
|
||||||
.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API
|
.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Mastodon:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_app(client_name, scopes = ['read', 'write', 'follow'], redirect_uris = None, to_file = None, api_base_url = __DEFAULT_BASE_URL):
|
def create_app(client_name, scopes = ['read', 'write', 'follow'], redirect_uris = None, to_file = None, api_base_url = __DEFAULT_BASE_URL):
|
||||||
"""
|
"""
|
||||||
Creates a new app with given client_name and scopes (read, write, follow)
|
Create a new app with given client_name and scopes (read, write, follow)
|
||||||
|
|
||||||
Specify redirect_uris if you want users to be redirected to a certain page after authenticating.
|
Specify redirect_uris if you want users to be redirected to a certain page after authenticating.
|
||||||
Specify to_file to persist your apps info to a file so you can use them in the constructor.
|
Specify to_file to persist your apps info to a file so you can use them in the constructor.
|
||||||
|
@ -64,7 +64,7 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def __init__(self, client_id, client_secret = None, access_token = None, api_base_url = __DEFAULT_BASE_URL, debug_requests = False, ratelimit_method = "wait", ratelimit_pacefactor = 0.9):
|
def __init__(self, client_id, client_secret = None, access_token = None, api_base_url = __DEFAULT_BASE_URL, debug_requests = False, ratelimit_method = "wait", ratelimit_pacefactor = 0.9):
|
||||||
"""
|
"""
|
||||||
Creates a new API wrapper instance based on the given client_secret and client_id. If you
|
Create a new API wrapper instance based on the given client_secret and client_id. If you
|
||||||
give a client_id and it is not a file, you must also give a secret.
|
give a client_id and it is not a file, you must also give a secret.
|
||||||
|
|
||||||
You can also directly specify an access_token, directly or as a file.
|
You can also directly specify an access_token, directly or as a file.
|
||||||
|
@ -108,15 +108,15 @@ class Mastodon:
|
||||||
|
|
||||||
def log_in(self, username, password, scopes = ['read', 'write', 'follow'], to_file = None):
|
def log_in(self, username, password, scopes = ['read', 'write', 'follow'], to_file = None):
|
||||||
"""
|
"""
|
||||||
Logs in and sets access_token to what was returned. Note that your
|
Log in and sets access_token to what was returned. Note that your
|
||||||
username is the e-mail you use to log in into mastodon.
|
username is the e-mail you use to log in into mastodon.
|
||||||
|
|
||||||
Can persist access token to file, to be used in the constructor.
|
Can persist access token to file, to be used in the constructor.
|
||||||
|
|
||||||
Will throw an exception if username / password are wrong, scopes are not
|
Will throw a MastodonIllegalArgumentError if username / password
|
||||||
valid or granted scopes differ from requested.
|
are wrong, scopes are not valid or granted scopes differ from requested.
|
||||||
|
|
||||||
Returns the access_token, as well.
|
Returns the access_token.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals())
|
params = self.__generate_params(locals())
|
||||||
params['client_id'] = self.client_id
|
params['client_id'] = self.client_id
|
||||||
|
@ -125,7 +125,7 @@ class Mastodon:
|
||||||
params['scope'] = " ".join(scopes)
|
params['scope'] = " ".join(scopes)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self.__api_request('POST', '/oauth/token', params)
|
response = self.__api_request('POST', '/oauth/token', params, do_ratelimiting = False)
|
||||||
self.access_token = response['access_token']
|
self.access_token = response['access_token']
|
||||||
except:
|
except:
|
||||||
raise MastodonIllegalArgumentError('Invalid user name, password or scopes.')
|
raise MastodonIllegalArgumentError('Invalid user name, password or scopes.')
|
||||||
|
@ -147,35 +147,45 @@ class Mastodon:
|
||||||
##
|
##
|
||||||
def timeline(self, timeline = "home", max_id = None, since_id = None, limit = None):
|
def timeline(self, timeline = "home", max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns statuses, most recent ones first. Timeline can be home, mentions, public
|
Fetch statuses, most recent ones first. Timeline can be home, mentions, public
|
||||||
or tag/hashtag. See the following functions documentation for what those do.
|
or tag/hashtag. See the following functions documentation for what those do.
|
||||||
|
|
||||||
The default timeline is the "home" timeline.
|
The default timeline is the "home" timeline.
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals(), ['timeline'])
|
params = self.__generate_params(locals(), ['timeline'])
|
||||||
return self.__api_request('GET', '/api/v1/timelines/' + timeline, params)
|
return self.__api_request('GET', '/api/v1/timelines/' + timeline, params)
|
||||||
|
|
||||||
def timeline_home(self, max_id = None, since_id = None, limit = None):
|
def timeline_home(self, max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns the authenticated users home timeline (i.e. followed users and self).
|
Fetch the authenticated users home timeline (i.e. followed users and self).
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
return self.timeline('home', max_id = max_id, since_id = since_id, limit = limit)
|
return self.timeline('home', max_id = max_id, since_id = since_id, limit = limit)
|
||||||
|
|
||||||
def timeline_mentions(self, max_id = None, since_id = None, limit = None):
|
def timeline_mentions(self, max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns the authenticated users mentions.
|
Fetches the authenticated users mentions.
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
return self.timeline('mentions', max_id = max_id, since_id = since_id, limit = limit)
|
return self.timeline('mentions', max_id = max_id, since_id = since_id, limit = limit)
|
||||||
|
|
||||||
def timeline_public(self, max_id = None, since_id = None, limit = None):
|
def timeline_public(self, max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns the public / visible-network timeline.
|
Fetches the public / visible-network timeline.
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
return self.timeline('public', max_id = max_id, since_id = since_id, limit = limit)
|
return self.timeline('public', max_id = max_id, since_id = since_id, limit = limit)
|
||||||
|
|
||||||
def timeline_hashtag(self, hashtag, max_id = None, since_id = None, limit = None):
|
def timeline_hashtag(self, hashtag, max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns all toots with a given hashtag.
|
Fetch a timeline of toots with a given hashtag.
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
return self.timeline('tag/' + str(hashtag), max_id = max_id, since_id = since_id, limit = limit)
|
return self.timeline('tag/' + str(hashtag), max_id = max_id, since_id = since_id, limit = limit)
|
||||||
|
|
||||||
|
@ -184,25 +194,33 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def status(self, id):
|
def status(self, id):
|
||||||
"""
|
"""
|
||||||
Returns a status.
|
Fetch information about a single toot.
|
||||||
|
|
||||||
|
Returns a toot dict.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id))
|
return self.__api_request('GET', '/api/v1/statuses/' + str(id))
|
||||||
|
|
||||||
def status_context(self, id):
|
def status_context(self, id):
|
||||||
"""
|
"""
|
||||||
Returns ancestors and descendants of the status.
|
Fetch information about ancestors and descendants of a toot.
|
||||||
|
|
||||||
|
Returns a context dict.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/context')
|
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/context')
|
||||||
|
|
||||||
def status_reblogged_by(self, id):
|
def status_reblogged_by(self, id):
|
||||||
"""
|
"""
|
||||||
Returns a list of users that have reblogged a status.
|
Fetch a list of users that have reblogged a status.
|
||||||
|
|
||||||
|
Returns a list of user dicts.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/reblogged_by')
|
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/reblogged_by')
|
||||||
|
|
||||||
def status_favourited_by(self, id):
|
def status_favourited_by(self, id):
|
||||||
"""
|
"""
|
||||||
Returns a list of users that have favourited a status.
|
Fetch a list of users that have favourited a status.
|
||||||
|
|
||||||
|
Returns a list of user dicts.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/favourited_by')
|
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/favourited_by')
|
||||||
|
|
||||||
|
@ -211,8 +229,10 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def notifications(self):
|
def notifications(self):
|
||||||
"""
|
"""
|
||||||
Returns notifications (mentions, favourites, reblogs, follows) for the authenticated
|
Fetch notifications (mentions, favourites, reblogs, follows) for the authenticated
|
||||||
user.
|
user.
|
||||||
|
|
||||||
|
Returns a list of notification dicts.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/notifications')
|
return self.__api_request('GET', '/api/v1/notifications')
|
||||||
|
|
||||||
|
@ -221,53 +241,61 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def account(self, id):
|
def account(self, id):
|
||||||
"""
|
"""
|
||||||
Returns account.
|
Fetch account information by user id.
|
||||||
|
|
||||||
|
Returns a user dict.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id))
|
return self.__api_request('GET', '/api/v1/accounts/' + str(id))
|
||||||
|
|
||||||
def account_verify_credentials(self):
|
def account_verify_credentials(self):
|
||||||
"""
|
"""
|
||||||
Returns authenticated user's account.
|
Fetch authenticated user's account information.
|
||||||
|
|
||||||
|
Returns a user dict.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/accounts/verify_credentials')
|
return self.__api_request('GET', '/api/v1/accounts/verify_credentials')
|
||||||
|
|
||||||
def account_statuses(self, id, max_id = None, since_id = None, limit = None):
|
def account_statuses(self, id, max_id = None, since_id = None, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns statuses by user. Same options as timeline are permitted.
|
Fetch statuses by user id. Same options as timeline are permitted.
|
||||||
|
|
||||||
|
Returns a list of toot dicts.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals(), ['id'])
|
params = self.__generate_params(locals(), ['id'])
|
||||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/statuses', params)
|
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/statuses', params)
|
||||||
|
|
||||||
def account_following(self, id):
|
def account_following(self, id):
|
||||||
"""
|
"""
|
||||||
Returns users the given user is following.
|
Fetch users the given user is following.
|
||||||
|
|
||||||
|
Returns a list of user dicts.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/following')
|
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/following')
|
||||||
|
|
||||||
def account_followers(self, id):
|
def account_followers(self, id):
|
||||||
"""
|
"""
|
||||||
Returns users the given user is followed by.
|
Fetch users the given user is followed by.
|
||||||
|
|
||||||
|
Returns a list of user dicts.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/followers')
|
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/followers')
|
||||||
|
|
||||||
def account_relationships(self, id):
|
def account_relationships(self, id):
|
||||||
"""
|
"""
|
||||||
Returns relationships (following, followed_by, blocking) of the logged in user to
|
Fetch relationships (following, followed_by, blocking) of the logged in user to
|
||||||
a given account. id can be a list.
|
a given account. id can be a list.
|
||||||
|
|
||||||
|
Returns a list of relationship dicts.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals())
|
params = self.__generate_params(locals())
|
||||||
return self.__api_request('GET', '/api/v1/accounts/relationships', params)
|
return self.__api_request('GET', '/api/v1/accounts/relationships', params)
|
||||||
|
|
||||||
def account_suggestions(self):
|
|
||||||
"""
|
|
||||||
Returns accounts that the system suggests the authenticated user to follow.
|
|
||||||
"""
|
|
||||||
return self.__api_request('GET', '/api/v1/accounts/suggestions')
|
|
||||||
|
|
||||||
def account_search(self, q, limit = None):
|
def account_search(self, q, limit = None):
|
||||||
"""
|
"""
|
||||||
Returns matching accounts. Will lookup an account remotely if the search term is
|
Fetch matching accounts. Will lookup an account remotely if the search term is
|
||||||
in the username@domain format and not yet in the database.
|
in the username@domain format and not yet in the database.
|
||||||
|
|
||||||
|
Returns a list of user dicts.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals())
|
params = self.__generate_params(locals())
|
||||||
return self.__api_request('GET', '/api/v1/accounts/search', params)
|
return self.__api_request('GET', '/api/v1/accounts/search', params)
|
||||||
|
@ -277,10 +305,10 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def status_post(self, status, in_reply_to_id = None, media_ids = None):
|
def status_post(self, status, in_reply_to_id = None, media_ids = None):
|
||||||
"""
|
"""
|
||||||
Posts a status. Can optionally be in reply to another status and contain
|
Post a status. Can optionally be in reply to another status and contain
|
||||||
up to four pieces of media (Uploaded via media_post()).
|
up to four pieces of media (Uploaded via media_post()).
|
||||||
|
|
||||||
Returns the new status.
|
Returns a toot dict with the new status.
|
||||||
"""
|
"""
|
||||||
params = self.__generate_params(locals())
|
params = self.__generate_params(locals())
|
||||||
return self.__api_request('POST', '/api/v1/statuses', params)
|
return self.__api_request('POST', '/api/v1/statuses', params)
|
||||||
|
@ -288,41 +316,46 @@ class Mastodon:
|
||||||
def toot(self, status):
|
def toot(self, status):
|
||||||
"""
|
"""
|
||||||
Synonym for status_post that only takes the status text as input.
|
Synonym for status_post that only takes the status text as input.
|
||||||
|
|
||||||
|
Returns a toot dict with the new status.
|
||||||
"""
|
"""
|
||||||
return self.status_post(status)
|
return self.status_post(status)
|
||||||
|
|
||||||
def status_delete(self, id):
|
def status_delete(self, id):
|
||||||
"""
|
"""
|
||||||
Deletes a status
|
Delete a status
|
||||||
|
|
||||||
|
Returns an empty dict for good measure.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('DELETE', '/api/v1/statuses/' + str(id))
|
return self.__api_request('DELETE', '/api/v1/statuses/' + str(id))
|
||||||
|
|
||||||
def status_reblog(self, id):
|
def status_reblog(self, id):
|
||||||
"""Reblogs a status.
|
"""Reblog a status.
|
||||||
|
|
||||||
Returns a new status that wraps around the reblogged one."""
|
Returns a toot with with a new status that wraps around the reblogged one.
|
||||||
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/reblog")
|
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/reblog")
|
||||||
|
|
||||||
def status_unreblog(self, id):
|
def status_unreblog(self, id):
|
||||||
"""
|
"""
|
||||||
Un-reblogs a status.
|
Un-reblog a status.
|
||||||
|
|
||||||
Returns the status that used to be reblogged.
|
Returns a toot dict with the status that used to be reblogged.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unreblog")
|
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unreblog")
|
||||||
|
|
||||||
def status_favourite(self, id):
|
def status_favourite(self, id):
|
||||||
"""
|
"""
|
||||||
Favourites a status.
|
Favourite a status.
|
||||||
|
|
||||||
Returns the favourited status.
|
Returns a toot dict with the favourited status.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/favourite")
|
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/favourite")
|
||||||
|
|
||||||
def status_unfavourite(self, id):
|
def status_unfavourite(self, id):
|
||||||
"""Favourites a status.
|
"""Favourite a status.
|
||||||
|
|
||||||
Returns the un-favourited status.
|
Returns a toot dict with the un-favourited status.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unfavourite")
|
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unfavourite")
|
||||||
|
|
||||||
|
@ -331,33 +364,33 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def account_follow(self, id):
|
def account_follow(self, id):
|
||||||
"""
|
"""
|
||||||
Follows a user.
|
Follow a user.
|
||||||
|
|
||||||
Returns the updated relationship to the user.
|
Returns a relationship dict containing the updated relationship to the user.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/follow")
|
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/follow")
|
||||||
|
|
||||||
def account_unfollow(self, id):
|
def account_unfollow(self, id):
|
||||||
"""
|
"""
|
||||||
Unfollows a user.
|
Unfollow a user.
|
||||||
|
|
||||||
Returns the updated relationship to the user.
|
Returns a relationship dict containing the updated relationship to the user.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unfollow")
|
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unfollow")
|
||||||
|
|
||||||
def account_block(self, id):
|
def account_block(self, id):
|
||||||
"""
|
"""
|
||||||
Blocks a user.
|
Block a user.
|
||||||
|
|
||||||
Returns the updated relationship to the user.
|
Returns a relationship dict containing the updated relationship to the user.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/block")
|
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/block")
|
||||||
|
|
||||||
def account_unblock(self, id):
|
def account_unblock(self, id):
|
||||||
"""
|
"""
|
||||||
Unblocks a user.
|
Unblock a user.
|
||||||
|
|
||||||
Returns the updated relationship to the user.
|
Returns a relationship dict containing the updated relationship to the user.
|
||||||
"""
|
"""
|
||||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unblock")
|
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unblock")
|
||||||
|
|
||||||
|
@ -366,20 +399,18 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
def media_post(self, media_file, mime_type = None):
|
def media_post(self, media_file, mime_type = None):
|
||||||
"""
|
"""
|
||||||
Posts an image. media_file can either be image data or
|
Post an image. media_file can either be image data or
|
||||||
a file name. If image data is passed directly, the mime
|
a file name. If image data is passed directly, the mime
|
||||||
type has to be specified manually, otherwise, it is
|
type has to be specified manually, otherwise, it is
|
||||||
determined from the file name.
|
determined from the file name.
|
||||||
|
|
||||||
Returns the uploaded media metadata object. Importantly, this contains
|
|
||||||
the ID that can then be used in status_post() to attach the media to
|
|
||||||
a toot.
|
|
||||||
|
|
||||||
Throws a MastodonIllegalArgumentError if the mime type of the
|
Throws a MastodonIllegalArgumentError if the mime type of the
|
||||||
passed data or file can not be determined properly.
|
passed data or file can not be determined properly.
|
||||||
|
|
||||||
|
Returns a media dict. This contains the id that can be used in
|
||||||
|
status_post to attach the media file to a toot.
|
||||||
"""
|
"""
|
||||||
|
if os.path.isfile(media_file) and mime_type == None:
|
||||||
if os.path.isfile(media_file):
|
|
||||||
mime_type = mimetypes.guess_type(media_file)[0]
|
mime_type = mimetypes.guess_type(media_file)[0]
|
||||||
media_file = open(media_file, 'rb')
|
media_file = open(media_file, 'rb')
|
||||||
|
|
||||||
|
@ -395,7 +426,7 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
# Internal helpers, dragons probably
|
# Internal helpers, dragons probably
|
||||||
###
|
###
|
||||||
def __api_request(self, method, endpoint, params = {}, files = {}):
|
def __api_request(self, method, endpoint, params = {}, files = {}, do_ratelimiting = True):
|
||||||
"""
|
"""
|
||||||
Internal API request helper.
|
Internal API request helper.
|
||||||
|
|
||||||
|
@ -410,7 +441,7 @@ class Mastodon:
|
||||||
|
|
||||||
# "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it
|
# "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it
|
||||||
# would take to not hit the rate limit at that request rate.
|
# would take to not hit the rate limit at that request rate.
|
||||||
if self.ratelimit_method == "pace":
|
if do_ratelimiting and self.ratelimit_method == "pace":
|
||||||
if self.ratelimit_remaining == 0:
|
if self.ratelimit_remaining == 0:
|
||||||
to_next = self.ratelimit_reset - time.time()
|
to_next = self.ratelimit_reset - time.time()
|
||||||
if to_next > 0:
|
if to_next > 0:
|
||||||
|
@ -472,20 +503,21 @@ class Mastodon:
|
||||||
raise MastodonAPIError("Could not parse response as JSON, respose code was " + str(response_object.status_code))
|
raise MastodonAPIError("Could not parse response as JSON, respose code was " + str(response_object.status_code))
|
||||||
|
|
||||||
# Handle rate limiting
|
# Handle rate limiting
|
||||||
self.ratelimit_remaining = int(response_object.headers['X-RateLimit-Remaining'])
|
if 'X-RateLimit-Remaining' in response_object.headers and do_ratelimiting:
|
||||||
self.ratelimit_limit = int(response_object.headers['X-RateLimit-Limit'])
|
self.ratelimit_remaining = int(response_object.headers['X-RateLimit-Remaining'])
|
||||||
self.ratelimit_reset = (datetime.strptime(response_object.headers['X-RateLimit-Reset'], "%Y-%m-%dT%H:%M:%S.%fZ") - datetime(1970, 1, 1)).total_seconds()
|
self.ratelimit_limit = int(response_object.headers['X-RateLimit-Limit'])
|
||||||
self.ratelimit_lastcall = time.time()
|
self.ratelimit_reset = (datetime.strptime(response_object.headers['X-RateLimit-Reset'], "%Y-%m-%dT%H:%M:%S.%fZ") - datetime(1970, 1, 1)).total_seconds()
|
||||||
|
self.ratelimit_lastcall = time.time()
|
||||||
if "error" in response and response["error"] == "Throttled":
|
|
||||||
if self.ratelimit_method == "throw":
|
if "error" in response and response["error"] == "Throttled":
|
||||||
raise MastodonRatelimitError("Hit rate limit.")
|
if self.ratelimit_method == "throw":
|
||||||
|
raise MastodonRatelimitError("Hit rate limit.")
|
||||||
if self.ratelimit_method == "wait" or self.ratelimit_method == "pace":
|
|
||||||
to_next = self.ratelimit_reset - time.time()
|
if self.ratelimit_method == "wait" or self.ratelimit_method == "pace":
|
||||||
if to_next > 0:
|
to_next = self.ratelimit_reset - time.time()
|
||||||
time.sleep(to_next)
|
if to_next > 0:
|
||||||
request_complete = False
|
time.sleep(to_next)
|
||||||
|
request_complete = False
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
Loading…
Referencia en una nova incidència