Skip to content

Commit 947890d

Browse files
authored
remaining classes
1 parent e961db5 commit 947890d

File tree

1 file changed

+219
-5
lines changed

1 file changed

+219
-5
lines changed

discord/components.py

Lines changed: 219 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
SeparatorSpacingSize,
3636
try_enum,
3737
)
38+
from .colour import Colour
3839
from .partial_emoji import PartialEmoji, _EmojiTag
3940
from .utils import MISSING, get_slots
4041

@@ -586,6 +587,219 @@ def to_dict(self) -> TextDisplayComponentPayload:
586587
return {"type": int(self.type), "id": self.id, "content": self.content}
587588

588589

590+
class UnfurledMediaItem:
591+
592+
def __init__(self, data: UnfurledMediaItemPayload):
593+
self.url = data.get("url")
594+
# need to test this more
595+
596+
def to_dict(self):
597+
return {"url": self.url}
598+
599+
600+
class Thumbnail(Component):
601+
"""Represents a Thumbnail from Components V2.
602+
603+
This is a component that displays media such as images and videos.
604+
605+
This inherits from :class:`Component`.
606+
607+
.. versionadded:: 2.7
608+
609+
Attributes
610+
----------
611+
media: :class:`UnfurledMediaItem`
612+
The component's media URL.
613+
description: Optional[:class:`str`]
614+
The thumbnail's description, up to 1024 characters.
615+
spoiler: Optional[:class:`bool`]
616+
Whether the thumbnail is a spoiler.
617+
"""
618+
619+
__slots__: tuple[str, ...] = ("media", "description", "spoiler", )
620+
621+
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
622+
623+
def __init__(self, data: ThumbnailComponentPayload):
624+
self.type: ComponentType = try_enum(ComponentType, data["type"])
625+
self.id: str = data.get("id")
626+
self.media: UnfurledMediaItem = (umi := data.get("media")) and UnfurledMediaItem(umi)
627+
self.description: str | None = data.get("description")
628+
self.spoiler: bool | None = data.get("spoiler")
629+
630+
def to_dict(self) -> ThumbnailComponentPayload:
631+
payload = {
632+
"type": int(self.type),
633+
"id": self.id,
634+
"media": self.media.to_dict()
635+
}
636+
if self.description:
637+
payload["description"] = self.description
638+
if self.spoiler is not None:
639+
payload["spoiler"] = self.spoiler
640+
return payload
641+
642+
643+
class MediaGalleryItem:
644+
645+
def __init__(self, data: MediaGalleryItemPayload):
646+
self.media: UnfurledMediaItem = (umi := data.get("media")) and UnfurledMediaItem(umi)
647+
self.description: str | None = data.get("description")
648+
self.spoiler: bool | None = data.get("spoiler")
649+
650+
def to_dict(self):
651+
payload = {
652+
"media": self.media.to_dict()
653+
}
654+
if self.description:
655+
payload["description"] = self.description
656+
if self.spoiler is not None:
657+
payload["spoiler"] = self.spoiler
658+
return payload
659+
660+
661+
class MediaGallery(Component):
662+
"""Represents a Media Gallery from Components V2.
663+
664+
This is a component that displays up to 10 different :class:`MediaGalleryItem`s.
665+
666+
This inherits from :class:`Component`.
667+
668+
.. versionadded:: 2.7
669+
670+
Attributes
671+
----------
672+
items: List[:class:`MediaGalleryItem`]
673+
The media this gallery contains.
674+
"""
675+
676+
__slots__: tuple[str, ...] = ("items", )
677+
678+
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
679+
680+
def __init__(self, data: MediaGalleryComponentPayload):
681+
self.type: ComponentType = try_enum(ComponentType, data["type"])
682+
self.id: str = data.get("id")
683+
self.items: list[MediaGalleryItem] = [MediaGalleryItem(d) for d in data.get("items", [])]
684+
685+
def to_dict(self) -> MediaGalleryComponentPayload:
686+
return {
687+
"type": int(self.type),
688+
"id": self.id,
689+
"items": [i.to_dict() for i in self.items]
690+
}
691+
692+
693+
class FileComponent(Component):
694+
"""Represents a File from Components V2.
695+
696+
This is a component that displays some file (elaborate?).
697+
698+
This inherits from :class:`Component`.
699+
700+
.. versionadded:: 2.7
701+
702+
Attributes
703+
----------
704+
file: :class:`UnfurledMediaItem`
705+
The file's media URL.
706+
spoiler: Optional[:class:`bool`]
707+
Whether the file is a spoiler.
708+
"""
709+
710+
__slots__: tuple[str, ...] = ("file", "spoiler", )
711+
712+
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
713+
714+
def __init__(self, data: FileComponentPayload):
715+
self.type: ComponentType = try_enum(ComponentType, data["type"])
716+
self.id: str = data.get("id")
717+
self.file: UnfurledMediaItem = (umi := data.get("media")) and UnfurledMediaItem(umi)
718+
self.spoiler: bool | None = data.get("spoiler")
719+
720+
def to_dict(self) -> FileComponentPayload:
721+
payload = {
722+
"type": int(self.type),
723+
"id": self.id,
724+
"file": self.file.to_dict()
725+
}
726+
if self.spoiler is not None:
727+
payload["spoiler"] = self.spoiler
728+
return payload
729+
730+
731+
class Separator(Component):
732+
"""Represents a Separator from Components V2.
733+
734+
This is a component that separates components.
735+
736+
This inherits from :class:`Component`.
737+
738+
.. versionadded:: 2.7
739+
740+
Attributes
741+
----------
742+
divider: :class:`bool`
743+
Whether the separator is a divider (provide example?)
744+
spacing: Optional[:class:`SeparatorSpacingSize`]
745+
The separator's spacing size.
746+
"""
747+
748+
__slots__: tuple[str, ...] = ("divider", "spacing",)
749+
750+
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
751+
752+
def __init__(self, data: SeparatorComponentPayload):
753+
self.type: ComponentType = try_enum(ComponentType, data["type"])
754+
self.divider: bool = data.get("divider")
755+
self.spacing: SeparatorSpacingSize = try_enum(SeparatorSpacingSize, data.get("spacing", 1))
756+
757+
def to_dict(self) -> SeparatorComponentPayload:
758+
return {"type": int(self.type), "id": self.id, "divider": self.divider, "spacing": int(self.spacing)}
759+
760+
761+
class Container(Component):
762+
"""Represents a Container from Components V2.
763+
764+
This is a component that contains up to 10 different :class:`Component`s.
765+
It may only contain :class:`ActionRow`, :class:`TextDisplay`, :class:`Section`, :class:`MediaGallery`, :class:`Separator`, and :class:`FileComponent`.
766+
767+
This inherits from :class:`Component`.
768+
769+
.. versionadded:: 2.7
770+
771+
Attributes
772+
----------
773+
items: List[:class:`MediaGalleryItem`]
774+
The media this gallery contains.
775+
"""
776+
777+
__slots__: tuple[str, ...] = ("accent_color", "spoiler", "components", )
778+
779+
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
780+
781+
def __init__(self, data: ContainerComponentPayload):
782+
self.type: ComponentType = try_enum(ComponentType, data["type"])
783+
self.id: str = data.get("id")
784+
self.accent_color: Colour | None = (c := data.get("accent_color")) and Colour(c) # at this point, not adding alternative spelling
785+
self.spoiler: bool | None = data.get("spoiler")
786+
self.components: list[Component] = [
787+
_component_factory(d) for d in data.get("components", [])
788+
]
789+
790+
def to_dict(self) -> ContainerComponentPayload:
791+
payload = {
792+
"type": int(self.type),
793+
"id": self.id,
794+
"components": [c.to_dict() for c in self.components],
795+
}
796+
if self.accent_color:
797+
payload["accent_color"] = self.accent_color.value
798+
if self.spoiler is not None:
799+
payload["spoiler"] = self.spoiler
800+
return payload
801+
802+
589803
COMPONENT_MAPPINGS = {
590804
1: ActionRow,
591805
2: Button,
@@ -597,11 +811,11 @@ def to_dict(self) -> TextDisplayComponentPayload:
597811
8: SelectMenu,
598812
9: Section,
599813
10: TextDisplay,
600-
11: None,
601-
12: None,
602-
13: None,
603-
14: None,
604-
17: None,
814+
11: Thumbnail,
815+
12: MediaGallery,
816+
13: FileComponent,
817+
14: Separator,
818+
17: Container,
605819
}
606820

607821

0 commit comments

Comments
 (0)