porting all github actions from bluesky-social/indigo to tangled CI
1package main
2
3import (
4 "context"
5 "fmt"
6 "log/slog"
7 "os"
8 "strings"
9
10 appbsky "github.com/bluesky-social/indigo/api/bsky"
11 "github.com/bluesky-social/indigo/atproto/identity"
12 "github.com/bluesky-social/indigo/atproto/syntax"
13
14 "github.com/urfave/cli/v2"
15)
16
17type MentionChecker struct {
18 slackWebhookURL string
19 mentionDIDs []syntax.DID
20 logger *slog.Logger
21 directory identity.Directory
22 minimumWords int
23}
24
25func (mc *MentionChecker) ProcessPost(ctx context.Context, did syntax.DID, rkey syntax.RecordKey, post appbsky.FeedPost) error {
26 mc.logger.Debug("processing post record", "did", did, "rkey", rkey)
27
28 if mc.minimumWords > 0 {
29 words := strings.Split(post.Text, " ")
30 if len(words) < mc.minimumWords {
31 return nil
32 }
33 }
34
35 for _, facet := range post.Facets {
36 for _, feature := range facet.Features {
37 mention := feature.RichtextFacet_Mention
38 if mention == nil {
39 continue
40 }
41 for _, d := range mc.mentionDIDs {
42 if mention.Did == d.String() {
43 mc.logger.Info("found mention", "target", d, "author", did, "rkey", rkey)
44 targetIdent, err := mc.directory.LookupDID(ctx, syntax.DID(mention.Did))
45 if err != nil {
46 return err
47 }
48 authorIdent, err := mc.directory.LookupDID(ctx, did)
49 if err != nil {
50 return err
51 }
52 msg := fmt.Sprintf("Mention of `@%s` by `@%s` (<https://bsky.app/profile/%s/post/%s|post link>):\n```%s```", targetIdent.Handle, authorIdent.Handle, did, rkey, post.Text)
53 if post.Embed != nil && (post.Embed.EmbedImages != nil || post.Embed.EmbedRecordWithMedia != nil || post.Embed.EmbedRecord != nil || post.Embed.EmbedExternal != nil) {
54 msg += "\n(post also contains an embed/quote/media)"
55 }
56 return sendSlackMsg(ctx, msg, mc.slackWebhookURL)
57 }
58 }
59 }
60 }
61 return nil
62}
63
64func notifyMentions(cctx *cli.Context) error {
65 ctx := context.Background()
66 logger := configLogger(cctx, os.Stdout)
67 relayHost := cctx.String("relay-host")
68 minimumWords := cctx.Int("minimum-words")
69
70 mentionDIDs := []syntax.DID{}
71 for _, raw := range strings.Split(cctx.String("mention-dids"), ",") {
72 did, err := syntax.ParseDID(raw)
73 if err != nil {
74 return err
75 }
76 mentionDIDs = append(mentionDIDs, did)
77 }
78
79 checker := MentionChecker{
80 slackWebhookURL: cctx.String("slack-webhook-url"),
81 mentionDIDs: mentionDIDs,
82 logger: logger,
83 directory: identity.DefaultDirectory(),
84 minimumWords: minimumWords,
85 }
86
87 logger.Info("beemo mention checker starting up...", "relayHost", relayHost, "mentionDIDs", mentionDIDs)
88
89 // can flip this bool to false to prevent spamming slack channel on startup
90 if true {
91 err := sendSlackMsg(ctx, fmt.Sprintf("beemo booting, looking for account mentions: `%s`", mentionDIDs), checker.slackWebhookURL)
92 if err != nil {
93 return err
94 }
95 }
96
97 return RunFirehoseConsumer(ctx, logger, relayHost, checker.ProcessPost)
98}