package social import ( "net/url" "regexp" "strings" "git.nakama.town/fmartingr/butterrobot/internal/model" "git.nakama.town/fmartingr/butterrobot/internal/plugin" ) // TwitterExpander transforms twitter.com links to fxtwitter.com links type TwitterExpander struct { plugin.BasePlugin } // New creates a new TwitterExpander instance func NewTwitterExpander() *TwitterExpander { return &TwitterExpander{ BasePlugin: plugin.BasePlugin{ ID: "social.twitter", Name: "Twitter Link Expander", Help: "Automatically converts twitter.com links to fxtwitter.com links and removes tracking parameters", }, } } // OnMessage handles incoming messages func (p *TwitterExpander) OnMessage(msg *model.Message, config map[string]interface{}) []*model.Message { // Skip empty messages if strings.TrimSpace(msg.Text) == "" { return nil } // Regex to match twitter.com links // Match both http://twitter.com and https://twitter.com formats // Also match www.twitter.com twitterRegex := regexp.MustCompile(`https?://(www\.)?(twitter\.com|x\.com)/[^\s]+`) // Check if the message contains a Twitter link if !twitterRegex.MatchString(msg.Text) { return nil } // Replace twitter.com with fxtwitter.com in the message and clean query parameters transformed := twitterRegex.ReplaceAllStringFunc(msg.Text, func(link string) string { // Parse the URL parsedURL, err := url.Parse(link) if err != nil { // If parsing fails, just do the simple replacement link = strings.Replace(link, "twitter.com", "fxtwitter.com", 1) link = strings.Replace(link, "x.com", "fxtwitter.com", 1) return link } // Change the host if strings.Contains(parsedURL.Host, "twitter.com") { parsedURL.Host = strings.Replace(parsedURL.Host, "twitter.com", "fxtwitter.com", 1) } else if strings.Contains(parsedURL.Host, "x.com") { parsedURL.Host = strings.Replace(parsedURL.Host, "x.com", "fxtwitter.com", 1) } // Remove query parameters parsedURL.RawQuery = "" // Return the cleaned URL return parsedURL.String() }) // Create response message response := &model.Message{ Text: transformed, Chat: msg.Chat, ReplyTo: msg.ID, Channel: msg.Channel, } return []*model.Message{response} }