Files
Pete/internal/matrix/post.go
prosolis 8cb5b38599 Adventure: stop signing my own posts
The source tag credits an outlet Pete is relaying (`ars technica`). On
his own reporting it rendered as a trailing `pete` under a message he
already sent - him signing his own name. Drop Source on adventure posts
and omit the tag line entirely when there's nothing to credit; RSS posts
keep theirs.
2026-07-12 22:01:12 -07:00

89 lines
2.5 KiB
Go

package matrix
import (
"fmt"
"html"
"net/url"
"strings"
)
// safeHref returns raw if it is an http(s) URL, else "". Keeps feed-supplied
// links from injecting javascript:/data: schemes into the formatted_body href
// (html.EscapeString blocks attribute breakout but not the scheme itself).
func safeHref(raw string) string {
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return ""
}
return raw
}
// PostableStory contains the data needed to format and send a story.
type PostableStory struct {
ImageURL string
Headline string
ArticleURL string
Lede string
Source string
Channel string
Platforms []string
}
// formatPost returns plain text and HTML bodies for a Matrix message.
func formatPost(s *PostableStory) (plain, htmlBody string) {
// Plain text body
var plainParts []string
plainParts = append(plainParts, fmt.Sprintf("**%s** \u2192 %s", s.Headline, s.ArticleURL))
if s.Lede != "" {
plainParts = append(plainParts, s.Lede)
}
if tag := formatSourceTag(s.Source, s.Platforms, false); tag != "" {
plainParts = append(plainParts, tag)
}
plain = strings.Join(plainParts, "\n")
// HTML body
var htmlParts []string
if href := safeHref(s.ArticleURL); href != "" {
htmlParts = append(htmlParts, fmt.Sprintf(
`<strong><a href="%s">%s</a></strong>`,
html.EscapeString(href),
html.EscapeString(s.Headline),
))
} else {
// Non-http(s) link: render the headline without an anchor.
htmlParts = append(htmlParts, fmt.Sprintf(`<strong>%s</strong>`, html.EscapeString(s.Headline)))
}
if s.Lede != "" {
htmlParts = append(htmlParts, html.EscapeString(s.Lede))
}
if tag := formatSourceTag(s.Source, s.Platforms, true); tag != "" {
htmlParts = append(htmlParts, tag)
}
htmlBody = strings.Join(htmlParts, "<br/>")
return plain, htmlBody
}
// formatSourceTag builds the source + platform tags line. An empty source is
// omitted rather than tagged: Pete's own reporting has no outlet to credit, and
// an empty tag would read as him signing his own name.
func formatSourceTag(source string, platforms []string, isHTML bool) string {
var parts []string
if source != "" {
parts = append(parts, strings.ToLower(source))
}
parts = append(parts, platforms...)
if len(parts) == 0 {
return ""
}
for i, p := range parts {
if isHTML {
parts[i] = fmt.Sprintf("<code>%s</code>", html.EscapeString(p))
} else {
parts[i] = fmt.Sprintf("`%s`", p)
}
}
return strings.Join(parts, " \u00b7 ")
}