Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/1628.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :meth:`~disnake.AttachmentFlags.contains_explicit_content`, :meth:`~disnake.AttachmentFlags.contains_gore_content`, :meth:`~disnake.AttachmentFlags.contains_self_harm_content`, :class:`~disnake.UnfurledScanMetadataFlags`, :attr:`.UnfurledMediaItem.content_scan_metadata` and :class:`.UnfurledScanMetadata`.
Comment thread
Snipy7374 marked this conversation as resolved.
Resolved
32 changes: 31 additions & 1 deletion disnake/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
TextInputStyle,
try_enum,
)
from .flags import UnfurledMediaItemFlags
from .flags import UnfurledMediaItemFlags, UnfurledScanMetadataFlags
from .partial_emoji import PartialEmoji, _EmojiTag
from .utils import MISSING, _get_as_snowflake, assert_never, get_slots

Expand Down Expand Up @@ -69,6 +69,7 @@
TextInput as TextInputPayload,
ThumbnailComponent as ThumbnailComponentPayload,
UnfurledMediaItem as UnfurledMediaItemPayload,
UnfurledScanMetadata as UnfurledScanMetadataPayload,
UserSelectMenu as UserSelectMenuPayload,
)

Expand All @@ -89,6 +90,7 @@
"Section",
"TextDisplay",
"UnfurledMediaItem",
"UnfurledScanMetadata",
"Thumbnail",
"MediaGallery",
"MediaGalleryItem",
Expand Down Expand Up @@ -1144,6 +1146,10 @@ class UnfurledMediaItem:
.. versionadded:: |vnext|
content_type: :class:`str` | :data:`None`
The `media type <https://en.wikipedia.org/wiki/Media_type>`_ of this media item.
content_scan_metadata: :class:`UnfurledScanMetadata` | :data:`None`
The content scan metadata for this media item, if any.

.. versionadded:: |vnext|
attachment_id: :class:`int` | :data:`None`
The ID of the uploaded attachment. Only present if the media item was
uploaded as an attachment.
Expand All @@ -1159,6 +1165,7 @@ class UnfurledMediaItem:
"_flags",
"content_type",
"attachment_id",
"content_scan_metadata",
)

# generally, users should also be able to pass a plain url where applicable instead of
Expand All @@ -1172,6 +1179,7 @@ def __init__(self, url: str) -> None:
self.placeholder_version: int | None = None
self._flags: int = 0
self.content_type: str | None = None
self.content_scan_metadata: UnfurledScanMetadata | None = None
self.attachment_id: int | None = None

@classmethod
Expand All @@ -1184,6 +1192,11 @@ def from_dict(cls, data: UnfurledMediaItemPayload) -> Self:
self.placeholder_version = data.get("placeholder_version")
self._flags = data.get("flags", 0)
self.content_type = data.get("content_type")
self.content_scan_metadata = (
UnfurledScanMetadata(metadata)
if (metadata := data.get("content_scan_metadata"))
else None
)
self.attachment_id = _get_as_snowflake(data, "attachment_id")
return self

Expand All @@ -1203,6 +1216,23 @@ def __repr__(self) -> str:
return f"<UnfurledMediaItem url={self.url} content_type={self.content_type}>"


class UnfurledScanMetadata:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a fan of this naming, but then again, UnfurledMediaItemContentScanMetadata would be... a lot :>
While the API docs group this object under the unfurled media item stuff (which makes sense), in the API spec it is simply ContentScanMetadata. Maybe we could adopt that as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With ContentScanMetadata we lose scope, these flags are meaningful only inside UnfurledMediaItem(s) we at least need Unfurled somewhere in the name IMO, e.g: UnfurledContentScanMetadata or UnfurledItemContentScanMetadata

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these flags are meaningful only inside UnfurledMediaItem(s)

For now, yes, but this could potentially change in the future, we just kinda don't know :/
You're right, though, I suppose ContentScanMetadata is a lil unspecific. Maybe UnfurledMediaScanMetadata/UnfurledMediaScanFlags, then?

"""Represents the content scan metadata for an unfurled media item.

.. versionadded:: |vnext|
"""

__slots__: tuple[str, ...] = ("_flags",)

def __init__(self, data: UnfurledScanMetadataPayload) -> None:
self._flags: int = data.get("flags", 0)

@property
def flags(self) -> UnfurledScanMetadataFlags:
""":class:`UnfurledScanMetadataFlags`: The flags for this content scan metadata."""
return UnfurledScanMetadataFlags._from_value(self._flags)


class Thumbnail(Component):
"""Represents a thumbnail from the Discord Bot UI Kit (v2).

Expand Down
148 changes: 147 additions & 1 deletion disnake/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"EmbedFlags",
"EmbedMediaFlags",
"UnfurledMediaItemFlags",
"UnfurledScanMetadataFlags",
)

BF = TypeVar("BF", bound="BaseFlags")
Expand Down Expand Up @@ -2643,6 +2644,9 @@ class AttachmentFlags(BaseFlags):
def __init__(
self,
*,
contains_explicit_content: bool = ...,
contains_gore_content: bool = ...,
contains_self_harm_content: bool = ...,
is_animated: bool = ...,
is_clip: bool = ...,
is_remix: bool = ...,
Expand Down Expand Up @@ -2679,6 +2683,14 @@ def is_spoiler(self) -> int:
"""
return 1 << 3

@flag_value
def contains_explicit_content(self) -> int:
""":class:`bool`: Returns ``True`` if the attachment was marked as explicit content.

.. versionadded:: |vnext|
"""
return 1 << 4

@flag_value
def is_animated(self) -> int:
""":class:`bool`: Returns ``True`` if the attachment is an animated image.
Expand All @@ -2687,6 +2699,22 @@ def is_animated(self) -> int:
"""
return 1 << 5

@flag_value
def contains_gore_content(self) -> int:
""":class:`bool`: Returns ``True`` if the attachment was marked as gore content.

.. versionadded:: |vnext|
"""
return 1 << 6

@flag_value
def contains_self_harm_content(self) -> int:
""":class:`bool`: Returns ``True`` if the attachment was marked as self-harm content.

.. versionadded:: |vnext|
"""
return 1 << 7


class SKUFlags(BaseFlags):
"""Wraps up Discord SKU flags.
Expand Down Expand Up @@ -3051,13 +3079,44 @@ class EmbedFlags(BaseFlags):
if TYPE_CHECKING:

@_generated
def __init__(self, *, is_content_inventory_entry: bool = ...) -> None: ...
def __init__(
self,
*,
contains_explicit_content: bool = ...,
contains_gore_content: bool = ...,
contains_self_harm_content: bool = ...,
is_content_inventory_entry: bool = ...,
) -> None: ...

@flag_value
def contains_explicit_content(self):
""":class:`bool`: Returns ``True`` if the embed contains explicit content.

.. versionadded:: |vnext|
"""
Comment thread
Snipy7374 marked this conversation as resolved.
Resolved
return 1 << 4

@flag_value
def is_content_inventory_entry(self):
""":class:`bool`: Returns ``True`` if the embed is a reply to an activity card."""
return 1 << 5

@flag_value
def contains_gore_content(self):
""":class:`bool`: Returns ``True`` if the embed contains gore content.

.. versionadded:: |vnext|
"""
Comment thread
Snipy7374 marked this conversation as resolved.
Resolved
return 1 << 6

@flag_value
def contains_self_harm_content(self):
""":class:`bool`: Returns ``True`` if the embed contains self-harm content.

.. versionadded:: |vnext|
"""
Comment thread
Snipy7374 marked this conversation as resolved.
Resolved
return 1 << 7


class EmbedMediaFlags(BaseFlags):
"""Wraps up Discord Embed media flags.
Expand Down Expand Up @@ -3211,3 +3270,90 @@ def __init__(self, *, is_animated: bool = ...) -> None: ...
def is_animated(self):
""":class:`bool`: Returns ``True`` if the unfurled media item is animated."""
return 1 << 0


class UnfurledScanMetadataFlags(BaseFlags):
"""Wraps up Discord unfurled scan metadata flags.

.. collapse:: operations

.. describe:: x == y

Checks if two UnfurledScanMetadataFlags instances are equal.
.. describe:: x != y

Checks if two UnfurledScanMetadataFlags instances are not equal.
.. describe:: x <= y

Checks if an UnfurledScanMetadataFlags instance is a subset of another UnfurledScanMetadataFlags instance.
.. describe:: x >= y

Checks if an UnfurledScanMetadataFlags instance is a superset of another UnfurledScanMetadataFlags instance.
.. describe:: x < y

Checks if an UnfurledScanMetadataFlags instance is a strict subset of another UnfurledScanMetadataFlags instance.
.. describe:: x > y

Checks if an UnfurledScanMetadataFlags instance is a strict superset of another UnfurledScanMetadataFlags instance.
.. describe:: x | y, x |= y

Returns a new UnfurledScanMetadataFlags instance with all enabled flags from both x and y.
(Using ``|=`` will update in place).
.. describe:: x & y, x &= y

Returns a new UnfurledScanMetadataFlags instance with only flags enabled on both x and y.
(Using ``&=`` will update in place).
.. describe:: x ^ y, x ^= y

Returns a new UnfurledScanMetadataFlags instance with only flags enabled on one of x or y, but not both.
(Using ``^=`` will update in place).
.. describe:: ~x

Returns a new UnfurledScanMetadataFlags instance with all flags from x inverted.
.. describe:: hash(x)

Returns the flag's hash.
.. describe:: iter(x)

Returns an iterator of ``(name, value)`` pairs. This allows it
to be, for example, constructed as a dict or a list of pairs.
Note that aliases are not shown.

Additionally supported are a few operations on class attributes.

.. describe:: UnfurledScanMetadataFlags.y | UnfurledScanMetadataFlags.z, UnfurledScanMetadataFlags(y=True) | UnfurledScanMetadataFlags.z

Returns an UnfurledScanMetadataFlags instance with all provided flags enabled.

.. describe:: ~UnfurledScanMetadataFlags.x

Returns an UnfurledScanMetadataFlags instance with all flags except ``x`` inverted from their default value.

.. versionadded:: |vnext|
Comment thread
Snipy7374 marked this conversation as resolved.
Resolved
"""

if TYPE_CHECKING:

@_generated
def __init__(
self,
*,
is_explicit_content: bool = ...,
is_gore_content: bool = ...,
is_self_harm_content: bool = ...,
) -> None: ...

@flag_value
def is_explicit_content(self):
""":class:`bool`: Returns ``True`` if the unfurled scan metadata is marked as explicit content."""
return 1 << 0

@flag_value
def is_gore_content(self):
""":class:`bool`: Returns ``True`` if the unfurled scan metadata is marked as gore content."""
return 1 << 1

@flag_value
def is_self_harm_content(self):
""":class:`bool`: Returns ``True`` if the unfurled scan metadata is marked as self-harm content."""
return 1 << 2
5 changes: 5 additions & 0 deletions disnake/types/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,14 @@ class UnfurledMediaItem(TypedDict, total=False):
placeholder_version: int
flags: int
content_type: str
content_scan_metadata: UnfurledScanMetadata
attachment_id: Snowflake


class UnfurledScanMetadata(TypedDict):
flags: int


# NOTE: these are type definitions for *sending*, while *receiving* likely has fewer optional fields


Expand Down
16 changes: 16 additions & 0 deletions docs/api/components.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ UnfurledMediaItem
:members:
:inherited-members:

UnfurledScanMetadata
~~~~~~~~~~~~~~~~~~~~

.. attributetable:: UnfurledScanMetadata

.. autoclass:: UnfurledScanMetadata()
:members:

Thumbnail
~~~~~~~~~

Expand Down Expand Up @@ -302,3 +310,11 @@ UnfurledMediaItemFlags

.. autoclass:: UnfurledMediaItemFlags()
:members:

UnfurledScanMetadataFlags
~~~~~~~~~~~~~~~~~~~~~~~~~

.. attributetable:: UnfurledScanMetadataFlags

.. autoclass:: UnfurledScanMetadataFlags()
:members:
Loading