mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-03 18:42:43 +00:00
Add support for file/attachment descriptions
This commit is contained in:
parent
7f54c45886
commit
08bee0eeb6
@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Optional, TYPE_CHECKING, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
import os
|
||||
import io
|
||||
@ -62,14 +62,13 @@ class File:
|
||||
a string then the ``filename`` will default to the string given.
|
||||
spoiler: :class:`bool`
|
||||
Whether the attachment is a spoiler.
|
||||
description: Optional[:class:`str`]
|
||||
The file description to display, currently only supported for images.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
||||
__slots__ = ('fp', 'filename', 'spoiler', '_original_pos', '_owner', '_closer')
|
||||
|
||||
if TYPE_CHECKING:
|
||||
fp: io.BufferedIOBase
|
||||
filename: Optional[str]
|
||||
spoiler: bool
|
||||
__slots__ = ('fp', 'filename', 'spoiler', 'description', '_original_pos', '_owner', '_closer')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -77,11 +76,12 @@ class File:
|
||||
filename: Optional[str] = None,
|
||||
*,
|
||||
spoiler: bool = False,
|
||||
description: Optional[str] = None,
|
||||
):
|
||||
if isinstance(fp, io.IOBase):
|
||||
if not (fp.seekable() and fp.readable()):
|
||||
raise ValueError(f'File buffer {fp!r} must be seekable and readable')
|
||||
self.fp = fp
|
||||
self.fp: io.BufferedIOBase = fp
|
||||
self._original_pos = fp.tell()
|
||||
self._owner = False
|
||||
else:
|
||||
@ -102,12 +102,13 @@ class File:
|
||||
else:
|
||||
self.filename = getattr(fp, 'name', None)
|
||||
else:
|
||||
self.filename = filename
|
||||
self.filename: Optional[str] = filename
|
||||
|
||||
if spoiler and self.filename is not None and not self.filename.startswith('SPOILER_'):
|
||||
self.filename = 'SPOILER_' + self.filename
|
||||
|
||||
self.spoiler = spoiler or (self.filename is not None and self.filename.startswith('SPOILER_'))
|
||||
self.spoiler: bool = spoiler or (self.filename is not None and self.filename.startswith('SPOILER_'))
|
||||
self.description: Optional[str] = description
|
||||
|
||||
def reset(self, *, seek: Union[int, bool] = True) -> None:
|
||||
# The `seek` parameter is needed because
|
||||
|
@ -267,7 +267,8 @@ class HTTPClient:
|
||||
f.reset(seek=tries)
|
||||
|
||||
if form:
|
||||
form_data = aiohttp.FormData()
|
||||
# with quote_fields=True '[' and ']' in file field names are escaped, which discord does not support
|
||||
form_data = aiohttp.FormData(quote_fields=False)
|
||||
for params in form:
|
||||
form_data.add_field(**params)
|
||||
kwargs['data'] = form_data
|
||||
@ -496,28 +497,31 @@ class HTTPClient:
|
||||
payload['components'] = components
|
||||
if stickers:
|
||||
payload['sticker_ids'] = stickers
|
||||
if files:
|
||||
attachments = []
|
||||
for index, file in enumerate(files):
|
||||
attachment = {
|
||||
"id": index,
|
||||
"filename": file.filename,
|
||||
}
|
||||
|
||||
if file.description is not None:
|
||||
attachment["description"] = file.description
|
||||
|
||||
attachments.append(attachment)
|
||||
|
||||
payload['attachments'] = attachments
|
||||
|
||||
form.append({'name': 'payload_json', 'value': utils._to_json(payload)})
|
||||
if len(files) == 1:
|
||||
file = files[0]
|
||||
for index, file in enumerate(files):
|
||||
form.append(
|
||||
{
|
||||
'name': 'file',
|
||||
'name': f'files[{index}]',
|
||||
'value': file.fp,
|
||||
'filename': file.filename,
|
||||
'content_type': 'application/octet-stream',
|
||||
'content_type': 'image/png',
|
||||
}
|
||||
)
|
||||
else:
|
||||
for index, file in enumerate(files):
|
||||
form.append(
|
||||
{
|
||||
'name': f'file{index}',
|
||||
'value': file.fp,
|
||||
'filename': file.filename,
|
||||
'content_type': 'application/octet-stream',
|
||||
}
|
||||
)
|
||||
|
||||
return self.request(route, form=form, files=files)
|
||||
|
||||
|
@ -151,9 +151,13 @@ class Attachment(Hashable):
|
||||
The attachment's `media type <https://en.wikipedia.org/wiki/Media_type>`_
|
||||
|
||||
.. versionadded:: 1.7
|
||||
description: Optional[:class:`str`]
|
||||
The attachment's description. Only applicable to images.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
||||
__slots__ = ('id', 'size', 'height', 'width', 'filename', 'url', 'proxy_url', '_http', 'content_type')
|
||||
__slots__ = ('id', 'size', 'height', 'width', 'filename', 'url', 'proxy_url', '_http', 'content_type', 'description')
|
||||
|
||||
def __init__(self, *, data: AttachmentPayload, state: ConnectionState):
|
||||
self.id: int = int(data['id'])
|
||||
@ -165,6 +169,7 @@ class Attachment(Hashable):
|
||||
self.proxy_url: str = data.get('proxy_url')
|
||||
self._http = state.http
|
||||
self.content_type: Optional[str] = data.get('content_type')
|
||||
self.description: Optional[str] = data.get('description')
|
||||
|
||||
def is_spoiler(self) -> bool:
|
||||
""":class:`bool`: Whether this attachment contains a spoiler."""
|
||||
@ -318,6 +323,8 @@ class Attachment(Hashable):
|
||||
result['width'] = self.width
|
||||
if self.content_type:
|
||||
result['content_type'] = self.content_type
|
||||
if self.description is not None:
|
||||
result['description'] = self.description
|
||||
return result
|
||||
|
||||
|
||||
|
@ -52,6 +52,7 @@ class Reaction(TypedDict):
|
||||
class _AttachmentOptional(TypedDict, total=False):
|
||||
height: Optional[int]
|
||||
width: Optional[int]
|
||||
description: str
|
||||
content_type: str
|
||||
spoiler: bool
|
||||
|
||||
|
@ -142,7 +142,7 @@ class AsyncWebhookAdapter:
|
||||
file.reset(seek=attempt)
|
||||
|
||||
if multipart:
|
||||
form_data = aiohttp.FormData()
|
||||
form_data = aiohttp.FormData(quote_fields=False)
|
||||
for p in multipart:
|
||||
form_data.add_field(**p)
|
||||
to_send = form_data
|
||||
@ -487,28 +487,32 @@ def handle_message_parameters(
|
||||
files = [file]
|
||||
|
||||
if files:
|
||||
for index, file in enumerate(files):
|
||||
attachments = []
|
||||
for index, file in enumerate(files):
|
||||
attachment = {
|
||||
"id": index,
|
||||
"filename": file.filename,
|
||||
}
|
||||
|
||||
if file.description is not None:
|
||||
attachment["description"] = file.description
|
||||
|
||||
attachments.append(attachment)
|
||||
|
||||
payload['attachments'] = attachments
|
||||
|
||||
multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
|
||||
payload = None
|
||||
if len(files) == 1:
|
||||
file = files[0]
|
||||
for index, file in enumerate(files):
|
||||
multipart.append(
|
||||
{
|
||||
'name': 'file',
|
||||
'name': f'files[{index}]',
|
||||
'value': file.fp,
|
||||
'filename': file.filename,
|
||||
'content_type': 'application/octet-stream',
|
||||
}
|
||||
)
|
||||
else:
|
||||
for index, file in enumerate(files):
|
||||
multipart.append(
|
||||
{
|
||||
'name': f'file{index}',
|
||||
'value': file.fp,
|
||||
'filename': file.filename,
|
||||
'content_type': 'application/octet-stream',
|
||||
}
|
||||
)
|
||||
|
||||
return ExecuteWebhookParameters(payload=payload, multipart=multipart, files=files)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user