diff options
Diffstat (limited to 'mastodon')
-rw-r--r-- | mastodon/Mastodon.py | 29 | ||||
-rw-r--r-- | mastodon/streaming.py | 48 |
2 files changed, 67 insertions, 10 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 7db5fba..e84df6d 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -303,7 +303,7 @@ class Mastodon: | |||
303 | api_base_url=None, debug_requests=False, | 303 | api_base_url=None, debug_requests=False, |
304 | ratelimit_method="wait", ratelimit_pacefactor=1.1, | 304 | ratelimit_method="wait", ratelimit_pacefactor=1.1, |
305 | request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None, | 305 | request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None, |
306 | version_check_mode = "created", session=None, feature_set="mainline", user_agent=None): | 306 | version_check_mode = "created", session=None, feature_set="mainline", user_agent="mastodonpy"): |
307 | """ | 307 | """ |
308 | Create a new API wrapper instance based on the given `client_secret` and `client_id`. If you | 308 | Create a new API wrapper instance based on the given `client_secret` and `client_id`. If you |
309 | give a `client_id` and it is not a file, you must also give a secret. If you specify an | 309 | give a `client_id` and it is not a file, you must also give a secret. If you specify an |
@@ -349,10 +349,12 @@ class Mastodon: | |||
349 | Details are documented in the functions that provide such functionality. Currently supported feature | 349 | Details are documented in the functions that provide such functionality. Currently supported feature |
350 | sets are `mainline`, `fedibird` and `pleroma`. | 350 | sets are `mainline`, `fedibird` and `pleroma`. |
351 | 351 | ||
352 | For some mastodon-instances a `User-Agent` header is needed. This can be set by parameter `user_agent`. From now | 352 | For some mastodon-instances a `User-Agent` header is needed. This can be set by parameter `user_agent`. Starting from |
353 | `create_app()` stores the application name into the client secret file. If `client_id` points to this file, | 353 | Mastodon.py 1.5.2 `create_app()` stores the application name into the client secret file. If `client_id` points to this file, |
354 | the app name will be used as `User-Agent` header as default. It's possible to modify old secret files and append | 354 | the app name will be used as `User-Agent` header as default. It's possible to modify old secret files and append |
355 | a client app name to use it as a `User-Agent` name. | 355 | a client app name to use it as a `User-Agent` name. |
356 | |||
357 | If no other user agent is specified, "mastodonpy" will be used. | ||
356 | """ | 358 | """ |
357 | self.api_base_url = None | 359 | self.api_base_url = None |
358 | if not api_base_url is None: | 360 | if not api_base_url is None: |
@@ -2870,6 +2872,26 @@ class Mastodon: | |||
2870 | id = self.__unpack_id(id) | 2872 | id = self.__unpack_id(id) |
2871 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsuspend'.format(id)) | 2873 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsuspend'.format(id)) |
2872 | 2874 | ||
2875 | @api_version("3.3.0", "3.3.0", __DICT_VERSION_ADMIN_ACCOUNT) | ||
2876 | def admin_account_delete(self, id): | ||
2877 | """ | ||
2878 | Delete a local user account. | ||
2879 | |||
2880 | The deleted accounts `admin account dict`_. | ||
2881 | """ | ||
2882 | id = self.__unpack_id(id) | ||
2883 | return self.__api_request('DELETE', '/api/v1/admin/accounts/{0}'.format(id)) | ||
2884 | |||
2885 | @api_version("3.3.0", "3.3.0", __DICT_VERSION_ADMIN_ACCOUNT) | ||
2886 | def admin_account_unsensitive(self, id): | ||
2887 | """ | ||
2888 | Unmark an account as force-sensitive. | ||
2889 | |||
2890 | Returns the updated `admin account dict`_. | ||
2891 | """ | ||
2892 | id = self.__unpack_id(id) | ||
2893 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsensitive'.format(id)) | ||
2894 | |||
2873 | @api_version("2.9.1", "2.9.1", "2.9.1") | 2895 | @api_version("2.9.1", "2.9.1", "2.9.1") |
2874 | def admin_account_moderate(self, id, action=None, report_id=None, warning_preset_id=None, text=None, send_email_notification=True): | 2896 | def admin_account_moderate(self, id, action=None, report_id=None, warning_preset_id=None, text=None, send_email_notification=True): |
2875 | """ | 2897 | """ |
@@ -2879,6 +2901,7 @@ class Mastodon: | |||
2879 | * "disable" - for a local user, disable login. | 2901 | * "disable" - for a local user, disable login. |
2880 | * "silence" - hide the users posts from all public timelines. | 2902 | * "silence" - hide the users posts from all public timelines. |
2881 | * "suspend" - irreversibly delete all the users posts, past and future. | 2903 | * "suspend" - irreversibly delete all the users posts, past and future. |
2904 | * "sensitive" - forcce an accounts media visibility to always be sensitive. | ||
2882 | If no action is specified, the user is only issued a warning. | 2905 | If no action is specified, the user is only issued a warning. |
2883 | 2906 | ||
2884 | Specify the id of a report as `report_id` to close the report with this moderation action as the resolution. | 2907 | Specify the id of a report as `report_id` to close the report with this moderation action as the resolution. |
diff --git a/mastodon/streaming.py b/mastodon/streaming.py index ceb61ea..65acba8 100644 --- a/mastodon/streaming.py +++ b/mastodon/streaming.py | |||
@@ -5,6 +5,11 @@ https://github.com/tootsuite/mastodon/blob/master/docs/Using-the-API/Streaming-A | |||
5 | 5 | ||
6 | import json | 6 | import json |
7 | import six | 7 | import six |
8 | try: | ||
9 | from inspect import signature | ||
10 | except: | ||
11 | pass | ||
12 | |||
8 | from mastodon import Mastodon | 13 | from mastodon import Mastodon |
9 | from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout | 14 | from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout |
10 | from requests.exceptions import ChunkedEncodingError, ReadTimeout | 15 | from requests.exceptions import ChunkedEncodingError, ReadTimeout |
@@ -16,10 +21,15 @@ class StreamListener(object): | |||
16 | Mastodon.hashtag_stream().""" | 21 | Mastodon.hashtag_stream().""" |
17 | 22 | ||
18 | def on_update(self, status): | 23 | def on_update(self, status): |
19 | """A new status has appeared! 'status' is the parsed JSON dictionary | 24 | """A new status has appeared. 'status' is the parsed JSON dictionary |
20 | describing the status.""" | 25 | describing the status.""" |
21 | pass | 26 | pass |
22 | 27 | ||
28 | def on_status_update(self, status): | ||
29 | """A status has been edited. 'status' is the parsed JSON dictionary | ||
30 | describing the updated status.""" | ||
31 | pass | ||
32 | |||
23 | def on_notification(self, notification): | 33 | def on_notification(self, notification): |
24 | """A new notification. 'notification' is the parsed JSON dictionary | 34 | """A new notification. 'notification' is the parsed JSON dictionary |
25 | describing the notification.""" | 35 | describing the notification.""" |
@@ -55,6 +65,7 @@ class StreamListener(object): | |||
55 | self.on_abort(exception) | 65 | self.on_abort(exception) |
56 | raise exception | 66 | raise exception |
57 | 67 | ||
68 | |||
58 | def handle_heartbeat(self): | 69 | def handle_heartbeat(self): |
59 | """The server has sent us a keep-alive message. This callback may be | 70 | """The server has sent us a keep-alive message. This callback may be |
60 | useful to carry out periodic housekeeping tasks, or just to confirm | 71 | useful to carry out periodic housekeeping tasks, or just to confirm |
@@ -135,6 +146,10 @@ class StreamListener(object): | |||
135 | try: | 146 | try: |
136 | name = event['event'] | 147 | name = event['event'] |
137 | data = event['data'] | 148 | data = event['data'] |
149 | try: | ||
150 | for_stream = json.loads(event['stream']) | ||
151 | except: | ||
152 | for_stream = None | ||
138 | payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks) | 153 | payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks) |
139 | except KeyError as err: | 154 | except KeyError as err: |
140 | exception = MastodonMalformedEventError('Missing field', err.args[0], event) | 155 | exception = MastodonMalformedEventError('Missing field', err.args[0], event) |
@@ -152,15 +167,29 @@ class StreamListener(object): | |||
152 | exception, | 167 | exception, |
153 | err | 168 | err |
154 | ) | 169 | ) |
155 | # New mastodon API also supports event names with dots: | 170 | # New mastodon API also supports event names with dots, |
171 | # specifically, status_update. | ||
156 | handler_name = 'on_' + name.replace('.', '_') | 172 | handler_name = 'on_' + name.replace('.', '_') |
173 | |||
157 | # A generic way to handle unknown events to make legacy code more stable for future changes | 174 | # A generic way to handle unknown events to make legacy code more stable for future changes |
158 | handler = getattr(self, handler_name, self.on_unknown_event) | 175 | handler = getattr(self, handler_name, self.on_unknown_event) |
159 | if handler != self.on_unknown_event: | 176 | try: |
160 | handler(payload) | 177 | handler_args = list(signature(handler).parameters) |
178 | except: | ||
179 | handler_args = handler.__code__.co_varnames[:handler.__code__.co_argcount] | ||
180 | |||
181 | # The "for_stream" is right now only theoretical - it's only supported on websocket, | ||
182 | # and we do not support websocket based multiplexed streams (yet). | ||
183 | if "for_stream" in handler_args: | ||
184 | if handler != self.on_unknown_event: | ||
185 | handler(payload, for_stream) | ||
186 | else: | ||
187 | handler(name, payload, for_stream) | ||
161 | else: | 188 | else: |
162 | handler(name, payload) | 189 | if handler != self.on_unknown_event: |
163 | 190 | handler(payload) | |
191 | else: | ||
192 | handler(name, payload) | ||
164 | 193 | ||
165 | class CallbackStreamListener(StreamListener): | 194 | class CallbackStreamListener(StreamListener): |
166 | """ | 195 | """ |
@@ -169,7 +198,7 @@ class CallbackStreamListener(StreamListener): | |||
169 | Define an unknown_event_handler for new Mastodon API events. If not, the | 198 | Define an unknown_event_handler for new Mastodon API events. If not, the |
170 | listener will raise an error on new, not handled, events from the API. | 199 | listener will raise an error on new, not handled, events from the API. |
171 | """ | 200 | """ |
172 | def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None): | 201 | def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None, status_update_handler = None): |
173 | super(CallbackStreamListener, self).__init__() | 202 | super(CallbackStreamListener, self).__init__() |
174 | self.update_handler = update_handler | 203 | self.update_handler = update_handler |
175 | self.local_update_handler = local_update_handler | 204 | self.local_update_handler = local_update_handler |
@@ -177,6 +206,7 @@ class CallbackStreamListener(StreamListener): | |||
177 | self.notification_handler = notification_handler | 206 | self.notification_handler = notification_handler |
178 | self.conversation_handler = conversation_handler | 207 | self.conversation_handler = conversation_handler |
179 | self.unknown_event_handler = unknown_event_handler | 208 | self.unknown_event_handler = unknown_event_handler |
209 | self.status_update_handler = status_update_handler | ||
180 | 210 | ||
181 | def on_update(self, status): | 211 | def on_update(self, status): |
182 | if self.update_handler != None: | 212 | if self.update_handler != None: |
@@ -210,3 +240,7 @@ class CallbackStreamListener(StreamListener): | |||
210 | exception = MastodonMalformedEventError('Bad event type', name) | 240 | exception = MastodonMalformedEventError('Bad event type', name) |
211 | self.on_abort(exception) | 241 | self.on_abort(exception) |
212 | raise exception | 242 | raise exception |
243 | |||
244 | def on_status_update(self, status): | ||
245 | if self.status_update_handler != None: | ||
246 | self.status_update_handler(status) \ No newline at end of file | ||