Skip to content

Commit 1ab47d6

Browse files
feat(subsonic): update play stats when scrobbling
closes: #207 Co-authored-by: Brian Doherty <[email protected]>
1 parent 59c4047 commit 1ab47d6

File tree

2 files changed

+53
-18
lines changed

2 files changed

+53
-18
lines changed

server/ctrlsubsonic/handlers_common.go

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ func (c *Controller) ServeScrobble(r *http.Request) *spec.Response {
5555
optStamp := params.GetOrTime("time", time.Now())
5656
optSubmission := params.GetOrBool("submission", true)
5757

58+
if err := streamUpdateStats(c.DB, user.ID, track.Album.ID, optStamp); err != nil {
59+
return spec.NewError(0, "error updating stats: %v", err)
60+
}
61+
5862
var scrobbleErrs multierr.Err
5963
for _, scrobbler := range c.Scrobblers {
6064
if err := scrobbler.Scrobble(user, track, optStamp, optSubmission); err != nil {

server/ctrlsubsonic/handlers_raw.go

+49-18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"github.com/disintegration/imaging"
14+
"github.com/jinzhu/gorm"
1415

1516
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
1617
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
@@ -26,42 +27,64 @@ import (
2627
// b) return a non-nil spec.Response
2728
// _but not both_
2829

29-
func streamGetTransPref(dbc *db.DB, userID int, client string) db.TranscodePreference {
30-
pref := db.TranscodePreference{}
31-
dbc.
30+
func streamGetTransPref(dbc *db.DB, userID int, client string) (*db.TranscodePreference, error) {
31+
var pref db.TranscodePreference
32+
err := dbc.
3233
Where("user_id=?", userID).
3334
Where("client COLLATE NOCASE IN (?)", []string{"*", client}).
3435
Order("client DESC"). // ensure "*" is last if it's there
35-
First(&pref)
36-
return pref
36+
First(&pref).
37+
Error
38+
if errors.Is(err, gorm.ErrRecordNotFound) {
39+
return &pref, nil
40+
}
41+
if err != nil {
42+
return nil, fmt.Errorf("find transcode preference: %w", err)
43+
}
44+
return &pref, nil
3745
}
3846

3947
func streamGetTrack(dbc *db.DB, trackID int) (*db.Track, error) {
40-
track := db.Track{}
48+
var track db.Track
4149
err := dbc.
4250
Preload("Album").
4351
First(&track, trackID).
4452
Error
45-
return &track, err
53+
if err != nil {
54+
return nil, fmt.Errorf("find track: %w", err)
55+
}
56+
return &track, nil
4657
}
4758

4859
func streamGetPodcast(dbc *db.DB, podcastID int) (*db.PodcastEpisode, error) {
49-
podcast := db.PodcastEpisode{}
50-
err := dbc.First(&podcast, podcastID).Error
51-
return &podcast, err
60+
var podcast db.PodcastEpisode
61+
if err := dbc.First(&podcast, podcastID).Error; err != nil {
62+
return nil, fmt.Errorf("find podcast: %w", err)
63+
}
64+
return &podcast, nil
5265
}
5366

54-
func streamUpdateStats(dbc *db.DB, userID, albumID int) {
67+
func streamUpdateStats(dbc *db.DB, userID, albumID int, playTime time.Time) error {
5568
play := db.Play{
5669
AlbumID: albumID,
5770
UserID: userID,
5871
}
59-
dbc.
72+
err := dbc.
6073
Where(play).
61-
First(&play)
62-
play.Time = time.Now() // for getAlbumList?type=recent
63-
play.Count++ // for getAlbumList?type=frequent
64-
dbc.Save(&play)
74+
First(&play).
75+
Error
76+
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
77+
return fmt.Errorf("find stat: %w", err)
78+
}
79+
80+
play.Count++ // for getAlbumList?type=frequent
81+
if playTime.After(play.Time) {
82+
play.Time = playTime // for getAlbumList?type=recent
83+
}
84+
if err := dbc.Save(&play).Error; err != nil {
85+
return fmt.Errorf("save stat: %w", err)
86+
}
87+
return nil
6588
}
6689

6790
const (
@@ -242,10 +265,18 @@ func (c *Controller) ServeStream(w http.ResponseWriter, r *http.Request) *spec.R
242265

243266
user := r.Context().Value(CtxUser).(*db.User)
244267
if track, ok := audioFile.(*db.Track); ok && track.Album != nil {
245-
defer streamUpdateStats(c.DB, user.ID, track.Album.ID)
268+
defer func() {
269+
if err := streamUpdateStats(c.DB, user.ID, track.Album.ID, time.Now()); err != nil {
270+
log.Printf("error updating listen stats: %v", err)
271+
}
272+
}()
273+
}
274+
275+
pref, err := streamGetTransPref(c.DB, user.ID, params.GetOr("c", ""))
276+
if err != nil {
277+
return spec.NewError(0, "failed to get transcode stream preference: %v", err)
246278
}
247279

248-
pref := streamGetTransPref(c.DB, user.ID, params.GetOr("c", ""))
249280
onInvalidProfile := func() error {
250281
log.Printf("serving raw `%s`\n", audioFile.AudioFilename())
251282
w.Header().Set("Content-Type", audioFile.MIME())

0 commit comments

Comments
 (0)