2727 content as beacon_content , file as beacon_file )
2828
2929class DiscordMessageContent :
30- def __init__ (self , content : str | None = None , components : discord .ui .BaseView | discord .ui .View | None = None ,
30+ def __init__ (self , content : str | None = None , components : discord .ui .DesignerView | discord .ui .View | None = None ,
3131 files : list [discord .File ] | None = None , embeds : list [discord .Embed ] | None = None ):
3232 self ._content : str | None = content
33- self ._components : discord .ui .BaseView | discord .ui .View | None = components
33+ self ._components : discord .ui .DesignerView | discord .ui .View | None = components
3434 self ._files : list [discord .File ] = files or []
3535 self ._embeds : list [discord .Embed ] = embeds or []
3636 self ._components_v2 : bool = (
37- type (components ) is discord .ui .BaseView and components .is_components_v2 ()
37+ type (components ) is discord .ui .DesignerView and components .is_components_v2 ()
3838 ) if components else False
3939
4040 @property
@@ -49,7 +49,7 @@ def raw_content(self) -> str | None:
4949 return self ._content
5050
5151 @property
52- def components (self ) -> discord .ui .BaseView | discord .ui .View | None :
52+ def components (self ) -> discord .ui .DesignerView | discord .ui .View | None :
5353 return self ._components
5454
5555 @property
@@ -125,8 +125,6 @@ def embed_container(block: beacon_content.BeaconContentEmbed) -> discord.ui.Cont
125125 container .add_text (author_content )
126126
127127 # Add title and description block
128- title_thumbnail_row = discord .ui .ActionRow ()
129-
130128 title_desc_content = f"## { block .title } \n { block .description } "
131129
132130 if block .url :
@@ -136,14 +134,17 @@ def embed_container(block: beacon_content.BeaconContentEmbed) -> discord.ui.Cont
136134 title_desc_content = block .description
137135
138136 if title_desc_content :
139- title_thumbnail_row .add_item (discord .ui .TextDisplay (title_desc_content ))
137+ title_thumbnail_section = discord .ui .Section ()
138+ title_thumbnail_section .add_text (title_desc_content )
139+
140+ # Add thumbnail
141+ if block .thumbnail :
142+ title_thumbnail_section .set_accessory (discord .ui .Thumbnail (block .thumbnail ))
140143
141- # Add thumbnail
142- if block .thumbnail :
143- title_thumbnail_row .add_item (discord .ui .Thumbnail (block .thumbnail ))
144+ container .add_item (title_thumbnail_section )
144145
145146 # Add fields
146- current_row = discord .ui .ActionRow ()
147+ current_section = discord .ui .Section ()
147148 for field in block .fields :
148149 field_components = []
149150
@@ -152,15 +153,15 @@ def embed_container(block: beacon_content.BeaconContentEmbed) -> discord.ui.Cont
152153 if field ["value" ]:
153154 field_components .append (field ["value" ])
154155
155- current_row . add_item ( discord . ui . TextDisplay ( "\n " .join (field_components ) ))
156+ current_section . add_text ( "\n " .join (field_components ))
156157
157- if not field ["inline" ] or len (current_row .items ) == 3 :
158- container .add_row ( current_row )
159- current_row = discord .ui .ActionRow ()
158+ if not field ["inline" ] or len (current_section .items ) == 3 :
159+ container .add_item ( current_section )
160+ current_section = discord .ui .Section ()
160161
161162 # Ensure all rows have been added
162- if len (current_row .items ) > 0 :
163- container .add_row ( current_row )
163+ if len (current_section .items ) > 0 :
164+ container .add_item ( current_section )
164165
165166 # Add media
166167 if block .media :
@@ -174,7 +175,8 @@ def embed_container(block: beacon_content.BeaconContentEmbed) -> discord.ui.Cont
174175 if block .timestamp :
175176 footer_components .append (f"<t:{ round (block .timestamp )} :f>" )
176177
177- current_row .add_item (discord .ui .TextDisplay (" • " .join (footer_components )))
178+ if len (footer_components ) > 0 :
179+ container .add_item (discord .ui .TextDisplay (" • " .join (footer_components )))
178180
179181 return container
180182
@@ -271,8 +273,9 @@ def _to_beacon_webhook(self, webhook: discord.Webhook) -> beacon_webhook.BeaconW
271273 channel = channel
272274 )
273275
274- async def _to_discord_content (self , content : beacon_message .BeaconMessageContent , use_components_v2 : bool | None = None
275- ) -> DiscordMessageContent :
276+ async def _to_discord_content (self , content : beacon_message .BeaconMessageContent ,
277+ destination : beacon_messageable .BeaconMessageable , use_components_v2 : bool | None = None
278+ ) -> DiscordMessageContent :
276279 if use_components_v2 is None :
277280 use_components_v2 = self ._use_components_v2
278281
@@ -299,7 +302,13 @@ async def _to_discord_content(self, content: beacon_message.BeaconMessageContent
299302 legacy_embeds .append (DiscordBeaconContentBlockConverter .embed (block_obj ))
300303
301304 # Process reply
302- for reply_message in content .replies :
305+ for reply_message_group in content .replies :
306+ # Find channel-specific reply
307+ reply_message : beacon_message .BeaconMessage | None = reply_message_group .get_message_for (destination )
308+
309+ if not reply_message :
310+ continue
311+
303312 reply_author : str = f"{ reply_message .author .display_name if reply_message .author else '[unknown]' } "
304313 reply_url : str = f"https://discord.com/channels/{ reply_message .server .id } /{ reply_message .channel .id } /{ reply_message .id } "
305314 reply_content : str | None = None
@@ -327,28 +336,32 @@ async def _to_discord_content(self, content: beacon_message.BeaconMessageContent
327336 # Create reply container (will get ID 10X)
328337 reply_container : discord .ui .Container = discord .ui .Container ()
329338
330- # Create list for reply items
339+ # Create reply jump button
331340 # noinspection PyTypeChecker
332- reply_items : list [ discord .ui .Item ] = [
333- discord .ui . Button (
334- style = discord . ButtonStyle . link ,
335- label = f'Replying to @ { reply_author } ' ,
336- emoji = ' \U000021AA \U0000FE0F ' ,
337- url = reply_url
338- )
339- ]
341+ reply_button : discord .ui .Button = discord . ui . Button (
342+ style = discord .ButtonStyle . link ,
343+ label = f'Jump to message' ,
344+ url = reply_url
345+ )
346+ reply_text : discord . ui . TextDisplay = discord . ui . TextDisplay (
347+ f" \U000021AA \U0000FE0F **Replying to @ { reply_author } **"
348+ )
340349
341350 # Create content text display (if possible)
342351 if reply_content :
343352 # We'll cap content to 200 characters
344353 if len (reply_content ) > 200 :
345354 reply_content = reply_content [:197 ] + "..."
346355
347- reply_items .append (discord .ui .TextDisplay (reply_content ))
356+ reply_text = discord .ui .TextDisplay (
357+ f"\U000021AA \U0000FE0F **Replying to @{ reply_author } ** - { reply_content } "
358+ )
348359
349360 # Create reply action row
350- reply_row : discord .ui .ActionRow = discord .ui .ActionRow (* reply_items )
351- reply_container .add_row (reply_row )
361+ reply_section : discord .ui .Section = discord .ui .Section (
362+ reply_text , accessory = reply_button
363+ )
364+ reply_container .add_item (reply_section )
352365 reply_blocks .append (reply_container )
353366
354367 # Add button to legacy reply components
@@ -370,7 +383,7 @@ async def _to_discord_content(self, content: beacon_message.BeaconMessageContent
370383 # Assemble to DiscordMessageContent
371384 if use_components_v2 :
372385 # Assemble components
373- components = discord .ui .BaseView (
386+ components = discord .ui .DesignerView (
374387 store = False
375388 )
376389
@@ -513,7 +526,7 @@ async def fetch_webhook(self, webhook_id: str):
513526
514527 async def send (self , destination : beacon_messageable .BeaconMessageable ,
515528 content : beacon_message .BeaconMessageContent , send_as : beacon_user .BeaconUser | None = None ,
516- webhook_id : str | None = None ):
529+ webhook_id : str | None = None , self_send : bool = False ):
517530 # Get message options
518531 send_as_webhook : bool = webhook_id is not None
519532 send_as_user : bool = send_as is not None
@@ -540,12 +553,42 @@ async def send(self, destination: beacon_messageable.BeaconMessageable,
540553
541554 # Convert message content data
542555 discord_content : DiscordMessageContent = await self ._to_discord_content (
543- content , use_components_v2 = self ._use_components_v2
556+ content , destination , use_components_v2 = self ._use_components_v2
544557 )
545558
546- # Send the message!
559+ # Convert bot user to BeaconUser
560+ self_user = self .get_user (str (self .bot .user .id ))
561+
562+ # Get target
547563 if webhook_id :
548564 target : discord .TextChannel | discord .abc .Messageable = webhook_obj .channel
565+ else :
566+ target : discord .TextChannel | discord .abc .Messageable = self .bot .get_channel (int (destination .id ))
567+
568+ # Convert channel to BeaconChannel
569+ channel : beacon_channel .BeaconChannel = self .get_channel (self .get_server (str (target .guild .id )), str (target .id ))
570+
571+ # Are we self-sending?
572+ if str (webhook_obj .channel_id ) == content .original_channel_id and not self_send :
573+ # Return message object but don't send
574+
575+ return beacon_message .BeaconMessage (
576+ message_id = content .original_id ,
577+ platform = self .platform ,
578+ author = send_as or self_user ,
579+ server = self .get_server (str (target .guild .id )),
580+ channel = channel ,
581+ content = discord_content .raw_content ,
582+ attachments = len (discord_content .files ),
583+ replies = [reply .get_message_for (channel ) for reply in content .replies ] if channel else [],
584+ webhook_id = webhook_id if webhook_obj else None
585+ )
586+
587+ # Send the message!
588+ if webhook_id :
589+ if not target :
590+ return None
591+
549592 message = await webhook_obj .send (
550593 content = discord_content .content ,
551594 view = discord_content .components ,
@@ -556,8 +599,6 @@ async def send(self, destination: beacon_messageable.BeaconMessageable,
556599 wait = True
557600 )
558601 else :
559- target : discord .TextChannel | discord .abc .Messageable = self .bot .get_channel (int (destination .id ))
560-
561602 if not target :
562603 return None
563604
@@ -568,18 +609,15 @@ async def send(self, destination: beacon_messageable.BeaconMessageable,
568609 files = discord_content .files
569610 )
570611
571- # Convert message to BeaconMessage
572- self_user = self .get_user (str (self .bot .user .id ))
573-
574612 return beacon_message .BeaconMessage (
575613 message_id = str (message .id ),
576614 platform = self .platform ,
577615 author = send_as or self_user ,
578616 server = self .get_server (str (target .guild .id )),
579- channel = self . get_channel ( self . get_server ( str ( target . guild . id )), str ( target . id )) ,
617+ channel = channel ,
580618 content = discord_content .raw_content ,
581619 attachments = len (discord_content .files ),
582- replies = content .replies ,
620+ replies = [ reply . get_message_for ( channel ) for reply in content .replies ] if channel else [] ,
583621 webhook_id = webhook_id if webhook_obj else None
584622 )
585623
@@ -589,7 +627,7 @@ async def _edit(self, message: beacon_message.BeaconMessage, content: beacon_mes
589627
590628 # Convert message content data
591629 discord_content : DiscordMessageContent = await self ._to_discord_content (
592- content , use_components_v2 = self ._use_components_v2
630+ content , destination = message . channel , use_components_v2 = self ._use_components_v2
593631 )
594632
595633 # Edit message
0 commit comments