kopia lustrzana https://github.com/halcy/Mastodon.py
add media attachment editing
rodzic
ea87feade0
commit
f7baffc085
|
@ -47,6 +47,7 @@ Writing
|
||||||
.. automethod:: Mastodon.status_delete
|
.. automethod:: Mastodon.status_delete
|
||||||
.. _status_update():
|
.. _status_update():
|
||||||
.. automethod:: Mastodon.status_update
|
.. automethod:: Mastodon.status_update
|
||||||
|
.. automethod:: Mastodon.generate_media_edit_attributes
|
||||||
|
|
||||||
Scheduled statuses
|
Scheduled statuses
|
||||||
------------------
|
------------------
|
||||||
|
|
|
@ -10,6 +10,7 @@ This function allows you to get information about a user's notifications as well
|
||||||
Reading
|
Reading
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
.. automethod:: Mastodon.notifications
|
.. automethod:: Mastodon.notifications
|
||||||
|
.. automethod:: Mastodon.notifications_unread_count
|
||||||
|
|
||||||
Writing
|
Writing
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
|
@ -6,7 +6,7 @@ from mastodon.utility import api_version
|
||||||
from mastodon.internals import Mastodon as Internals
|
from mastodon.internals import Mastodon as Internals
|
||||||
from typing import Optional, List, Union
|
from typing import Optional, List, Union
|
||||||
from mastodon.return_types import IdType, PrimitiveIdType, Account, AdminAccount, AdminReport, PaginatableList, NonPaginatableList, Status, Tag,\
|
from mastodon.return_types import IdType, PrimitiveIdType, Account, AdminAccount, AdminReport, PaginatableList, NonPaginatableList, Status, Tag,\
|
||||||
PreviewCard, AdminDomainBlock, AdminMeasure, AdminDimension, AdminRetention, AdminCanonicalEmailBlock
|
PreviewCard, AdminDomainBlock, AdminMeasure, AdminDimension, AdminRetention, AdminCanonicalEmailBlock, AdminDomainAllow
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class Mastodon(Internals):
|
class Mastodon(Internals):
|
||||||
|
@ -609,3 +609,52 @@ class Mastodon(Internals):
|
||||||
"""
|
"""
|
||||||
id = self.__unpack_id(id)
|
id = self.__unpack_id(id)
|
||||||
return self.__api_request('DELETE', f'/api/v1/admin/canonical_email_blocks/{id}')
|
return self.__api_request('DELETE', f'/api/v1/admin/canonical_email_blocks/{id}')
|
||||||
|
|
||||||
|
@api_version("4.0.0", "4.0.0")
|
||||||
|
def admin_domain_allows(self, max_id: Optional[IdType] = None, min_id: Optional[IdType] = None,
|
||||||
|
since_id: Optional[IdType] = None, limit: Optional[int] = None) -> PaginatableList[AdminDomainAllow]:
|
||||||
|
"""
|
||||||
|
Fetches a list of allowed domains. Requires scope `admin:read:domain_allows`.
|
||||||
|
|
||||||
|
The returned list may be paginated using max_id, min_id, and since_id.
|
||||||
|
|
||||||
|
NB: Untested, since I don't have a Mastodon instance in allowlist mode to test this with.
|
||||||
|
"""
|
||||||
|
params = self.__generate_params(locals())
|
||||||
|
return self.__api_request('GET', '/api/v1/admin/domain_allows', params)
|
||||||
|
|
||||||
|
@api_version("4.0.0", "4.0.0")
|
||||||
|
def admin_domain_allow(self, id: Union[AdminDomainAllow, IdType]) -> AdminDomainAllow:
|
||||||
|
"""
|
||||||
|
Fetch a single allowed domain by ID. Requires scope `admin:read:domain_allows`.
|
||||||
|
|
||||||
|
Raises `MastodonAPIError` if the domain allow does not exist.
|
||||||
|
|
||||||
|
NB: Untested, since I don't have a Mastodon instance in allowlist mode to test this with.
|
||||||
|
"""
|
||||||
|
id = self.__unpack_id(id)
|
||||||
|
return self.__api_request('GET', f'/api/v1/admin/domain_allows/{id}')
|
||||||
|
|
||||||
|
@api_version("4.0.0", "4.0.0")
|
||||||
|
def admin_create_domain_allow(self, domain: str) -> AdminDomainAllow:
|
||||||
|
"""
|
||||||
|
Allow a domain for federation. Requires scope `admin:write:domain_allows`.
|
||||||
|
|
||||||
|
If the domain is already allowed, returns the existing record.
|
||||||
|
|
||||||
|
NB: Untested, since I don't have a Mastodon instance in allowlist mode to test this with.
|
||||||
|
"""
|
||||||
|
params = {"domain": domain}
|
||||||
|
return self.__api_request('POST', '/api/v1/admin/domain_allows', params)
|
||||||
|
|
||||||
|
@api_version("4.0.0", "4.0.0")
|
||||||
|
def admin_delete_domain_allow(self, id: Union[AdminDomainAllow, IdType]):
|
||||||
|
"""
|
||||||
|
Remove a domain from the allowlist. Requires scope `admin:write:domain_allows`.
|
||||||
|
|
||||||
|
Raises `MastodonAPIError` if the domain allow does not exist.
|
||||||
|
|
||||||
|
NB: Untested, since I don't have a Mastodon instance in allowlist mode to test this with.
|
||||||
|
"""
|
||||||
|
id = self.__unpack_id(id)
|
||||||
|
self.__api_request('DELETE', f'/api/v1/admin/domain_allows/{id}')
|
||||||
|
|
|
@ -158,6 +158,10 @@ class Mastodon():
|
||||||
kwargs['data'] = params
|
kwargs['data'] = params
|
||||||
|
|
||||||
response_object = self.session.request(method, base_url + endpoint, **kwargs)
|
response_object = self.session.request(method, base_url + endpoint, **kwargs)
|
||||||
|
if self.debug_requests:
|
||||||
|
print(f'Mastodon: Request URL: {response_object.request.url}')
|
||||||
|
print(f'Mastodon: Request body: {response_object.request.body}')
|
||||||
|
print(f'Mastodon: Response body: {response_object.text}')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise MastodonNetworkError(f"Could not complete request: {e}")
|
raise MastodonNetworkError(f"Could not complete request: {e}")
|
||||||
|
|
||||||
|
@ -480,7 +484,7 @@ class Mastodon():
|
||||||
with closing(connection) as r:
|
with closing(connection) as r:
|
||||||
listener.handle_stream(r)
|
listener.handle_stream(r)
|
||||||
|
|
||||||
def __generate_params(self, params, exclude=[], dateconv=False):
|
def __generate_params(self, params, exclude=[], dateconv=False, for_json=False):
|
||||||
"""
|
"""
|
||||||
Internal named-parameters-to-dict helper.
|
Internal named-parameters-to-dict helper.
|
||||||
|
|
||||||
|
@ -503,6 +507,7 @@ class Mastodon():
|
||||||
if params[key] is None or key in exclude:
|
if params[key] is None or key in exclude:
|
||||||
del params[key]
|
del params[key]
|
||||||
|
|
||||||
|
if not for_json:
|
||||||
param_keys = list(params.keys())
|
param_keys = list(params.keys())
|
||||||
for key in param_keys:
|
for key in param_keys:
|
||||||
if isinstance(params[key], list):
|
if isinstance(params[key], list):
|
||||||
|
|
|
@ -100,6 +100,10 @@ class Mastodon(Internals):
|
||||||
`focus` and `thumbnail` are as in :ref:`media_post() <media_post()>` .
|
`focus` and `thumbnail` are as in :ref:`media_post() <media_post()>` .
|
||||||
|
|
||||||
The returned dict reflects the updates to the media attachment.
|
The returned dict reflects the updates to the media attachment.
|
||||||
|
|
||||||
|
Note: This is for updating the metadata of an *unattached* media attachment (i.e. one that has
|
||||||
|
not been used in a status yet). For editing media attachment metadata after posting, see `status_update` and
|
||||||
|
`generate_media_edit_attributes`.
|
||||||
"""
|
"""
|
||||||
id = self.__unpack_id(id)
|
id = self.__unpack_id(id)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ class Mastodon(Internals):
|
||||||
* `status` - A user that the logged in user has enabned notifications for has enabled `notify` (see :ref:`account_follow() <account_follow()>`)
|
* `status` - A user that the logged in user has enabned notifications for has enabled `notify` (see :ref:`account_follow() <account_follow()>`)
|
||||||
* `admin.sign_up` - For accounts with appropriate permissions: A new user has signed up
|
* `admin.sign_up` - For accounts with appropriate permissions: A new user has signed up
|
||||||
* `admin.report` - For accounts with appropriate permissions: A new report has been received
|
* `admin.report` - For accounts with appropriate permissions: A new report has been received
|
||||||
* TODO: document the rest
|
* `severed_relationships` - Some of the logged in users relationships have been severed due to a moderation action on this server
|
||||||
|
* `moderation_warning` - The logged in user has been warned by a moderator
|
||||||
Parameters `exclude_types` and `types` are array of these types, specifying them will in- or exclude the
|
Parameters `exclude_types` and `types` are array of these types, specifying them will in- or exclude the
|
||||||
types of notifications given. It is legal to give both parameters at the same tine, the result will then
|
types of notifications given. It is legal to give both parameters at the same tine, the result will then
|
||||||
be the intersection of the results of both filters. Specifying `mentions_only` is a deprecated way to set
|
be the intersection of the results of both filters. Specifying `mentions_only` is a deprecated way to set
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import base64
|
||||||
|
|
||||||
from mastodon.errors import MastodonIllegalArgumentError
|
from mastodon.errors import MastodonIllegalArgumentError, MastodonVersionError
|
||||||
from mastodon.utility import api_version
|
from mastodon.utility import api_version
|
||||||
|
|
||||||
from mastodon.internals import Mastodon as Internals
|
from mastodon.internals import Mastodon as Internals
|
||||||
from mastodon.return_types import Status, IdType, ScheduledStatus, PreviewCard, Context, NonPaginatableList, Account,\
|
from mastodon.return_types import Status, IdType, ScheduledStatus, PreviewCard, Context, NonPaginatableList, Account,\
|
||||||
MediaAttachment, Poll, StatusSource, StatusEdit, PaginatableList
|
MediaAttachment, Poll, StatusSource, StatusEdit, PaginatableList, PathOrFile
|
||||||
|
|
||||||
from typing import Union, Optional, List
|
from typing import Union, Optional, List, Dict, Any, Tuple
|
||||||
|
|
||||||
class Mastodon(Internals):
|
class Mastodon(Internals):
|
||||||
###
|
###
|
||||||
|
@ -112,12 +113,11 @@ class Mastodon(Internals):
|
||||||
###
|
###
|
||||||
# Writing data: Statuses
|
# Writing data: Statuses
|
||||||
###
|
###
|
||||||
|
|
||||||
def __status_internal(self, status: Optional[str], in_reply_to_id: Optional[Union[Status, IdType]] = None, media_ids: Optional[List[Union[MediaAttachment, IdType]]] = None,
|
def __status_internal(self, status: Optional[str], in_reply_to_id: Optional[Union[Status, IdType]] = None, media_ids: Optional[List[Union[MediaAttachment, IdType]]] = None,
|
||||||
sensitive: Optional[bool] = False, visibility: Optional[str] = None, spoiler_text: Optional[str] = None, language: Optional[str] = None,
|
sensitive: Optional[bool] = False, visibility: Optional[str] = None, spoiler_text: Optional[str] = None, language: Optional[str] = None,
|
||||||
idempotency_key: Optional[str] = None, content_type: Optional[str] = None, scheduled_at: Optional[datetime] = None,
|
idempotency_key: Optional[str] = None, content_type: Optional[str] = None, scheduled_at: Optional[datetime] = None,
|
||||||
poll: Optional[Union[Poll, IdType]] = None, quote_id: Optional[Union[Status, IdType]] = None, edit: bool = False,
|
poll: Optional[Union[Poll, IdType]] = None, quote_id: Optional[Union[Status, IdType]] = None, edit: bool = False,
|
||||||
strict_content_type: bool = False) -> Union[Status, ScheduledStatus]:
|
strict_content_type: bool = False, media_attributes: Optional[List[Dict[str, Any]]] = None) -> Union[Status, ScheduledStatus]:
|
||||||
"""
|
"""
|
||||||
Internal statuses poster helper
|
Internal statuses poster helper
|
||||||
"""
|
"""
|
||||||
|
@ -185,10 +185,17 @@ class Mastodon(Internals):
|
||||||
del params_initial['content_type']
|
del params_initial['content_type']
|
||||||
|
|
||||||
use_json = False
|
use_json = False
|
||||||
if poll is not None:
|
if poll is not None or media_attributes is not None:
|
||||||
use_json = True
|
use_json = True
|
||||||
|
|
||||||
params = self.__generate_params(params_initial, ['idempotency_key', 'edit', 'strict_content_type'])
|
# If media_attributes is set, make sure that media_ids contains at least all the IDs of the media from media_attributes
|
||||||
|
if media_attributes is not None:
|
||||||
|
if "media_ids" in params_initial and params_initial["media_ids"] is not None:
|
||||||
|
params_initial["media_ids"] = list(set(params_initial["media_ids"]) + set([x["id"] for x in media_attributes]))
|
||||||
|
else:
|
||||||
|
params_initial["media_ids"] = [x["id"] for x in media_attributes]
|
||||||
|
|
||||||
|
params = self.__generate_params(params_initial, ['idempotency_key', 'edit', 'strict_content_type'], for_json = use_json)
|
||||||
cast_type = Status
|
cast_type = Status
|
||||||
if scheduled_at is not None:
|
if scheduled_at is not None:
|
||||||
cast_type = ScheduledStatus
|
cast_type = ScheduledStatus
|
||||||
|
@ -290,17 +297,49 @@ class Mastodon(Internals):
|
||||||
"""
|
"""
|
||||||
return self.status_post(status)
|
return self.status_post(status)
|
||||||
|
|
||||||
@api_version("3.5.0", "3.5.0")
|
|
||||||
def status_update(self, id: Union[Status, IdType], status: Optional[str] = None, spoiler_text: Optional[str] = None,
|
def generate_media_edit_attributes(self, id: Union[MediaAttachment, IdType], description: Optional[str] = None,
|
||||||
|
focus: Optional[Tuple[float, float]] = None,
|
||||||
|
thumbnail: Optional[PathOrFile] = None, thumb_mimetype: Optional[str] = None) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Helper function to generate a single media edit attribute dictionary.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- `id` (str): The ID of the media attachment (mandatory).
|
||||||
|
- `description` (Optional[str]): A new description for the media.
|
||||||
|
- `focus` (Optional[Tuple[float, float]]): The focal point of the media.
|
||||||
|
- `thumbnail` (Optional[PathOrFile]): The thumbnail to be used.
|
||||||
|
"""
|
||||||
|
media_edit = {"id": self.__unpack_id(id)}
|
||||||
|
|
||||||
|
if description is not None:
|
||||||
|
media_edit["description"] = description
|
||||||
|
|
||||||
|
if focus is not None:
|
||||||
|
if isinstance(focus, tuple) and len(focus) == 2:
|
||||||
|
media_edit["focus"] = f"{focus[0]},{focus[1]}"
|
||||||
|
else:
|
||||||
|
raise MastodonIllegalArgumentError("Focus must be a tuple of two floats between -1 and 1")
|
||||||
|
|
||||||
|
if thumbnail is not None:
|
||||||
|
if not self.verify_minimum_version("3.2.0", cached=True):
|
||||||
|
raise MastodonVersionError('Thumbnail requires version > 3.2.0')
|
||||||
|
_, thumb_file, thumb_mimetype = self.__load_media_file(thumbnail, thumb_mimetype)
|
||||||
|
media_edit["thumbnail"] = f"data:{thumb_mimetype};base64,{base64.b64encode(thumb_file.read()).decode()}"
|
||||||
|
|
||||||
|
return media_edit
|
||||||
|
|
||||||
|
@api_version("3.5.0", "4.1.0")
|
||||||
|
def status_update(self, id: Union[Status, IdType], status: str, spoiler_text: Optional[str] = None,
|
||||||
sensitive: Optional[bool] = None, media_ids: Optional[List[Union[MediaAttachment, IdType]]] = None,
|
sensitive: Optional[bool] = None, media_ids: Optional[List[Union[MediaAttachment, IdType]]] = None,
|
||||||
poll: Optional[Union[Poll, IdType]] = None) -> Status:
|
poll: Optional[Union[Poll, IdType]] = None, media_attributes: Optional[List[Dict[str, Any]]] = None) -> Status:
|
||||||
"""
|
"""
|
||||||
Edit a status. The meanings of the fields are largely the same as in :ref:`status_post() <status_post()>`,
|
Edit a status. The meanings of the fields are largely the same as in :ref:`status_post() <status_post()>`,
|
||||||
though not every field can be edited.
|
though not every field can be edited. The `status` parameter is mandatory.
|
||||||
|
|
||||||
Note that editing a poll will reset the votes.
|
Note that editing a poll will reset the votes.
|
||||||
|
|
||||||
TODO: Currently doesn't support editing media descriptions, implement that.
|
To edit media metadata, generate a list of dictionaries with the following keys:
|
||||||
"""
|
"""
|
||||||
return self.__status_internal(
|
return self.__status_internal(
|
||||||
status=status,
|
status=status,
|
||||||
|
@ -308,7 +347,8 @@ class Mastodon(Internals):
|
||||||
sensitive=sensitive,
|
sensitive=sensitive,
|
||||||
spoiler_text=spoiler_text,
|
spoiler_text=spoiler_text,
|
||||||
poll=poll,
|
poll=poll,
|
||||||
edit=id
|
edit=id,
|
||||||
|
media_attributes=media_attributes
|
||||||
)
|
)
|
||||||
|
|
||||||
@api_version("3.5.0", "3.5.0")
|
@api_version("3.5.0", "3.5.0")
|
||||||
|
|
|
@ -44,8 +44,9 @@ class StreamListener(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_notification(self, notification):
|
def on_notification(self, notification):
|
||||||
"""A new notification. `notification` is the parsed `notification dict`
|
"""A new notification. `notification` is the object
|
||||||
describing the notification."""
|
describing the notification. For more information, see the documentation
|
||||||
|
for the notifications() method."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_filters_changed(self):
|
def on_filters_changed(self):
|
||||||
|
@ -106,7 +107,7 @@ class StreamListener(object):
|
||||||
|
|
||||||
def on_any_event(self, name, data):
|
def on_any_event(self, name, data):
|
||||||
"""A generic event handler that is called for every event received.
|
"""A generic event handler that is called for every event received.
|
||||||
The name contains the event-name and data contains the content of the event.
|
The name contains the event name and data contains the content of the event.
|
||||||
|
|
||||||
Called before the more specific on_xxx handlers.
|
Called before the more specific on_xxx handlers.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -8022,7 +8022,7 @@
|
||||||
{
|
{
|
||||||
"name": "Admin email block",
|
"name": "Admin email block",
|
||||||
"python_name": "AdminCanonicalEmailBlock",
|
"python_name": "AdminCanonicalEmailBlock",
|
||||||
"func_call": "api2.admin_create_canonical_email_block(email=<some email>)",
|
"func_call": "mastodon.admin_create_canonical_email_block(email=<some email>)",
|
||||||
"func_call_real": null,
|
"func_call_real": null,
|
||||||
"func_call_additional": null,
|
"func_call_additional": null,
|
||||||
"func_alternate_acc": null,
|
"func_alternate_acc": null,
|
||||||
|
@ -8065,11 +8065,11 @@
|
||||||
{
|
{
|
||||||
"name": "Admin domain allow",
|
"name": "Admin domain allow",
|
||||||
"python_name": "AdminDomainAllow",
|
"python_name": "AdminDomainAllow",
|
||||||
"func_call": "TODO_TO_BE_IMPLEMENTED",
|
"func_call": "mastodon.admin_domain_allows()[0]",
|
||||||
"func_call_real": null,
|
"func_call_real": null,
|
||||||
"func_call_additional": null,
|
"func_call_additional": null,
|
||||||
"func_alternate_acc": null,
|
"func_alternate_acc": null,
|
||||||
"manual_update": false,
|
"manual_update": true,
|
||||||
"masto_doc_link": "https://docs.joinmastodon.org/entities/Admin_DomainAllow",
|
"masto_doc_link": "https://docs.joinmastodon.org/entities/Admin_DomainAllow",
|
||||||
"description": "The opposite of a domain block, specifically allowing a domain to federate when the instance is in allowlist mode.",
|
"description": "The opposite of a domain block, specifically allowing a domain to federate when the instance is in allowlist mode.",
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -9178,11 +9178,11 @@
|
||||||
{
|
{
|
||||||
"name": "Relationship Severance Event",
|
"name": "Relationship Severance Event",
|
||||||
"python_name": "RelationshipSeveranceEvent",
|
"python_name": "RelationshipSeveranceEvent",
|
||||||
"func_call": "TODO_TO_BE_IMPLEMENTED",
|
"func_call": "# There isn't really a good way to get this manually - you get it if a moderation takes action.",
|
||||||
"func_call_real": null,
|
"func_call_real": null,
|
||||||
"func_call_additional": null,
|
"func_call_additional": null,
|
||||||
"func_alternate_acc": null,
|
"func_alternate_acc": null,
|
||||||
"manual_update": false,
|
"manual_update": true,
|
||||||
"masto_doc_link": "https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent",
|
"masto_doc_link": "https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent",
|
||||||
"description": "Summary of a moderation or block event that caused follow relationships to be severed.",
|
"description": "Summary of a moderation or block event that caused follow relationships to be severed.",
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -9206,7 +9206,7 @@
|
||||||
"version_history": [["4.3.0", "added"]],
|
"version_history": [["4.3.0", "added"]],
|
||||||
"field_type": "str",
|
"field_type": "str",
|
||||||
"field_subtype": null,
|
"field_subtype": null,
|
||||||
"field_structuretype": null,
|
"field_structuretype": "RelationshipSeveranceEventType",
|
||||||
"is_optional": false,
|
"is_optional": false,
|
||||||
"is_nullable": false
|
"is_nullable": false
|
||||||
},
|
},
|
||||||
|
@ -9547,7 +9547,7 @@
|
||||||
{
|
{
|
||||||
"name": "Account Warning",
|
"name": "Account Warning",
|
||||||
"python_name": "AccountWarning",
|
"python_name": "AccountWarning",
|
||||||
"func_call": "TODO_TO_BE_IMPLEMENTED",
|
"func_call": "# There isn't really a good way to get this manually - you get it if a moderation takes action.",
|
||||||
"func_call_real": null,
|
"func_call_real": null,
|
||||||
"func_call_additional": null,
|
"func_call_additional": null,
|
||||||
"func_alternate_acc": null,
|
"func_alternate_acc": null,
|
||||||
|
@ -9643,7 +9643,7 @@
|
||||||
"func_call_additional": null,
|
"func_call_additional": null,
|
||||||
"func_alternate_acc": null,
|
"func_alternate_acc": null,
|
||||||
"manual_update": false,
|
"manual_update": false,
|
||||||
"masto_doc_link": "https://docs.joinmastodon.org/methods/notifications/#unread_count",
|
"masto_doc_link": "https://docs.joinmastodon.org/methods/notifications/#unread-count",
|
||||||
"description": "Get the (capped) number of unread notifications for the current user.",
|
"description": "Get the (capped) number of unread notifications for the current user.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"count": {
|
"count": {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -241,3 +241,51 @@ def test_status_edit(api3, api2):
|
||||||
source = api2.status_source(status)
|
source = api2.status_source(status)
|
||||||
assert source.text == "the best editor? why, of course it is the KDE Advanced Text Editor, Kate"
|
assert source.text == "the best editor? why, of course it is the KDE Advanced Text Editor, Kate"
|
||||||
|
|
||||||
|
@pytest.mark.vcr(match_on=['path'])
|
||||||
|
def test_status_update_with_media_edit(api2):
|
||||||
|
media = api2.media_post(
|
||||||
|
'tests/video.mp4',
|
||||||
|
description="Original description",
|
||||||
|
focus=(-0.5, 0.3),
|
||||||
|
thumbnail='tests/amewatson.jpg'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert media
|
||||||
|
assert media.url is None
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
media2 = api2.media(media)
|
||||||
|
assert media2.id == media.id
|
||||||
|
assert media2.url is not None
|
||||||
|
|
||||||
|
status = api2.status_post(
|
||||||
|
'Initial post with media',
|
||||||
|
media_ids=media2
|
||||||
|
)
|
||||||
|
|
||||||
|
assert status
|
||||||
|
assert status['media_attachments'][0]['description'] == "Original description"
|
||||||
|
assert status['media_attachments'][0]['meta']['focus']['x'] == -0.5
|
||||||
|
assert status['media_attachments'][0]['meta']['focus']['y'] == 0.3
|
||||||
|
|
||||||
|
try:
|
||||||
|
updated_media_attributes = api2.generate_media_edit_attributes(
|
||||||
|
id=media2.id,
|
||||||
|
description="Updated description",
|
||||||
|
focus=(0.2, -0.1),
|
||||||
|
thumbnail='tests/image.jpg'
|
||||||
|
)
|
||||||
|
|
||||||
|
updated_status = api2.status_update(
|
||||||
|
status['id'],
|
||||||
|
"I have altered the media attachment. Pray I do not alter it further.",
|
||||||
|
media_attributes=[updated_media_attributes]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updated_status
|
||||||
|
assert updated_status['media_attachments'][0]['description'] == "Updated description"
|
||||||
|
assert updated_status['media_attachments'][0]['meta']['focus']['x'] == 0.2
|
||||||
|
assert updated_status['media_attachments'][0]['meta']['focus']['y'] == -0.1
|
||||||
|
assert updated_status['media_attachments'][0]['preview_url'] != status['media_attachments'][0]['preview_url']
|
||||||
|
finally:
|
||||||
|
api2.status_delete(status['id'])
|
||||||
|
|
Ładowanie…
Reference in New Issue