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)
14
15func findUserPDS(ctx context.Context, did syntax.DID) (string, error) {
16 id, err := identity.DefaultDirectory().LookupDID(ctx, did)
17 if err != nil {
18 return "", err
19 }
20 pdsURI := id.PDSEndpoint()
21 if len(pdsURI) == 0 {
22 return "", fmt.Errorf("no PDS URL was found in identity document")
23 }
24
25 return pdsURI, nil
26}
27
28func fetchProfile(ctx context.Context, did syntax.DID) (*bsky.ActorDefs_ProfileViewDetailed, error) {
29 return bsky.ActorGetProfile(ctx, &xrpc.Client{Host: "https://public.api.bsky.app"}, string(did))
30}
31
32func fetchRecords[v any](ctx context.Context, xrpcClient *xrpc.Client, cb func(syntax.ATURI, v), cursor *string, collection string, did syntax.DID) error {
33 if xrpcClient == nil {
34 pdsURI, err := findUserPDS(ctx, did)
35 if err != nil {
36 return err
37 }
38 xrpcClient = &xrpc.Client{
39 Host: pdsURI,
40 }
41 }
42
43 var cur string = ""
44 if cursor != nil {
45 cur = *cursor
46 }
47
48 for {
49 // todo: ratelimits?? idk what this does for those
50 out, err := atproto.RepoListRecords(ctx, xrpcClient, collection, cur, 100, string(did), true)
51 if err != nil {
52 return err
53 }
54
55 for _, record := range out.Records {
56 raw, _ := record.Value.MarshalJSON()
57 var val v
58 if err := json.Unmarshal(raw, &val); err != nil {
59 return err
60 }
61 cb(syntax.ATURI(record.Uri), val)
62 }
63
64 if out.Cursor == nil || *out.Cursor == "" {
65 break
66 }
67 cur = *out.Cursor
68 }
69
70 return nil
71}
72
73type FetchFollowItem struct {
74 rkey syntax.RecordKey
75 follow bsky.GraphFollow
76}
77
78func fetchFollows(ctx context.Context, xrpcClient *xrpc.Client, cursor *string, did syntax.DID) ([]FetchFollowItem, error) {
79 out := make([]FetchFollowItem, 0)
80 fetchRecords(ctx, xrpcClient, func(uri syntax.ATURI, f bsky.GraphFollow) {
81 out = append(out, FetchFollowItem{rkey: uri.RecordKey(), follow: f})
82 }, cursor, "app.bsky.graph.follow", did)
83 return out, nil
84}
85
86func fetchRepostLikes(ctx context.Context, xrpcClient *xrpc.Client, cursor *string, did syntax.DID) (map[syntax.RecordKey]bsky.FeedLike, error) {
87 out := make(map[syntax.RecordKey]bsky.FeedLike)
88 fetchRecords(ctx, xrpcClient, func(uri syntax.ATURI, f bsky.FeedLike) {
89 if f.Via != nil && syntax.ATURI(f.Via.Uri).Collection() == "app.bsky.feed.repost" {
90 out[uri.RecordKey()] = f
91 }
92 }, cursor, "app.bsky.feed.like", did)
93 return out, nil
94}