Code style: All uppercase acronyms URL, ISRC, ID, HTTP

This commit is contained in:
Philipp Wolfer 2025-04-29 13:23:41 +02:00
parent 39b31fc664
commit d51c97c648
No known key found for this signature in database
GPG key ID: 8FDF744D4919943B
26 changed files with 137 additions and 137 deletions

View file

@ -27,7 +27,7 @@ type OAuth2Authenticator interface {
models.Backend models.Backend
// Returns OAuth2 config suitable for this backend // Returns OAuth2 config suitable for this backend
OAuth2Strategy(redirectUrl *url.URL) OAuth2Strategy OAuth2Strategy(redirectURL *url.URL) OAuth2Strategy
// Setup the OAuth2 client // Setup the OAuth2 client
OAuth2Setup(token oauth2.TokenSource) error OAuth2Setup(token oauth2.TokenSource) error

View file

@ -24,14 +24,14 @@ import (
type OAuth2Strategy interface { type OAuth2Strategy interface {
Config() oauth2.Config Config() oauth2.Config
AuthCodeURL(verifier string, state string) AuthUrl AuthCodeURL(verifier string, state string) AuthURL
ExchangeToken(code CodeResponse, verifier string) (*oauth2.Token, error) ExchangeToken(code CodeResponse, verifier string) (*oauth2.Token, error)
} }
type AuthUrl struct { type AuthURL struct {
// The URL the user must visit to approve access // The URL the user must visit to approve access
Url string URL string
// Random state string passed on to the callback. // Random state string passed on to the callback.
// Leave empty if the service does not support state. // Leave empty if the service does not support state.
State string State string
@ -56,10 +56,10 @@ func (s StandardStrategy) Config() oauth2.Config {
return s.conf return s.conf
} }
func (s StandardStrategy) AuthCodeURL(verifier string, state string) AuthUrl { func (s StandardStrategy) AuthCodeURL(verifier string, state string) AuthURL {
url := s.conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(verifier)) url := s.conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(verifier))
return AuthUrl{ return AuthURL{
Url: url, URL: url,
State: state, State: state,
Param: "code", Param: "code",
} }

View file

@ -33,10 +33,10 @@ func (s deezerStrategy) Config() oauth2.Config {
return s.conf return s.conf
} }
func (s deezerStrategy) AuthCodeURL(verifier string, state string) auth.AuthUrl { func (s deezerStrategy) AuthCodeURL(verifier string, state string) auth.AuthURL {
url := s.conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(verifier)) url := s.conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(verifier))
return auth.AuthUrl{ return auth.AuthURL{
Url: url, URL: url,
State: state, State: state,
Param: "code", Param: "code",
} }

View file

@ -36,7 +36,7 @@ const MaxItemsPerGet = 1000
const DefaultRateLimitWaitSeconds = 5 const DefaultRateLimitWaitSeconds = 5
type Client struct { type Client struct {
HttpClient *resty.Client HTTPClient *resty.Client
token oauth2.TokenSource token oauth2.TokenSource
} }
@ -47,7 +47,7 @@ func NewClient(token oauth2.TokenSource) Client {
client.SetHeader("User-Agent", version.UserAgent()) client.SetHeader("User-Agent", version.UserAgent())
client.SetRetryCount(5) client.SetRetryCount(5)
return Client{ return Client{
HttpClient: client, HTTPClient: client,
token: token, token: token,
} }
} }
@ -73,7 +73,7 @@ func (c Client) setToken(req *resty.Request) error {
} }
func listRequest[T Result](c Client, path string, offset int, limit int) (result T, err error) { func listRequest[T Result](c Client, path string, offset int, limit int) (result T, err error) {
request := c.HttpClient.R(). request := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"index": strconv.Itoa(offset), "index": strconv.Itoa(offset),
"limit": strconv.Itoa(limit), "limit": strconv.Itoa(limit),

View file

@ -44,7 +44,7 @@ func TestGetUserHistory(t *testing.T) {
token := oauth2.StaticTokenSource(&oauth2.Token{}) token := oauth2.StaticTokenSource(&oauth2.Token{})
client := deezer.NewClient(token) client := deezer.NewClient(token)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.deezer.com/user/me/history", "https://api.deezer.com/user/me/history",
"testdata/user-history.json") "testdata/user-history.json")
@ -65,7 +65,7 @@ func TestGetUserTracks(t *testing.T) {
token := oauth2.StaticTokenSource(&oauth2.Token{}) token := oauth2.StaticTokenSource(&oauth2.Token{})
client := deezer.NewClient(token) client := deezer.NewClient(token)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.deezer.com/user/me/tracks", "https://api.deezer.com/user/me/tracks",
"testdata/user-tracks.json") "testdata/user-tracks.json")
@ -81,7 +81,7 @@ func TestGetUserTracks(t *testing.T) {
assert.Equal("Outland", track1.Track.Album.Title) assert.Equal("Outland", track1.Track.Album.Title)
} }
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) { func setupHTTPMock(t *testing.T, client *http.Client, url string, testDataPath string) {
httpmock.ActivateNonDefault(client) httpmock.ActivateNonDefault(client)
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath)) responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))

View file

@ -31,7 +31,7 @@ import (
type DeezerApiBackend struct { type DeezerApiBackend struct {
client Client client Client
clientId string clientID string
clientSecret string clientSecret string
} }
@ -50,19 +50,19 @@ func (b *DeezerApiBackend) Options() []models.BackendOption {
} }
func (b *DeezerApiBackend) InitConfig(config *config.ServiceConfig) error { func (b *DeezerApiBackend) InitConfig(config *config.ServiceConfig) error {
b.clientId = config.GetString("client-id") b.clientID = config.GetString("client-id")
b.clientSecret = config.GetString("client-secret") b.clientSecret = config.GetString("client-secret")
return nil return nil
} }
func (b *DeezerApiBackend) OAuth2Strategy(redirectUrl *url.URL) auth.OAuth2Strategy { func (b *DeezerApiBackend) OAuth2Strategy(redirectURL *url.URL) auth.OAuth2Strategy {
conf := oauth2.Config{ conf := oauth2.Config{
ClientID: b.clientId, ClientID: b.clientID,
ClientSecret: b.clientSecret, ClientSecret: b.clientSecret,
Scopes: []string{ Scopes: []string{
"offline_access,basic_access,listening_history", "offline_access,basic_access,listening_history",
}, },
RedirectURL: redirectUrl.String(), RedirectURL: redirectURL.String(),
Endpoint: oauth2.Endpoint{ Endpoint: oauth2.Endpoint{
AuthURL: "https://connect.deezer.com/oauth/auth.php", AuthURL: "https://connect.deezer.com/oauth/auth.php",
TokenURL: "https://connect.deezer.com/oauth/access_token.php", TokenURL: "https://connect.deezer.com/oauth/access_token.php",
@ -244,8 +244,8 @@ func (t Track) AsTrack() models.Track {
info["music_service"] = "deezer.com" info["music_service"] = "deezer.com"
info["origin_url"] = t.Link info["origin_url"] = t.Link
info["deezer_id"] = t.Link info["deezer_id"] = t.Link
info["deezer_album_id"] = fmt.Sprintf("https://www.deezer.com/album/%v", t.Album.Id) info["deezer_album_id"] = fmt.Sprintf("https://www.deezer.com/album/%v", t.Album.ID)
info["deezer_artist_id"] = fmt.Sprintf("https://www.deezer.com/artist/%v", t.Artist.Id) info["deezer_artist_id"] = fmt.Sprintf("https://www.deezer.com/artist/%v", t.Artist.ID)
return track return track
} }

View file

@ -51,7 +51,7 @@ type HistoryResult struct {
} }
type Track struct { type Track struct {
Id int `json:"id"` ID int `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Link string `json:"link"` Link string `json:"link"`
Title string `json:"title"` Title string `json:"title"`
@ -75,7 +75,7 @@ type LovedTrack struct {
} }
type Album struct { type Album struct {
Id int `json:"id"` ID int `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Link string `json:"link"` Link string `json:"link"`
Title string `json:"title"` Title string `json:"title"`
@ -83,7 +83,7 @@ type Album struct {
} }
type Artist struct { type Artist struct {
Id int `json:"id"` ID int `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Link string `json:"link"` Link string `json:"link"`
Name string `json:"name"` Name string `json:"name"`

View file

@ -33,13 +33,13 @@ import (
const MaxItemsPerGet = 50 const MaxItemsPerGet = 50
type Client struct { type Client struct {
HttpClient *resty.Client HTTPClient *resty.Client
token string token string
} }
func NewClient(serverUrl string, token string) Client { func NewClient(serverURL string, token string) Client {
client := resty.New() client := resty.New()
client.SetBaseURL(serverUrl) client.SetBaseURL(serverURL)
client.SetAuthScheme("Bearer") client.SetAuthScheme("Bearer")
client.SetAuthToken(token) client.SetAuthToken(token)
client.SetHeader("Accept", "application/json") client.SetHeader("Accept", "application/json")
@ -49,14 +49,14 @@ func NewClient(serverUrl string, token string) Client {
ratelimit.EnableHTTPHeaderRateLimit(client, "Retry-After") ratelimit.EnableHTTPHeaderRateLimit(client, "Retry-After")
return Client{ return Client{
HttpClient: client, HTTPClient: client,
token: token, token: token,
} }
} }
func (c Client) GetHistoryListenings(user string, page int, perPage int) (result ListeningsResult, err error) { func (c Client) GetHistoryListenings(user string, page int, perPage int) (result ListeningsResult, err error) {
const path = "/api/v1/history/listenings" const path = "/api/v1/history/listenings"
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"username": user, "username": user,
"page": strconv.Itoa(page), "page": strconv.Itoa(page),
@ -75,7 +75,7 @@ func (c Client) GetHistoryListenings(user string, page int, perPage int) (result
func (c Client) GetFavoriteTracks(page int, perPage int) (result FavoriteTracksResult, err error) { func (c Client) GetFavoriteTracks(page int, perPage int) (result FavoriteTracksResult, err error) {
const path = "/api/v1/favorites/tracks" const path = "/api/v1/favorites/tracks"
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"page": strconv.Itoa(page), "page": strconv.Itoa(page),
"page_size": strconv.Itoa(perPage), "page_size": strconv.Itoa(perPage),

View file

@ -32,20 +32,20 @@ import (
) )
func TestNewClient(t *testing.T) { func TestNewClient(t *testing.T) {
serverUrl := "https://funkwhale.example.com" serverURL := "https://funkwhale.example.com"
token := "foobar123" token := "foobar123"
client := funkwhale.NewClient(serverUrl, token) client := funkwhale.NewClient(serverURL, token)
assert.Equal(t, serverUrl, client.HttpClient.BaseURL) assert.Equal(t, serverURL, client.HTTPClient.BaseURL)
assert.Equal(t, token, client.HttpClient.Token) assert.Equal(t, token, client.HTTPClient.Token)
} }
func TestGetHistoryListenings(t *testing.T) { func TestGetHistoryListenings(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
serverUrl := "https://funkwhale.example.com" serverURL := "https://funkwhale.example.com"
token := "thetoken" token := "thetoken"
client := funkwhale.NewClient(serverUrl, token) client := funkwhale.NewClient(serverURL, token)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://funkwhale.example.com/api/v1/history/listenings", "https://funkwhale.example.com/api/v1/history/listenings",
"testdata/listenings.json") "testdata/listenings.json")
@ -67,9 +67,9 @@ func TestGetFavoriteTracks(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
token := "thetoken" token := "thetoken"
serverUrl := "https://funkwhale.example.com" serverURL := "https://funkwhale.example.com"
client := funkwhale.NewClient(serverUrl, token) client := funkwhale.NewClient(serverURL, token)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://funkwhale.example.com/api/v1/favorites/tracks", "https://funkwhale.example.com/api/v1/favorites/tracks",
"testdata/favorite-tracks.json") "testdata/favorite-tracks.json")
@ -87,7 +87,7 @@ func TestGetFavoriteTracks(t *testing.T) {
assert.Equal("phw", fav1.User.UserName) assert.Equal("phw", fav1.User.UserName)
} }
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) { func setupHTTPMock(t *testing.T, client *http.Client, url string, testDataPath string) {
httpmock.ActivateNonDefault(client) httpmock.ActivateNonDefault(client)
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath)) responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))

View file

@ -31,7 +31,7 @@ type ListeningsResult struct {
} }
type Listening struct { type Listening struct {
Id int `json:"int"` ID int `json:"int"`
User User `json:"user"` User User `json:"user"`
Track Track `json:"track"` Track Track `json:"track"`
CreationDate string `json:"creation_date"` CreationDate string `json:"creation_date"`
@ -45,14 +45,14 @@ type FavoriteTracksResult struct {
} }
type FavoriteTrack struct { type FavoriteTrack struct {
Id int `json:"int"` ID int `json:"int"`
User User `json:"user"` User User `json:"user"`
Track Track `json:"track"` Track Track `json:"track"`
CreationDate string `json:"creation_date"` CreationDate string `json:"creation_date"`
} }
type Track struct { type Track struct {
Id int `json:"int"` ID int `json:"int"`
Artist Artist `json:"artist"` Artist Artist `json:"artist"`
Album Album `json:"album"` Album Album `json:"album"`
Title string `json:"title"` Title string `json:"title"`
@ -64,13 +64,13 @@ type Track struct {
} }
type Artist struct { type Artist struct {
Id int `json:"int"` ID int `json:"int"`
Name string `json:"name"` Name string `json:"name"`
ArtistMBID mbtypes.MBID `json:"mbid"` ArtistMBID mbtypes.MBID `json:"mbid"`
} }
type Album struct { type Album struct {
Id int `json:"int"` ID int `json:"int"`
Title string `json:"title"` Title string `json:"title"`
AlbumArtist Artist `json:"artist"` AlbumArtist Artist `json:"artist"`
ReleaseDate string `json:"release_date"` ReleaseDate string `json:"release_date"`
@ -79,7 +79,7 @@ type Album struct {
} }
type User struct { type User struct {
Id int `json:"int"` ID int `json:"int"`
UserName string `json:"username"` UserName string `json:"username"`
} }

View file

@ -69,7 +69,7 @@ func (b *JSPFBackend) InitConfig(config *config.ServiceConfig) error {
Identifier: config.GetString("identifier"), Identifier: config.GetString("identifier"),
Tracks: make([]jspf.Track, 0), Tracks: make([]jspf.Track, 0),
Extension: map[string]any{ Extension: map[string]any{
jspf.MusicBrainzPlaylistExtensionId: jspf.MusicBrainzPlaylistExtension{ jspf.MusicBrainzPlaylistExtensionID: jspf.MusicBrainzPlaylistExtension{
LastModifiedAt: time.Now(), LastModifiedAt: time.Now(),
Public: true, Public: true,
}, },
@ -116,7 +116,7 @@ func listenAsTrack(l models.Listen) jspf.Track {
extension := makeMusicBrainzExtension(l.Track) extension := makeMusicBrainzExtension(l.Track)
extension.AddedAt = l.ListenedAt extension.AddedAt = l.ListenedAt
extension.AddedBy = l.UserName extension.AddedBy = l.UserName
track.Extension[jspf.MusicBrainzTrackExtensionId] = extension track.Extension[jspf.MusicBrainzTrackExtensionID] = extension
if l.RecordingMBID != "" { if l.RecordingMBID != "" {
track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(l.RecordingMBID)) track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(l.RecordingMBID))
@ -131,7 +131,7 @@ func loveAsTrack(l models.Love) jspf.Track {
extension := makeMusicBrainzExtension(l.Track) extension := makeMusicBrainzExtension(l.Track)
extension.AddedAt = l.Created extension.AddedAt = l.Created
extension.AddedBy = l.UserName extension.AddedBy = l.UserName
track.Extension[jspf.MusicBrainzTrackExtensionId] = extension track.Extension[jspf.MusicBrainzTrackExtensionID] = extension
recordingMBID := l.Track.RecordingMBID recordingMBID := l.Track.RecordingMBID
if l.RecordingMBID != "" { if l.RecordingMBID != "" {

View file

@ -25,21 +25,21 @@ import (
type lastfmStrategy struct { type lastfmStrategy struct {
client *lastfm.Api client *lastfm.Api
redirectUrl *url.URL redirectURL *url.URL
} }
func (s lastfmStrategy) Config() oauth2.Config { func (s lastfmStrategy) Config() oauth2.Config {
return oauth2.Config{} return oauth2.Config{}
} }
func (s lastfmStrategy) AuthCodeURL(verifier string, state string) auth.AuthUrl { func (s lastfmStrategy) AuthCodeURL(verifier string, state string) auth.AuthURL {
// Last.fm does not use OAuth2, but the provided authorization flow with // Last.fm does not use OAuth2, but the provided authorization flow with
// callback URL is close enough we can shoehorn it into the existing // callback URL is close enough we can shoehorn it into the existing
// authentication strategy. // authentication strategy.
// TODO: Investigate and use callback-less flow with api.GetAuthTokenUrl(token) // TODO: Investigate and use callback-less flow with api.GetAuthTokenUrl(token)
url := s.client.GetAuthRequestUrl(s.redirectUrl.String()) url := s.client.GetAuthRequestUrl(s.redirectURL.String())
return auth.AuthUrl{ return auth.AuthURL{
Url: url, URL: url,
State: "", // last.fm does not use state State: "", // last.fm does not use state
Param: "token", Param: "token",
} }

View file

@ -62,9 +62,9 @@ func (b *LastfmApiBackend) Options() []models.BackendOption {
} }
func (b *LastfmApiBackend) InitConfig(config *config.ServiceConfig) error { func (b *LastfmApiBackend) InitConfig(config *config.ServiceConfig) error {
clientId := config.GetString("client-id") clientID := config.GetString("client-id")
clientSecret := config.GetString("client-secret") clientSecret := config.GetString("client-secret")
b.client = lastfm.New(clientId, clientSecret) b.client = lastfm.New(clientID, clientSecret)
b.username = config.GetString("username") b.username = config.GetString("username")
return nil return nil
} }
@ -72,10 +72,10 @@ func (b *LastfmApiBackend) InitConfig(config *config.ServiceConfig) error {
func (b *LastfmApiBackend) StartImport() error { return nil } func (b *LastfmApiBackend) StartImport() error { return nil }
func (b *LastfmApiBackend) FinishImport() error { return nil } func (b *LastfmApiBackend) FinishImport() error { return nil }
func (b *LastfmApiBackend) OAuth2Strategy(redirectUrl *url.URL) auth.OAuth2Strategy { func (b *LastfmApiBackend) OAuth2Strategy(redirectURL *url.URL) auth.OAuth2Strategy {
return lastfmStrategy{ return lastfmStrategy{
client: b.client, client: b.client,
redirectUrl: redirectUrl, redirectURL: redirectURL,
} }
} }

View file

@ -39,7 +39,7 @@ const (
) )
type Client struct { type Client struct {
HttpClient *resty.Client HTTPClient *resty.Client
MaxResults int MaxResults int
} }
@ -55,7 +55,7 @@ func NewClient(token string) Client {
ratelimit.EnableHTTPHeaderRateLimit(client, "X-RateLimit-Reset-In") ratelimit.EnableHTTPHeaderRateLimit(client, "X-RateLimit-Reset-In")
return Client{ return Client{
HttpClient: client, HTTPClient: client,
MaxResults: DefaultItemsPerGet, MaxResults: DefaultItemsPerGet,
} }
} }
@ -63,7 +63,7 @@ func NewClient(token string) Client {
func (c Client) GetListens(user string, maxTime time.Time, minTime time.Time) (result GetListensResult, err error) { func (c Client) GetListens(user string, maxTime time.Time, minTime time.Time) (result GetListensResult, err error) {
const path = "/user/{username}/listens" const path = "/user/{username}/listens"
errorResult := ErrorResult{} errorResult := ErrorResult{}
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetPathParam("username", user). SetPathParam("username", user).
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"max_ts": strconv.FormatInt(maxTime.Unix(), 10), "max_ts": strconv.FormatInt(maxTime.Unix(), 10),
@ -84,7 +84,7 @@ func (c Client) GetListens(user string, maxTime time.Time, minTime time.Time) (r
func (c Client) SubmitListens(listens ListenSubmission) (result StatusResult, err error) { func (c Client) SubmitListens(listens ListenSubmission) (result StatusResult, err error) {
const path = "/submit-listens" const path = "/submit-listens"
errorResult := ErrorResult{} errorResult := ErrorResult{}
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetBody(listens). SetBody(listens).
SetResult(&result). SetResult(&result).
SetError(&errorResult). SetError(&errorResult).
@ -100,7 +100,7 @@ func (c Client) SubmitListens(listens ListenSubmission) (result StatusResult, er
func (c Client) GetFeedback(user string, status int, offset int) (result GetFeedbackResult, err error) { func (c Client) GetFeedback(user string, status int, offset int) (result GetFeedbackResult, err error) {
const path = "/feedback/user/{username}/get-feedback" const path = "/feedback/user/{username}/get-feedback"
errorResult := ErrorResult{} errorResult := ErrorResult{}
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetPathParam("username", user). SetPathParam("username", user).
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"status": strconv.Itoa(status), "status": strconv.Itoa(status),
@ -122,7 +122,7 @@ func (c Client) GetFeedback(user string, status int, offset int) (result GetFeed
func (c Client) SendFeedback(feedback Feedback) (result StatusResult, err error) { func (c Client) SendFeedback(feedback Feedback) (result StatusResult, err error) {
const path = "/feedback/recording-feedback" const path = "/feedback/recording-feedback"
errorResult := ErrorResult{} errorResult := ErrorResult{}
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetBody(feedback). SetBody(feedback).
SetResult(&result). SetResult(&result).
SetError(&errorResult). SetError(&errorResult).
@ -138,7 +138,7 @@ func (c Client) SendFeedback(feedback Feedback) (result StatusResult, err error)
func (c Client) Lookup(recordingName string, artistName string) (result LookupResult, err error) { func (c Client) Lookup(recordingName string, artistName string) (result LookupResult, err error) {
const path = "/metadata/lookup" const path = "/metadata/lookup"
errorResult := ErrorResult{} errorResult := ErrorResult{}
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"recording_name": recordingName, "recording_name": recordingName,
"artist_name": artistName, "artist_name": artistName,

View file

@ -36,7 +36,7 @@ import (
func TestNewClient(t *testing.T) { func TestNewClient(t *testing.T) {
token := "foobar123" token := "foobar123"
client := listenbrainz.NewClient(token) client := listenbrainz.NewClient(token)
assert.Equal(t, token, client.HttpClient.Token) assert.Equal(t, token, client.HTTPClient.Token)
assert.Equal(t, listenbrainz.DefaultItemsPerGet, client.MaxResults) assert.Equal(t, listenbrainz.DefaultItemsPerGet, client.MaxResults)
} }
@ -45,7 +45,7 @@ func TestGetListens(t *testing.T) {
client := listenbrainz.NewClient("thetoken") client := listenbrainz.NewClient("thetoken")
client.MaxResults = 2 client.MaxResults = 2
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.listenbrainz.org/1/user/outsidecontext/listens", "https://api.listenbrainz.org/1/user/outsidecontext/listens",
"testdata/listens.json") "testdata/listens.json")
@ -62,7 +62,7 @@ func TestGetListens(t *testing.T) {
func TestSubmitListens(t *testing.T) { func TestSubmitListens(t *testing.T) {
client := listenbrainz.NewClient("thetoken") client := listenbrainz.NewClient("thetoken")
httpmock.ActivateNonDefault(client.HttpClient.GetClient()) httpmock.ActivateNonDefault(client.HTTPClient.GetClient())
responder, err := httpmock.NewJsonResponder(200, listenbrainz.StatusResult{ responder, err := httpmock.NewJsonResponder(200, listenbrainz.StatusResult{
Status: "ok", Status: "ok",
@ -103,7 +103,7 @@ func TestGetFeedback(t *testing.T) {
client := listenbrainz.NewClient("thetoken") client := listenbrainz.NewClient("thetoken")
client.MaxResults = 2 client.MaxResults = 2
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.listenbrainz.org/1/feedback/user/outsidecontext/get-feedback", "https://api.listenbrainz.org/1/feedback/user/outsidecontext/get-feedback",
"testdata/feedback.json") "testdata/feedback.json")
@ -120,7 +120,7 @@ func TestGetFeedback(t *testing.T) {
func TestSendFeedback(t *testing.T) { func TestSendFeedback(t *testing.T) {
client := listenbrainz.NewClient("thetoken") client := listenbrainz.NewClient("thetoken")
httpmock.ActivateNonDefault(client.HttpClient.GetClient()) httpmock.ActivateNonDefault(client.HTTPClient.GetClient())
responder, err := httpmock.NewJsonResponder(200, listenbrainz.StatusResult{ responder, err := httpmock.NewJsonResponder(200, listenbrainz.StatusResult{
Status: "ok", Status: "ok",
@ -145,7 +145,7 @@ func TestLookup(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
client := listenbrainz.NewClient("thetoken") client := listenbrainz.NewClient("thetoken")
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.listenbrainz.org/1/metadata/lookup", "https://api.listenbrainz.org/1/metadata/lookup",
"testdata/lookup.json") "testdata/lookup.json")
@ -158,7 +158,7 @@ func TestLookup(t *testing.T) {
assert.Equal(mbtypes.MBID("569436a1-234a-44bc-a370-8f4d252bef21"), result.RecordingMBID) assert.Equal(mbtypes.MBID("569436a1-234a-44bc-a370-8f4d252bef21"), result.RecordingMBID)
} }
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) { func setupHTTPMock(t *testing.T, client *http.Client, url string, testDataPath string) {
httpmock.ActivateNonDefault(client) httpmock.ActivateNonDefault(client)
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath)) responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))

View file

@ -131,7 +131,7 @@ func TestTrackTrackNumberString(t *testing.T) {
assert.Equal(t, 12, track.TrackNumber()) assert.Equal(t, 12, track.TrackNumber())
} }
func TestTrackIsrc(t *testing.T) { func TestTrackISRC(t *testing.T) {
expected := mbtypes.ISRC("TCAEJ1934417") expected := mbtypes.ISRC("TCAEJ1934417")
track := listenbrainz.Track{ track := listenbrainz.Track{
AdditionalInfo: map[string]any{ AdditionalInfo: map[string]any{

View file

@ -32,25 +32,25 @@ import (
const MaxItemsPerGet = 1000 const MaxItemsPerGet = 1000
type Client struct { type Client struct {
HttpClient *resty.Client HTTPClient *resty.Client
token string token string
} }
func NewClient(serverUrl string, token string) Client { func NewClient(serverURL string, token string) Client {
client := resty.New() client := resty.New()
client.SetBaseURL(serverUrl) client.SetBaseURL(serverURL)
client.SetHeader("Accept", "application/json") client.SetHeader("Accept", "application/json")
client.SetHeader("User-Agent", version.UserAgent()) client.SetHeader("User-Agent", version.UserAgent())
client.SetRetryCount(5) client.SetRetryCount(5)
return Client{ return Client{
HttpClient: client, HTTPClient: client,
token: token, token: token,
} }
} }
func (c Client) GetScrobbles(page int, perPage int) (result GetScrobblesResult, err error) { func (c Client) GetScrobbles(page int, perPage int) (result GetScrobblesResult, err error) {
const path = "/apis/mlj_1/scrobbles" const path = "/apis/mlj_1/scrobbles"
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"page": strconv.Itoa(page), "page": strconv.Itoa(page),
"perpage": strconv.Itoa(perPage), "perpage": strconv.Itoa(perPage),
@ -68,7 +68,7 @@ func (c Client) GetScrobbles(page int, perPage int) (result GetScrobblesResult,
func (c Client) NewScrobble(scrobble NewScrobble) (result NewScrobbleResult, err error) { func (c Client) NewScrobble(scrobble NewScrobble) (result NewScrobbleResult, err error) {
const path = "/apis/mlj_1/newscrobble" const path = "/apis/mlj_1/newscrobble"
scrobble.Key = c.token scrobble.Key = c.token
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetBody(scrobble). SetBody(scrobble).
SetResult(&result). SetResult(&result).
Post(path) Post(path)

View file

@ -32,19 +32,19 @@ import (
) )
func TestNewClient(t *testing.T) { func TestNewClient(t *testing.T) {
serverUrl := "https://maloja.example.com" serverURL := "https://maloja.example.com"
token := "foobar123" token := "foobar123"
client := maloja.NewClient(serverUrl, token) client := maloja.NewClient(serverURL, token)
assert.Equal(t, serverUrl, client.HttpClient.BaseURL) assert.Equal(t, serverURL, client.HTTPClient.BaseURL)
} }
func TestGetScrobbles(t *testing.T) { func TestGetScrobbles(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
serverUrl := "https://maloja.example.com" serverURL := "https://maloja.example.com"
token := "thetoken" token := "thetoken"
client := maloja.NewClient(serverUrl, token) client := maloja.NewClient(serverURL, token)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://maloja.example.com/apis/mlj_1/scrobbles", "https://maloja.example.com/apis/mlj_1/scrobbles",
"testdata/scrobbles.json") "testdata/scrobbles.json")
@ -60,7 +60,7 @@ func TestGetScrobbles(t *testing.T) {
func TestNewScrobble(t *testing.T) { func TestNewScrobble(t *testing.T) {
server := "https://maloja.example.com" server := "https://maloja.example.com"
client := maloja.NewClient(server, "thetoken") client := maloja.NewClient(server, "thetoken")
httpmock.ActivateNonDefault(client.HttpClient.GetClient()) httpmock.ActivateNonDefault(client.HTTPClient.GetClient())
responder, err := httpmock.NewJsonResponder(200, httpmock.File("testdata/newscrobble-result.json")) responder, err := httpmock.NewJsonResponder(200, httpmock.File("testdata/newscrobble-result.json"))
if err != nil { if err != nil {
@ -80,7 +80,7 @@ func TestNewScrobble(t *testing.T) {
assert.Equal(t, "success", result.Status) assert.Equal(t, "success", result.Status)
} }
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) { func setupHTTPMock(t *testing.T, client *http.Client, url string, testDataPath string) {
httpmock.ActivateNonDefault(client) httpmock.ActivateNonDefault(client)
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath)) responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))

View file

@ -40,7 +40,7 @@ const (
) )
type Client struct { type Client struct {
HttpClient *resty.Client HTTPClient *resty.Client
} }
func NewClient(token oauth2.TokenSource) Client { func NewClient(token oauth2.TokenSource) Client {
@ -55,7 +55,7 @@ func NewClient(token oauth2.TokenSource) Client {
ratelimit.EnableHTTPHeaderRateLimit(client, "Retry-After") ratelimit.EnableHTTPHeaderRateLimit(client, "Retry-After")
return Client{ return Client{
HttpClient: client, HTTPClient: client,
} }
} }
@ -69,7 +69,7 @@ func (c Client) RecentlyPlayedBefore(before time.Time, limit int) (RecentlyPlaye
func (c Client) recentlyPlayed(after *time.Time, before *time.Time, limit int) (result RecentlyPlayedResult, err error) { func (c Client) recentlyPlayed(after *time.Time, before *time.Time, limit int) (result RecentlyPlayedResult, err error) {
const path = "/me/player/recently-played" const path = "/me/player/recently-played"
request := c.HttpClient.R(). request := c.HTTPClient.R().
SetQueryParam("limit", strconv.Itoa(limit)). SetQueryParam("limit", strconv.Itoa(limit)).
SetResult(&result) SetResult(&result)
if after != nil { if after != nil {
@ -87,7 +87,7 @@ func (c Client) recentlyPlayed(after *time.Time, before *time.Time, limit int) (
func (c Client) UserTracks(offset int, limit int) (result TracksResult, err error) { func (c Client) UserTracks(offset int, limit int) (result TracksResult, err error) {
const path = "/me/tracks" const path = "/me/tracks"
response, err := c.HttpClient.R(). response, err := c.HTTPClient.R().
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"offset": strconv.Itoa(offset), "offset": strconv.Itoa(offset),
"limit": strconv.Itoa(limit), "limit": strconv.Itoa(limit),

View file

@ -43,7 +43,7 @@ func TestRecentlyPlayedAfter(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
client := spotify.NewClient(nil) client := spotify.NewClient(nil)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.spotify.com/v1/me/player/recently-played", "https://api.spotify.com/v1/me/player/recently-played",
"testdata/recently-played.json") "testdata/recently-played.json")
@ -63,7 +63,7 @@ func TestGetUserTracks(t *testing.T) {
defer httpmock.DeactivateAndReset() defer httpmock.DeactivateAndReset()
client := spotify.NewClient(nil) client := spotify.NewClient(nil)
setupHttpMock(t, client.HttpClient.GetClient(), setupHTTPMock(t, client.HTTPClient.GetClient(),
"https://api.spotify.com/v1/me/tracks", "https://api.spotify.com/v1/me/tracks",
"testdata/user-tracks.json") "testdata/user-tracks.json")
@ -79,7 +79,7 @@ func TestGetUserTracks(t *testing.T) {
assert.Equal("Zeal & Ardor", track1.Track.Album.Name) assert.Equal("Zeal & Ardor", track1.Track.Album.Name)
} }
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) { func setupHTTPMock(t *testing.T, client *http.Client, url string, testDataPath string) {
httpmock.ActivateNonDefault(client) httpmock.ActivateNonDefault(client)
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath)) responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))

View file

@ -58,7 +58,7 @@ type Listen struct {
} }
type Track struct { type Track struct {
Id string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Href string `json:"href"` Href string `json:"href"`
Uri string `json:"uri"` Uri string `json:"uri"`
@ -69,14 +69,14 @@ type Track struct {
Explicit bool `json:"explicit"` Explicit bool `json:"explicit"`
IsLocal bool `json:"is_local"` IsLocal bool `json:"is_local"`
Popularity int `json:"popularity"` Popularity int `json:"popularity"`
ExternalIds ExternalIds `json:"external_ids"` ExternalIDs ExternalIDs `json:"external_ids"`
ExternalUrls ExternalUrls `json:"external_urls"` ExternalURLs ExternalURLs `json:"external_urls"`
Album Album `json:"album"` Album Album `json:"album"`
Artists []Artist `json:"artists"` Artists []Artist `json:"artists"`
} }
type Album struct { type Album struct {
Id string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Href string `json:"href"` Href string `json:"href"`
Uri string `json:"uri"` Uri string `json:"uri"`
@ -85,32 +85,32 @@ type Album struct {
ReleaseDate string `json:"release_date"` ReleaseDate string `json:"release_date"`
ReleaseDatePrecision string `json:"release_date_precision"` ReleaseDatePrecision string `json:"release_date_precision"`
AlbumType string `json:"album_type"` AlbumType string `json:"album_type"`
ExternalUrls ExternalUrls `json:"external_urls"` ExternalURLs ExternalURLs `json:"external_urls"`
Artists []Artist `json:"artists"` Artists []Artist `json:"artists"`
Images []Image `json:"images"` Images []Image `json:"images"`
} }
type Artist struct { type Artist struct {
Id string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Href string `json:"href"` Href string `json:"href"`
Uri string `json:"uri"` Uri string `json:"uri"`
Type string `json:"type"` Type string `json:"type"`
ExternalUrls ExternalUrls `json:"external_urls"` ExternalURLs ExternalURLs `json:"external_urls"`
} }
type ExternalIds struct { type ExternalIDs struct {
ISRC mbtypes.ISRC `json:"isrc"` ISRC mbtypes.ISRC `json:"isrc"`
EAN string `json:"ean"` EAN string `json:"ean"`
UPC string `json:"upc"` UPC string `json:"upc"`
} }
type ExternalUrls struct { type ExternalURLs struct {
Spotify string `json:"spotify"` Spotify string `json:"spotify"`
} }
type Image struct { type Image struct {
Url string `json:"url"` URL string `json:"url"`
Height int `json:"height"` Height int `json:"height"`
Width int `json:"width"` Width int `json:"width"`
} }

View file

@ -34,7 +34,7 @@ import (
type SpotifyApiBackend struct { type SpotifyApiBackend struct {
client Client client Client
clientId string clientID string
clientSecret string clientSecret string
} }
@ -53,14 +53,14 @@ func (b *SpotifyApiBackend) Options() []models.BackendOption {
} }
func (b *SpotifyApiBackend) InitConfig(config *config.ServiceConfig) error { func (b *SpotifyApiBackend) InitConfig(config *config.ServiceConfig) error {
b.clientId = config.GetString("client-id") b.clientID = config.GetString("client-id")
b.clientSecret = config.GetString("client-secret") b.clientSecret = config.GetString("client-secret")
return nil return nil
} }
func (b *SpotifyApiBackend) OAuth2Strategy(redirectUrl *url.URL) auth.OAuth2Strategy { func (b *SpotifyApiBackend) OAuth2Strategy(redirectURL *url.URL) auth.OAuth2Strategy {
conf := oauth2.Config{ conf := oauth2.Config{
ClientID: b.clientId, ClientID: b.clientID,
ClientSecret: b.clientSecret, ClientSecret: b.clientSecret,
Scopes: []string{ Scopes: []string{
"user-read-currently-playing", "user-read-currently-playing",
@ -68,16 +68,16 @@ func (b *SpotifyApiBackend) OAuth2Strategy(redirectUrl *url.URL) auth.OAuth2Stra
"user-library-read", "user-library-read",
"user-library-modify", "user-library-modify",
}, },
RedirectURL: redirectUrl.String(), RedirectURL: redirectURL.String(),
Endpoint: spotify.Endpoint, Endpoint: spotify.Endpoint,
} }
return auth.NewStandardStrategy(conf) return auth.NewStandardStrategy(conf)
} }
func (b *SpotifyApiBackend) OAuth2Config(redirectUrl *url.URL) oauth2.Config { func (b *SpotifyApiBackend) OAuth2Config(redirectURL *url.URL) oauth2.Config {
return oauth2.Config{ return oauth2.Config{
ClientID: b.clientId, ClientID: b.clientID,
ClientSecret: b.clientSecret, ClientSecret: b.clientSecret,
Scopes: []string{ Scopes: []string{
"user-read-currently-playing", "user-read-currently-playing",
@ -85,7 +85,7 @@ func (b *SpotifyApiBackend) OAuth2Config(redirectUrl *url.URL) oauth2.Config {
"user-library-read", "user-library-read",
"user-library-modify", "user-library-modify",
}, },
RedirectURL: redirectUrl.String(), RedirectURL: redirectURL.String(),
Endpoint: spotify.Endpoint, Endpoint: spotify.Endpoint,
} }
} }
@ -251,7 +251,7 @@ func (t Track) AsTrack() models.Track {
Duration: time.Duration(t.DurationMs * int(time.Millisecond)), Duration: time.Duration(t.DurationMs * int(time.Millisecond)),
TrackNumber: t.TrackNumber, TrackNumber: t.TrackNumber,
DiscNumber: t.DiscNumber, DiscNumber: t.DiscNumber,
ISRC: t.ExternalIds.ISRC, ISRC: t.ExternalIDs.ISRC,
AdditionalInfo: map[string]any{}, AdditionalInfo: map[string]any{},
} }
@ -264,30 +264,30 @@ func (t Track) AsTrack() models.Track {
info["music_service"] = "spotify.com" info["music_service"] = "spotify.com"
} }
if t.ExternalUrls.Spotify != "" { if t.ExternalURLs.Spotify != "" {
info["origin_url"] = t.ExternalUrls.Spotify info["origin_url"] = t.ExternalURLs.Spotify
info["spotify_id"] = t.ExternalUrls.Spotify info["spotify_id"] = t.ExternalURLs.Spotify
} }
if t.Album.ExternalUrls.Spotify != "" { if t.Album.ExternalURLs.Spotify != "" {
info["spotify_album_id"] = t.Album.ExternalUrls.Spotify info["spotify_album_id"] = t.Album.ExternalURLs.Spotify
} }
if len(t.Artists) > 0 { if len(t.Artists) > 0 {
info["spotify_artist_ids"] = extractArtistIds(t.Artists) info["spotify_artist_ids"] = extractArtistIDs(t.Artists)
} }
if len(t.Album.Artists) > 0 { if len(t.Album.Artists) > 0 {
info["spotify_album_artist_ids"] = extractArtistIds(t.Album.Artists) info["spotify_album_artist_ids"] = extractArtistIDs(t.Album.Artists)
} }
return track return track
} }
func extractArtistIds(artists []Artist) []string { func extractArtistIDs(artists []Artist) []string {
artistIds := make([]string, len(artists)) artistIDs := make([]string, len(artists))
for i, artist := range artists { for i, artist := range artists {
artistIds[i] = artist.ExternalUrls.Spotify artistIDs[i] = artist.ExternalURLs.Spotify
} }
return artistIds return artistIDs
} }

View file

@ -92,8 +92,8 @@ func (i HistoryItem) AsListen() models.Listen {
PlaybackDuration: time.Duration(i.MillisecondsPlayed * int(time.Millisecond)), PlaybackDuration: time.Duration(i.MillisecondsPlayed * int(time.Millisecond)),
UserName: i.UserName, UserName: i.UserName,
} }
if trackUrl, err := formatSpotifyUri(i.SpotifyTrackUri); err != nil { if trackURL, err := formatSpotifyUri(i.SpotifyTrackUri); err != nil {
listen.AdditionalInfo["spotify_id"] = trackUrl listen.AdditionalInfo["spotify_id"] = trackURL
} }
return listen return listen
} }

View file

@ -43,20 +43,20 @@ func AuthenticationFlow(service config.ServiceConfig, backend auth.OAuth2Authent
state := auth.RandomState() state := auth.RandomState()
// Redirect user to consent page to ask for permission specified scopes. // Redirect user to consent page to ask for permission specified scopes.
authUrl := strategy.AuthCodeURL(verifier, state) authURL := strategy.AuthCodeURL(verifier, state)
// Start an HTTP server to listen for the response // Start an HTTP server to listen for the response
responseChan := make(chan auth.CodeResponse) responseChan := make(chan auth.CodeResponse)
auth.RunOauth2CallbackServer(*redirectURL, authUrl.Param, responseChan) auth.RunOauth2CallbackServer(*redirectURL, authURL.Param, responseChan)
// Open the URL // Open the URL
fmt.Println(i18n.Tr("Visit the URL for authorization: %v", authUrl.Url)) fmt.Println(i18n.Tr("Visit the URL for authorization: %v", authURL.URL))
err = browser.OpenURL(authUrl.Url) err = browser.OpenURL(authURL.URL)
cobra.CheckErr(err) cobra.CheckErr(err)
// Retrieve the code from the authentication callback // Retrieve the code from the authentication callback
code := <-responseChan code := <-responseChan
if code.State != authUrl.State { if code.State != authURL.State {
cobra.CompErrorln(i18n.Tr("Error: OAuth state mismatch")) cobra.CompErrorln(i18n.Tr("Error: OAuth state mismatch"))
os.Exit(1) os.Exit(1)
} }

View file

@ -26,9 +26,9 @@ import "time"
const ( const (
// The identifier for the MusicBrainz / ListenBrainz JSPF playlist extension // The identifier for the MusicBrainz / ListenBrainz JSPF playlist extension
MusicBrainzPlaylistExtensionId = "https://musicbrainz.org/doc/jspf#playlist" MusicBrainzPlaylistExtensionID = "https://musicbrainz.org/doc/jspf#playlist"
// The identifier for the MusicBrainz / ListenBrainz JSPF track extension // The identifier for the MusicBrainz / ListenBrainz JSPF track extension
MusicBrainzTrackExtensionId = "https://musicbrainz.org/doc/jspf#track" MusicBrainzTrackExtensionID = "https://musicbrainz.org/doc/jspf#track"
) )
// MusicBrainz / ListenBrainz JSPF track extension // MusicBrainz / ListenBrainz JSPF track extension

View file

@ -39,7 +39,7 @@ func ExampleMusicBrainzTrackExtension() {
{ {
Title: "Oweynagat", Title: "Oweynagat",
Extension: map[string]any{ Extension: map[string]any{
jspf.MusicBrainzTrackExtensionId: jspf.MusicBrainzTrackExtension{ jspf.MusicBrainzTrackExtensionID: jspf.MusicBrainzTrackExtension{
AddedAt: time.Date(2023, 11, 24, 07, 47, 50, 0, time.UTC), AddedAt: time.Date(2023, 11, 24, 07, 47, 50, 0, time.UTC),
AddedBy: "scotty", AddedBy: "scotty",
}, },