Allow inline links in Discord embed descriptions

This commit is contained in:
Tulir Asokan
2023-01-30 18:35:16 +02:00
parent a9e03f092c
commit 5b715cd9e2
2 changed files with 28 additions and 17 deletions

View File

@@ -55,24 +55,35 @@ func (b *indentableParagraphParser) CanAcceptIndentedLine() bool {
return true return true
} }
var removeFeaturesExceptLinks = []any{
parser.NewListParser(), parser.NewListItemParser(), parser.NewHTMLBlockParser(), parser.NewRawHTMLParser(),
parser.NewSetextHeadingParser(), parser.NewATXHeadingParser(), parser.NewThematicBreakParser(),
parser.NewCodeBlockParser(),
}
var removeFeaturesAndLinks = append(removeFeaturesExceptLinks, parser.NewLinkParser())
var fixIndentedParagraphs = goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500)))
var discordExtensions = goldmark.WithExtensions(extension.Strikethrough, mdext.SimpleSpoiler, mdext.DiscordUnderline, ExtDiscordEveryone, ExtDiscordTag)
var discordRenderer = goldmark.New( var discordRenderer = goldmark.New(
goldmark.WithParser(mdext.ParserWithoutFeatures( goldmark.WithParser(mdext.ParserWithoutFeatures(removeFeaturesAndLinks...)),
parser.NewListParser(), parser.NewListItemParser(), parser.NewHTMLBlockParser(), parser.NewRawHTMLParser(), fixIndentedParagraphs, format.HTMLOptions, discordExtensions,
parser.NewSetextHeadingParser(), parser.NewATXHeadingParser(), parser.NewThematicBreakParser(), )
parser.NewLinkParser(), parser.NewCodeBlockParser(), var discordRendererWithInlineLinks = goldmark.New(
)), goldmark.WithParser(mdext.ParserWithoutFeatures(removeFeaturesExceptLinks...)),
goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500))), fixIndentedParagraphs, format.HTMLOptions, discordExtensions,
format.HTMLOptions,
goldmark.WithExtensions(extension.Strikethrough, mdext.SimpleSpoiler, mdext.DiscordUnderline, ExtDiscordEveryone, ExtDiscordTag),
) )
func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string) string { func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string, allowInlineLinks bool) string {
text = escapeFixer.ReplaceAllStringFunc(text, escapeReplacement) text = escapeFixer.ReplaceAllStringFunc(text, escapeReplacement)
var buf strings.Builder var buf strings.Builder
ctx := parser.NewContext() ctx := parser.NewContext()
ctx.Set(parserContextPortal, portal) ctx.Set(parserContextPortal, portal)
err := discordRenderer.Convert([]byte(text), &buf, parser.WithContext(ctx)) renderer := discordRenderer
if allowInlineLinks {
renderer = discordRendererWithInlineLinks
}
err := renderer.Convert([]byte(text), &buf, parser.WithContext(ctx))
if err != nil { if err != nil {
panic(fmt.Errorf("markdown parser errored: %w", err)) panic(fmt.Errorf("markdown parser errored: %w", err))
} }

View File

@@ -779,7 +779,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
} }
if embed.Title != "" { if embed.Title != "" {
var titleHTML string var titleHTML string
baseTitleHTML := portal.renderDiscordMarkdownOnlyHTML(embed.Title) baseTitleHTML := portal.renderDiscordMarkdownOnlyHTML(embed.Title, false)
if embed.URL != "" { if embed.URL != "" {
titleHTML = fmt.Sprintf(embedHTMLTitleWithLink, html.EscapeString(embed.URL), baseTitleHTML) titleHTML = fmt.Sprintf(embedHTMLTitleWithLink, html.EscapeString(embed.URL), baseTitleHTML)
} else { } else {
@@ -788,7 +788,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
htmlParts = append(htmlParts, titleHTML) htmlParts = append(htmlParts, titleHTML)
} }
if embed.Description != "" { if embed.Description != "" {
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLDescription, portal.renderDiscordMarkdownOnlyHTML(embed.Description))) htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLDescription, portal.renderDiscordMarkdownOnlyHTML(embed.Description, true)))
} }
for i := 0; i < len(embed.Fields); i++ { for i := 0; i < len(embed.Fields); i++ {
item := embed.Fields[i] item := embed.Fields[i]
@@ -805,15 +805,15 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
headerParts := make([]string, len(splitItems)) headerParts := make([]string, len(splitItems))
contentParts := make([]string, len(splitItems)) contentParts := make([]string, len(splitItems))
for j, splitItem := range splitItems { for j, splitItem := range splitItems {
headerParts[j] = fmt.Sprintf(embedHTMLFieldName, portal.renderDiscordMarkdownOnlyHTML(splitItem.Name)) headerParts[j] = fmt.Sprintf(embedHTMLFieldName, portal.renderDiscordMarkdownOnlyHTML(splitItem.Name, false))
contentParts[j] = fmt.Sprintf(embedHTMLFieldValue, portal.renderDiscordMarkdownOnlyHTML(splitItem.Value)) contentParts[j] = fmt.Sprintf(embedHTMLFieldValue, portal.renderDiscordMarkdownOnlyHTML(splitItem.Value, true))
} }
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLFields, strings.Join(headerParts, ""), strings.Join(contentParts, ""))) htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLFields, strings.Join(headerParts, ""), strings.Join(contentParts, "")))
} else { } else {
htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLLinearField, htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLLinearField,
strconv.FormatBool(item.Inline), strconv.FormatBool(item.Inline),
portal.renderDiscordMarkdownOnlyHTML(item.Name), portal.renderDiscordMarkdownOnlyHTML(item.Name, false),
portal.renderDiscordMarkdownOnlyHTML(item.Value), portal.renderDiscordMarkdownOnlyHTML(item.Value, true),
)) ))
} }
} }
@@ -927,7 +927,7 @@ func (portal *Portal) convertDiscordTextMessage(intent *appservice.IntentAPI, ms
htmlParts = append(htmlParts, fmt.Sprintf(msgInteractionTemplateHTML, puppet.MXID, puppet.Name, msg.Interaction.Name)) htmlParts = append(htmlParts, fmt.Sprintf(msgInteractionTemplateHTML, puppet.MXID, puppet.Name, msg.Interaction.Name))
} }
if msg.Content != "" && !isPlainGifMessage(msg) { if msg.Content != "" && !isPlainGifMessage(msg) {
htmlParts = append(htmlParts, portal.renderDiscordMarkdownOnlyHTML(msg.Content)) htmlParts = append(htmlParts, portal.renderDiscordMarkdownOnlyHTML(msg.Content, false))
} }
previews := make([]*BeeperLinkPreview, 0) previews := make([]*BeeperLinkPreview, 0)
for i, embed := range msg.Embeds { for i, embed := range msg.Embeds {