Files
Sneedchat-Matrix-Bridge-Go/utils/bbcode.go
2025-11-18 02:07:08 -05:00

113 lines
3.6 KiB
Go

package utils
import (
"regexp"
"strings"
)
// BBCodeToMarkdown converts simplified Siropu-style BBCode into Matrix-safe Markdown.
//
// RULES:
// - [img]URL[/img] remains an image but without video tagging
// - [url] and [url=...] become markdown links
// - All [video]...[/video] wrappers are REMOVED entirely (your requirement)
// - Bold/italic/underline basic BBCode converted to markdown
// - Unknown tags stripped and inner text preserved
//
func BBCodeToMarkdown(in string) string {
if in == "" {
return ""
}
s := in
// ----------------------------------------------------
// STRIP VIDEO TAGS COMPLETELY
// ----------------------------------------------------
s = stripTagCompletely(s, "video")
// ----------------------------------------------------
// IMAGE TAGS → leave as-is, but sanitize formatting
// ----------------------------------------------------
s = regexp.MustCompile(`(?i)\[img\](.*?)\[/img\]`).ReplaceAllString(s, "![]($1)")
// ----------------------------------------------------
// URL TAGS → Markdown links
// ----------------------------------------------------
// [url]http://x[/url]
s = regexp.MustCompile(`(?i)\[url\](.*?)\[/url\]`).ReplaceAllString(s, "[$1]($1)")
// [url=http://x]label[/url]
s = regexp.MustCompile(`(?i)\[url=(.*?)\](.*?)\[/url\]`).ReplaceAllString(s, "[$2]($1)")
// ----------------------------------------------------
// BASIC FORMATTING → Markdown
// ----------------------------------------------------
replacements := map[*regexp.Regexp]string{
regexp.MustCompile(`(?i)\[b\](.*?)\[/b\]`): "**$1**",
regexp.MustCompile(`(?i)\[i\](.*?)\[/i\]`): "*$1*",
regexp.MustCompile(`(?i)\[u\](.*?)\[/u\]`): "__$1__",
regexp.MustCompile(`(?i)\[s\](.*?)\[/s\]`): "~~$1~~",
regexp.MustCompile(`(?i)\[quote\](.*?)\[/quote\]`): "> $1",
}
for re, repl := range replacements {
s = re.ReplaceAllString(s, repl)
}
// ----------------------------------------------------
// REMOVE ANY OTHER BBCODE TAGS, KEEP CONTENT
// ----------------------------------------------------
s = regexp.MustCompile(`(?i)\[(\/?)[a-zA-Z0-9\=\#]+?\]`).ReplaceAllString(s, "")
// Cleanup whitespace
return strings.TrimSpace(s)
}
// stripTagCompletely removes [tag]...[/tag] entirely, preserving inner text only if desired.
// Here we drop everything inside video tags.
func stripTagCompletely(s, tag string) string {
re := regexp.MustCompile(`(?is)\[` + tag + `(?:=[^\]]*)?\].*?\[\/` + tag + `\]`)
return re.ReplaceAllString(s, "")
}
// IsImageURL determines whether a string looks like an image link.
// Used by both Matrix → Sneed and Sneed → Matrix paths.
func IsImageURL(u string) bool {
u = strings.ToLower(strings.TrimSpace(u))
if !(strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")) {
return false
}
// strip query
if i := strings.Index(u, "?"); i > 0 {
u = u[:i]
}
return strings.HasSuffix(u, ".png") ||
strings.HasSuffix(u, ".jpg") ||
strings.HasSuffix(u, ".jpeg") ||
strings.HasSuffix(u, ".gif") ||
strings.HasSuffix(u, ".webp")
}
// WrapImageForSneed produces the BBCode wrapper used for outbound
// Matrix → Sneed image messages.
//
// Example:
// input: "https://example.com/img.jpg"
// output: "[url=https://example.com/img.jpg][img]https://example.com/img.jpg[/img][/url]"
//
func WrapImageForSneed(url string) string {
if url == "" {
return ""
}
return "[url=" + url + "][img]" + url + "[/img][/url]"
}
// ExtractFirstURL finds the first URL-like token in a message.
// Useful for deciding if a message is an image-only post.
func ExtractFirstURL(s string) string {
re := regexp.MustCompile(`https?://[^\s]+`)
found := re.FindString(s)
return found
}