server/lastfm: make a scrobbler interface and migrate lastfm to use it
This commit is contained in:
committed by
Senan Kelly
parent
cc93d61908
commit
f4ff7e70f2
@@ -13,6 +13,7 @@ import (
|
|||||||
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
||||||
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
|
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
|
||||||
"go.senan.xyz/gonic/server/jukebox"
|
"go.senan.xyz/gonic/server/jukebox"
|
||||||
|
"go.senan.xyz/gonic/server/lastfm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CtxKey int
|
type CtxKey int
|
||||||
@@ -28,6 +29,7 @@ type Controller struct {
|
|||||||
CachePath string
|
CachePath string
|
||||||
CoverCachePath string
|
CoverCachePath string
|
||||||
Jukebox *jukebox.Jukebox
|
Jukebox *jukebox.Jukebox
|
||||||
|
Scrobblers []lastfm.Scrobbler
|
||||||
}
|
}
|
||||||
|
|
||||||
type metaResponse struct {
|
type metaResponse struct {
|
||||||
|
|||||||
@@ -61,14 +61,16 @@ func (c *Controller) ServeScrobble(r *http.Request) *spec.Response {
|
|||||||
StampMili: params.GetOrInt("time", int(time.Now().UnixNano()/1e6)),
|
StampMili: params.GetOrInt("time", int(time.Now().UnixNano()/1e6)),
|
||||||
Submission: params.GetOrBool("submission", true),
|
Submission: params.GetOrBool("submission", true),
|
||||||
}
|
}
|
||||||
err = lastfm.Scrobble(
|
scrobbleErrs := []error{}
|
||||||
c.DB.GetSetting("lastfm_api_key"),
|
for _, scrobbler := range c.Scrobblers {
|
||||||
c.DB.GetSetting("lastfm_secret"),
|
if !scrobbler.Enabled(user) {
|
||||||
user.LastFMSession,
|
continue
|
||||||
opts,
|
}
|
||||||
)
|
err = scrobbler.Scrobble(user, opts)
|
||||||
if err != nil {
|
scrobbleErrs = append(scrobbleErrs, err)
|
||||||
return spec.NewError(0, "error when submitting: %v", err)
|
}
|
||||||
|
if len(scrobbleErrs) != 0 {
|
||||||
|
return spec.NewError(0, "error when submitting: %v", scrobbleErrs)
|
||||||
}
|
}
|
||||||
return spec.NewResponse()
|
return spec.NewResponse()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
baseURL = "https://ws.audioscrobbler.com/2.0/"
|
lastfmBaseURL = "https://ws.audioscrobbler.com/2.0/"
|
||||||
|
lbBaseURL = "https://api.listenbrainz.org"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -42,7 +43,7 @@ func getParamSignature(params url.Values, secret string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeRequest(method string, params url.Values) (LastFM, error) {
|
func makeRequest(method string, params url.Values) (LastFM, error) {
|
||||||
req, _ := http.NewRequest(method, baseURL, nil)
|
req, _ := http.NewRequest(method, lastfmBaseURL, nil)
|
||||||
req.URL.RawQuery = params.Encode()
|
req.URL.RawQuery = params.Encode()
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -79,7 +80,18 @@ type ScrobbleOptions struct {
|
|||||||
Submission bool
|
Submission bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Scrobble(apiKey, secret, session string, opts ScrobbleOptions) error {
|
type LastfmScrobbler struct { //nolint
|
||||||
|
DB *db.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lfm *LastfmScrobbler) Scrobble(reqUser interface{}, opts ScrobbleOptions) error {
|
||||||
|
apiKey := lfm.DB.GetSetting("lastfm_api_key")
|
||||||
|
secret := lfm.DB.GetSetting("lastfm_secret")
|
||||||
|
// fetch user to get lastfm session
|
||||||
|
user := reqUser.(*db.User)
|
||||||
|
if user.LastFMSession == "" {
|
||||||
|
return fmt.Errorf("you don't have a last.fm session: %w", ErrLastFM)
|
||||||
|
}
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
if opts.Submission {
|
if opts.Submission {
|
||||||
params.Add("method", "track.Scrobble")
|
params.Add("method", "track.Scrobble")
|
||||||
@@ -89,7 +101,7 @@ func Scrobble(apiKey, secret, session string, opts ScrobbleOptions) error {
|
|||||||
params.Add("method", "track.updateNowPlaying")
|
params.Add("method", "track.updateNowPlaying")
|
||||||
}
|
}
|
||||||
params.Add("api_key", apiKey)
|
params.Add("api_key", apiKey)
|
||||||
params.Add("sk", session)
|
params.Add("sk", user.LastFMSession)
|
||||||
params.Add("artist", opts.Track.TagTrackArtist)
|
params.Add("artist", opts.Track.TagTrackArtist)
|
||||||
params.Add("track", opts.Track.TagTitle)
|
params.Add("track", opts.Track.TagTitle)
|
||||||
params.Add("trackNumber", strconv.Itoa(opts.Track.TagTrackNumber))
|
params.Add("trackNumber", strconv.Itoa(opts.Track.TagTrackNumber))
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import (
|
|||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Scrobbler interface {
|
||||||
|
Scrobble(interface{}, ScrobbleOptions) error
|
||||||
|
}
|
||||||
|
|
||||||
type LastFM struct {
|
type LastFM struct {
|
||||||
XMLName xml.Name `xml:"lfm"`
|
XMLName xml.Name `xml:"lfm"`
|
||||||
Status string `xml:"status,attr"`
|
Status string `xml:"status,attr"`
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"go.senan.xyz/gonic/server/ctrlsubsonic"
|
"go.senan.xyz/gonic/server/ctrlsubsonic"
|
||||||
"go.senan.xyz/gonic/server/db"
|
"go.senan.xyz/gonic/server/db"
|
||||||
"go.senan.xyz/gonic/server/jukebox"
|
"go.senan.xyz/gonic/server/jukebox"
|
||||||
|
"go.senan.xyz/gonic/server/lastfm"
|
||||||
"go.senan.xyz/gonic/server/scanner"
|
"go.senan.xyz/gonic/server/scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,11 +63,16 @@ func New(opts Options) *Server {
|
|||||||
sessDB.SessionOpts.SameSite = http.SameSiteLaxMode
|
sessDB.SessionOpts.SameSite = http.SameSiteLaxMode
|
||||||
//
|
//
|
||||||
ctrlAdmin := ctrladmin.New(base, sessDB)
|
ctrlAdmin := ctrladmin.New(base, sessDB)
|
||||||
|
lastfmScrobbler := &lastfm.LastfmScrobbler{DB: opts.DB}
|
||||||
|
scrobblers := []lastfm.Scrobbler{
|
||||||
|
lastfmScrobbler,
|
||||||
|
}
|
||||||
ctrlSubsonic := &ctrlsubsonic.Controller{
|
ctrlSubsonic := &ctrlsubsonic.Controller{
|
||||||
Controller: base,
|
Controller: base,
|
||||||
CachePath: opts.CachePath,
|
CachePath: opts.CachePath,
|
||||||
CoverCachePath: opts.CoverCachePath,
|
CoverCachePath: opts.CoverCachePath,
|
||||||
Jukebox: jukebox,
|
Jukebox: jukebox,
|
||||||
|
Scrobblers: scrobblers,
|
||||||
}
|
}
|
||||||
setupMisc(r, base)
|
setupMisc(r, base)
|
||||||
setupAdmin(r.PathPrefix("/admin").Subrouter(), ctrlAdmin)
|
setupAdmin(r.PathPrefix("/admin").Subrouter(), ctrlAdmin)
|
||||||
|
|||||||
Reference in New Issue
Block a user