From f3d25fa19deb2caf0793d685a542509f94c2c8a9 Mon Sep 17 00:00:00 2001 From: halcy Date: Tue, 22 Nov 2022 00:10:02 +0200 Subject: add status editing --- mastodon/Mastodon.py | 218 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 82 deletions(-) (limited to 'mastodon') diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 2a70ce7..48b1307 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -229,30 +229,25 @@ class Mastodon: __DICT_VERSION_HASHTAG = "2.3.4" __DICT_VERSION_EMOJI = "3.0.0" __DICT_VERSION_RELATIONSHIP = "3.3.0" - __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version( - "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) + __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) __DICT_VERSION_LIST = "2.1.0" __DICT_VERSION_CARD = "3.2.0" - __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version( - "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) + __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) __DICT_VERSION_ACTIVITY = "2.1.2" __DICT_VERSION_REPORT = "2.9.1" __DICT_VERSION_PUSH = "2.4.0" __DICT_VERSION_PUSH_NOTIF = "2.4.0" __DICT_VERSION_FILTER = "2.4.3" - __DICT_VERSION_CONVERSATION = bigger_version(bigger_version( - "2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) - __DICT_VERSION_SCHEDULED_STATUS = bigger_version( - "2.7.0", __DICT_VERSION_STATUS) + __DICT_VERSION_CONVERSATION = bigger_version(bigger_version("2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) + __DICT_VERSION_SCHEDULED_STATUS = bigger_version("2.7.0", __DICT_VERSION_STATUS) __DICT_VERSION_PREFERENCES = "2.8.0" - __DICT_VERSION_ADMIN_ACCOUNT = bigger_version( - "2.9.1", __DICT_VERSION_ACCOUNT) + __DICT_VERSION_ADMIN_ACCOUNT = bigger_version("2.9.1", __DICT_VERSION_ACCOUNT) __DICT_VERSION_FEATURED_TAG = "3.0.0" __DICT_VERSION_MARKER = "3.0.0" __DICT_VERSION_REACTION = "3.1.0" - __DICT_VERSION_ANNOUNCEMENT = bigger_version( - "3.1.0", __DICT_VERSION_REACTION) + __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION) + __DICT_VERSION_STATUS_EDIT = "3.5.0" ### # Registering apps @@ -1797,80 +1792,21 @@ class Mastodon: ### # Writing data: Statuses ### - @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) - def status_post(self, status, in_reply_to_id=None, media_ids=None, + def __status_internal(self, status, in_reply_to_id=None, media_ids=None, sensitive=False, visibility=None, spoiler_text=None, language=None, idempotency_key=None, content_type=None, - scheduled_at=None, poll=None, quote_id=None): - """ - Post a status. Can optionally be in reply to another status and contain - media. - - `media_ids` should be a list. (If it's not, the function will turn it - into one.) It can contain up to four pieces of media (uploaded via - `media_post()`_). `media_ids` can also be the `media dicts`_ returned - by `media_post()`_ - they are unpacked automatically. - - The `sensitive` boolean decides whether or not media attached to the post - should be marked as sensitive, which hides it by default on the Mastodon - web front-end. - - The visibility parameter is a string value and accepts any of: - 'direct' - post will be visible only to mentioned users - 'private' - post will be visible only to followers - 'unlisted' - post will be public but not appear on the public timeline - 'public' - post will be public - - If not passed in, visibility defaults to match the current account's - default-privacy setting (starting with Mastodon version 1.6) or its - locked setting - private if the account is locked, public otherwise - (for Mastodon versions lower than 1.6). - - The `spoiler_text` parameter is a string to be shown as a warning before - the text of the status. If no text is passed in, no warning will be - displayed. - - Specify `language` to override automatic language detection. The parameter - accepts all valid ISO 639-2 language codes. - - You can set `idempotency_key` to a value to uniquely identify an attempt - at posting a status. Even if you call this function more than once, - if you call it with the same `idempotency_key`, only one status will - be created. - - Pass a datetime as `scheduled_at` to schedule the toot for a specific time - (the time must be at least 5 minutes into the future). If this is passed, - status_post returns a `scheduled toot dict`_ instead. - - Pass `poll` to attach a poll to the status. An appropriate object can be - constructed using `make_poll()`_ . Note that as of Mastodon version - 2.8.2, you can only have either media or a poll attached, not both at - the same time. - - **Specific to "pleroma" feature set:**: Specify `content_type` to set - the content type of your post on Pleroma. It accepts 'text/plain' (default), - 'text/markdown', 'text/html' and 'text/bbcode'. This parameter is not - supported on Mastodon servers, but will be safely ignored if set. - - **Specific to "fedibird" feature set:**: The `quote_id` parameter is - a non-standard extension that specifies the id of a quoted status. - - Returns a `toot dict`_ with the new status. - """ + scheduled_at=None, poll=None, quote_id=None, edit=False): if quote_id is not None: if self.feature_set != "fedibird": - raise MastodonIllegalArgumentError( - 'quote_id is only available with feature set fedibird') + raise MastodonIllegalArgumentError('quote_id is only available with feature set fedibird') quote_id = self.__unpack_id(quote_id) if content_type is not None: if self.feature_set != "pleroma": - raise MastodonIllegalArgumentError( - 'content_type is only available with feature set pleroma') + raise MastodonIllegalArgumentError('content_type is only available with feature set pleroma') # It would be better to read this from nodeinfo and cache, but this is easier if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: - raise MastodonIllegalArgumentError( - 'Invalid content type specified') + raise MastodonIllegalArgumentError('Invalid content type specified') if in_reply_to_id is not None: in_reply_to_id = self.__unpack_id(in_reply_to_id) @@ -1893,8 +1829,7 @@ class Mastodon: else: params_initial['visibility'] = params_initial['visibility'].lower() if params_initial['visibility'] not in valid_visibilities: - raise ValueError('Invalid visibility value! Acceptable ' - 'values are %s' % valid_visibilities) + raise ValueError('Invalid visibility value! Acceptable values are %s' % valid_visibilities) if params_initial['language'] is None: del params_initial['language'] @@ -1914,8 +1849,7 @@ class Mastodon: for media_id in media_ids: media_ids_proper.append(self.__unpack_id(media_id)) except Exception as e: - raise MastodonIllegalArgumentError("Invalid media " - "dict: %s" % e) + raise MastodonIllegalArgumentError("Invalid media dict: %s" % e) params_initial["media_ids"] = media_ids_proper @@ -1926,8 +1860,89 @@ class Mastodon: if poll is not None: use_json = True - params = self.__generate_params(params_initial, ['idempotency_key']) - return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) + params = self.__generate_params(params_initial, ['idempotency_key', 'edit']) + if edit is None: + # Post + return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) + else: + # Edit + return self.__api_request('PUT', '/api/v1/statuses/{0}'.format(str(self.__unpack_id(edit))), params, headers=headers, use_json=use_json) + + @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) + def status_post(self, status, in_reply_to_id=None, media_ids=None, + sensitive=False, visibility=None, spoiler_text=None, + language=None, idempotency_key=None, content_type=None, + scheduled_at=None, poll=None, quote_id=None): + """ + Post a status. Can optionally be in reply to another status and contain + media. + + `media_ids` should be a list. (If it's not, the function will turn it + into one.) It can contain up to four pieces of media (uploaded via + `media_post()`_). `media_ids` can also be the `media dicts`_ returned + by `media_post()`_ - they are unpacked automatically. + + The `sensitive` boolean decides whether or not media attached to the post + should be marked as sensitive, which hides it by default on the Mastodon + web front-end. + + The visibility parameter is a string value and accepts any of: + 'direct' - post will be visible only to mentioned users + 'private' - post will be visible only to followers + 'unlisted' - post will be public but not appear on the public timeline + 'public' - post will be public + + If not passed in, visibility defaults to match the current account's + default-privacy setting (starting with Mastodon version 1.6) or its + locked setting - private if the account is locked, public otherwise + (for Mastodon versions lower than 1.6). + + The `spoiler_text` parameter is a string to be shown as a warning before + the text of the status. If no text is passed in, no warning will be + displayed. + + Specify `language` to override automatic language detection. The parameter + accepts all valid ISO 639-2 language codes. + + You can set `idempotency_key` to a value to uniquely identify an attempt + at posting a status. Even if you call this function more than once, + if you call it with the same `idempotency_key`, only one status will + be created. + + Pass a datetime as `scheduled_at` to schedule the toot for a specific time + (the time must be at least 5 minutes into the future). If this is passed, + status_post returns a `scheduled toot dict`_ instead. + + Pass `poll` to attach a poll to the status. An appropriate object can be + constructed using `make_poll()`_ . Note that as of Mastodon version + 2.8.2, you can only have either media or a poll attached, not both at + the same time. + + **Specific to "pleroma" feature set:**: Specify `content_type` to set + the content type of your post on Pleroma. It accepts 'text/plain' (default), + 'text/markdown', 'text/html' and 'text/bbcode'. This parameter is not + supported on Mastodon servers, but will be safely ignored if set. + + **Specific to "fedibird" feature set:**: The `quote_id` parameter is + a non-standard extension that specifies the id of a quoted status. + + Returns a `toot dict`_ with the new status. + """ + return self.__status_internal( + status, + in_reply_to_id, + media_ids, + sensitive, + visibility, + spoiler_text, + language, + idempotency_key, + content_type, + scheduled_at, + poll, + quote_id, + edit=None + ) @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) def toot(self, status): @@ -1940,6 +1955,45 @@ class Mastodon: """ return self.status_post(status) + @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS) + def status_update(self, id, status = None, spoiler_text = None, sensitive = None, media_ids = None, poll = None): + """ + Edit a status. The meanings of the fields are largely the same as in `status_post()`_, + though not every field can be edited. + + Note that editing a poll will reset the votes. + """ + return self.__status_internal( + status = status, + media_ids = media_ids, + sensitive = sensitive, + spoiler_text = spoiler_text, + poll = poll, + edit = id + ) + + @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS_EDIT) + def status_history(self, id): + """ + Returns the edit history of a status as a list of `status edit dicts`_, starting + from the original form. Note that this means that a status that has been edited + once will have *two* entries in this list, a status that has been edited twice + will have three, and so on. + """ + id = self.__unpack_id(id) + return self.__api_request('GET', "/api/v1/statuses/{0}/history".format(str(id))) + + def status_source(self, id): + """ + Returns the source of a status for editing. + + Return value is a dictionary containing exactly the parameters you could pass to + `status_update()`_ to change nothing about the status, except `status` is `text` + instead. + """ + id = self.__unpack_id(id) + return self.__api_request('GET', "/api/v1/statuses/{0}/source".format(str(id))) + @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, sensitive=False, visibility=None, spoiler_text=None, -- cgit v1.2.3