package notes import ( "fmt" "llostre/backend/general" "strings" "time" ) type AppBskyFeedPostNote struct { URI string `json:"uri"` AuthorDID string `json:"authorDid"` AuthorHandle string `json:"authorHandle"` AuthorName string `json:"authorName"` AvatarURL string `json:"avatarURL"` Text string `json:"text"` CreatedAt time.Time `json:"createdAt"` ReplyTo *string `json:"replyTo,omitempty"` Facets []Facet `json:"facets,omitempty"` } type Facet struct { ByteStart int `json:"byteStart"` ByteEnd int `json:"byteEnd"` Type string `json:"type"` Value string `json:"value"` // the link destination, whether url, profile or tag } type AppBskyFeedPostRecord struct { URI string `json:"uri"` Value struct { Text string `json:"text"` CreatedAt string `json:"createdAt"` Reply *struct { Parent struct { URI string `json:"uri"` } `json:"parent"` } `json:"reply,omitempty"` Facets []struct { Index struct { ByteStart int `json:"byteStart"` ByteEnd int `json:"byteEnd"` } `json:"index"` Features []struct { Type string `json:"$type"` URI string `json:"uri,omitempty"` DID string `json:"did,omitempty"` Tag string `json:"tag,omitempty"` } `json:"features"` } `json:"facets,omitempty"` } `json:"value"` } func (bp *AppBskyFeedPostNote) GetID() string { return bp.URI } func (bp *AppBskyFeedPostNote) GetAuthorDID() string { return bp.AuthorDID } func (bp *AppBskyFeedPostNote) GetAuthorHandle() string { return bp.AuthorHandle } func (bp *AppBskyFeedPostNote) GetTimestamp() time.Time { return bp.CreatedAt } func (bp *AppBskyFeedPostNote) GetReplyTo() *string { return bp.ReplyTo } func AppBskyFeedPostFromRecord(record AppBskyFeedPostRecord, profile *general.Profile) (*AppBskyFeedPostNote, error) { if record.URI == "" { return nil, fmt.Errorf("missing required field: uri") } createdAt, err := time.Parse(time.RFC3339, record.Value.CreatedAt) if err != nil { return nil, fmt.Errorf("failed to parse timestamp: %w", err) } var replyTo *string if record.Value.Reply != nil { replyTo = &record.Value.Reply.Parent.URI } parts := strings.Split(record.URI, "/") // at://DID/collection/rkey did := parts[2] var facets []Facet for _, f := range record.Value.Facets { for _, feature := range f.Features { var value string var facetType string switch feature.Type { case "app.bsky.richtext.facet#link": facetType = "link" value = feature.URI case "app.bsky.richtext.facet#mention": facetType = "mention" value = feature.DID case "app.bsky.richtext.facet#tag": facetType = "tag" value = feature.Tag default: continue } facets = append(facets, Facet{ ByteStart: f.Index.ByteStart, ByteEnd: f.Index.ByteEnd, Type: facetType, Value: value, }) } } var handle, displayName, avatarURL string if profile != nil { handle = profile.Handle displayName = profile.DisplayName avatarURL = profile.AvatarURL } else { handle = "handle.invalid" displayName = "" avatarURL = "" } return &AppBskyFeedPostNote{ URI: record.URI, AuthorDID: did, AuthorHandle: handle, AuthorName: displayName, AvatarURL: avatarURL, CreatedAt: createdAt, Text: record.Value.Text, ReplyTo: replyTo, Facets: facets, }, nil }