its for when you want to get like notifications for your reposts
1package main 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 8 "github.com/bluesky-social/indigo/api/atproto" 9 "github.com/bluesky-social/indigo/api/bsky" 10 "github.com/bluesky-social/indigo/atproto/identity" 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 "github.com/bluesky-social/indigo/xrpc" 13 "github.com/bluesky-social/jetstream/pkg/models" 14) 15 16func findUserPDS(ctx context.Context, did syntax.DID) (string, error) { 17 id, err := identity.DefaultDirectory().LookupDID(ctx, did) 18 if err != nil { 19 return "", err 20 } 21 pdsURI := id.PDSEndpoint() 22 if len(pdsURI) == 0 { 23 return "", fmt.Errorf("no PDS URL was found in identity document") 24 } 25 26 return pdsURI, nil 27} 28 29func fetchRecord[v any](ctx context.Context, xrpcClient *xrpc.Client, val *v, event *models.Event) error { 30 out, err := atproto.RepoGetRecord(ctx, xrpcClient, "", event.Commit.Collection, event.Did, event.Commit.RKey) 31 if err != nil { 32 return err 33 } 34 raw, _ := out.Value.MarshalJSON() 35 if err := json.Unmarshal(raw, val); err != nil { 36 return err 37 } 38 return nil 39} 40 41func fetchRecords[v any](ctx context.Context, xrpcClient *xrpc.Client, cb func(syntax.ATURI, v), cursor *string, collection string, did syntax.DID) error { 42 if xrpcClient == nil { 43 pdsURI, err := findUserPDS(ctx, did) 44 if err != nil { 45 return err 46 } 47 xrpcClient = &xrpc.Client{ 48 Host: pdsURI, 49 } 50 } 51 52 var cur string = "" 53 if cursor != nil { 54 cur = *cursor 55 } 56 57 for { 58 // todo: ratelimits?? idk what this does for those 59 out, err := atproto.RepoListRecords(ctx, xrpcClient, collection, cur, 100, string(did), true) 60 if err != nil { 61 return err 62 } 63 64 for _, record := range out.Records { 65 raw, _ := record.Value.MarshalJSON() 66 var val v 67 if err := json.Unmarshal(raw, &val); err != nil { 68 return err 69 } 70 cb(syntax.ATURI(record.Uri), val) 71 } 72 73 if out.Cursor == nil || *out.Cursor == "" { 74 break 75 } 76 cur = *out.Cursor 77 } 78 79 return nil 80} 81 82type FetchFollowItem struct { 83 rkey syntax.RecordKey 84 follow bsky.GraphFollow 85} 86 87func fetchFollows(ctx context.Context, xrpcClient *xrpc.Client, cursor *string, did syntax.DID) ([]FetchFollowItem, error) { 88 out := make([]FetchFollowItem, 0) 89 fetchRecords(ctx, xrpcClient, func(uri syntax.ATURI, f bsky.GraphFollow) { 90 out = append(out, FetchFollowItem{rkey: uri.RecordKey(), follow: f}) 91 }, cursor, "app.bsky.graph.follow", did) 92 return out, nil 93} 94 95func fetchRepostLikes(ctx context.Context, xrpcClient *xrpc.Client, cursor *string, did syntax.DID) (map[syntax.RecordKey]bsky.FeedLike, error) { 96 out := make(map[syntax.RecordKey]bsky.FeedLike) 97 fetchRecords(ctx, xrpcClient, func(uri syntax.ATURI, f bsky.FeedLike) { 98 if f.Via != nil && syntax.ATURI(f.Via.Uri).Collection() == "app.bsky.feed.repost" { 99 out[uri.RecordKey()] = f 100 } 101 }, cursor, "app.bsky.feed.like", did) 102 return out, nil 103}