···6 "log"
7 "os"
8 "strconv"
09 "time"
1011 "github.com/bluesky-social/indigo/atproto/client"
···24 db *db.DB
25 atprotoService *atprotoauth.ATprotoAuthService
26 logger *log.Logger
0027}
2829// NewPlayingNowService creates a new playing now service
···34 db: database,
35 atprotoService: atprotoService,
36 logger: logger,
037 }
38}
39···75 Item: playView,
76 }
7778- var swapRecord *string
79 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient)
80 if err != nil {
81 return err
82 }
83000000084 // Create the record input
85 input := comatproto.RepoPutRecord_Input{
86 Collection: "fm.teal.alpha.actor.status",
87 Repo: atProtoClient.AccountDID.String(),
88 Rkey: "self", // Use "self" as the record key for current status
89 Record: &lexutil.LexiconTypeDecoder{Val: status},
90- SwapRecord: swapRecord,
91 }
9293 // Submit to PDS
···96 return fmt.Errorf("failed to create playing now status for DID %s: %w", did, err)
97 }
9899- p.logger.Printf("Successfully published playing now status for user %d (DID: %s): %s - %s",
100- userID, did, track.Artist[0].Name, track.Name)
000101102 return nil
103}
104105// ClearPlayingNow removes the current playing status by setting an expired status
106func (p *PlayingNowService) ClearPlayingNow(ctx context.Context, userID int64) error {
000000000107 // Get user information
108 user, err := p.db.GetUserByID(userID)
109 if err != nil {
···140 Item: emptyPlayView,
141 }
142143- var swapRecord *string
144 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient)
0145 if err != nil {
146 return err
147 }
14800000149 // Update the record
150 input := comatproto.RepoPutRecord_Input{
151 Collection: "fm.teal.alpha.actor.status",
152 Repo: atProtoClient.AccountDID.String(),
153 Rkey: "self",
154 Record: &lexutil.LexiconTypeDecoder{Val: status},
155- SwapRecord: swapRecord,
156 }
157158 if _, err := comatproto.RepoPutRecord(ctx, atProtoClient, &input); err != nil {
···161 }
162163 p.logger.Printf("Successfully cleared playing now status for user %d (DID: %s)", userID, did)
000000164 return nil
165}
166···216 // Get submission client agent
217 submissionAgent := viper.GetString("app.submission_agent")
218 if submissionAgent == "" {
219- submissionAgent = "piper/v0.0.2"
220 }
221222 playView := &teal.AlphaFeedDefs_PlayView{
···238239// getStatusSwapRecord retrieves the current swap record (CID) for the actor status record.
240// Returns (nil, nil) if the record does not exist yet.
241-func (p *PlayingNowService) getStatusSwapRecord(ctx context.Context, atApiClient *client.APIClient) (*string, error) {
242 result, err := comatproto.RepoGetRecord(ctx, atApiClient, "", "fm.teal.alpha.actor.status", atApiClient.AccountDID.String(), "self")
243244 if err != nil {
···253 return nil, fmt.Errorf("error getting the record: %w", err)
254255 }
256- return result.Cid, nil
0257}
···6 "log"
7 "os"
8 "strconv"
9+ "sync"
10 "time"
1112 "github.com/bluesky-social/indigo/atproto/client"
···25 db *db.DB
26 atprotoService *atprotoauth.ATprotoAuthService
27 logger *log.Logger
28+ mu sync.RWMutex
29+ clearedStatus map[int64]bool // tracks if a user's status has been cleared on their repo
30}
3132// NewPlayingNowService creates a new playing now service
···37 db: database,
38 atprotoService: atprotoService,
39 logger: logger,
40+ clearedStatus: make(map[int64]bool),
41 }
42}
43···79 Item: playView,
80 }
8182+ var swapRecord *comatproto.RepoGetRecord_Output
83 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient)
84 if err != nil {
85 return err
86 }
8788+ var swapCid *string
89+ if swapRecord != nil {
90+ swapCid = swapRecord.Cid
91+ }
92+93+ p.logger.Printf("Publishing playing now status for user %d (DID: %s): %s - %s", userID, did, track.Artist[0].Name, track.Name)
94+95 // Create the record input
96 input := comatproto.RepoPutRecord_Input{
97 Collection: "fm.teal.alpha.actor.status",
98 Repo: atProtoClient.AccountDID.String(),
99 Rkey: "self", // Use "self" as the record key for current status
100 Record: &lexutil.LexiconTypeDecoder{Val: status},
101+ SwapRecord: swapCid,
102 }
103104 // Submit to PDS
···107 return fmt.Errorf("failed to create playing now status for DID %s: %w", did, err)
108 }
109110+ // Resets clear to false since there is a song playing. The publish playing state is kept in the services from
111+ // if a song has changed/stamped
112+ p.mu.Lock()
113+ p.clearedStatus[userID] = false
114+ p.mu.Unlock()
115116 return nil
117}
118119// ClearPlayingNow removes the current playing status by setting an expired status
120func (p *PlayingNowService) ClearPlayingNow(ctx context.Context, userID int64) error {
121+ // Check if status is already cleared to avoid clearing on the users repo over and over
122+ p.mu.RLock()
123+ alreadyCleared := p.clearedStatus[userID]
124+ p.mu.RUnlock()
125+126+ if alreadyCleared {
127+ return nil
128+ }
129+130 // Get user information
131 user, err := p.db.GetUserByID(userID)
132 if err != nil {
···163 Item: emptyPlayView,
164 }
165166+ var swapRecord *comatproto.RepoGetRecord_Output
167 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient)
168+169 if err != nil {
170 return err
171 }
172173+ var swapCid *string
174+ if swapRecord != nil {
175+ swapCid = swapRecord.Cid
176+ }
177+178 // Update the record
179 input := comatproto.RepoPutRecord_Input{
180 Collection: "fm.teal.alpha.actor.status",
181 Repo: atProtoClient.AccountDID.String(),
182 Rkey: "self",
183 Record: &lexutil.LexiconTypeDecoder{Val: status},
184+ SwapRecord: swapCid,
185 }
186187 if _, err := comatproto.RepoPutRecord(ctx, atProtoClient, &input); err != nil {
···190 }
191192 p.logger.Printf("Successfully cleared playing now status for user %d (DID: %s)", userID, did)
193+194+ // Mark status as cleared so we don't clear again until user starts playing a song again
195+ p.mu.Lock()
196+ p.clearedStatus[userID] = true
197+ p.mu.Unlock()
198+199 return nil
200}
201···251 // Get submission client agent
252 submissionAgent := viper.GetString("app.submission_agent")
253 if submissionAgent == "" {
254+ submissionAgent = models.SubmissionAgent
255 }
256257 playView := &teal.AlphaFeedDefs_PlayView{
···273274// getStatusSwapRecord retrieves the current swap record (CID) for the actor status record.
275// Returns (nil, nil) if the record does not exist yet.
276+func (p *PlayingNowService) getStatusSwapRecord(ctx context.Context, atApiClient *client.APIClient) (*comatproto.RepoGetRecord_Output, error) {
277 result, err := comatproto.RepoGetRecord(ctx, atApiClient, "", "fm.teal.alpha.actor.status", atApiClient.AccountDID.String(), "self")
278279 if err != nil {
···288 return nil, fmt.Errorf("error getting the record: %w", err)
289290 }
291+292+ return result, nil
293}