Add options to improve handling of webhook messages sent by other bridges
This commit is contained in:
@@ -51,6 +51,8 @@ type BridgeConfig struct {
|
||||
DeletePortalOnChannelDelete bool `yaml:"delete_portal_on_channel_delete"`
|
||||
DeleteGuildOnLeave bool `yaml:"delete_guild_on_leave"`
|
||||
FederateRooms bool `yaml:"federate_rooms"`
|
||||
PrefixWebhookMessages bool `yaml:"prefix_webhook_messages"`
|
||||
EnableWebhookAvatars bool `yaml:"enable_webhook_avatars"`
|
||||
UseDiscordCDNUpload bool `yaml:"use_discord_cdn_upload"`
|
||||
|
||||
CacheMedia string `yaml:"cache_media"`
|
||||
@@ -287,9 +289,14 @@ func (bc BridgeConfig) FormatUsername(userID string) string {
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (bc BridgeConfig) FormatDisplayname(user *discordgo.User) string {
|
||||
type DisplaynameParams struct {
|
||||
*discordgo.User
|
||||
Webhook bool
|
||||
}
|
||||
|
||||
func (bc BridgeConfig) FormatDisplayname(user *discordgo.User, webhook bool) string {
|
||||
var buffer strings.Builder
|
||||
_ = bc.displaynameTemplate.Execute(&buffer, user)
|
||||
_ = bc.displaynameTemplate.Execute(&buffer, &DisplaynameParams{user, webhook})
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ func DoUpgrade(helper *up.Helper) {
|
||||
helper.Copy(up.Bool, "bridge", "delete_portal_on_channel_delete")
|
||||
helper.Copy(up.Bool, "bridge", "delete_guild_on_leave")
|
||||
helper.Copy(up.Bool, "bridge", "federate_rooms")
|
||||
helper.Copy(up.Bool, "bridge", "prefix_webhook_messages")
|
||||
helper.Copy(up.Bool, "bridge", "enable_webhook_avatars")
|
||||
helper.Copy(up.Bool, "bridge", "use_discord_cdn_upload")
|
||||
helper.Copy(up.Bool, "bridge", "media_patterns", "enabled")
|
||||
helper.Copy(up.Str, "bridge", "cache_media")
|
||||
|
||||
@@ -85,6 +85,7 @@ bridge:
|
||||
# .Discriminator - The 4 numbers after the name on Discord
|
||||
# .Bot - Whether the user is a bot
|
||||
# .System - Whether the user is an official system user
|
||||
# .Webhook - Whether the user is a webhook
|
||||
displayname_template: '{{or .GlobalName .Username}}{{if .Bot}} (bot){{end}}'
|
||||
# Displayname template for Discord channels (bridged as rooms, or spaces when type=4).
|
||||
# Available variables:
|
||||
@@ -146,6 +147,11 @@ bridge:
|
||||
# Whether or not created rooms should have federation enabled.
|
||||
# If false, created portal rooms will never be federated.
|
||||
federate_rooms: true
|
||||
# Prefix messages from webhooks with the profile info? This can be used along with a custom displayname_template
|
||||
# to better handle webhooks that change their name all the time (like ones used by bridges).
|
||||
prefix_webhook_messages: false
|
||||
# Bridge webhook avatars?
|
||||
enable_webhook_avatars: true
|
||||
# Should the bridge upload media to the Discord CDN directly before sending the message when using a user token,
|
||||
# like the official client does? The other option is sending the media in the message send request as a form part
|
||||
# (which is always used by bots and webhooks).
|
||||
|
||||
@@ -897,6 +897,9 @@ func (portal *Portal) handleDiscordMessageUpdate(user *User, msg *discordgo.Mess
|
||||
Msg("Dropping non-text edit")
|
||||
return
|
||||
}
|
||||
if msg.WebhookID != "" {
|
||||
addWebhookMeta(converted, msg)
|
||||
}
|
||||
converted.Content.Mentions = portal.convertDiscordMentions(msg, "", false)
|
||||
converted.Content.SetEdit(existing[0].MXID)
|
||||
// Never actually mention new users of edits, only include mentions inside m.new_content
|
||||
|
||||
@@ -308,9 +308,33 @@ func (portal *Portal) convertDiscordMessage(ctx context.Context, intent *appserv
|
||||
parts = append(parts, part)
|
||||
}
|
||||
}
|
||||
if msg.WebhookID != "" {
|
||||
for _, part := range parts {
|
||||
addWebhookMeta(part, msg)
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func addWebhookMeta(part *ConvertedMessage, msg *discordgo.Message) {
|
||||
if msg.WebhookID == "" {
|
||||
return
|
||||
}
|
||||
if part.Extra == nil {
|
||||
part.Extra = make(map[string]any)
|
||||
}
|
||||
part.Extra["fi.mau.discord.webhook_metadata"] = map[string]any{
|
||||
"id": msg.WebhookID,
|
||||
"name": msg.Author.Username,
|
||||
"avatar_id": msg.Author.Avatar,
|
||||
"avatar_url": msg.Author.AvatarURL(""),
|
||||
}
|
||||
part.Extra["com.beeper.per_message_profile"] = map[string]any{
|
||||
"avatar_url": msg.Author.AvatarURL(""),
|
||||
"displayname": msg.Author.Username,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
embedHTMLWrapper = `<blockquote class="discord-embed">%s</blockquote>`
|
||||
embedHTMLWrapperColor = `<blockquote class="discord-embed" background-color="#%06X">%s</blockquote>`
|
||||
@@ -628,5 +652,11 @@ func (portal *Portal) convertDiscordTextMessage(ctx context.Context, intent *app
|
||||
"com.beeper.linkpreviews": previews,
|
||||
}
|
||||
|
||||
if msg.WebhookID != "" && portal.bridge.Config.Bridge.PrefixWebhookMessages {
|
||||
content.EnsureHasHTML()
|
||||
content.Body = fmt.Sprintf("%s: %s", msg.Author.Username, content.Body)
|
||||
content.FormattedBody = fmt.Sprintf("<strong>%s</strong>: %s", html.EscapeString(msg.Author.Username), content.FormattedBody)
|
||||
}
|
||||
|
||||
return &ConvertedMessage{Type: event.EventMessage, Content: &content, Extra: extraContent}
|
||||
}
|
||||
|
||||
10
puppet.go
10
puppet.go
@@ -207,7 +207,7 @@ func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) {
|
||||
}
|
||||
|
||||
func (puppet *Puppet) UpdateName(info *discordgo.User) bool {
|
||||
newName := puppet.bridge.Config.Bridge.FormatDisplayname(info)
|
||||
newName := puppet.bridge.Config.Bridge.FormatDisplayname(info, puppet.IsWebhook)
|
||||
if puppet.Name == newName && puppet.NameSet {
|
||||
return false
|
||||
}
|
||||
@@ -229,6 +229,9 @@ func (puppet *Puppet) UpdateName(info *discordgo.User) bool {
|
||||
}
|
||||
|
||||
func (puppet *Puppet) UpdateAvatar(info *discordgo.User) bool {
|
||||
if puppet.IsWebhook && !puppet.bridge.Config.Bridge.EnableWebhookAvatars {
|
||||
info.Avatar = ""
|
||||
}
|
||||
if puppet.Avatar == info.Avatar && puppet.AvatarSet {
|
||||
return false
|
||||
}
|
||||
@@ -324,7 +327,7 @@ func (puppet *Puppet) UpdateContactInfo(info *discordgo.User) bool {
|
||||
puppet.IsBot = info.Bot
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
if (changed && !puppet.IsWebhook) || !puppet.ContactInfoSet {
|
||||
puppet.ContactInfoSet = false
|
||||
puppet.ResendContactInfo()
|
||||
return true
|
||||
@@ -345,6 +348,9 @@ func (puppet *Puppet) ResendContactInfo() {
|
||||
"com.beeper.bridge.network": puppet.bridge.BeeperNetworkName,
|
||||
"com.beeper.bridge.is_network_bot": puppet.IsBot,
|
||||
}
|
||||
if puppet.IsWebhook {
|
||||
contactInfo["com.beeper.bridge.identifiers"] = []string{}
|
||||
}
|
||||
err := puppet.DefaultIntent().BeeperUpdateProfile(contactInfo)
|
||||
if err != nil {
|
||||
puppet.log.Warn().Err(err).Msg("Failed to store custom contact info in profile")
|
||||
|
||||
Reference in New Issue
Block a user