Add support for text embeds
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/appservice"
|
"maunium.net/go/mautrix/appservice"
|
||||||
@@ -75,6 +76,9 @@ func (br *DiscordBridge) uploadMatrixAttachment(intent *appservice.IntentAPI, da
|
|||||||
dbFile.URL = url
|
dbFile.URL = url
|
||||||
dbFile.ID = attachmentID
|
dbFile.ID = attachmentID
|
||||||
dbFile.Size = len(data)
|
dbFile.Size = len(data)
|
||||||
|
if mime == "" {
|
||||||
|
mime = mimetype.Detect(data).String()
|
||||||
|
}
|
||||||
if strings.HasPrefix(mime, "image/") {
|
if strings.HasPrefix(mime, "image/") {
|
||||||
cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
|
cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
|
||||||
dbFile.Width = cfg.Width
|
dbFile.Width = cfg.Width
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type BridgeConfig struct {
|
|||||||
MessageErrorNotices bool `yaml:"message_error_notices"`
|
MessageErrorNotices bool `yaml:"message_error_notices"`
|
||||||
RestrictedRooms bool `yaml:"restricted_rooms"`
|
RestrictedRooms bool `yaml:"restricted_rooms"`
|
||||||
AutojoinThreadOnOpen bool `yaml:"autojoin_thread_on_open"`
|
AutojoinThreadOnOpen bool `yaml:"autojoin_thread_on_open"`
|
||||||
|
EmbedFieldsAsTables bool `yaml:"embed_fields_as_tables"`
|
||||||
MuteChannelsOnCreate bool `yaml:"mute_channels_on_create"`
|
MuteChannelsOnCreate bool `yaml:"mute_channels_on_create"`
|
||||||
SyncDirectChatList bool `yaml:"sync_direct_chat_list"`
|
SyncDirectChatList bool `yaml:"sync_direct_chat_list"`
|
||||||
ResendBridgeInfo bool `yaml:"resend_bridge_info"`
|
ResendBridgeInfo bool `yaml:"resend_bridge_info"`
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ func DoUpgrade(helper *up.Helper) {
|
|||||||
helper.Copy(up.Bool, "bridge", "message_error_notices")
|
helper.Copy(up.Bool, "bridge", "message_error_notices")
|
||||||
helper.Copy(up.Bool, "bridge", "restricted_rooms")
|
helper.Copy(up.Bool, "bridge", "restricted_rooms")
|
||||||
helper.Copy(up.Bool, "bridge", "autojoin_thread_on_open")
|
helper.Copy(up.Bool, "bridge", "autojoin_thread_on_open")
|
||||||
|
helper.Copy(up.Bool, "bridge", "embed_fields_as_tables")
|
||||||
helper.Copy(up.Bool, "bridge", "mute_channels_on_create")
|
helper.Copy(up.Bool, "bridge", "mute_channels_on_create")
|
||||||
helper.Copy(up.Bool, "bridge", "sync_direct_chat_list")
|
helper.Copy(up.Bool, "bridge", "sync_direct_chat_list")
|
||||||
helper.Copy(up.Bool, "bridge", "resend_bridge_info")
|
helper.Copy(up.Bool, "bridge", "resend_bridge_info")
|
||||||
|
|||||||
@@ -115,6 +115,9 @@ bridge:
|
|||||||
# Should the bridge automatically join the user to threads on Discord when the thread is opened on Matrix?
|
# Should the bridge automatically join the user to threads on Discord when the thread is opened on Matrix?
|
||||||
# This only works with clients that support thread read receipts (MSC3771 added in Matrix v1.4).
|
# This only works with clients that support thread read receipts (MSC3771 added in Matrix v1.4).
|
||||||
autojoin_thread_on_open: true
|
autojoin_thread_on_open: true
|
||||||
|
# Should inline fields in Discord embeds be bridged as HTML tables to Matrix?
|
||||||
|
# Tables aren't supported in all clients, but are the only way to emulate the Discord inline field UI.
|
||||||
|
embed_fields_as_tables: true
|
||||||
# Should guild channels be muted when the portal is created? This only meant for single-user instances,
|
# Should guild channels be muted when the portal is created? This only meant for single-user instances,
|
||||||
# it won't mute it for all users if there are multiple Matrix users in the same Discord guild.
|
# it won't mute it for all users if there are multiple Matrix users in the same Discord guild.
|
||||||
mute_channels_on_create: false
|
mute_channels_on_create: false
|
||||||
|
|||||||
12
formatter.go
12
formatter.go
@@ -34,6 +34,10 @@ var discordExtensions = goldmark.WithExtensions(mdext.SimpleSpoiler, mdext.Disco
|
|||||||
var escapeFixer = regexp.MustCompile(`\\(__[^_]|\*\*[^*])`)
|
var escapeFixer = regexp.MustCompile(`\\(__[^_]|\*\*[^*])`)
|
||||||
|
|
||||||
func (portal *Portal) renderDiscordMarkdown(text string) event.MessageEventContent {
|
func (portal *Portal) renderDiscordMarkdown(text string) event.MessageEventContent {
|
||||||
|
return format.HTMLToContent(portal.renderDiscordMarkdownOnlyHTML(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string) string {
|
||||||
text = escapeFixer.ReplaceAllStringFunc(text, func(s string) string {
|
text = escapeFixer.ReplaceAllStringFunc(text, func(s string) string {
|
||||||
return s[:2] + `\` + s[2:]
|
return s[:2] + `\` + s[2:]
|
||||||
})
|
})
|
||||||
@@ -45,7 +49,13 @@ func (portal *Portal) renderDiscordMarkdown(text string) event.MessageEventConte
|
|||||||
format.Extensions, format.HTMLOptions, discordExtensions,
|
format.Extensions, format.HTMLOptions, discordExtensions,
|
||||||
goldmark.WithExtensions(&DiscordTag{portal}),
|
goldmark.WithExtensions(&DiscordTag{portal}),
|
||||||
)
|
)
|
||||||
return format.RenderMarkdownCustom(text, mdRenderer)
|
|
||||||
|
var buf strings.Builder
|
||||||
|
err := mdRenderer.Convert([]byte(text), &buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("markdown parser errored: %w", err))
|
||||||
|
}
|
||||||
|
return format.UnwrapSingleParagraph(buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatterContextUserKey = "fi.mau.discord.user"
|
const formatterContextUserKey = "fi.mau.discord.user"
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -4,6 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bwmarrin/discordgo v0.26.1
|
github.com/bwmarrin/discordgo v0.26.1
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/lib/pq v1.10.7
|
github.com/lib/pq v1.10.7
|
||||||
|
|||||||
7
go.sum
7
go.sum
@@ -5,6 +5,8 @@ github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
@@ -49,15 +51,20 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
|||||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
141
portal.go
141
portal.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"maunium.net/go/mautrix/bridge/status"
|
"maunium.net/go/mautrix/bridge/status"
|
||||||
"maunium.net/go/mautrix/crypto/attachment"
|
"maunium.net/go/mautrix/crypto/attachment"
|
||||||
|
"maunium.net/go/mautrix/format"
|
||||||
"maunium.net/go/mautrix/util/variationselector"
|
"maunium.net/go/mautrix/util/variationselector"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
@@ -654,6 +656,139 @@ func (portal *Portal) handleDiscordAttachment(intent *appservice.IntentAPI, att
|
|||||||
return portal.handleDiscordFile("attachment", intent, att.ID, att.URL, content, ts, threadRelation)
|
return portal.handleDiscordFile("attachment", intent, att.ID, att.URL, content, ts, threadRelation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
embedHTMLWrapper = `<blockquote class="discord-embed">%s</blockquote>`
|
||||||
|
embedHTMLWrapperColor = `<blockquote class="discord-embed" background-color="#%06X">%s</blockquote>`
|
||||||
|
embedHTMLAuthorWithImage = `<p class="discord-embed-author"><img data-mx-emoticon width="24" height="24" src="%s" title="Author icon" alt="Author icon"> <span>%s</span></p>`
|
||||||
|
embedHTMLAuthorPlain = `<p class="discord-embed-author"><span>%s</span></p>`
|
||||||
|
embedHTMLAuthorLink = `<a href="%s">%s</a>`
|
||||||
|
embedHTMLTitleWithLink = `<p class="discord-embed-title"><a href="%s"><strong>%s</strong></a></p>`
|
||||||
|
embedHTMLTitlePlain = `<p class="discord-embed-title"><strong>%s</strong></p>`
|
||||||
|
embedHTMLDescription = `<p class="discord-embed-description">%s</p>`
|
||||||
|
embedHTMLFieldName = `<th>%s</th>`
|
||||||
|
embedHTMLFieldValue = `<td>%s</td>`
|
||||||
|
embedHTMLFields = `<table class="discord-embed-fields"><tr>%s</tr><tr>%s</tr></table>`
|
||||||
|
embedHTMLLinearField = `<p class="discord-embed-field" x-inline="%s"><strong>%s</strong><br><span>%s</span></p>`
|
||||||
|
embedHTMLFooterWithImage = `<p class="discord-embed-footer"><sub><img data-mx-emoticon width="20" height="20" src="%s" title="Footer icon" alt="Footer icon"> <span>%s</span>%s</sub></p>`
|
||||||
|
embedHTMLFooterPlain = `<p class="discord-embed-footer"><sub><span>%s</span>%s</sub></p>`
|
||||||
|
embedHTMLFooterOnlyDate = `<p class="discord-embed-footer"><sub>%s</sub></p>`
|
||||||
|
embedHTMLDate = `<time datetime="%s">%s</time>`
|
||||||
|
embedFooterDateSeparator = ` • `
|
||||||
|
)
|
||||||
|
|
||||||
|
func (portal *Portal) handleDiscordEmbed(intent *appservice.IntentAPI, embed *discordgo.MessageEmbed, msgID string, index int, ts time.Time, threadRelation *event.RelatesTo) *database.MessagePart {
|
||||||
|
var htmlParts []string
|
||||||
|
if embed.Author != nil {
|
||||||
|
var authorHTML string
|
||||||
|
authorNameHTML := html.EscapeString(embed.Author.Name)
|
||||||
|
if embed.Author.URL != "" {
|
||||||
|
authorNameHTML = fmt.Sprintf(embedHTMLAuthorLink, embed.Author.URL, authorNameHTML)
|
||||||
|
}
|
||||||
|
authorHTML = fmt.Sprintf(embedHTMLAuthorPlain, authorNameHTML)
|
||||||
|
if embed.Author.ProxyIconURL != "" {
|
||||||
|
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Author.ProxyIconURL, false, "", "")
|
||||||
|
// TODO log error
|
||||||
|
if err == nil {
|
||||||
|
authorHTML = fmt.Sprintf(embedHTMLAuthorWithImage, dbFile.MXC, authorNameHTML)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
htmlParts = append(htmlParts, authorHTML)
|
||||||
|
}
|
||||||
|
if embed.Title != "" {
|
||||||
|
var titleHTML string
|
||||||
|
baseTitleHTML := portal.renderDiscordMarkdownOnlyHTML(embed.Title)
|
||||||
|
if embed.URL != "" {
|
||||||
|
titleHTML = fmt.Sprintf(embedHTMLTitleWithLink, html.EscapeString(embed.URL), baseTitleHTML)
|
||||||
|
} else {
|
||||||
|
titleHTML = fmt.Sprintf(embedHTMLTitlePlain, baseTitleHTML)
|
||||||
|
}
|
||||||
|
htmlParts = append(htmlParts, titleHTML)
|
||||||
|
}
|
||||||
|
if embed.Description != "" {
|
||||||
|
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLDescription, portal.renderDiscordMarkdownOnlyHTML(embed.Description)))
|
||||||
|
}
|
||||||
|
for i := 0; i < len(embed.Fields); i++ {
|
||||||
|
item := embed.Fields[i]
|
||||||
|
if portal.bridge.Config.Bridge.EmbedFieldsAsTables {
|
||||||
|
splitItems := []*discordgo.MessageEmbedField{item}
|
||||||
|
if item.Inline && len(embed.Fields) > i+1 && embed.Fields[i+1].Inline {
|
||||||
|
splitItems = append(splitItems, embed.Fields[i+1])
|
||||||
|
i++
|
||||||
|
if len(embed.Fields) > i+1 && embed.Fields[i+1].Inline {
|
||||||
|
splitItems = append(splitItems, embed.Fields[i+1])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headerParts := make([]string, len(splitItems))
|
||||||
|
contentParts := make([]string, len(splitItems))
|
||||||
|
for j, splitItem := range splitItems {
|
||||||
|
headerParts[j] = fmt.Sprintf(embedHTMLFieldName, portal.renderDiscordMarkdownOnlyHTML(splitItem.Name))
|
||||||
|
contentParts[j] = fmt.Sprintf(embedHTMLFieldValue, portal.renderDiscordMarkdownOnlyHTML(splitItem.Value))
|
||||||
|
}
|
||||||
|
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLFields, strings.Join(headerParts, ""), strings.Join(contentParts, "")))
|
||||||
|
} else {
|
||||||
|
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLLinearField,
|
||||||
|
strconv.FormatBool(item.Inline),
|
||||||
|
portal.renderDiscordMarkdownOnlyHTML(item.Name),
|
||||||
|
portal.renderDiscordMarkdownOnlyHTML(item.Value),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var embedDateHTML string
|
||||||
|
if embed.Timestamp != "" {
|
||||||
|
formattedTime := embed.Timestamp
|
||||||
|
parsedTS, err := time.Parse(time.RFC3339, embed.Timestamp)
|
||||||
|
// TODO log error?
|
||||||
|
if err == nil {
|
||||||
|
formattedTime = parsedTS.Format(discordTimestampStyle('F').Format())
|
||||||
|
}
|
||||||
|
embedDateHTML = fmt.Sprintf(embedHTMLDate, embed.Timestamp, formattedTime)
|
||||||
|
}
|
||||||
|
if embed.Footer != nil {
|
||||||
|
var footerHTML string
|
||||||
|
var datePart string
|
||||||
|
if embedDateHTML != "" {
|
||||||
|
datePart = embedFooterDateSeparator + embedDateHTML
|
||||||
|
}
|
||||||
|
footerHTML = fmt.Sprintf(embedHTMLFooterPlain, html.EscapeString(embed.Footer.Text), datePart)
|
||||||
|
if embed.Footer.ProxyIconURL != "" {
|
||||||
|
dbFile, err := portal.bridge.copyAttachmentToMatrix(intent, embed.Footer.ProxyIconURL, false, "", "")
|
||||||
|
// TODO log error
|
||||||
|
if err == nil {
|
||||||
|
footerHTML = fmt.Sprintf(embedHTMLFooterWithImage, dbFile.MXC, html.EscapeString(embed.Footer.Text), datePart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
htmlParts = append(htmlParts, footerHTML)
|
||||||
|
} else if embed.Timestamp != "" {
|
||||||
|
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLFooterOnlyDate, embedDateHTML))
|
||||||
|
}
|
||||||
|
|
||||||
|
compiledHTML := strings.Join(htmlParts, "")
|
||||||
|
if embed.Color != 0 {
|
||||||
|
compiledHTML = fmt.Sprintf(embedHTMLWrapperColor, embed.Color, compiledHTML)
|
||||||
|
} else {
|
||||||
|
compiledHTML = fmt.Sprintf(embedHTMLWrapper, compiledHTML)
|
||||||
|
}
|
||||||
|
content := format.HTMLToContent(compiledHTML)
|
||||||
|
content.RelatesTo = threadRelation.Copy()
|
||||||
|
|
||||||
|
resp, err := portal.sendMatrixMessage(intent, event.EventMessage, &content, nil, ts.UnixMilli())
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Warnfln("Failed to send embed #%d of message %s to Matrix: %v", index+1, msgID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the fallback reply event for the next attachment
|
||||||
|
if threadRelation != nil {
|
||||||
|
threadRelation.InReplyTo.EventID = resp.EventID
|
||||||
|
}
|
||||||
|
|
||||||
|
return &database.MessagePart{
|
||||||
|
AttachmentID: fmt.Sprintf("%s-e%d", msgID, index+1),
|
||||||
|
MXID: resp.EventID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (portal *Portal) handleDiscordMessageCreate(user *User, msg *discordgo.Message, thread *Thread) {
|
func (portal *Portal) handleDiscordMessageCreate(user *User, msg *discordgo.Message, thread *Thread) {
|
||||||
if portal.MXID == "" {
|
if portal.MXID == "" {
|
||||||
portal.log.Warnln("handle message called without a valid portal")
|
portal.log.Warnln("handle message called without a valid portal")
|
||||||
@@ -732,6 +867,12 @@ func (portal *Portal) handleDiscordMessageCreate(user *User, msg *discordgo.Mess
|
|||||||
parts = append(parts, *part)
|
parts = append(parts, *part)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i, embed := range msg.Embeds {
|
||||||
|
part := portal.handleDiscordEmbed(intent, embed, msg.ID, i, ts, threadRelation)
|
||||||
|
if part != nil {
|
||||||
|
parts = append(parts, *part)
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(parts) == 0 {
|
if len(parts) == 0 {
|
||||||
portal.log.Warnfln("Unhandled message %s (type %d)", msg.ID, msg.Type)
|
portal.log.Warnfln("Unhandled message %s (type %d)", msg.ID, msg.Type)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user