mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-04 13:07:36 +03:00
feat: Add listenbrainz base url configuration (#1774)
* feat: Add listenbrainz base url configuration - ListenBrainz.BaseURL config value * Don't need to store baseUrl * Use `url.JoinPath` to concatenate url paths * Replace url.JoinPath (Go 1.19 only) with custom function Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
cb3ba23fce
commit
2f7a3c5eda
8 changed files with 34 additions and 17 deletions
|
@ -98,6 +98,7 @@ type spotifyOptions struct {
|
||||||
|
|
||||||
type listenBrainzOptions struct {
|
type listenBrainzOptions struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
BaseURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -254,6 +255,7 @@ func init() {
|
||||||
viper.SetDefault("spotify.id", "")
|
viper.SetDefault("spotify.id", "")
|
||||||
viper.SetDefault("spotify.secret", "")
|
viper.SetDefault("spotify.secret", "")
|
||||||
viper.SetDefault("listenbrainz.enabled", true)
|
viper.SetDefault("listenbrainz.enabled", true)
|
||||||
|
viper.SetDefault("listenbrainz.baseurl", "https://api.listenbrainz.org/1/")
|
||||||
|
|
||||||
// DevFlags. These are used to enable/disable debugging and incomplete features
|
// DevFlags. These are used to enable/disable debugging and incomplete features
|
||||||
viper.SetDefault("devlogsourceline", false)
|
viper.SetDefault("devlogsourceline", false)
|
||||||
|
|
|
@ -21,6 +21,7 @@ const (
|
||||||
type listenBrainzAgent struct {
|
type listenBrainzAgent struct {
|
||||||
ds model.DataStore
|
ds model.DataStore
|
||||||
sessionKeys *agents.SessionKeys
|
sessionKeys *agents.SessionKeys
|
||||||
|
baseURL string
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +29,13 @@ func listenBrainzConstructor(ds model.DataStore) *listenBrainzAgent {
|
||||||
l := &listenBrainzAgent{
|
l := &listenBrainzAgent{
|
||||||
ds: ds,
|
ds: ds,
|
||||||
sessionKeys: &agents.SessionKeys{DataStore: ds, KeyName: sessionKeyProperty},
|
sessionKeys: &agents.SessionKeys{DataStore: ds, KeyName: sessionKeyProperty},
|
||||||
|
baseURL: conf.Server.ListenBrainz.BaseURL,
|
||||||
}
|
}
|
||||||
hc := &http.Client{
|
hc := &http.Client{
|
||||||
Timeout: consts.DefaultHttpClientTimeOut,
|
Timeout: consts.DefaultHttpClientTimeOut,
|
||||||
}
|
}
|
||||||
chc := utils.NewCachedHTTPClient(hc, consts.DefaultHttpClientTimeOut)
|
chc := utils.NewCachedHTTPClient(hc, consts.DefaultHttpClientTimeOut)
|
||||||
l.client = NewClient(chc)
|
l.client = NewClient(l.baseURL, chc)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ var _ = Describe("listenBrainzAgent", func() {
|
||||||
_ = ds.UserProps(ctx).Put("user-1", sessionKeyProperty, "SK-1")
|
_ = ds.UserProps(ctx).Put("user-1", sessionKeyProperty, "SK-1")
|
||||||
httpClient = &tests.FakeHttpClient{}
|
httpClient = &tests.FakeHttpClient{}
|
||||||
agent = listenBrainzConstructor(ds)
|
agent = listenBrainzConstructor(ds)
|
||||||
agent.client = NewClient(httpClient)
|
agent.client = NewClient("http://localhost:8080", httpClient)
|
||||||
track = &model.MediaFile{
|
track = &model.MediaFile{
|
||||||
ID: "123",
|
ID: "123",
|
||||||
Title: "Track Title",
|
Title: "Track Title",
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/deluan/rest"
|
"github.com/deluan/rest"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
"github.com/navidrome/navidrome/conf"
|
||||||
"github.com/navidrome/navidrome/consts"
|
"github.com/navidrome/navidrome/consts"
|
||||||
"github.com/navidrome/navidrome/core/agents"
|
"github.com/navidrome/navidrome/core/agents"
|
||||||
"github.com/navidrome/navidrome/log"
|
"github.com/navidrome/navidrome/log"
|
||||||
|
@ -38,7 +39,7 @@ func NewRouter(ds model.DataStore) *Router {
|
||||||
hc := &http.Client{
|
hc := &http.Client{
|
||||||
Timeout: consts.DefaultHttpClientTimeOut,
|
Timeout: consts.DefaultHttpClientTimeOut,
|
||||||
}
|
}
|
||||||
r.client = NewClient(hc)
|
r.client = NewClient(conf.Server.ListenBrainz.BaseURL, hc)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ var _ = Describe("ListenBrainz Auth Router", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
sk = &fakeSessionKeys{KeyName: sessionKeyProperty}
|
sk = &fakeSessionKeys{KeyName: sessionKeyProperty}
|
||||||
httpClient = &tests.FakeHttpClient{}
|
httpClient = &tests.FakeHttpClient{}
|
||||||
cl := NewClient(httpClient)
|
cl := NewClient("http://localhost/", httpClient)
|
||||||
r = Router{
|
r = Router{
|
||||||
sessionKeys: sk,
|
sessionKeys: sk,
|
||||||
client: cl,
|
client: cl,
|
||||||
|
|
|
@ -6,14 +6,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/navidrome/navidrome/log"
|
"github.com/navidrome/navidrome/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
apiBaseUrl = "https://api.listenbrainz.org/1/"
|
|
||||||
)
|
|
||||||
|
|
||||||
type listenBrainzError struct {
|
type listenBrainzError struct {
|
||||||
Code int
|
Code int
|
||||||
Message string
|
Message string
|
||||||
|
@ -27,12 +25,13 @@ type httpDoer interface {
|
||||||
Do(req *http.Request) (*http.Response, error)
|
Do(req *http.Request) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(hc httpDoer) *Client {
|
func NewClient(baseURL string, hc httpDoer) *Client {
|
||||||
return &Client{hc}
|
return &Client{baseURL, hc}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
hc httpDoer
|
baseURL string
|
||||||
|
hc httpDoer
|
||||||
}
|
}
|
||||||
|
|
||||||
type listenBrainzResponse struct {
|
type listenBrainzResponse struct {
|
||||||
|
@ -128,9 +127,22 @@ func (c *Client) Scrobble(ctx context.Context, apiKey string, li listenInfo) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) path(endpoint string) (string, error) {
|
||||||
|
u, err := url.Parse(c.baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, endpoint)
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) makeRequest(method string, endpoint string, r *listenBrainzRequest) (*listenBrainzResponse, error) {
|
func (c *Client) makeRequest(method string, endpoint string, r *listenBrainzRequest) (*listenBrainzResponse, error) {
|
||||||
b, _ := json.Marshal(r.Body)
|
b, _ := json.Marshal(r.Body)
|
||||||
req, _ := http.NewRequest(method, apiBaseUrl+endpoint, bytes.NewBuffer(b))
|
uri, err := c.path(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequest(method, uri, bytes.NewBuffer(b))
|
||||||
|
|
||||||
if r.ApiKey != "" {
|
if r.ApiKey != "" {
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Token %s", r.ApiKey))
|
req.Header.Add("Authorization", fmt.Sprintf("Token %s", r.ApiKey))
|
||||||
|
|
|
@ -18,7 +18,7 @@ var _ = Describe("Client", func() {
|
||||||
var client *Client
|
var client *Client
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
httpClient = &tests.FakeHttpClient{}
|
httpClient = &tests.FakeHttpClient{}
|
||||||
client = NewClient(httpClient)
|
client = NewClient("BASE_URL/", httpClient)
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("listenBrainzResponse", func() {
|
Describe("listenBrainzResponse", func() {
|
||||||
|
@ -48,7 +48,7 @@ var _ = Describe("Client", func() {
|
||||||
_, err := client.ValidateToken(context.Background(), "LB-TOKEN")
|
_, err := client.ValidateToken(context.Background(), "LB-TOKEN")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodGet))
|
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodGet))
|
||||||
Expect(httpClient.SavedRequest.URL.String()).To(Equal(apiBaseUrl + "validate-token"))
|
Expect(httpClient.SavedRequest.URL.String()).To(Equal("BASE_URL/validate-token"))
|
||||||
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ var _ = Describe("Client", func() {
|
||||||
It("formats the request properly", func() {
|
It("formats the request properly", func() {
|
||||||
Expect(client.UpdateNowPlaying(context.Background(), "LB-TOKEN", li)).To(Succeed())
|
Expect(client.UpdateNowPlaying(context.Background(), "LB-TOKEN", li)).To(Succeed())
|
||||||
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodPost))
|
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodPost))
|
||||||
Expect(httpClient.SavedRequest.URL.String()).To(Equal(apiBaseUrl + "submit-listens"))
|
Expect(httpClient.SavedRequest.URL.String()).To(Equal("BASE_URL/submit-listens"))
|
||||||
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
||||||
|
|
||||||
body, _ := io.ReadAll(httpClient.SavedRequest.Body)
|
body, _ := io.ReadAll(httpClient.SavedRequest.Body)
|
||||||
|
@ -103,7 +103,7 @@ var _ = Describe("Client", func() {
|
||||||
It("formats the request properly", func() {
|
It("formats the request properly", func() {
|
||||||
Expect(client.Scrobble(context.Background(), "LB-TOKEN", li)).To(Succeed())
|
Expect(client.Scrobble(context.Background(), "LB-TOKEN", li)).To(Succeed())
|
||||||
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodPost))
|
Expect(httpClient.SavedRequest.Method).To(Equal(http.MethodPost))
|
||||||
Expect(httpClient.SavedRequest.URL.String()).To(Equal(apiBaseUrl + "submit-listens"))
|
Expect(httpClient.SavedRequest.URL.String()).To(Equal("BASE_URL/submit-listens"))
|
||||||
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
Expect(httpClient.SavedRequest.Header.Get("Authorization")).To(Equal("Token LB-TOKEN"))
|
||||||
|
|
||||||
body, _ := io.ReadAll(httpClient.SavedRequest.Body)
|
body, _ := io.ReadAll(httpClient.SavedRequest.Body)
|
||||||
|
|
|
@ -100,7 +100,7 @@ func checkExternalCredentials() {
|
||||||
if !conf.Server.ListenBrainz.Enabled {
|
if !conf.Server.ListenBrainz.Enabled {
|
||||||
log.Info("ListenBrainz integration is DISABLED")
|
log.Info("ListenBrainz integration is DISABLED")
|
||||||
} else {
|
} else {
|
||||||
log.Debug("ListenBrainz integration is ENABLED")
|
log.Debug("ListenBrainz integration is ENABLED", "ListenBrainz.BaseURL", conf.Server.ListenBrainz.BaseURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.Server.Spotify.ID == "" || conf.Server.Spotify.Secret == "" {
|
if conf.Server.Spotify.ID == "" || conf.Server.Spotify.Secret == "" {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue