A fork of https://github.com/teal-fm/piper

Merge pull request #30 from fatfingers23/bugfix/ClearClearClearClear

Bugfix: Resolves #29 and keeps a local state if a play status has been clearned

authored by

natalie and committed by
GitHub
d732dadf eff5d1c2

+51 -11
+2 -1
.gitignore
··· 4 jwk*.json 5 **.bak 6 .idea 7 - AM_AUTHKEY.p8
··· 4 jwk*.json 5 **.bak 6 .idea 7 + AM_AUTHKEY.p8 8 + .DS_Store
+3
models/constants.go
···
··· 1 + package models 2 + 3 + const SubmissionAgent = "piper/v0.0.3"
+1 -1
service/atproto/submission.go
··· 99 // Get submission client agent 100 submissionAgent := viper.GetString("app.submission_agent") 101 if submissionAgent == "" { 102 - submissionAgent = "piper/v0.0.1" 103 } 104 105 playRecord := &teal.AlphaFeedPlay{
··· 99 // Get submission client agent 100 submissionAgent := viper.GetString("app.submission_agent") 101 if submissionAgent == "" { 102 + submissionAgent = models.SubmissionAgent 103 } 104 105 playRecord := &teal.AlphaFeedPlay{
+45 -9
service/playingnow/playingnow.go
··· 6 "log" 7 "os" 8 "strconv" 9 "time" 10 11 "github.com/bluesky-social/indigo/atproto/client" ··· 24 db *db.DB 25 atprotoService *atprotoauth.ATprotoAuthService 26 logger *log.Logger 27 } 28 29 // NewPlayingNowService creates a new playing now service ··· 34 db: database, 35 atprotoService: atprotoService, 36 logger: logger, 37 } 38 } 39 ··· 75 Item: playView, 76 } 77 78 - var swapRecord *string 79 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient) 80 if err != nil { 81 return err 82 } 83 84 // 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 } 92 93 // Submit to PDS ··· 96 return fmt.Errorf("failed to create playing now status for DID %s: %w", did, err) 97 } 98 99 - p.logger.Printf("Successfully published playing now status for user %d (DID: %s): %s - %s", 100 - userID, did, track.Artist[0].Name, track.Name) 101 102 return nil 103 } 104 105 // ClearPlayingNow removes the current playing status by setting an expired status 106 func (p *PlayingNowService) ClearPlayingNow(ctx context.Context, userID int64) error { 107 // Get user information 108 user, err := p.db.GetUserByID(userID) 109 if err != nil { ··· 140 Item: emptyPlayView, 141 } 142 143 - var swapRecord *string 144 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient) 145 if err != nil { 146 return err 147 } 148 149 // 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 } 157 158 if _, err := comatproto.RepoPutRecord(ctx, atProtoClient, &input); err != nil { ··· 161 } 162 163 p.logger.Printf("Successfully cleared playing now status for user %d (DID: %s)", userID, did) 164 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 } 221 222 playView := &teal.AlphaFeedDefs_PlayView{ ··· 238 239 // 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") 243 244 if err != nil { ··· 253 return nil, fmt.Errorf("error getting the record: %w", err) 254 255 } 256 - return result.Cid, nil 257 }
··· 6 "log" 7 "os" 8 "strconv" 9 + "sync" 10 "time" 11 12 "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 } 31 32 // 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 } 81 82 + var swapRecord *comatproto.RepoGetRecord_Output 83 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient) 84 if err != nil { 85 return err 86 } 87 88 + 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 } 103 104 // Submit to PDS ··· 107 return fmt.Errorf("failed to create playing now status for DID %s: %w", did, err) 108 } 109 110 + // 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() 115 116 return nil 117 } 118 119 // ClearPlayingNow removes the current playing status by setting an expired status 120 func (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 } 165 166 + var swapRecord *comatproto.RepoGetRecord_Output 167 swapRecord, err = p.getStatusSwapRecord(ctx, atProtoClient) 168 + 169 if err != nil { 170 return err 171 } 172 173 + 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 } 186 187 if _, err := comatproto.RepoPutRecord(ctx, atProtoClient, &input); err != nil { ··· 190 } 191 192 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 } 256 257 playView := &teal.AlphaFeedDefs_PlayView{ ··· 273 274 // 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") 278 279 if err != nil { ··· 288 return nil, fmt.Errorf("error getting the record: %w", err) 289 290 } 291 + 292 + return result, nil 293 }