Merge 3e7d8bcef89a91d1c5a417a7e58fc8602290992a into 600ea5482c36d3705fbca1d9ab749d9bdafd6f80

This commit is contained in:
quepasaquepasa 2026-07-30 23:13:46 -04:00 committed by GitHub
commit 68e9f6d330
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 0 deletions

View File

@ -370,11 +370,26 @@ func (l *lastfmAgent) NowPlaying(ctx context.Context, userId string, track *mode
})
if err != nil {
log.Warn(ctx, "Last.fm client.updateNowPlaying returned error", "track", track.Title, err)
l.dropSessionKeyIfInvalid(ctx, userId, err)
return errors.Join(err, scrobbler.ErrUnrecoverable)
}
return nil
}
// dropSessionKeyIfInvalid discards a session key that Last.fm has rejected, so the
// account stops reporting as linked and the user is prompted to re-authenticate
// instead of scrobbles failing silently.
func (l *lastfmAgent) dropSessionKeyIfInvalid(ctx context.Context, userId string, err error) {
var lfErr *lastFMError
if !errors.As(err, &lfErr) || lfErr.Code != errorInvalidSessionKey {
return
}
log.Warn(ctx, "Last.fm session key was rejected, unlinking account", "userId", userId, err)
if delErr := l.sessionKeys.Delete(ctx, userId); delErr != nil {
log.Error(ctx, "Could not delete rejected Last.fm session key", "userId", userId, delErr)
}
}
func (l *lastfmAgent) Scrobble(ctx context.Context, userId string, s scrobbler.Scrobble) error {
sk, err := l.sessionKeys.Get(ctx, userId)
if err != nil || sk == "" {
@ -407,6 +422,7 @@ func (l *lastfmAgent) Scrobble(ctx context.Context, userId string, s scrobbler.S
if lfErr.Code == 11 || lfErr.Code == 16 {
return errors.Join(err, scrobbler.ErrRetryLater)
}
l.dropSessionKeyIfInvalid(ctx, userId, err)
return errors.Join(err, scrobbler.ErrUnrecoverable)
}

View File

@ -24,6 +24,7 @@ import (
const (
lastfmError3 = `{"error":3,"message":"Invalid Method - No method with that name in this package","links":[]}`
lastfmError6 = `{"error":6,"message":"The artist you supplied could not be found","links":[]}`
lastfmError9 = `{"error":9,"message":"Invalid session key - Please re-authenticate","links":[]}`
)
var _ = Describe("lastfmAgent", func() {
@ -516,6 +517,32 @@ var _ = Describe("lastfmAgent", func() {
err := agent.Scrobble(ctx, "user-1", scrobbler.Scrobble{MediaFile: *track, TimeStamp: time.Now()})
Expect(err).To(MatchError(scrobbler.ErrUnrecoverable))
})
It("unlinks the account when the session key is rejected", func() {
httpClient.Res = http.Response{
Body: io.NopCloser(bytes.NewBufferString(lastfmError9)),
StatusCode: 403,
}
err := agent.Scrobble(ctx, "user-1", scrobbler.Scrobble{MediaFile: *track, TimeStamp: time.Now()})
Expect(err).To(MatchError(scrobbler.ErrUnrecoverable))
Expect(agent.IsAuthorized(ctx, "user-1")).To(BeFalse())
})
})
Describe("session key rejected during NowPlaying", func() {
It("unlinks the account", func() {
httpClient.Res = http.Response{
Body: io.NopCloser(bytes.NewBufferString(lastfmError9)),
StatusCode: 403,
}
err := agent.NowPlaying(ctx, "user-1", track, 0)
Expect(err).To(HaveOccurred())
Expect(agent.IsAuthorized(ctx, "user-1")).To(BeFalse())
})
})
})

View File

@ -19,6 +19,9 @@ import (
const (
apiBaseUrl = "https://ws.audioscrobbler.com/2.0/"
// https://www.last.fm/api/errorcodes
errorInvalidSessionKey = 9
)
type lastFMError struct {