diff --git a/internal/bridge/bluesky.go b/internal/bridge/bluesky.go index 855574c1..394da3a1 100644 --- a/internal/bridge/bluesky.go +++ b/internal/bridge/bluesky.go @@ -15,6 +15,7 @@ import ( "github.com/systemli/ticker/internal/bluesky" "github.com/systemli/ticker/internal/config" "github.com/systemli/ticker/internal/storage" + "github.com/systemli/ticker/internal/util" ) type BlueskyBridge struct { @@ -40,6 +41,26 @@ func (bb *BlueskyBridge) Send(ticker storage.Ticker, message *storage.Message) e post := &bsky.FeedPost{ Text: message.Text, CreatedAt: time.Now().Local().Format(time.RFC3339), + Facets: []*bsky.RichtextFacet{}, + } + + links := util.ExtractURLs(message.Text) + for _, link := range links { + startIndex := strings.Index(message.Text, link) + endIndex := startIndex + len(link) + post.Facets = append(post.Facets, &bsky.RichtextFacet{ + Features: []*bsky.RichtextFacet_Features_Elem{ + { + RichtextFacet_Link: &bsky.RichtextFacet_Link{ + Uri: link, + }, + }, + }, + Index: &bsky.RichtextFacet_ByteSlice{ + ByteStart: int64(startIndex), + ByteEnd: int64(endIndex), + }, + }) } if len(message.Attachments) > 0 { @@ -76,6 +97,7 @@ func (bb *BlueskyBridge) Send(ticker storage.Ticker, message *storage.Message) e if post.Embed == nil { post.Embed = &bsky.FeedPost_Embed{} } + post.Embed.EmbedImages = &bsky.EmbedImages{ Images: images, } diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index 4d4cb696..792e3887 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -59,7 +59,7 @@ func (s *BridgeTestSuite) SetupTest() { }, } messageWithoutBridges = storage.Message{ - Text: "Hello World", + Text: "Hello World https://example.com", Attachments: []storage.Attachment{ { UUID: "123", diff --git a/internal/util/url.go b/internal/util/url.go new file mode 100644 index 00000000..fd7192af --- /dev/null +++ b/internal/util/url.go @@ -0,0 +1,9 @@ +package util + +import "regexp" + +// ExtractURLs extracts URLs from a text. +func ExtractURLs(text string) []string { + urlRegex := regexp.MustCompile(`(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)`) + return urlRegex.FindAllString(text, -1) +} diff --git a/internal/util/url_test.go b/internal/util/url_test.go new file mode 100644 index 00000000..00a00079 --- /dev/null +++ b/internal/util/url_test.go @@ -0,0 +1,39 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExtractURL(t *testing.T) { + text := "This is a text with a URL https://example.com" + urls := ExtractURLs(text) + + assert.Equal(t, 1, len(urls)) + assert.Equal(t, "https://example.com", urls[0]) + + text = "This is a text with a URL https://example.com and another URL http://example.org" + urls = ExtractURLs(text) + + assert.Equal(t, 2, len(urls)) + assert.Equal(t, "https://example.com", urls[0]) + assert.Equal(t, "http://example.org", urls[1]) + + text = "This is a text without a URL" + urls = ExtractURLs(text) + + assert.Equal(t, 0, len(urls)) + + text = "This is a text with a URL https://www.systemli.org/en/contact/" + urls = ExtractURLs(text) + + assert.Equal(t, 1, len(urls)) + assert.Equal(t, "https://www.systemli.org/en/contact/", urls[0]) + + text = "This is a text with a URL https://www.systemli.org/en/contact/?key=value" + urls = ExtractURLs(text) + + assert.Equal(t, 1, len(urls)) + assert.Equal(t, "https://www.systemli.org/en/contact/?key=value", urls[0]) +}