package notes import ( "sort" "time" ) type Note struct { URI string `json:"uri"` AuthorDID string `json:"authorDID"` AuthorHandle string `json:"authorHandle"` AuthorName string `json:"authorName"` AuthorNoUnauth bool `json:"authorNoUnauth"` // author has !no-unauthenticated label AvatarURL string `json:"avatarURL"` Text string `json:"text"` CreatedAt time.Time `json:"createdAt"` ReplyTo *string `json:"replyTo,omitempty"` Facets []Facet `json:"facets,omitempty"` Parents []Note `json:"parents,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 } func MissingNote(uri string) *Note { return &Note{ URI: uri, AuthorDID: "MISSING", Text: "This post could not be fetched. It may have been deleted.", CreatedAt: time.Time{}, } } func isChainContained(smallChainPost, bigChainPost Note) bool { if len(smallChainPost.Parents) > len(bigChainPost.Parents) { return false } // check if parents of smallChainPost are included in bigChainPost offset := len(bigChainPost.Parents) - len(smallChainPost.Parents) for i, note := range smallChainPost.Parents { if bigChainPost.Parents[offset+i].URI != note.URI { return false } } return smallChainPost.URI == bigChainPost.Parents[offset-1].URI } func DeduplicateThreads(posts []Note) []Note { sort.Slice(posts, func(i, j int) bool { return len(posts[i].Parents) > len(posts[j].Parents) }) filtered := []Note{} for _, post := range posts { isRedundant := false for _, kept := range filtered { // check if this post's chain is contained in any kept post if isChainContained(post, kept) { isRedundant = true break } } if !isRedundant { filtered = append(filtered, post) } } return filtered }