ref: 906489cfcc61b985c2300936ea22ec5fedc2f013
dir: /renderer.go/
package main
import (
"bytes"
"fmt"
"strings"
"github.com/k3a/html2text"
mastodon "codeberg.org/penny64/hellclient-go-mastodon"
"golang.org/x/net/html"
)
type StatusFormatter struct {
hc *Hellclient
status *mastodon.Status
postContext *postref
}
// Returns the rendered content of a status
func (st *StatusFormatter) statusContent() string {
renderedPost, plaintexts := st.hc.renderStatus(st.status.Content, st.postContext.ref)
for key, plaintext := range plaintexts {
renderedPost = strings.Replace(renderedPost, key, plaintext, 1)
}
renderedPost = html2text.HTML2Text(renderedPost)
return renderedPost
}
func (st *StatusFormatter) username() string {
var sb strings.Builder
sb.WriteString("<")
sb.WriteString(st.status.Account.Username)
sb.WriteString(">")
return sb.String()
}
func (st *StatusFormatter) detailLine() string {
var sb strings.Builder
var items []string
if st.status.FavouritesCount > 0 {
items = append(items, fmt.Sprintf("Likes:%v", st.status.FavouritesCount))
}
if st.status.ReblogsCount > 0 {
items = append(items, fmt.Sprintf("Reblogs:%v", st.status.ReblogsCount))
}
if st.status.RepliesCount > 0 {
items = append(items, fmt.Sprintf("Replies:%v", st.status.RepliesCount))
}
for i := range items {
sb.WriteString(items[i])
if i != len(items) - 1 {
sb.WriteString(" ")
}
}
sb.WriteString("\n")
return sb.String()
}
func (hc *Hellclient) renderStatus(content string, index string) (string, map[string]string) {
doc, err := html.Parse(strings.NewReader(content))
if err != nil {
fmt.Printf("Failed to parse status\n")
return "", nil
}
//clear out the url map
hc.urlMap[index] = []string{}
preformats := make(map[string]string)
for node := range doc.Descendants() {
if (node.Data == "pre" || node.Data == "") && node.FirstChild != nil {
preformats[fmt.Sprintf("%p%p", hc, node.FirstChild)] = node.FirstChild.Data
node.FirstChild.Data = fmt.Sprintf("%p%p", hc, node.FirstChild)
}
if node.Data == "a" && node.Type == html.ElementNode {
ismention := false
href := ""
for attr := range node.Attr {
if node.Attr[attr].Key == "class" && strings.Contains(node.Attr[attr].Val, "mention") {
node.Data = "div"
ismention = true
continue
}
if node.Attr[attr].Key == "href" {
href = node.Attr[attr].Val
//Replace the href with the description if the URL has one
if node.FirstChild != nil && node.FirstChild.Type == html.TextNode && !ismention {
node.Attr[attr].Val = fmt.Sprintf("(%s)", node.FirstChild.Data)
} else {
href = href + " "
}
}
}
if !ismention {
hc.urlMap[index] = append(hc.urlMap[index], href)
refnode := &html.Node{
Type: html.TextNode,
Data: fmt.Sprintf(" [%v]", len(hc.urlMap[index]))}
if node.Parent != nil {
node.Parent.InsertBefore(refnode, node.NextSibling)
}
}
}
}
//Rip off the HTML body the parser made for us
for node := range doc.Descendants() {
if node.Data == "body" {
node.Type = html.DocumentNode
doc = node
}
}
var rendered bytes.Buffer
err = html.Render(&rendered, doc)
if err != nil {
return "", nil
}
renderedPlainText := rendered.String()
return renderedPlainText, preformats
}