refactor: run Go modernize (#5002)

This commit is contained in:
Maximilian
2026-02-08 08:57:30 -06:00
committed by GitHub
parent 408aa78ed5
commit a704e86ac1
102 changed files with 322 additions and 352 deletions
+2 -2
View File
@@ -252,7 +252,7 @@ var _ = Describe("JWT Authentication", func() {
// Writer goroutine // Writer goroutine
wg.Go(func() { wg.Go(func() {
for i := 0; i < 100; i++ { for i := range 100 {
cache.set(fmt.Sprintf("token-%d", i), 1*time.Hour) cache.set(fmt.Sprintf("token-%d", i), 1*time.Hour)
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
} }
@@ -260,7 +260,7 @@ var _ = Describe("JWT Authentication", func() {
// Reader goroutine // Reader goroutine
wg.Go(func() { wg.Go(func() {
for i := 0; i < 100; i++ { for range 100 {
cache.get() cache.get()
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
} }
+1 -1
View File
@@ -255,7 +255,7 @@ func parseTIPL(tags map[string][]string) {
} }
var currentRole string var currentRole string
var currentValue []string var currentValue []string
for _, part := range strings.Split(tipl[0], " ") { for part := range strings.SplitSeq(tipl[0], " ") {
if _, ok := tiplMapping[part]; ok { if _, ok := tiplMapping[part]; ok {
addRole(currentRole, currentValue) addRole(currentRole, currentValue)
currentRole = part currentRole = part
+1 -1
View File
@@ -65,7 +65,7 @@ func (s *Router) routes() http.Handler {
} }
func (s *Router) getLinkStatus(w http.ResponseWriter, r *http.Request) { func (s *Router) getLinkStatus(w http.ResponseWriter, r *http.Request) {
resp := map[string]interface{}{ resp := map[string]any{
"apiKey": s.apiKey, "apiKey": s.apiKey,
} }
u, _ := request.UserFrom(r.Context()) u, _ := request.UserFrom(r.Context())
+2 -2
View File
@@ -60,7 +60,7 @@ func (s *Router) routes() http.Handler {
} }
func (s *Router) getLinkStatus(w http.ResponseWriter, r *http.Request) { func (s *Router) getLinkStatus(w http.ResponseWriter, r *http.Request) {
resp := map[string]interface{}{} resp := map[string]any{}
u, _ := request.UserFrom(r.Context()) u, _ := request.UserFrom(r.Context())
key, err := s.sessionKeys.Get(r.Context(), u.ID) key, err := s.sessionKeys.Get(r.Context(), u.ID)
if err != nil && !errors.Is(err, model.ErrNotFound) { if err != nil && !errors.Is(err, model.ErrNotFound) {
@@ -107,7 +107,7 @@ func (s *Router) link(w http.ResponseWriter, r *http.Request) {
return return
} }
_ = rest.RespondWithJSON(w, http.StatusOK, map[string]interface{}{"status": resp.Valid, "user": resp.UserName}) _ = rest.RespondWithJSON(w, http.StatusOK, map[string]any{"status": resp.Valid, "user": resp.UserName})
} }
func (s *Router) unlink(w http.ResponseWriter, r *http.Request) { func (s *Router) unlink(w http.ResponseWriter, r *http.Request) {
+3 -3
View File
@@ -37,7 +37,7 @@ var _ = Describe("ListenBrainz Auth Router", func() {
req = httptest.NewRequest("GET", "/listenbrainz/link", nil) req = httptest.NewRequest("GET", "/listenbrainz/link", nil)
r.getLinkStatus(resp, req) r.getLinkStatus(resp, req)
Expect(resp.Code).To(Equal(http.StatusOK)) Expect(resp.Code).To(Equal(http.StatusOK))
var parsed map[string]interface{} var parsed map[string]any
Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil())
Expect(parsed["status"]).To(Equal(false)) Expect(parsed["status"]).To(Equal(false))
}) })
@@ -47,7 +47,7 @@ var _ = Describe("ListenBrainz Auth Router", func() {
req = httptest.NewRequest("GET", "/listenbrainz/link", nil) req = httptest.NewRequest("GET", "/listenbrainz/link", nil)
r.getLinkStatus(resp, req) r.getLinkStatus(resp, req)
Expect(resp.Code).To(Equal(http.StatusOK)) Expect(resp.Code).To(Equal(http.StatusOK))
var parsed map[string]interface{} var parsed map[string]any
Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil())
Expect(parsed["status"]).To(Equal(true)) Expect(parsed["status"]).To(Equal(true))
}) })
@@ -80,7 +80,7 @@ var _ = Describe("ListenBrainz Auth Router", func() {
req = httptest.NewRequest("PUT", "/listenbrainz/link", strings.NewReader(`{"token": "tok-1"}`)) req = httptest.NewRequest("PUT", "/listenbrainz/link", strings.NewReader(`{"token": "tok-1"}`))
r.link(resp, req) r.link(resp, req)
Expect(resp.Code).To(Equal(http.StatusOK)) Expect(resp.Code).To(Equal(http.StatusOK))
var parsed map[string]interface{} var parsed map[string]any
Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil())
Expect(parsed["status"]).To(Equal(true)) Expect(parsed["status"]).To(Equal(true))
Expect(parsed["user"]).To(Equal("ListenBrainzUser")) Expect(parsed["user"]).To(Equal("ListenBrainzUser"))
+2 -2
View File
@@ -75,14 +75,14 @@ const (
type listenInfo struct { type listenInfo struct {
ListenedAt int `json:"listened_at,omitempty"` ListenedAt int `json:"listened_at,omitempty"`
TrackMetadata trackMetadata `json:"track_metadata,omitempty"` TrackMetadata trackMetadata `json:"track_metadata"`
} }
type trackMetadata struct { type trackMetadata struct {
ArtistName string `json:"artist_name,omitempty"` ArtistName string `json:"artist_name,omitempty"`
TrackName string `json:"track_name,omitempty"` TrackName string `json:"track_name,omitempty"`
ReleaseName string `json:"release_name,omitempty"` ReleaseName string `json:"release_name,omitempty"`
AdditionalInfo additionalInfo `json:"additional_info,omitempty"` AdditionalInfo additionalInfo `json:"additional_info"`
} }
type additionalInfo struct { type additionalInfo struct {
+2 -2
View File
@@ -73,7 +73,7 @@ func (c *client) authorize(ctx context.Context) (string, error) {
auth := c.id + ":" + c.secret auth := c.id + ":" + c.secret
req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
response := map[string]interface{}{} response := map[string]any{}
err := c.makeRequest(req, &response) err := c.makeRequest(req, &response)
if err != nil { if err != nil {
return "", err return "", err
@@ -86,7 +86,7 @@ func (c *client) authorize(ctx context.Context) (string, error) {
return "", errors.New("invalid response") return "", errors.New("invalid response")
} }
func (c *client) makeRequest(req *http.Request, response interface{}) error { func (c *client) makeRequest(req *http.Request, response any) error {
log.Trace(req.Context(), fmt.Sprintf("Sending Spotify %s request", req.Method), "url", req.URL) log.Trace(req.Context(), fmt.Sprintf("Sending Spotify %s request", req.Method), "url", req.URL)
resp, err := c.hc.Do(req) resp, err := c.hc.Do(req)
if err != nil { if err != nil {
+5 -10
View File
@@ -7,6 +7,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"slices"
"strings" "strings"
"time" "time"
@@ -433,7 +434,7 @@ func mapDeprecatedOption(legacyName, newName string) {
func parseIniFileConfiguration() { func parseIniFileConfiguration() {
cfgFile := viper.ConfigFileUsed() cfgFile := viper.ConfigFileUsed()
if strings.ToLower(filepath.Ext(cfgFile)) == ".ini" { if strings.ToLower(filepath.Ext(cfgFile)) == ".ini" {
var iniConfig map[string]interface{} var iniConfig map[string]any
err := viper.Unmarshal(&iniConfig) err := viper.Unmarshal(&iniConfig)
if err != nil { if err != nil {
_, _ = fmt.Fprintln(os.Stderr, "FATAL: Error parsing config:", err) _, _ = fmt.Fprintln(os.Stderr, "FATAL: Error parsing config:", err)
@@ -466,7 +467,7 @@ func disableExternalServices() {
} }
func validatePlaylistsPath() error { func validatePlaylistsPath() error {
for _, path := range strings.Split(Server.PlaylistsPath, string(filepath.ListSeparator)) { for path := range strings.SplitSeq(Server.PlaylistsPath, string(filepath.ListSeparator)) {
_, err := doublestar.Match(path, "") _, err := doublestar.Match(path, "")
if err != nil { if err != nil {
log.Error("Invalid PlaylistsPath", "path", path, err) log.Error("Invalid PlaylistsPath", "path", path, err)
@@ -480,7 +481,7 @@ func validatePlaylistsPath() error {
// It trims whitespace from each entry and ensures at least [DefaultInfoLanguage] is returned. // It trims whitespace from each entry and ensures at least [DefaultInfoLanguage] is returned.
func parseLanguages(lang string) []string { func parseLanguages(lang string) []string {
var languages []string var languages []string
for _, l := range strings.Split(lang, ",") { for l := range strings.SplitSeq(lang, ",") {
l = strings.TrimSpace(l) l = strings.TrimSpace(l)
if l != "" { if l != "" {
languages = append(languages, l) languages = append(languages, l)
@@ -494,13 +495,7 @@ func parseLanguages(lang string) []string {
func validatePurgeMissingOption() error { func validatePurgeMissingOption() error {
allowedValues := []string{consts.PurgeMissingNever, consts.PurgeMissingAlways, consts.PurgeMissingFull} allowedValues := []string{consts.PurgeMissingNever, consts.PurgeMissingAlways, consts.PurgeMissingFull}
valid := false valid := slices.Contains(allowedValues, Server.Scanner.PurgeMissing)
for _, v := range allowedValues {
if v == Server.Scanner.PurgeMissing {
valid = true
break
}
}
if !valid { if !valid {
err := fmt.Errorf("invalid Scanner.PurgeMissing value: '%s'. Must be one of: %v", Server.Scanner.PurgeMissing, allowedValues) err := fmt.Errorf("invalid Scanner.PurgeMissing value: '%s'. Must be one of: %v", Server.Scanner.PurgeMissing, allowedValues)
log.Error(err.Error()) log.Error(err.Error())
+13 -13
View File
@@ -365,7 +365,7 @@ var _ = Describe("Agents", func() {
}) })
type mockAgent struct { type mockAgent struct {
Args []interface{} Args []any
Err error Err error
} }
@@ -374,7 +374,7 @@ func (a *mockAgent) AgentName() string {
} }
func (a *mockAgent) GetArtistMBID(_ context.Context, id string, name string) (string, error) { func (a *mockAgent) GetArtistMBID(_ context.Context, id string, name string) (string, error) {
a.Args = []interface{}{id, name} a.Args = []any{id, name}
if a.Err != nil { if a.Err != nil {
return "", a.Err return "", a.Err
} }
@@ -382,7 +382,7 @@ func (a *mockAgent) GetArtistMBID(_ context.Context, id string, name string) (st
} }
func (a *mockAgent) GetArtistURL(_ context.Context, id, name, mbid string) (string, error) { func (a *mockAgent) GetArtistURL(_ context.Context, id, name, mbid string) (string, error) {
a.Args = []interface{}{id, name, mbid} a.Args = []any{id, name, mbid}
if a.Err != nil { if a.Err != nil {
return "", a.Err return "", a.Err
} }
@@ -390,7 +390,7 @@ func (a *mockAgent) GetArtistURL(_ context.Context, id, name, mbid string) (stri
} }
func (a *mockAgent) GetArtistBiography(_ context.Context, id, name, mbid string) (string, error) { func (a *mockAgent) GetArtistBiography(_ context.Context, id, name, mbid string) (string, error) {
a.Args = []interface{}{id, name, mbid} a.Args = []any{id, name, mbid}
if a.Err != nil { if a.Err != nil {
return "", a.Err return "", a.Err
} }
@@ -398,7 +398,7 @@ func (a *mockAgent) GetArtistBiography(_ context.Context, id, name, mbid string)
} }
func (a *mockAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([]ExternalImage, error) { func (a *mockAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([]ExternalImage, error) {
a.Args = []interface{}{id, name, mbid} a.Args = []any{id, name, mbid}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -409,7 +409,7 @@ func (a *mockAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([
} }
func (a *mockAgent) GetSimilarArtists(_ context.Context, id, name, mbid string, limit int) ([]Artist, error) { func (a *mockAgent) GetSimilarArtists(_ context.Context, id, name, mbid string, limit int) ([]Artist, error) {
a.Args = []interface{}{id, name, mbid, limit} a.Args = []any{id, name, mbid, limit}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -420,7 +420,7 @@ func (a *mockAgent) GetSimilarArtists(_ context.Context, id, name, mbid string,
} }
func (a *mockAgent) GetArtistTopSongs(_ context.Context, id, artistName, mbid string, count int) ([]Song, error) { func (a *mockAgent) GetArtistTopSongs(_ context.Context, id, artistName, mbid string, count int) ([]Song, error) {
a.Args = []interface{}{id, artistName, mbid, count} a.Args = []any{id, artistName, mbid, count}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -431,7 +431,7 @@ func (a *mockAgent) GetArtistTopSongs(_ context.Context, id, artistName, mbid st
} }
func (a *mockAgent) GetAlbumInfo(ctx context.Context, name, artist, mbid string) (*AlbumInfo, error) { func (a *mockAgent) GetAlbumInfo(ctx context.Context, name, artist, mbid string) (*AlbumInfo, error) {
a.Args = []interface{}{name, artist, mbid} a.Args = []any{name, artist, mbid}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -444,7 +444,7 @@ func (a *mockAgent) GetAlbumInfo(ctx context.Context, name, artist, mbid string)
} }
func (a *mockAgent) GetSimilarSongsByTrack(_ context.Context, id, name, artist, mbid string, count int) ([]Song, error) { func (a *mockAgent) GetSimilarSongsByTrack(_ context.Context, id, name, artist, mbid string, count int) ([]Song, error) {
a.Args = []interface{}{id, name, artist, mbid, count} a.Args = []any{id, name, artist, mbid, count}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -455,7 +455,7 @@ func (a *mockAgent) GetSimilarSongsByTrack(_ context.Context, id, name, artist,
} }
func (a *mockAgent) GetSimilarSongsByAlbum(_ context.Context, id, name, artist, mbid string, count int) ([]Song, error) { func (a *mockAgent) GetSimilarSongsByAlbum(_ context.Context, id, name, artist, mbid string, count int) ([]Song, error) {
a.Args = []interface{}{id, name, artist, mbid, count} a.Args = []any{id, name, artist, mbid, count}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -466,7 +466,7 @@ func (a *mockAgent) GetSimilarSongsByAlbum(_ context.Context, id, name, artist,
} }
func (a *mockAgent) GetSimilarSongsByArtist(_ context.Context, id, name, mbid string, count int) ([]Song, error) { func (a *mockAgent) GetSimilarSongsByArtist(_ context.Context, id, name, mbid string, count int) ([]Song, error) {
a.Args = []interface{}{id, name, mbid, count} a.Args = []any{id, name, mbid, count}
if a.Err != nil { if a.Err != nil {
return nil, a.Err return nil, a.Err
} }
@@ -488,12 +488,12 @@ type testImageAgent struct {
Name string Name string
Images []ExternalImage Images []ExternalImage
Err error Err error
Args []interface{} Args []any
} }
func (t *testImageAgent) AgentName() string { return t.Name } func (t *testImageAgent) AgentName() string { return t.Name }
func (t *testImageAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([]ExternalImage, error) { func (t *testImageAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([]ExternalImage, error) {
t.Args = []interface{}{id, name, mbid} t.Args = []any{id, name, mbid}
return t.Images, t.Err return t.Images, t.Err
} }
+1 -1
View File
@@ -143,7 +143,7 @@ var _ = Describe("CacheWarmer", func() {
It("processes items in batches", func() { It("processes items in batches", func() {
cw := NewCacheWarmer(aw, fc).(*cacheWarmer) cw := NewCacheWarmer(aw, fc).(*cacheWarmer)
for i := 0; i < 5; i++ { for i := range 5 {
cw.PreCache(model.MustParseArtworkID(fmt.Sprintf("al-%d", i))) cw.PreCache(model.MustParseArtworkID(fmt.Sprintf("al-%d", i)))
} }
+1 -1
View File
@@ -79,7 +79,7 @@ func (a *albumArtworkReader) Reader(ctx context.Context) (io.ReadCloser, string,
func (a *albumArtworkReader) fromCoverArtPriority(ctx context.Context, ffmpeg ffmpeg.FFmpeg, priority string) []sourceFunc { func (a *albumArtworkReader) fromCoverArtPriority(ctx context.Context, ffmpeg ffmpeg.FFmpeg, priority string) []sourceFunc {
var ff []sourceFunc var ff []sourceFunc
for _, pattern := range strings.Split(strings.ToLower(priority), ",") { for pattern := range strings.SplitSeq(strings.ToLower(priority), ",") {
pattern = strings.TrimSpace(pattern) pattern = strings.TrimSpace(pattern)
switch { switch {
case pattern == "embedded": case pattern == "embedded":
+2 -2
View File
@@ -99,7 +99,7 @@ func (a *artistReader) Reader(ctx context.Context) (io.ReadCloser, string, error
func (a *artistReader) fromArtistArtPriority(ctx context.Context, priority string) []sourceFunc { func (a *artistReader) fromArtistArtPriority(ctx context.Context, priority string) []sourceFunc {
var ff []sourceFunc var ff []sourceFunc
for _, pattern := range strings.Split(strings.ToLower(priority), ",") { for pattern := range strings.SplitSeq(strings.ToLower(priority), ",") {
pattern = strings.TrimSpace(pattern) pattern = strings.TrimSpace(pattern)
switch { switch {
case pattern == "external": case pattern == "external":
@@ -116,7 +116,7 @@ func (a *artistReader) fromArtistArtPriority(ctx context.Context, priority strin
func fromArtistFolder(ctx context.Context, artistFolder string, pattern string) sourceFunc { func fromArtistFolder(ctx context.Context, artistFolder string, pattern string) sourceFunc {
return func() (io.ReadCloser, string, error) { return func() (io.ReadCloser, string, error) {
current := artistFolder current := artistFolder
for i := 0; i < maxArtistFolderTraversalDepth; i++ { for range maxArtistFolderTraversalDepth {
if reader, path, err := findImageInFolder(ctx, current, pattern); err == nil { if reader, path, err := findImageInFolder(ctx, current, pattern); err == nil {
return reader, path, nil return reader, path, nil
} }
+4 -7
View File
@@ -4,6 +4,7 @@ import (
"cmp" "cmp"
"context" "context"
"crypto/sha256" "crypto/sha256"
"maps"
"sync" "sync"
"time" "time"
@@ -53,9 +54,7 @@ func createBaseClaims() map[string]any {
func CreatePublicToken(claims map[string]any) (string, error) { func CreatePublicToken(claims map[string]any) (string, error) {
tokenClaims := createBaseClaims() tokenClaims := createBaseClaims()
for k, v := range claims { maps.Copy(tokenClaims, claims)
tokenClaims[k] = v
}
_, token, err := TokenAuth.Encode(tokenClaims) _, token, err := TokenAuth.Encode(tokenClaims)
return token, err return token, err
@@ -66,9 +65,7 @@ func CreateExpiringPublicToken(exp time.Time, claims map[string]any) (string, er
if !exp.IsZero() { if !exp.IsZero() {
tokenClaims[jwt.ExpirationKey] = exp.UTC().Unix() tokenClaims[jwt.ExpirationKey] = exp.UTC().Unix()
} }
for k, v := range claims { maps.Copy(tokenClaims, claims)
tokenClaims[k] = v
}
_, token, err := TokenAuth.Encode(tokenClaims) _, token, err := TokenAuth.Encode(tokenClaims)
return token, err return token, err
@@ -100,7 +97,7 @@ func TouchToken(token jwt.Token) (string, error) {
return newToken, err return newToken, err
} }
func Validate(tokenStr string) (map[string]interface{}, error) { func Validate(tokenStr string) (map[string]any, error) {
token, err := jwtauth.VerifyToken(TokenAuth, tokenStr) token, err := jwtauth.VerifyToken(TokenAuth, tokenStr)
if err != nil { if err != nil {
return nil, err return nil, err
+3 -3
View File
@@ -45,7 +45,7 @@ var _ = Describe("Auth", func() {
}) })
It("returns the claims from a valid JWT token", func() { It("returns the claims from a valid JWT token", func() {
claims := map[string]interface{}{} claims := map[string]any{}
claims["iss"] = "issuer" claims["iss"] = "issuer"
claims["iat"] = time.Now().Unix() claims["iat"] = time.Now().Unix()
claims["exp"] = time.Now().Add(1 * time.Minute).Unix() claims["exp"] = time.Now().Add(1 * time.Minute).Unix()
@@ -58,7 +58,7 @@ var _ = Describe("Auth", func() {
}) })
It("returns ErrExpired if the `exp` field is in the past", func() { It("returns ErrExpired if the `exp` field is in the past", func() {
claims := map[string]interface{}{} claims := map[string]any{}
claims["iss"] = "issuer" claims["iss"] = "issuer"
claims["exp"] = time.Now().Add(-1 * time.Minute).Unix() claims["exp"] = time.Now().Add(-1 * time.Minute).Unix()
_, tokenStr, err := auth.TokenAuth.Encode(claims) _, tokenStr, err := auth.TokenAuth.Encode(claims)
@@ -93,7 +93,7 @@ var _ = Describe("Auth", func() {
Describe("TouchToken", func() { Describe("TouchToken", func() {
It("updates the expiration time", func() { It("updates the expiration time", func() {
yesterday := time.Now().Add(-oneDay) yesterday := time.Now().Add(-oneDay)
claims := map[string]interface{}{} claims := map[string]any{}
claims["iss"] = "issuer" claims["iss"] = "issuer"
claims["exp"] = yesterday.Unix() claims["exp"] = yesterday.Unix()
token, _, err := auth.TokenAuth.Encode(claims) token, _, err := auth.TokenAuth.Encode(claims)
+3 -3
View File
@@ -40,7 +40,7 @@ func (m *mockArtistRepo) Get(id string) (*model.Artist, error) {
// GetAll implements model.ArtistRepository. // GetAll implements model.ArtistRepository.
func (m *mockArtistRepo) GetAll(options ...model.QueryOptions) (model.Artists, error) { func (m *mockArtistRepo) GetAll(options ...model.QueryOptions) (model.Artists, error) {
argsSlice := make([]interface{}, len(options)) argsSlice := make([]any, len(options))
for i, v := range options { for i, v := range options {
argsSlice[i] = v argsSlice[i] = v
} }
@@ -99,7 +99,7 @@ func (m *mockMediaFileRepo) GetAllByTags(_ model.TagName, _ []string, options ..
// GetAll implements model.MediaFileRepository. // GetAll implements model.MediaFileRepository.
func (m *mockMediaFileRepo) GetAll(options ...model.QueryOptions) (model.MediaFiles, error) { func (m *mockMediaFileRepo) GetAll(options ...model.QueryOptions) (model.MediaFiles, error) {
argsSlice := make([]interface{}, len(options)) argsSlice := make([]any, len(options))
for i, v := range options { for i, v := range options {
argsSlice[i] = v argsSlice[i] = v
} }
@@ -152,7 +152,7 @@ func (m *mockAlbumRepo) Get(id string) (*model.Album, error) {
// GetAll implements model.AlbumRepository. // GetAll implements model.AlbumRepository.
func (m *mockAlbumRepo) GetAll(options ...model.QueryOptions) (model.Albums, error) { func (m *mockAlbumRepo) GetAll(options ...model.QueryOptions) (model.Albums, error) {
argsSlice := make([]interface{}, len(options)) argsSlice := make([]any, len(options))
for i, v := range options { for i, v := range options {
argsSlice[i] = v argsSlice[i] = v
} }
+2 -2
View File
@@ -93,7 +93,7 @@ func NewProvider(ds model.DataStore, agents Agents) Provider {
} }
func (e *provider) getAlbum(ctx context.Context, id string) (auxAlbum, error) { func (e *provider) getAlbum(ctx context.Context, id string) (auxAlbum, error) {
var entity interface{} var entity any
entity, err := model.GetEntityByID(ctx, e.ds, id) entity, err := model.GetEntityByID(ctx, e.ds, id)
if err != nil { if err != nil {
return auxAlbum{}, err return auxAlbum{}, err
@@ -187,7 +187,7 @@ func (e *provider) populateAlbumInfo(ctx context.Context, album auxAlbum) (auxAl
} }
func (e *provider) getArtist(ctx context.Context, id string) (auxArtist, error) { func (e *provider) getArtist(ctx context.Context, id string) (auxArtist, error) {
var entity interface{} var entity any
entity, err := model.GetEntityByID(ctx, e.ds, id) entity, err := model.GetEntityByID(ctx, e.ds, id)
if err != nil { if err != nil {
return auxArtist{}, err return auxArtist{}, err
+2 -2
View File
@@ -159,7 +159,7 @@ type libraryRepositoryWrapper struct {
pluginManager PluginUnloader pluginManager PluginUnloader
} }
func (r *libraryRepositoryWrapper) Save(entity interface{}) (string, error) { func (r *libraryRepositoryWrapper) Save(entity any) (string, error) {
lib := entity.(*model.Library) lib := entity.(*model.Library)
if err := r.validateLibrary(lib); err != nil { if err := r.validateLibrary(lib); err != nil {
return "", err return "", err
@@ -191,7 +191,7 @@ func (r *libraryRepositoryWrapper) Save(entity interface{}) (string, error) {
return strconv.Itoa(lib.ID), nil return strconv.Itoa(lib.ID), nil
} }
func (r *libraryRepositoryWrapper) Update(id string, entity interface{}, _ ...string) error { func (r *libraryRepositoryWrapper) Update(id string, entity any, _ ...string) error {
lib := entity.(*model.Library) lib := entity.(*model.Library)
libID, err := strconv.Atoi(id) libID, err := strconv.Atoi(id)
if err != nil { if err != nil {
+2 -4
View File
@@ -196,9 +196,7 @@ func (s *maintenanceService) getAffectedAlbumIDs(ctx context.Context, ids []stri
// refreshStatsAsync refreshes artist and album statistics in background goroutines // refreshStatsAsync refreshes artist and album statistics in background goroutines
func (s *maintenanceService) refreshStatsAsync(ctx context.Context, affectedAlbumIDs []string) { func (s *maintenanceService) refreshStatsAsync(ctx context.Context, affectedAlbumIDs []string) {
// Refresh artist stats in background // Refresh artist stats in background
s.wg.Add(1) s.wg.Go(func() {
go func() {
defer s.wg.Done()
bgCtx := request.AddValues(context.Background(), ctx) bgCtx := request.AddValues(context.Background(), ctx)
if _, err := s.ds.Artist(bgCtx).RefreshStats(true); err != nil { if _, err := s.ds.Artist(bgCtx).RefreshStats(true); err != nil {
log.Error(bgCtx, "Error refreshing artist stats after deleting missing files", err) log.Error(bgCtx, "Error refreshing artist stats after deleting missing files", err)
@@ -214,7 +212,7 @@ func (s *maintenanceService) refreshStatsAsync(ctx context.Context, affectedAlbu
log.Debug(bgCtx, "Successfully refreshed album stats after deleting missing files", "count", len(affectedAlbumIDs)) log.Debug(bgCtx, "Successfully refreshed album stats after deleting missing files", "count", len(affectedAlbumIDs))
} }
} }
}() })
} }
// Wait waits for all background goroutines to complete. // Wait waits for all background goroutines to complete.
+4 -3
View File
@@ -3,6 +3,7 @@ package playback
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"strings"
"github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/model"
@@ -21,11 +22,11 @@ func NewQueue() *Queue {
} }
func (pd *Queue) String() string { func (pd *Queue) String() string {
filenames := "" var filenames strings.Builder
for idx, item := range pd.Items { for idx, item := range pd.Items {
filenames += fmt.Sprint(idx) + ":" + item.Path + " " filenames.WriteString(fmt.Sprint(idx) + ":" + item.Path + " ")
} }
return fmt.Sprintf("#Items: %d, idx: %d, files: %s", len(pd.Items), pd.Index, filenames) return fmt.Sprintf("#Items: %d, idx: %d, files: %s", len(pd.Items), pd.Index, filenames.String())
} }
// returns the current mediafile or nil // returns the current mediafile or nil
+4 -4
View File
@@ -45,7 +45,7 @@ func InPlaylistsPath(folder model.Folder) bool {
return true return true
} }
rel, _ := filepath.Rel(folder.LibraryPath, folder.AbsolutePath()) rel, _ := filepath.Rel(folder.LibraryPath, folder.AbsolutePath())
for _, path := range strings.Split(conf.Server.PlaylistsPath, string(filepath.ListSeparator)) { for path := range strings.SplitSeq(conf.Server.PlaylistsPath, string(filepath.ListSeparator)) {
if match, _ := doublestar.Match(path, rel); match { if match, _ := doublestar.Match(path, rel); match {
return true return true
} }
@@ -193,8 +193,8 @@ func (s *playlists) parseM3U(ctx context.Context, pls *model.Playlist, folder *m
if line == "" || strings.HasPrefix(line, "#") { if line == "" || strings.HasPrefix(line, "#") {
continue continue
} }
if strings.HasPrefix(line, "file://") { if after, ok := strings.CutPrefix(line, "file://"); ok {
line = strings.TrimPrefix(line, "file://") line = after
line, _ = url.QueryUnescape(line) line, _ = url.QueryUnescape(line)
} }
if !model.IsAudioFile(line) { if !model.IsAudioFile(line) {
@@ -533,7 +533,7 @@ type nspFile struct {
} }
func (i *nspFile) UnmarshalJSON(data []byte) error { func (i *nspFile) UnmarshalJSON(data []byte) error {
m := map[string]interface{}{} m := map[string]any{}
err := json.Unmarshal(data, &m) err := json.Unmarshal(data, &m)
if err != nil { if err != nil {
return err return err
+1 -4
View File
@@ -212,10 +212,7 @@ func (p *playTracker) NowPlaying(ctx context.Context, playerId string, playerNam
// Calculate TTL based on remaining track duration. If position exceeds track duration, // Calculate TTL based on remaining track duration. If position exceeds track duration,
// remaining is set to 0 to avoid negative TTL. // remaining is set to 0 to avoid negative TTL.
remaining := int(mf.Duration) - position remaining := max(int(mf.Duration)-position, 0)
if remaining < 0 {
remaining = 0
}
// Add 5 seconds buffer to ensure the NowPlaying info is available slightly longer than the track duration. // Add 5 seconds buffer to ensure the NowPlaying info is available slightly longer than the track duration.
ttl := time.Duration(remaining+5) * time.Second ttl := time.Duration(remaining+5) * time.Second
_ = p.playMap.AddWithTTL(playerId, info, ttl) _ = p.playMap.AddWithTTL(playerId, info, ttl)
+2 -2
View File
@@ -87,7 +87,7 @@ func (r *shareRepositoryWrapper) newId() (string, error) {
} }
} }
func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) { func (r *shareRepositoryWrapper) Save(entity any) (string, error) {
s := entity.(*model.Share) s := entity.(*model.Share)
id, err := r.newId() id, err := r.newId()
if err != nil { if err != nil {
@@ -127,7 +127,7 @@ func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) {
return id, err return id, err
} }
func (r *shareRepositoryWrapper) Update(id string, entity interface{}, _ ...string) error { func (r *shareRepositoryWrapper) Update(id string, entity any, _ ...string) error {
cols := []string{"description", "downloadable"} cols := []string{"description", "downloadable"}
// TODO Better handling of Share expiration // TODO Better handling of Share expiration
+4 -9
View File
@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"maps"
"net/url" "net/url"
"path" "path"
"testing/fstest" "testing/fstest"
@@ -135,9 +136,7 @@ func (ffs *FakeFS) UpdateTags(filePath string, newTags map[string]any, when ...t
if err != nil { if err != nil {
panic(err) panic(err)
} }
for k, v := range newTags { maps.Copy(tags, newTags)
tags[k] = v
}
data, _ := json.Marshal(tags) data, _ := json.Marshal(tags)
f.Data = data f.Data = data
ffs.Touch(filePath, when...) ffs.Touch(filePath, when...)
@@ -180,9 +179,7 @@ func Track(num int, title string, tags ...map[string]any) map[string]any {
ts["title"] = title ts["title"] = title
ts["track"] = num ts["track"] = num
for _, t := range tags { for _, t := range tags {
for k, v := range t { maps.Copy(ts, t)
ts[k] = v
}
} }
return ts return ts
} }
@@ -200,9 +197,7 @@ func MP3(tags ...map[string]any) *fstest.MapFile {
func File(tags ...map[string]any) *fstest.MapFile { func File(tags ...map[string]any) *fstest.MapFile {
ts := map[string]any{} ts := map[string]any{}
for _, t := range tags { for _, t := range tags {
for k, v := range t { maps.Copy(ts, t)
ts[k] = v
}
} }
modTime := time.Now() modTime := time.Now()
if mt, ok := ts[fakeFileInfoModTime]; !ok { if mt, ok := ts[fakeFileInfoModTime]; !ok {
+2 -2
View File
@@ -50,12 +50,12 @@ type userRepositoryWrapper struct {
} }
// Save implements rest.Persistable by delegating to the underlying repository. // Save implements rest.Persistable by delegating to the underlying repository.
func (r *userRepositoryWrapper) Save(entity interface{}) (string, error) { func (r *userRepositoryWrapper) Save(entity any) (string, error) {
return r.UserRepository.(rest.Persistable).Save(entity) return r.UserRepository.(rest.Persistable).Save(entity)
} }
// Update implements rest.Persistable by delegating to the underlying repository. // Update implements rest.Persistable by delegating to the underlying repository.
func (r *userRepositoryWrapper) Update(id string, entity interface{}, cols ...string) error { func (r *userRepositoryWrapper) Update(id string, entity any, cols ...string) error {
return r.UserRepository.(rest.Persistable).Update(id, entity, cols...) return r.UserRepository.(rest.Persistable).Update(id, entity, cols...)
} }
+8 -8
View File
@@ -126,7 +126,7 @@ func Optimize(ctx context.Context) {
} }
log.Debug(ctx, "Optimizing open connections", "numConns", numConns) log.Debug(ctx, "Optimizing open connections", "numConns", numConns)
var conns []*sql.Conn var conns []*sql.Conn
for i := 0; i < numConns; i++ { for range numConns {
conn, err := Db().Conn(ctx) conn, err := Db().Conn(ctx)
conns = append(conns, conn) conns = append(conns, conn)
if err != nil { if err != nil {
@@ -147,8 +147,8 @@ func Optimize(ctx context.Context) {
type statusLogger struct{ numPending int } type statusLogger struct{ numPending int }
func (*statusLogger) Fatalf(format string, v ...interface{}) { log.Fatal(fmt.Sprintf(format, v...)) } func (*statusLogger) Fatalf(format string, v ...any) { log.Fatal(fmt.Sprintf(format, v...)) }
func (l *statusLogger) Printf(format string, v ...interface{}) { func (l *statusLogger) Printf(format string, v ...any) {
if len(v) < 1 { if len(v) < 1 {
return return
} }
@@ -183,27 +183,27 @@ type logAdapter struct {
silent bool silent bool
} }
func (l *logAdapter) Fatal(v ...interface{}) { func (l *logAdapter) Fatal(v ...any) {
log.Fatal(l.ctx, fmt.Sprint(v...)) log.Fatal(l.ctx, fmt.Sprint(v...))
} }
func (l *logAdapter) Fatalf(format string, v ...interface{}) { func (l *logAdapter) Fatalf(format string, v ...any) {
log.Fatal(l.ctx, fmt.Sprintf(format, v...)) log.Fatal(l.ctx, fmt.Sprintf(format, v...))
} }
func (l *logAdapter) Print(v ...interface{}) { func (l *logAdapter) Print(v ...any) {
if !l.silent { if !l.silent {
log.Info(l.ctx, fmt.Sprint(v...)) log.Info(l.ctx, fmt.Sprint(v...))
} }
} }
func (l *logAdapter) Println(v ...interface{}) { func (l *logAdapter) Println(v ...any) {
if !l.silent { if !l.silent {
log.Info(l.ctx, fmt.Sprintln(v...)) log.Info(l.ctx, fmt.Sprintln(v...))
} }
} }
func (l *logAdapter) Printf(format string, v ...interface{}) { func (l *logAdapter) Printf(format string, v ...any) {
if !l.silent { if !l.silent {
log.Info(l.ctx, fmt.Sprintf(format, v...)) log.Info(l.ctx, fmt.Sprintf(format, v...))
} }
+12 -12
View File
@@ -19,7 +19,7 @@ import (
type Level uint32 type Level uint32
type LevelFunc = func(ctx interface{}, msg interface{}, keyValuePairs ...interface{}) type LevelFunc = func(ctx any, msg any, keyValuePairs ...any)
var redacted = &Hook{ var redacted = &Hook{
AcceptedLevels: logrus.AllLevels, AcceptedLevels: logrus.AllLevels,
@@ -152,7 +152,7 @@ func Redact(msg string) string {
return r return r
} }
func NewContext(ctx context.Context, keyValuePairs ...interface{}) context.Context { func NewContext(ctx context.Context, keyValuePairs ...any) context.Context {
if ctx == nil { if ctx == nil {
ctx = context.Background() ctx = context.Background()
} }
@@ -184,32 +184,32 @@ func IsGreaterOrEqualTo(level Level) bool {
return shouldLog(level, 2) return shouldLog(level, 2)
} }
func Fatal(args ...interface{}) { func Fatal(args ...any) {
Log(LevelFatal, args...) Log(LevelFatal, args...)
os.Exit(1) os.Exit(1)
} }
func Error(args ...interface{}) { func Error(args ...any) {
Log(LevelError, args...) Log(LevelError, args...)
} }
func Warn(args ...interface{}) { func Warn(args ...any) {
Log(LevelWarn, args...) Log(LevelWarn, args...)
} }
func Info(args ...interface{}) { func Info(args ...any) {
Log(LevelInfo, args...) Log(LevelInfo, args...)
} }
func Debug(args ...interface{}) { func Debug(args ...any) {
Log(LevelDebug, args...) Log(LevelDebug, args...)
} }
func Trace(args ...interface{}) { func Trace(args ...any) {
Log(LevelTrace, args...) Log(LevelTrace, args...)
} }
func Log(level Level, args ...interface{}) { func Log(level Level, args ...any) {
if !shouldLog(level, 3) { if !shouldLog(level, 3) {
return return
} }
@@ -250,7 +250,7 @@ func shouldLog(requiredLevel Level, skip int) bool {
return false return false
} }
func parseArgs(args []interface{}) (*logrus.Entry, string) { func parseArgs(args []any) (*logrus.Entry, string) {
var l *logrus.Entry var l *logrus.Entry
var err error var err error
if args[0] == nil { if args[0] == nil {
@@ -289,7 +289,7 @@ func parseArgs(args []interface{}) (*logrus.Entry, string) {
return l, "" return l, ""
} }
func addFields(logger *logrus.Entry, keyValuePairs []interface{}) *logrus.Entry { func addFields(logger *logrus.Entry, keyValuePairs []any) *logrus.Entry {
for i := 0; i < len(keyValuePairs); i += 2 { for i := 0; i < len(keyValuePairs); i += 2 {
switch name := keyValuePairs[i].(type) { switch name := keyValuePairs[i].(type) {
case error: case error:
@@ -316,7 +316,7 @@ func addFields(logger *logrus.Entry, keyValuePairs []interface{}) *logrus.Entry
return logger return logger
} }
func extractLogger(ctx interface{}) (*logrus.Entry, error) { func extractLogger(ctx any) (*logrus.Entry, error) {
switch ctx := ctx.(type) { switch ctx := ctx.(type) {
case *logrus.Entry: case *logrus.Entry:
return ctx, nil return ctx, nil
+1 -1
View File
@@ -41,7 +41,7 @@ type DataStore interface {
Scrobble(ctx context.Context) ScrobbleRepository Scrobble(ctx context.Context) ScrobbleRepository
Plugin(ctx context.Context) PluginRepository Plugin(ctx context.Context) PluginRepository
Resource(ctx context.Context, model interface{}) ResourceRepository Resource(ctx context.Context, model any) ResourceRepository
WithTx(block func(tx DataStore) error, scope ...string) error WithTx(block func(tx DataStore) error, scope ...string) error
WithTxImmediate(block func(tx DataStore) error, scope ...string) error WithTxImmediate(block func(tx DataStore) error, scope ...string) error
+1 -1
View File
@@ -5,7 +5,7 @@ import (
) )
// TODO: Should the type be encoded in the ID? // TODO: Should the type be encoded in the ID?
func GetEntityByID(ctx context.Context, ds DataStore, id string) (interface{}, error) { func GetEntityByID(ctx context.Context, ds DataStore, id string) (any, error) {
ar, err := ds.Artist(ctx).Get(id) ar, err := ds.Artist(ctx).Get(id)
if err == nil { if err == nil {
return ar, nil return ar, nil
+1 -1
View File
@@ -140,7 +140,7 @@ func (mf MediaFile) Hash() string {
} }
hash, _ := hashstructure.Hash(mf, opts) hash, _ := hashstructure.Hash(mf, opts)
sum := md5.New() sum := md5.New()
sum.Write([]byte(fmt.Sprintf("%d", hash))) sum.Write(fmt.Appendf(nil, "%d", hash))
sum.Write(mf.Tags.Hash()) sum.Write(mf.Tags.Hash())
sum.Write(mf.Participants.Hash()) sum.Write(mf.Participants.Hash())
return fmt.Sprintf("%x", sum.Sum(nil)) return fmt.Sprintf("%x", sum.Sum(nil))
+2 -2
View File
@@ -268,8 +268,8 @@ func parseID3Pairs(name model.TagName, lowered model.Tags) []string {
prefix := string(name) + ":" prefix := string(name) + ":"
for tagKey, tagValues := range lowered { for tagKey, tagValues := range lowered {
keyStr := string(tagKey) keyStr := string(tagKey)
if strings.HasPrefix(keyStr, prefix) { if after, ok := strings.CutPrefix(keyStr, prefix); ok {
keyPart := strings.TrimPrefix(keyStr, prefix) keyPart := after
if keyPart == string(name) { if keyPart == string(name) {
keyPart = "" keyPart = ""
} }
+2 -2
View File
@@ -49,8 +49,8 @@ func createGetPID(hash hashFunc) getPIDFunc {
} }
getPID = func(mf model.MediaFile, md Metadata, spec string, prependLibId bool) string { getPID = func(mf model.MediaFile, md Metadata, spec string, prependLibId bool) string {
pid := "" pid := ""
fields := strings.Split(spec, "|") fields := strings.SplitSeq(spec, "|")
for _, field := range fields { for field := range fields {
attributes := strings.Split(field, ",") attributes := strings.Split(field, ",")
hasValue := false hasValue := false
values := slice.Map(attributes, func(attr string) string { values := slice.Map(attributes, func(attr string) string {
+4 -4
View File
@@ -51,13 +51,13 @@ func ParseTargets(libFolders []string) ([]ScanTarget, error) {
} }
// Split by the first colon // Split by the first colon
colonIdx := strings.Index(part, ":") before, after, ok := strings.Cut(part, ":")
if colonIdx == -1 { if !ok {
return nil, fmt.Errorf("invalid target format: %q (expected libraryID:folderPath)", part) return nil, fmt.Errorf("invalid target format: %q (expected libraryID:folderPath)", part)
} }
libIDStr := part[:colonIdx] libIDStr := before
folderPath := part[colonIdx+1:] folderPath := after
libID, err := strconv.Atoi(libIDStr) libID, err := strconv.Atoi(libIDStr)
if err != nil { if err != nil {
+2 -2
View File
@@ -22,8 +22,8 @@ type Share struct {
Format string `structs:"format" json:"format,omitempty"` Format string `structs:"format" json:"format,omitempty"`
MaxBitRate int `structs:"max_bit_rate" json:"maxBitRate,omitempty"` MaxBitRate int `structs:"max_bit_rate" json:"maxBitRate,omitempty"`
VisitCount int `structs:"visit_count" json:"visitCount,omitempty"` VisitCount int `structs:"visit_count" json:"visitCount,omitempty"`
CreatedAt time.Time `structs:"created_at" json:"createdAt,omitempty"` CreatedAt time.Time `structs:"created_at" json:"createdAt"`
UpdatedAt time.Time `structs:"updated_at" json:"updatedAt,omitempty"` UpdatedAt time.Time `structs:"updated_at" json:"updatedAt"`
Tracks MediaFiles `structs:"-" json:"tracks,omitempty"` Tracks MediaFiles `structs:"-" json:"tracks,omitempty"`
Albums Albums `structs:"-" json:"albums,omitempty"` Albums Albums `structs:"-" json:"albums,omitempty"`
URL string `structs:"-" json:"-"` URL string `structs:"-" json:"-"`
+1 -3
View File
@@ -144,11 +144,9 @@ func (t Tags) Merge(tags Tags) {
} }
func (t Tags) Add(name TagName, v string) { func (t Tags) Add(name TagName, v string) {
for _, existing := range t[name] { if slices.Contains(t[name], v) {
if existing == v {
return return
} }
}
t[name] = append(t[name], v) t[name] = append(t[name], v)
} }
+9 -9
View File
@@ -145,11 +145,11 @@ func recentlyAddedSort() string {
return "created_at" return "created_at"
} }
func recentlyPlayedFilter(string, interface{}) Sqlizer { func recentlyPlayedFilter(string, any) Sqlizer {
return Gt{"play_count": 0} return Gt{"play_count": 0}
} }
func yearFilter(_ string, value interface{}) Sqlizer { func yearFilter(_ string, value any) Sqlizer {
return Or{ return Or{
And{ And{
Gt{"min_year": 0}, Gt{"min_year": 0},
@@ -160,14 +160,14 @@ func yearFilter(_ string, value interface{}) Sqlizer {
} }
} }
func artistFilter(_ string, value interface{}) Sqlizer { func artistFilter(_ string, value any) Sqlizer {
return Or{ return Or{
Exists("json_tree(participants, '$.albumartist')", Eq{"value": value}), Exists("json_tree(participants, '$.albumartist')", Eq{"value": value}),
Exists("json_tree(participants, '$.artist')", Eq{"value": value}), Exists("json_tree(participants, '$.artist')", Eq{"value": value}),
} }
} }
func artistRoleFilter(name string, value interface{}) Sqlizer { func artistRoleFilter(name string, value any) Sqlizer {
roleName := strings.TrimSuffix(strings.TrimPrefix(name, "role_"), "_id") roleName := strings.TrimSuffix(strings.TrimPrefix(name, "role_"), "_id")
// Check if the role name is valid. If not, return an invalid filter // Check if the role name is valid. If not, return an invalid filter
@@ -177,7 +177,7 @@ func artistRoleFilter(name string, value interface{}) Sqlizer {
return Exists(fmt.Sprintf("json_tree(participants, '$.%s')", roleName), Eq{"value": value}) return Exists(fmt.Sprintf("json_tree(participants, '$.%s')", roleName), Eq{"value": value})
} }
func allRolesFilter(_ string, value interface{}) Sqlizer { func allRolesFilter(_ string, value any) Sqlizer {
return Like{"participants": fmt.Sprintf(`%%"%s"%%`, value)} return Like{"participants": fmt.Sprintf(`%%"%s"%%`, value)}
} }
@@ -248,7 +248,7 @@ func (r *albumRepository) CopyAttributes(fromID, toID string, columns ...string)
if err != nil { if err != nil {
return fmt.Errorf("getting album to copy fields from: %w", err) return fmt.Errorf("getting album to copy fields from: %w", err)
} }
to := make(map[string]interface{}) to := make(map[string]any)
for _, col := range columns { for _, col := range columns {
to[col] = from[col] to[col] = from[col]
} }
@@ -370,11 +370,11 @@ func (r *albumRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *albumRepository) Read(id string) (interface{}, error) { func (r *albumRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *albumRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *albumRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
@@ -382,7 +382,7 @@ func (r *albumRepository) EntityName() string {
return "album" return "album"
} }
func (r *albumRepository) NewInstance() interface{} { func (r *albumRepository) NewInstance() any {
return &model.Album{} return &model.Album{}
} }
+4 -4
View File
@@ -162,7 +162,7 @@ var _ = Describe("AlbumRepository", func() {
newID := id.NewRandom() newID := id.NewRandom()
Expect(albumRepo.Put(&model.Album{LibraryID: 1, ID: newID, Name: "name", SongCount: songCount})).To(Succeed()) Expect(albumRepo.Put(&model.Album{LibraryID: 1, ID: newID, Name: "name", SongCount: songCount})).To(Succeed())
for i := 0; i < playCount; i++ { for range playCount {
Expect(albumRepo.IncPlayCount(newID, time.Now())).To(Succeed()) Expect(albumRepo.IncPlayCount(newID, time.Now())).To(Succeed())
} }
@@ -185,7 +185,7 @@ var _ = Describe("AlbumRepository", func() {
newID := id.NewRandom() newID := id.NewRandom()
Expect(albumRepo.Put(&model.Album{LibraryID: 1, ID: newID, Name: "name", SongCount: songCount})).To(Succeed()) Expect(albumRepo.Put(&model.Album{LibraryID: 1, ID: newID, Name: "name", SongCount: songCount})).To(Succeed())
for i := 0; i < playCount; i++ { for range playCount {
Expect(albumRepo.IncPlayCount(newID, time.Now())).To(Succeed()) Expect(albumRepo.IncPlayCount(newID, time.Now())).To(Succeed())
} }
@@ -406,7 +406,7 @@ var _ = Describe("AlbumRepository", func() {
sql, args, err := sqlizer.ToSql() sql, args, err := sqlizer.ToSql()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sql).To(Equal(expectedSQL)) Expect(sql).To(Equal(expectedSQL))
Expect(args).To(Equal([]interface{}{artistID})) Expect(args).To(Equal([]any{artistID}))
}, },
Entry("artist role", "role_artist_id", "123", Entry("artist role", "role_artist_id", "123",
"exists (select 1 from json_tree(participants, '$.artist') where value = ?)"), "exists (select 1 from json_tree(participants, '$.artist') where value = ?)"),
@@ -428,7 +428,7 @@ var _ = Describe("AlbumRepository", func() {
sql, args, err := sqlizer.ToSql() sql, args, err := sqlizer.ToSql()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sql).To(Equal(fmt.Sprintf("exists (select 1 from json_tree(participants, '$.%s') where value = ?)", roleName))) Expect(sql).To(Equal(fmt.Sprintf("exists (select 1 from json_tree(participants, '$.%s') where value = ?)", roleName)))
Expect(args).To(Equal([]interface{}{"test-id"})) Expect(args).To(Equal([]any{"test-id"}))
} }
}) })
+4 -4
View File
@@ -164,7 +164,7 @@ func roleFilter(_ string, role any) Sqlizer {
} }
// artistLibraryIdFilter filters artists based on library access through the library_artist table // artistLibraryIdFilter filters artists based on library access through the library_artist table
func artistLibraryIdFilter(_ string, value interface{}) Sqlizer { func artistLibraryIdFilter(_ string, value any) Sqlizer {
return Eq{"library_artist.library_id": value} return Eq{"library_artist.library_id": value}
} }
@@ -534,11 +534,11 @@ func (r *artistRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *artistRepository) Read(id string) (interface{}, error) { func (r *artistRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *artistRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *artistRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
role := "total" role := "total"
if len(options) > 0 { if len(options) > 0 {
if v, ok := options[0].Filters["role"].(string); ok { if v, ok := options[0].Filters["role"].(string); ok {
@@ -555,7 +555,7 @@ func (r *artistRepository) EntityName() string {
return "artist" return "artist"
} }
func (r *artistRepository) NewInstance() interface{} { func (r *artistRepository) NewInstance() any {
return &model.Artist{} return &model.Artist{}
} }
+2 -3
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"maps"
"os" "os"
"path/filepath" "path/filepath"
"slices" "slices"
@@ -117,9 +118,7 @@ func (r folderRepository) GetFolderUpdateInfo(lib model.Library, targetPaths ...
if err != nil { if err != nil {
return nil, err return nil, err
} }
for id, info := range batchResult { maps.Copy(result, batchResult)
result[id] = info
}
} }
return result, nil return result, nil
+3 -3
View File
@@ -33,18 +33,18 @@ func (r *genreRepository) GetAll(opt ...model.QueryOptions) (model.Genres, error
// Override ResourceRepository methods to return Genre objects instead of Tag objects // Override ResourceRepository methods to return Genre objects instead of Tag objects
func (r *genreRepository) Read(id string) (interface{}, error) { func (r *genreRepository) Read(id string) (any, error) {
sel := r.selectGenre().Where(Eq{"tag.id": id}) sel := r.selectGenre().Where(Eq{"tag.id": id})
var res model.Genre var res model.Genre
err := r.queryOne(sel, &res) err := r.queryOne(sel, &res)
return &res, err return &res, err
} }
func (r *genreRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *genreRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *genreRepository) NewInstance() interface{} { func (r *genreRepository) NewInstance() any {
return &model.Genre{} return &model.Genre{}
} }
+2 -2
View File
@@ -182,7 +182,7 @@ var _ = Describe("GenreRepository", func() {
It("should filter by name using like match", func() { It("should filter by name using like match", func() {
// Test filtering by partial name match using the "name" filter which maps to containsFilter("tag_value") // Test filtering by partial name match using the "name" filter which maps to containsFilter("tag_value")
options := rest.QueryOptions{ options := rest.QueryOptions{
Filters: map[string]interface{}{"name": "%rock%"}, Filters: map[string]any{"name": "%rock%"},
} }
count, err := restRepo.Count(options) count, err := restRepo.Count(options)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -289,7 +289,7 @@ var _ = Describe("GenreRepository", func() {
It("should allow headless processes to apply explicit library_id filters", func() { It("should allow headless processes to apply explicit library_id filters", func() {
// Filter by specific library // Filter by specific library
genres, err := headlessRestRepo.ReadAll(rest.QueryOptions{ genres, err := headlessRestRepo.ReadAll(rest.QueryOptions{
Filters: map[string]interface{}{"library_id": 2}, Filters: map[string]any{"library_id": 2},
}) })
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
+2 -2
View File
@@ -15,7 +15,7 @@ type PostMapper interface {
PostMapArgs(map[string]any) error PostMapArgs(map[string]any) error
} }
func toSQLArgs(rec interface{}) (map[string]interface{}, error) { func toSQLArgs(rec any) (map[string]any, error) {
m := structs.Map(rec) m := structs.Map(rec)
for k, v := range m { for k, v := range m {
switch t := v.(type) { switch t := v.(type) {
@@ -71,7 +71,7 @@ type existsCond struct {
not bool not bool
} }
func (e existsCond) ToSql() (string, []interface{}, error) { func (e existsCond) ToSql() (string, []any, error) {
sql, args, err := e.cond.ToSql() sql, args, err := e.cond.ToSql()
sql = fmt.Sprintf("exists (select 1 from %s where %s)", e.subTable, sql) sql = fmt.Sprintf("exists (select 1 from %s where %s)", e.subTable, sql)
if e.not { if e.not {
+5 -5
View File
@@ -305,7 +305,7 @@ func (r *libraryRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *libraryRepository) Read(id string) (interface{}, error) { func (r *libraryRepository) Read(id string) (any, error) {
idInt, err := strconv.Atoi(id) idInt, err := strconv.Atoi(id)
if err != nil { if err != nil {
log.Trace(r.ctx, "invalid library id: %s", id, err) log.Trace(r.ctx, "invalid library id: %s", id, err)
@@ -314,7 +314,7 @@ func (r *libraryRepository) Read(id string) (interface{}, error) {
return r.Get(idInt) return r.Get(idInt)
} }
func (r *libraryRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *libraryRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
@@ -322,11 +322,11 @@ func (r *libraryRepository) EntityName() string {
return "library" return "library"
} }
func (r *libraryRepository) NewInstance() interface{} { func (r *libraryRepository) NewInstance() any {
return &model.Library{} return &model.Library{}
} }
func (r *libraryRepository) Save(entity interface{}) (string, error) { func (r *libraryRepository) Save(entity any) (string, error) {
lib := entity.(*model.Library) lib := entity.(*model.Library)
lib.ID = 0 // Reset ID to ensure we create a new library lib.ID = 0 // Reset ID to ensure we create a new library
err := r.Put(lib) err := r.Put(lib)
@@ -336,7 +336,7 @@ func (r *libraryRepository) Save(entity interface{}) (string, error) {
return strconv.Itoa(lib.ID), nil return strconv.Itoa(lib.ID), nil
} }
func (r *libraryRepository) Update(id string, entity interface{}, cols ...string) error { func (r *libraryRepository) Update(id string, entity any, cols ...string) error {
lib := entity.(*model.Library) lib := entity.(*model.Library)
idInt, err := strconv.Atoi(id) idInt, err := strconv.Atoi(id)
if err != nil { if err != nil {
+3 -3
View File
@@ -443,11 +443,11 @@ func (r *mediaFileRepository) Count(options ...rest.QueryOptions) (int64, error)
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *mediaFileRepository) Read(id string) (interface{}, error) { func (r *mediaFileRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *mediaFileRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *mediaFileRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
@@ -455,7 +455,7 @@ func (r *mediaFileRepository) EntityName() string {
return "mediafile" return "mediafile"
} }
func (r *mediaFileRepository) NewInstance() interface{} { func (r *mediaFileRepository) NewInstance() any {
return &model.MediaFile{} return &model.MediaFile{}
} }
+3 -3
View File
@@ -310,7 +310,7 @@ var _ = Describe("MediaRepository", func() {
// Update "Old Song": created long ago, updated recently // Update "Old Song": created long ago, updated recently
_, err := db.Update("media_file", _, err := db.Update("media_file",
map[string]interface{}{ map[string]any{
"created_at": oldTime, "created_at": oldTime,
"updated_at": newTime, "updated_at": newTime,
}, },
@@ -319,7 +319,7 @@ var _ = Describe("MediaRepository", func() {
// Update "Middle Song": created and updated at the same middle time // Update "Middle Song": created and updated at the same middle time
_, err = db.Update("media_file", _, err = db.Update("media_file",
map[string]interface{}{ map[string]any{
"created_at": middleTime, "created_at": middleTime,
"updated_at": middleTime, "updated_at": middleTime,
}, },
@@ -328,7 +328,7 @@ var _ = Describe("MediaRepository", func() {
// Update "New Song": created recently, updated long ago // Update "New Song": created recently, updated long ago
_, err = db.Update("media_file", _, err = db.Update("media_file",
map[string]interface{}{ map[string]any{
"created_at": newTime, "created_at": newTime,
"updated_at": oldTime, "updated_at": oldTime,
}, },
+1 -1
View File
@@ -97,7 +97,7 @@ func (s *SQLStore) Plugin(ctx context.Context) model.PluginRepository {
return NewPluginRepository(ctx, s.getDBXBuilder()) return NewPluginRepository(ctx, s.getDBXBuilder())
} }
func (s *SQLStore) Resource(ctx context.Context, m interface{}) model.ResourceRepository { func (s *SQLStore) Resource(ctx context.Context, m any) model.ResourceRepository {
switch m.(type) { switch m.(type) {
case model.User: case model.User:
return s.User(ctx).(model.ResourceRepository) return s.User(ctx).(model.ResourceRepository)
+5 -5
View File
@@ -103,14 +103,14 @@ func (r *playerRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *playerRepository) Read(id string) (interface{}, error) { func (r *playerRepository) Read(id string) (any, error) {
sel := r.newRestSelect().Where(Eq{"player.id": id}) sel := r.newRestSelect().Where(Eq{"player.id": id})
var res model.Player var res model.Player
err := r.queryOne(sel, &res) err := r.queryOne(sel, &res)
return &res, err return &res, err
} }
func (r *playerRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *playerRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
sel := r.newRestSelect(r.parseRestOptions(r.ctx, options...)) sel := r.newRestSelect(r.parseRestOptions(r.ctx, options...))
res := model.Players{} res := model.Players{}
err := r.queryAll(sel, &res) err := r.queryAll(sel, &res)
@@ -121,7 +121,7 @@ func (r *playerRepository) EntityName() string {
return "player" return "player"
} }
func (r *playerRepository) NewInstance() interface{} { func (r *playerRepository) NewInstance() any {
return &model.Player{} return &model.Player{}
} }
@@ -130,7 +130,7 @@ func (r *playerRepository) isPermitted(p *model.Player) bool {
return u.IsAdmin || p.UserId == u.ID return u.IsAdmin || p.UserId == u.ID
} }
func (r *playerRepository) Save(entity interface{}) (string, error) { func (r *playerRepository) Save(entity any) (string, error) {
t := entity.(*model.Player) t := entity.(*model.Player)
if !r.isPermitted(t) { if !r.isPermitted(t) {
return "", rest.ErrPermissionDenied return "", rest.ErrPermissionDenied
@@ -142,7 +142,7 @@ func (r *playerRepository) Save(entity interface{}) (string, error) {
return id, err return id, err
} }
func (r *playerRepository) Update(id string, entity interface{}, cols ...string) error { func (r *playerRepository) Update(id string, entity any, cols ...string) error {
t := entity.(*model.Player) t := entity.(*model.Player)
t.ID = id t.ID = id
if !r.isPermitted(t) { if !r.isPermitted(t) {
+7 -7
View File
@@ -61,14 +61,14 @@ func NewPlaylistRepository(ctx context.Context, db dbx.Builder) model.PlaylistRe
return r return r
} }
func playlistFilter(_ string, value interface{}) Sqlizer { func playlistFilter(_ string, value any) Sqlizer {
return Or{ return Or{
substringFilter("playlist.name", value), substringFilter("playlist.name", value),
substringFilter("playlist.comment", value), substringFilter("playlist.comment", value),
} }
} }
func smartPlaylistFilter(string, interface{}) Sqlizer { func smartPlaylistFilter(string, any) Sqlizer {
return Or{ return Or{
Eq{"rules": ""}, Eq{"rules": ""},
Eq{"rules": nil}, Eq{"rules": nil},
@@ -421,11 +421,11 @@ func (r *playlistRepository) Count(options ...rest.QueryOptions) (int64, error)
return r.CountAll(r.parseRestOptions(r.ctx, options...)) return r.CountAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *playlistRepository) Read(id string) (interface{}, error) { func (r *playlistRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *playlistRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *playlistRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
@@ -433,11 +433,11 @@ func (r *playlistRepository) EntityName() string {
return "playlist" return "playlist"
} }
func (r *playlistRepository) NewInstance() interface{} { func (r *playlistRepository) NewInstance() any {
return &model.Playlist{} return &model.Playlist{}
} }
func (r *playlistRepository) Save(entity interface{}) (string, error) { func (r *playlistRepository) Save(entity any) (string, error) {
pls := entity.(*model.Playlist) pls := entity.(*model.Playlist)
pls.OwnerID = loggedUser(r.ctx).ID pls.OwnerID = loggedUser(r.ctx).ID
pls.ID = "" // Make sure we don't override an existing playlist pls.ID = "" // Make sure we don't override an existing playlist
@@ -448,7 +448,7 @@ func (r *playlistRepository) Save(entity interface{}) (string, error) {
return pls.ID, err return pls.ID, err
} }
func (r *playlistRepository) Update(id string, entity interface{}, cols ...string) error { func (r *playlistRepository) Update(id string, entity any, cols ...string) error {
pls := dbPlaylist{Playlist: *entity.(*model.Playlist)} pls := dbPlaylist{Playlist: *entity.(*model.Playlist)}
current, err := r.Get(id) current, err := r.Get(id)
if err != nil { if err != nil {
+3 -3
View File
@@ -84,7 +84,7 @@ func (r *playlistTrackRepository) Count(options ...rest.QueryOptions) (int64, er
return r.count(query, r.parseRestOptions(r.ctx, options...)) return r.count(query, r.parseRestOptions(r.ctx, options...))
} }
func (r *playlistTrackRepository) Read(id string) (interface{}, error) { func (r *playlistTrackRepository) Read(id string) (any, error) {
userID := loggedUser(r.ctx).ID userID := loggedUser(r.ctx).ID
sel := r.newSelect(). sel := r.newSelect().
LeftJoin("annotation on ("+ LeftJoin("annotation on ("+
@@ -128,7 +128,7 @@ func (r *playlistTrackRepository) GetAlbumIDs(options ...model.QueryOptions) ([]
return ids, nil return ids, nil
} }
func (r *playlistTrackRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *playlistTrackRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
@@ -136,7 +136,7 @@ func (r *playlistTrackRepository) EntityName() string {
return "playlist_tracks" return "playlist_tracks"
} }
func (r *playlistTrackRepository) NewInstance() interface{} { func (r *playlistTrackRepository) NewInstance() any {
return &model.PlaylistTrack{} return &model.PlaylistTrack{}
} }
+2 -2
View File
@@ -122,8 +122,8 @@ func (r *playQueueRepository) toModel(pq *playQueue) model.PlayQueue {
UpdatedAt: pq.UpdatedAt, UpdatedAt: pq.UpdatedAt,
} }
if strings.TrimSpace(pq.Items) != "" { if strings.TrimSpace(pq.Items) != "" {
tracks := strings.Split(pq.Items, ",") tracks := strings.SplitSeq(pq.Items, ",")
for _, t := range tracks { for t := range tracks {
q.Items = append(q.Items, model.MediaFile{ID: t}) q.Items = append(q.Items, model.MediaFile{ID: t})
} }
} }
+6 -6
View File
@@ -63,7 +63,7 @@ func (r *radioRepository) Put(radio *model.Radio) error {
return rest.ErrPermissionDenied return rest.ErrPermissionDenied
} }
var values map[string]interface{} var values map[string]any
radio.UpdatedAt = time.Now() radio.UpdatedAt = time.Now()
@@ -97,19 +97,19 @@ func (r *radioRepository) EntityName() string {
return "radio" return "radio"
} }
func (r *radioRepository) NewInstance() interface{} { func (r *radioRepository) NewInstance() any {
return &model.Radio{} return &model.Radio{}
} }
func (r *radioRepository) Read(id string) (interface{}, error) { func (r *radioRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *radioRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *radioRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
return r.GetAll(r.parseRestOptions(r.ctx, options...)) return r.GetAll(r.parseRestOptions(r.ctx, options...))
} }
func (r *radioRepository) Save(entity interface{}) (string, error) { func (r *radioRepository) Save(entity any) (string, error) {
t := entity.(*model.Radio) t := entity.(*model.Radio)
if !r.isPermitted() { if !r.isPermitted() {
return "", rest.ErrPermissionDenied return "", rest.ErrPermissionDenied
@@ -121,7 +121,7 @@ func (r *radioRepository) Save(entity interface{}) (string, error) {
return t.ID, err return t.ID, err
} }
func (r *radioRepository) Update(id string, entity interface{}, cols ...string) error { func (r *radioRepository) Update(id string, entity any, cols ...string) error {
t := entity.(*model.Radio) t := entity.(*model.Radio)
t.ID = id t.ID = id
if !r.isPermitted() { if !r.isPermitted() {
+1 -1
View File
@@ -51,7 +51,7 @@ func (r *scrobbleBufferRepository) UserIDs(service string) ([]string, error) {
} }
func (r *scrobbleBufferRepository) Enqueue(service, userId, mediaFileId string, playTime time.Time) error { func (r *scrobbleBufferRepository) Enqueue(service, userId, mediaFileId string, playTime time.Time) error {
ins := Insert(r.tableName).SetMap(map[string]interface{}{ ins := Insert(r.tableName).SetMap(map[string]any{
"id": id.NewRandom(), "id": id.NewRandom(),
"user_id": userId, "user_id": userId,
"service": service, "service": service,
@@ -24,7 +24,7 @@ var _ = Describe("ScrobbleBufferRepository", func() {
id := id.NewRandom() id := id.NewRandom()
ids = append(ids, id) ids = append(ids, id)
ins := squirrel.Insert("scrobble_buffer").SetMap(map[string]interface{}{ ins := squirrel.Insert("scrobble_buffer").SetMap(map[string]any{
"id": id, "id": id,
"user_id": userId, "user_id": userId,
"service": service, "service": service,
+1 -1
View File
@@ -23,7 +23,7 @@ func NewScrobbleRepository(ctx context.Context, db dbx.Builder) model.ScrobbleRe
func (r *scrobbleRepository) RecordScrobble(mediaFileID string, submissionTime time.Time) error { func (r *scrobbleRepository) RecordScrobble(mediaFileID string, submissionTime time.Time) error {
userID := loggedUser(r.ctx).ID userID := loggedUser(r.ctx).ID
values := map[string]interface{}{ values := map[string]any{
"media_file_id": mediaFileID, "media_file_id": mediaFileID,
"user_id": userID, "user_id": userID,
"submission_time": submissionTime.Unix(), "submission_time": submissionTime.Unix(),
+5 -5
View File
@@ -138,7 +138,7 @@ func sortByIdPosition(mfs model.MediaFiles, ids []string) model.MediaFiles {
return sorted return sorted
} }
func (r *shareRepository) Update(id string, entity interface{}, cols ...string) error { func (r *shareRepository) Update(id string, entity any, cols ...string) error {
s := entity.(*model.Share) s := entity.(*model.Share)
// TODO Validate record // TODO Validate record
s.ID = id s.ID = id
@@ -151,7 +151,7 @@ func (r *shareRepository) Update(id string, entity interface{}, cols ...string)
return err return err
} }
func (r *shareRepository) Save(entity interface{}) (string, error) { func (r *shareRepository) Save(entity any) (string, error) {
s := entity.(*model.Share) s := entity.(*model.Share)
// TODO Validate record // TODO Validate record
u := loggedUser(r.ctx) u := loggedUser(r.ctx)
@@ -179,18 +179,18 @@ func (r *shareRepository) EntityName() string {
return "share" return "share"
} }
func (r *shareRepository) NewInstance() interface{} { func (r *shareRepository) NewInstance() any {
return &model.Share{} return &model.Share{}
} }
func (r *shareRepository) Read(id string) (interface{}, error) { func (r *shareRepository) Read(id string) (any, error) {
sel := r.selectShare().Where(Eq{"share.id": id}) sel := r.selectShare().Where(Eq{"share.id": id})
var res model.Share var res model.Share
err := r.queryOne(sel, &res) err := r.queryOne(sel, &res)
return &res, err return &res, err
} }
func (r *shareRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *shareRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
sq := r.selectShare(r.parseRestOptions(r.ctx, options...)) sq := r.selectShare(r.parseRestOptions(r.ctx, options...))
res := model.Shares{} res := model.Shares{}
err := r.queryAll(sq, &res) err := r.queryAll(sq, &res)
+3 -3
View File
@@ -47,7 +47,7 @@ var _ = Describe("ShareRepository", func() {
_, err := GetDBXBuilder().NewQuery(` _, err := GetDBXBuilder().NewQuery(`
INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at) INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at)
VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated}) VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated})
`).Bind(map[string]interface{}{ `).Bind(map[string]any{
"id": shareID, "id": shareID,
"user": adminUser.ID, "user": adminUser.ID,
"desc": "Headless Test Share", "desc": "Headless Test Share",
@@ -79,7 +79,7 @@ var _ = Describe("ShareRepository", func() {
_, err := GetDBXBuilder().NewQuery(` _, err := GetDBXBuilder().NewQuery(`
INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at) INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at)
VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated}) VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated})
`).Bind(map[string]interface{}{ `).Bind(map[string]any{
"id": shareID, "id": shareID,
"user": adminUser.ID, "user": adminUser.ID,
"desc": "Headless Get Share", "desc": "Headless Get Share",
@@ -110,7 +110,7 @@ var _ = Describe("ShareRepository", func() {
_, err := GetDBXBuilder().NewQuery(` _, err := GetDBXBuilder().NewQuery(`
INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at) INSERT INTO share (id, user_id, description, resource_type, resource_ids, created_at, updated_at)
VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated}) VALUES ({:id}, {:user}, {:desc}, {:type}, {:ids}, {:created}, {:updated})
`).Bind(map[string]interface{}{ `).Bind(map[string]any{
"id": shareID, "id": shareID,
"user": adminUser.ID, "user": adminUser.ID,
"desc": "SQL Test Share", "desc": "SQL Test Share",
+4 -4
View File
@@ -66,7 +66,7 @@ func (r sqlRepository) annId(itemID ...string) And {
} }
} }
func (r sqlRepository) annUpsert(values map[string]interface{}, itemIDs ...string) error { func (r sqlRepository) annUpsert(values map[string]any, itemIDs ...string) error {
upd := Update(annotationTable).Where(r.annId(itemIDs...)) upd := Update(annotationTable).Where(r.annId(itemIDs...))
for f, v := range values { for f, v := range values {
upd = upd.Set(f, v) upd = upd.Set(f, v)
@@ -90,12 +90,12 @@ func (r sqlRepository) annUpsert(values map[string]interface{}, itemIDs ...strin
func (r sqlRepository) SetStar(starred bool, ids ...string) error { func (r sqlRepository) SetStar(starred bool, ids ...string) error {
starredAt := time.Now() starredAt := time.Now()
return r.annUpsert(map[string]interface{}{"starred": starred, "starred_at": starredAt}, ids...) return r.annUpsert(map[string]any{"starred": starred, "starred_at": starredAt}, ids...)
} }
func (r sqlRepository) SetRating(rating int, itemID string) error { func (r sqlRepository) SetRating(rating int, itemID string) error {
ratedAt := time.Now() ratedAt := time.Now()
err := r.annUpsert(map[string]interface{}{"rating": rating, "rated_at": ratedAt}, itemID) err := r.annUpsert(map[string]any{"rating": rating, "rated_at": ratedAt}, itemID)
if err != nil { if err != nil {
return err return err
} }
@@ -121,7 +121,7 @@ func (r sqlRepository) IncPlayCount(itemID string, ts time.Time) error {
if c == 0 || errors.Is(err, sql.ErrNoRows) { if c == 0 || errors.Is(err, sql.ErrNoRows) {
userID := loggedUser(r.ctx).ID userID := loggedUser(r.ctx).ID
values := map[string]interface{}{} values := map[string]any{}
values["user_id"] = userID values["user_id"] = userID
values["item_type"] = r.tableName values["item_type"] = r.tableName
values["item_id"] = itemID values["item_id"] = itemID
+5 -5
View File
@@ -32,17 +32,17 @@ var _ = Describe("Annotation Filters", func() {
Describe("annotationBoolFilter", func() { Describe("annotationBoolFilter", func() {
DescribeTable("creates correct SQL expressions", DescribeTable("creates correct SQL expressions",
func(field, value string, expectedSQL string, expectedArgs []interface{}) { func(field, value string, expectedSQL string, expectedArgs []any) {
sqlizer := annotationBoolFilter(field)(field, value) sqlizer := annotationBoolFilter(field)(field, value)
sql, args, err := sqlizer.ToSql() sql, args, err := sqlizer.ToSql()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sql).To(Equal(expectedSQL)) Expect(sql).To(Equal(expectedSQL))
Expect(args).To(Equal(expectedArgs)) Expect(args).To(Equal(expectedArgs))
}, },
Entry("starred=true", "starred", "true", "COALESCE(starred, 0) > 0", []interface{}(nil)), Entry("starred=true", "starred", "true", "COALESCE(starred, 0) > 0", []any(nil)),
Entry("starred=false", "starred", "false", "COALESCE(starred, 0) = 0", []interface{}(nil)), Entry("starred=false", "starred", "false", "COALESCE(starred, 0) = 0", []any(nil)),
Entry("starred=True (case insensitive)", "starred", "True", "COALESCE(starred, 0) > 0", []interface{}(nil)), Entry("starred=True (case insensitive)", "starred", "True", "COALESCE(starred, 0) > 0", []any(nil)),
Entry("rating=true", "rating", "true", "COALESCE(rating, 0) > 0", []interface{}(nil)), Entry("rating=true", "rating", "true", "COALESCE(rating, 0) > 0", []any(nil)),
) )
It("returns nil if value is not a string", func() { It("returns nil if value is not a string", func() {
+7 -7
View File
@@ -196,7 +196,7 @@ func (r *sqlRepository) withTableName(filter filterFunc) filterFunc {
} }
// libraryIdFilter is a filter function to be added to resources that have a library_id column. // libraryIdFilter is a filter function to be added to resources that have a library_id column.
func libraryIdFilter(_ string, value interface{}) Sqlizer { func libraryIdFilter(_ string, value any) Sqlizer {
return Eq{"library_id": value} return Eq{"library_id": value}
} }
@@ -281,7 +281,7 @@ func (r sqlRepository) toSQL(sq Sqlizer) (string, dbx.Params, error) {
return result, params, nil return result, params, nil
} }
func (r sqlRepository) queryOne(sq Sqlizer, response interface{}) error { func (r sqlRepository) queryOne(sq Sqlizer, response any) error {
query, args, err := r.toSQL(sq) query, args, err := r.toSQL(sq)
if err != nil { if err != nil {
return err return err
@@ -328,7 +328,7 @@ func queryWithStableResults[T any](r sqlRepository, sq SelectBuilder, options ..
}, nil }, nil
} }
func (r sqlRepository) queryAll(sq SelectBuilder, response interface{}, options ...model.QueryOptions) error { func (r sqlRepository) queryAll(sq SelectBuilder, response any, options ...model.QueryOptions) error {
if len(options) > 0 && options[0].Offset > 0 { if len(options) > 0 && options[0].Offset > 0 {
sq = r.optimizePagination(sq, options[0]) sq = r.optimizePagination(sq, options[0])
} }
@@ -347,7 +347,7 @@ func (r sqlRepository) queryAll(sq SelectBuilder, response interface{}, options
} }
// queryAllSlice is a helper function to query a single column and return the result in a slice // queryAllSlice is a helper function to query a single column and return the result in a slice
func (r sqlRepository) queryAllSlice(sq SelectBuilder, response interface{}) error { func (r sqlRepository) queryAllSlice(sq SelectBuilder, response any) error {
query, args, err := r.toSQL(sq) query, args, err := r.toSQL(sq)
if err != nil { if err != nil {
return err return err
@@ -394,7 +394,7 @@ func (r sqlRepository) count(countQuery SelectBuilder, options ...model.QueryOpt
return res.Count, err return res.Count, err
} }
func (r sqlRepository) putByMatch(filter Sqlizer, id string, m interface{}, colsToUpdate ...string) (string, error) { func (r sqlRepository) putByMatch(filter Sqlizer, id string, m any, colsToUpdate ...string) (string, error) {
if id != "" { if id != "" {
return r.put(id, m, colsToUpdate...) return r.put(id, m, colsToUpdate...)
} }
@@ -408,14 +408,14 @@ func (r sqlRepository) putByMatch(filter Sqlizer, id string, m interface{}, cols
return r.put(res.ID, m, colsToUpdate...) return r.put(res.ID, m, colsToUpdate...)
} }
func (r sqlRepository) put(id string, m interface{}, colsToUpdate ...string) (newId string, err error) { func (r sqlRepository) put(id string, m any, colsToUpdate ...string) (newId string, err error) {
values, err := toSQLArgs(m) values, err := toSQLArgs(m)
if err != nil { if err != nil {
return "", fmt.Errorf("error preparing values to write to DB: %w", err) return "", fmt.Errorf("error preparing values to write to DB: %w", err)
} }
// If there's an ID, try to update first // If there's an ID, try to update first
if id != "" { if id != "" {
updateValues := map[string]interface{}{} updateValues := map[string]any{}
// This is a map of the columns that need to be updated, if specified // This is a map of the columns that need to be updated, if specified
c2upd := slice.ToMap(colsToUpdate, func(s string) (string, struct{}) { c2upd := slice.ToMap(colsToUpdate, func(s string) (string, struct{}) {
+1 -1
View File
@@ -37,7 +37,7 @@ func (r sqlRepository) bmkID(itemID ...string) And {
func (r sqlRepository) bmkUpsert(itemID, comment string, position int64) error { func (r sqlRepository) bmkUpsert(itemID, comment string, position int64) error {
client, _ := request.ClientFrom(r.ctx) client, _ := request.ClientFrom(r.ctx)
user, _ := request.UserFrom(r.ctx) user, _ := request.UserFrom(r.ctx)
values := map[string]interface{}{ values := map[string]any{
"comment": comment, "comment": comment,
"position": position, "position": position,
"updated_at": time.Now(), "updated_at": time.Now(),
+7 -7
View File
@@ -30,7 +30,7 @@ var _ = Describe("sqlRestful", func() {
r.filterMappings = map[string]filterFunc{ r.filterMappings = map[string]filterFunc{
"name": fullTextFilter("table"), "name": fullTextFilter("table"),
} }
options.Filters = map[string]interface{}{"name": "'"} options.Filters = map[string]any{"name": "'"}
Expect(r.parseRestFilters(context.Background(), options)).To(BeEmpty()) Expect(r.parseRestFilters(context.Background(), options)).To(BeEmpty())
}) })
@@ -40,32 +40,32 @@ var _ = Describe("sqlRestful", func() {
return nil return nil
}, },
} }
options.Filters = map[string]interface{}{"name": "joe"} options.Filters = map[string]any{"name": "joe"}
Expect(r.parseRestFilters(context.Background(), options)).To(BeEmpty()) Expect(r.parseRestFilters(context.Background(), options)).To(BeEmpty())
}) })
It("returns a '=' condition for 'id' filter", func() { It("returns a '=' condition for 'id' filter", func() {
options.Filters = map[string]interface{}{"id": "123"} options.Filters = map[string]any{"id": "123"}
Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Eq{"id": "123"}})) Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Eq{"id": "123"}}))
}) })
It("returns a 'in' condition for multiples 'id' filters", func() { It("returns a 'in' condition for multiples 'id' filters", func() {
options.Filters = map[string]interface{}{"id": []string{"123", "456"}} options.Filters = map[string]any{"id": []string{"123", "456"}}
Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Eq{"id": []string{"123", "456"}}})) Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Eq{"id": []string{"123", "456"}}}))
}) })
It("returns a 'like' condition for other filters", func() { It("returns a 'like' condition for other filters", func() {
options.Filters = map[string]interface{}{"name": "joe"} options.Filters = map[string]any{"name": "joe"}
Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Like{"name": "joe%"}})) Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Like{"name": "joe%"}}))
}) })
It("uses the custom filter", func() { It("uses the custom filter", func() {
r.filterMappings = map[string]filterFunc{ r.filterMappings = map[string]filterFunc{
"test": func(field string, value interface{}) squirrel.Sqlizer { "test": func(field string, value any) squirrel.Sqlizer {
return squirrel.Gt{field: value} return squirrel.Gt{field: value}
}, },
} }
options.Filters = map[string]interface{}{"test": 100} options.Filters = map[string]any{"test": 100}
Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Gt{"test": 100}})) Expect(r.parseRestFilters(context.Background(), options)).To(Equal(squirrel.And{squirrel.Gt{"test": 100}}))
}) })
}) })
+4 -4
View File
@@ -60,7 +60,7 @@ func tagIDFilter(name string, idValue any) Sqlizer {
} }
// tagLibraryIdFilter filters tags based on library access through the library_tag table // tagLibraryIdFilter filters tags based on library access through the library_tag table
func tagLibraryIdFilter(_ string, value interface{}) Sqlizer { func tagLibraryIdFilter(_ string, value any) Sqlizer {
return Eq{"library_tag.library_id": value} return Eq{"library_tag.library_id": value}
} }
@@ -142,14 +142,14 @@ func (r *baseTagRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.count(sq, r.parseRestOptions(r.ctx, options...)) return r.count(sq, r.parseRestOptions(r.ctx, options...))
} }
func (r *baseTagRepository) Read(id string) (interface{}, error) { func (r *baseTagRepository) Read(id string) (any, error) {
query := r.newSelect().Where(Eq{"id": id}) query := r.newSelect().Where(Eq{"id": id})
var res model.Tag var res model.Tag
err := r.queryOne(query, &res) err := r.queryOne(query, &res)
return &res, err return &res, err
} }
func (r *baseTagRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *baseTagRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
query := r.newSelect(r.parseRestOptions(r.ctx, options...)) query := r.newSelect(r.parseRestOptions(r.ctx, options...))
var res model.TagList var res model.TagList
err := r.queryAll(query, &res) err := r.queryAll(query, &res)
@@ -160,7 +160,7 @@ func (r *baseTagRepository) EntityName() string {
return "tag" return "tag"
} }
func (r *baseTagRepository) NewInstance() interface{} { func (r *baseTagRepository) NewInstance() any {
return model.Tag{} return model.Tag{}
} }
+6 -6
View File
@@ -165,7 +165,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should respect explicit library_id filters within accessible libraries", func() { It("should respect explicit library_id filters within accessible libraries", func() {
tags := readAllTags(&regularUser, rest.QueryOptions{ tags := readAllTags(&regularUser, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID2}, Filters: map[string]any{"library_id": libraryID2},
}) })
// Should see only tags from library 2: pop and rock(lib2) // Should see only tags from library 2: pop and rock(lib2)
Expect(tags).To(HaveLen(2)) Expect(tags).To(HaveLen(2))
@@ -174,7 +174,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should not return tags when filtering by inaccessible library", func() { It("should not return tags when filtering by inaccessible library", func() {
tags := readAllTags(&regularUser, rest.QueryOptions{ tags := readAllTags(&regularUser, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID3}, Filters: map[string]any{"library_id": libraryID3},
}) })
// Should return no tags since user can't access library 3 // Should return no tags since user can't access library 3
Expect(tags).To(HaveLen(0)) Expect(tags).To(HaveLen(0))
@@ -182,7 +182,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should filter by library 1 correctly", func() { It("should filter by library 1 correctly", func() {
tags := readAllTags(&regularUser, rest.QueryOptions{ tags := readAllTags(&regularUser, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID1}, Filters: map[string]any{"library_id": libraryID1},
}) })
// Should see only rock from library 1 // Should see only rock from library 1
Expect(tags).To(HaveLen(1)) Expect(tags).To(HaveLen(1))
@@ -227,7 +227,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should allow headless processes to apply explicit library_id filters", func() { It("should allow headless processes to apply explicit library_id filters", func() {
tags := readAllTags(nil, rest.QueryOptions{ tags := readAllTags(nil, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID3}, Filters: map[string]any{"library_id": libraryID3},
}) })
// Should see only jazz from library 3 // Should see only jazz from library 3
Expect(tags).To(HaveLen(1)) Expect(tags).To(HaveLen(1))
@@ -243,7 +243,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should respect explicit library_id filters", func() { It("should respect explicit library_id filters", func() {
tags := readAllTags(&adminUser, rest.QueryOptions{ tags := readAllTags(&adminUser, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID3}, Filters: map[string]any{"library_id": libraryID3},
}) })
// Should see only jazz from library 3 // Should see only jazz from library 3
Expect(tags).To(HaveLen(1)) Expect(tags).To(HaveLen(1))
@@ -252,7 +252,7 @@ var _ = Describe("Tag Library Filtering", func() {
It("should filter by library 2 correctly", func() { It("should filter by library 2 correctly", func() {
tags := readAllTags(&adminUser, rest.QueryOptions{ tags := readAllTags(&adminUser, rest.QueryOptions{
Filters: map[string]interface{}{"library_id": libraryID2}, Filters: map[string]any{"library_id": libraryID2},
}) })
// Should see pop and rock from library 2 // Should see pop and rock from library 2
Expect(tags).To(HaveLen(2)) Expect(tags).To(HaveLen(2))
+4 -4
View File
@@ -234,7 +234,7 @@ var _ = Describe("TagRepository", func() {
It("should filter tags by partial value correctly", func() { It("should filter tags by partial value correctly", func() {
options := rest.QueryOptions{ options := rest.QueryOptions{
Filters: map[string]interface{}{"name": "%rock%"}, // Tags containing 'rock' Filters: map[string]any{"name": "%rock%"}, // Tags containing 'rock'
} }
result, err := restRepo.ReadAll(options) result, err := restRepo.ReadAll(options)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -249,7 +249,7 @@ var _ = Describe("TagRepository", func() {
It("should filter tags by partial value using LIKE", func() { It("should filter tags by partial value using LIKE", func() {
options := rest.QueryOptions{ options := rest.QueryOptions{
Filters: map[string]interface{}{"name": "%e%"}, // Tags containing 'e' Filters: map[string]any{"name": "%e%"}, // Tags containing 'e'
} }
result, err := restRepo.ReadAll(options) result, err := restRepo.ReadAll(options)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -264,7 +264,7 @@ var _ = Describe("TagRepository", func() {
It("should sort tags by value ascending", func() { It("should sort tags by value ascending", func() {
options := rest.QueryOptions{ options := rest.QueryOptions{
Filters: map[string]interface{}{"name": "%r%"}, // Tags containing 'r' Filters: map[string]any{"name": "%r%"}, // Tags containing 'r'
Sort: "name", Sort: "name",
Order: "asc", Order: "asc",
} }
@@ -280,7 +280,7 @@ var _ = Describe("TagRepository", func() {
It("should sort tags by value descending", func() { It("should sort tags by value descending", func() {
options := rest.QueryOptions{ options := rest.QueryOptions{
Filters: map[string]interface{}{"name": "%r%"}, // Tags containing 'r' Filters: map[string]any{"name": "%r%"}, // Tags containing 'r'
Sort: "name", Sort: "name",
Order: "desc", Order: "desc",
} }
+5 -5
View File
@@ -52,11 +52,11 @@ func (r *transcodingRepository) Count(options ...rest.QueryOptions) (int64, erro
return r.count(Select(), r.parseRestOptions(r.ctx, options...)) return r.count(Select(), r.parseRestOptions(r.ctx, options...))
} }
func (r *transcodingRepository) Read(id string) (interface{}, error) { func (r *transcodingRepository) Read(id string) (any, error) {
return r.Get(id) return r.Get(id)
} }
func (r *transcodingRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (r *transcodingRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
sel := r.newSelect(r.parseRestOptions(r.ctx, options...)).Columns("*") sel := r.newSelect(r.parseRestOptions(r.ctx, options...)).Columns("*")
res := model.Transcodings{} res := model.Transcodings{}
err := r.queryAll(sel, &res) err := r.queryAll(sel, &res)
@@ -67,11 +67,11 @@ func (r *transcodingRepository) EntityName() string {
return "transcoding" return "transcoding"
} }
func (r *transcodingRepository) NewInstance() interface{} { func (r *transcodingRepository) NewInstance() any {
return &model.Transcoding{} return &model.Transcoding{}
} }
func (r *transcodingRepository) Save(entity interface{}) (string, error) { func (r *transcodingRepository) Save(entity any) (string, error) {
if !loggedUser(r.ctx).IsAdmin { if !loggedUser(r.ctx).IsAdmin {
return "", rest.ErrPermissionDenied return "", rest.ErrPermissionDenied
} }
@@ -83,7 +83,7 @@ func (r *transcodingRepository) Save(entity interface{}) (string, error) {
return id, err return id, err
} }
func (r *transcodingRepository) Update(id string, entity interface{}, cols ...string) error { func (r *transcodingRepository) Update(id string, entity any, cols ...string) error {
if !loggedUser(r.ctx).IsAdmin { if !loggedUser(r.ctx).IsAdmin {
return rest.ErrPermissionDenied return rest.ErrPermissionDenied
} }
+5 -11
View File
@@ -1,5 +1,7 @@
package plugins package plugins
import "slices"
// Capability represents a plugin capability type. // Capability represents a plugin capability type.
// Capabilities are detected by checking which functions a plugin exports. // Capabilities are detected by checking which functions a plugin exports.
type Capability string type Capability string
@@ -25,11 +27,8 @@ func detectCapabilities(plugin functionExistsChecker) []Capability {
var capabilities []Capability var capabilities []Capability
for cap, functions := range capabilityFunctions { for cap, functions := range capabilityFunctions {
for _, fn := range functions { if slices.ContainsFunc(functions, plugin.FunctionExists) {
if plugin.FunctionExists(fn) { capabilities = append(capabilities, cap) // Found at least one function, plugin has this capability
capabilities = append(capabilities, cap)
break // Found at least one function, plugin has this capability
}
} }
} }
@@ -38,10 +37,5 @@ func detectCapabilities(plugin functionExistsChecker) []Capability {
// hasCapability checks if the given capabilities slice contains a specific capability. // hasCapability checks if the given capabilities slice contains a specific capability.
func hasCapability(capabilities []Capability, cap Capability) bool { func hasCapability(capabilities []Capability, cap Capability) bool {
for _, c := range capabilities { return slices.Contains(capabilities, cap)
if c == cap {
return true
}
}
return false
} }
+2 -3
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"maps"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@@ -200,9 +201,7 @@ func (s *webSocketServiceImpl) CloseConnection(ctx context.Context, connectionID
func (s *webSocketServiceImpl) Close() error { func (s *webSocketServiceImpl) Close() error {
s.mu.Lock() s.mu.Lock()
connections := make(map[string]*wsConnection, len(s.connections)) connections := make(map[string]*wsConnection, len(s.connections))
for k, v := range s.connections { maps.Copy(connections, s.connections)
connections[k] = v
}
s.connections = make(map[string]*wsConnection) s.connections = make(map[string]*wsConnection)
s.mu.Unlock() s.mu.Unlock()
+2 -2
View File
@@ -65,8 +65,8 @@ func (ic *IgnoreChecker) PushAllParents(ctx context.Context, targetPath string)
// Load patterns for each parent directory // Load patterns for each parent directory
currentPath := "." currentPath := "."
parts := strings.Split(path.Clean(targetPath), "/") parts := strings.SplitSeq(path.Clean(targetPath), "/")
for _, part := range parts { for part := range parts {
if part == "." || part == "" { if part == "." || part == "" {
continue continue
} }
+2 -2
View File
@@ -215,8 +215,8 @@ func (t Tags) Lyrics() string {
} }
for tag, value := range t.Tags { for tag, value := range t.Tags {
if strings.HasPrefix(tag, "lyrics-") { if after, ok := strings.CutPrefix(tag, "lyrics-"); ok {
language := strings.TrimSpace(strings.TrimPrefix(tag, "lyrics-")) language := strings.TrimSpace(after)
if language == "" { if language == "" {
language = "xxx" language = "xxx"
+4 -4
View File
@@ -6,16 +6,16 @@ import (
type logger struct{} type logger struct{}
func (l *logger) Info(msg string, keysAndValues ...interface{}) { func (l *logger) Info(msg string, keysAndValues ...any) {
args := []interface{}{ args := []any{
"Scheduler: " + msg, "Scheduler: " + msg,
} }
args = append(args, keysAndValues...) args = append(args, keysAndValues...)
log.Debug(args...) log.Debug(args...)
} }
func (l *logger) Error(err error, msg string, keysAndValues ...interface{}) { func (l *logger) Error(err error, msg string, keysAndValues ...any) {
args := []interface{}{ args := []any{
"Scheduler: " + msg, "Scheduler: " + msg,
} }
args = append(args, keysAndValues...) args = append(args, keysAndValues...)
+3 -3
View File
@@ -68,8 +68,8 @@ func doLogin(ds model.DataStore, username string, password string, w http.Respon
_ = rest.RespondWithJSON(w, http.StatusOK, payload) _ = rest.RespondWithJSON(w, http.StatusOK, payload)
} }
func buildAuthPayload(user *model.User) map[string]interface{} { func buildAuthPayload(user *model.User) map[string]any {
payload := map[string]interface{}{ payload := map[string]any{
"id": user.ID, "id": user.ID,
"name": user.Name, "name": user.Name,
"username": user.UserName, "username": user.UserName,
@@ -288,7 +288,7 @@ func JWTRefresher(next http.Handler) http.Handler {
}) })
} }
func handleLoginFromHeaders(ds model.DataStore, r *http.Request) map[string]interface{} { func handleLoginFromHeaders(ds model.DataStore, r *http.Request) map[string]any {
username := UsernameFromConfig(r) username := UsernameFromConfig(r)
if username == "" { if username == "" {
username = UsernameFromExtAuthHeader(r) username = UsernameFromExtAuthHeader(r)
+7 -7
View File
@@ -53,7 +53,7 @@ var _ = Describe("Auth", func() {
It("returns the expected payload", func() { It("returns the expected payload", func() {
Expect(resp.Code).To(Equal(http.StatusOK)) Expect(resp.Code).To(Equal(http.StatusOK))
var parsed map[string]interface{} var parsed map[string]any
Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil())
Expect(parsed["isAdmin"]).To(Equal(true)) Expect(parsed["isAdmin"]).To(Equal(true))
Expect(parsed["username"]).To(Equal("johndoe")) Expect(parsed["username"]).To(Equal("johndoe"))
@@ -88,7 +88,7 @@ var _ = Describe("Auth", func() {
serveIndex(ds, fs, nil)(resp, req) serveIndex(ds, fs, nil)(resp, req)
config := extractAppConfig(resp.Body.String()) config := extractAppConfig(resp.Body.String())
parsed := config["auth"].(map[string]interface{}) parsed := config["auth"].(map[string]any)
Expect(parsed["id"]).To(Equal("111")) Expect(parsed["id"]).To(Equal("111"))
}) })
@@ -106,7 +106,7 @@ var _ = Describe("Auth", func() {
serveIndex(ds, fs, nil)(resp, req) serveIndex(ds, fs, nil)(resp, req)
config := extractAppConfig(resp.Body.String()) config := extractAppConfig(resp.Body.String())
parsed := config["auth"].(map[string]interface{}) parsed := config["auth"].(map[string]any)
Expect(parsed["id"]).To(Equal("111")) Expect(parsed["id"]).To(Equal("111"))
}) })
@@ -127,7 +127,7 @@ var _ = Describe("Auth", func() {
serveIndex(ds, fs, nil)(resp, req) serveIndex(ds, fs, nil)(resp, req)
config := extractAppConfig(resp.Body.String()) config := extractAppConfig(resp.Body.String())
parsed := config["auth"].(map[string]interface{}) parsed := config["auth"].(map[string]any)
Expect(parsed["username"]).To(Equal(newUser)) Expect(parsed["username"]).To(Equal(newUser))
}) })
@@ -137,7 +137,7 @@ var _ = Describe("Auth", func() {
serveIndex(ds, fs, nil)(resp, req) serveIndex(ds, fs, nil)(resp, req)
config := extractAppConfig(resp.Body.String()) config := extractAppConfig(resp.Body.String())
parsed := config["auth"].(map[string]interface{}) parsed := config["auth"].(map[string]any)
Expect(parsed["id"]).To(Equal("111")) Expect(parsed["id"]).To(Equal("111"))
Expect(parsed["isAdmin"]).To(BeFalse()) Expect(parsed["isAdmin"]).To(BeFalse())
@@ -182,7 +182,7 @@ var _ = Describe("Auth", func() {
serveIndex(ds, fs, nil)(resp, req) serveIndex(ds, fs, nil)(resp, req)
config := extractAppConfig(resp.Body.String()) config := extractAppConfig(resp.Body.String())
parsed := config["auth"].(map[string]interface{}) parsed := config["auth"].(map[string]any)
Expect(parsed["id"]).To(Equal("111")) Expect(parsed["id"]).To(Equal("111"))
}) })
@@ -206,7 +206,7 @@ var _ = Describe("Auth", func() {
login(ds)(resp, req) login(ds)(resp, req)
Expect(resp.Code).To(Equal(http.StatusOK)) Expect(resp.Code).To(Equal(http.StatusOK))
var parsed map[string]interface{} var parsed map[string]any
Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil())
Expect(parsed["isAdmin"]).To(Equal(false)) Expect(parsed["isAdmin"]).To(Equal(false))
Expect(parsed["username"]).To(Equal("janedoe")) Expect(parsed["username"]).To(Equal("janedoe"))
+1 -1
View File
@@ -37,7 +37,7 @@ func requestLogger(next http.Handler) http.Handler {
status := ww.Status() status := ww.Status()
message := fmt.Sprintf("HTTP: %s %s://%s%s", r.Method, scheme, r.Host, r.RequestURI) message := fmt.Sprintf("HTTP: %s %s://%s%s", r.Method, scheme, r.Host, r.RequestURI)
logArgs := []interface{}{ logArgs := []any{
r.Context(), r.Context(),
message, message,
"remoteAddr", r.RemoteAddr, "remoteAddr", r.RemoteAddr,
+6 -7
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"slices"
"strings" "strings"
"github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/conf"
@@ -37,7 +38,7 @@ var sensitiveFieldsFullMask = []string{
type configResponse struct { type configResponse struct {
ID string `json:"id"` ID string `json:"id"`
ConfigFile string `json:"configFile"` ConfigFile string `json:"configFile"`
Config map[string]interface{} `json:"config"` Config map[string]any `json:"config"`
} }
func redactValue(key string, value string) string { func redactValue(key string, value string) string {
@@ -47,11 +48,9 @@ func redactValue(key string, value string) string {
} }
// Check if this field should be fully masked // Check if this field should be fully masked
for _, field := range sensitiveFieldsFullMask { if slices.Contains(sensitiveFieldsFullMask, key) {
if field == key {
return "****" return "****"
} }
}
// Check if this field should be partially masked // Check if this field should be partially masked
for _, field := range sensitiveFieldsPartialMask { for _, field := range sensitiveFieldsPartialMask {
@@ -69,7 +68,7 @@ func redactValue(key string, value string) string {
} }
// applySensitiveFieldMasking recursively applies masking to sensitive fields in the configuration map // applySensitiveFieldMasking recursively applies masking to sensitive fields in the configuration map
func applySensitiveFieldMasking(ctx context.Context, config map[string]interface{}, prefix string) { func applySensitiveFieldMasking(ctx context.Context, config map[string]any, prefix string) {
for key, value := range config { for key, value := range config {
fullKey := key fullKey := key
if prefix != "" { if prefix != "" {
@@ -77,7 +76,7 @@ func applySensitiveFieldMasking(ctx context.Context, config map[string]interface
} }
switch v := value.(type) { switch v := value.(type) {
case map[string]interface{}: case map[string]any:
// Recursively process nested maps // Recursively process nested maps
applySensitiveFieldMasking(ctx, v, fullKey) applySensitiveFieldMasking(ctx, v, fullKey)
case string: case string:
@@ -108,7 +107,7 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
} }
// Unmarshal back to map to get the structure with proper field names // Unmarshal back to map to get the structure with proper field names
var configMap map[string]interface{} var configMap map[string]any
err = json.Unmarshal(configBytes, &configMap) err = json.Unmarshal(configBytes, &configMap)
if err != nil { if err != nil {
log.Error(ctx, "Error unmarshaling config to map", err) log.Error(ctx, "Error unmarshaling config to map", err)
+4 -4
View File
@@ -93,12 +93,12 @@ var _ = Describe("Config API", func() {
Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed()) Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed())
// Check LastFM.ApiKey (partially masked) // Check LastFM.ApiKey (partially masked)
lastfm, ok := resp.Config["LastFM"].(map[string]interface{}) lastfm, ok := resp.Config["LastFM"].(map[string]any)
Expect(ok).To(BeTrue()) Expect(ok).To(BeTrue())
Expect(lastfm["ApiKey"]).To(Equal("s*************3")) Expect(lastfm["ApiKey"]).To(Equal("s*************3"))
// Check Spotify.Secret (partially masked) // Check Spotify.Secret (partially masked)
spotify, ok := resp.Config["Spotify"].(map[string]interface{}) spotify, ok := resp.Config["Spotify"].(map[string]any)
Expect(ok).To(BeTrue()) Expect(ok).To(BeTrue())
Expect(spotify["Secret"]).To(Equal("s**************6")) Expect(spotify["Secret"]).To(Equal("s**************6"))
@@ -109,7 +109,7 @@ var _ = Describe("Config API", func() {
Expect(resp.Config["DevAutoCreateAdminPassword"]).To(Equal("****")) Expect(resp.Config["DevAutoCreateAdminPassword"]).To(Equal("****"))
// Check Prometheus.Password (fully masked) // Check Prometheus.Password (fully masked)
prometheus, ok := resp.Config["Prometheus"].(map[string]interface{}) prometheus, ok := resp.Config["Prometheus"].(map[string]any)
Expect(ok).To(BeTrue()) Expect(ok).To(BeTrue())
Expect(prometheus["Password"]).To(Equal("****")) Expect(prometheus["Password"]).To(Equal("****"))
}) })
@@ -128,7 +128,7 @@ var _ = Describe("Config API", func() {
Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed()) Expect(json.Unmarshal(w.Body.Bytes(), &resp)).To(Succeed())
// Check LastFM.ApiKey - should be preserved because it's sensitive // Check LastFM.ApiKey - should be preserved because it's sensitive
lastfm, ok := resp.Config["LastFM"].(map[string]interface{}) lastfm, ok := resp.Config["LastFM"].(map[string]any)
Expect(ok).To(BeTrue()) Expect(ok).To(BeTrue())
Expect(lastfm["ApiKey"]).To(Equal("")) Expect(lastfm["ApiKey"]).To(Equal(""))
+1 -1
View File
@@ -95,7 +95,7 @@ func (api *Router) routes() http.Handler {
return r return r
} }
func (api *Router) R(r chi.Router, pathPrefix string, model interface{}, persistable bool) { func (api *Router) R(r chi.Router, pathPrefix string, model any, persistable bool) {
constructor := func(ctx context.Context) rest.Repository { constructor := func(ctx context.Context) rest.Repository {
return api.ds.Resource(ctx, model) return api.ds.Resource(ctx, model)
} }
+1 -1
View File
@@ -218,7 +218,7 @@ func reorderItem(ds model.DataStore) http.HandlerFunc {
return return
} }
_, err = w.Write([]byte(fmt.Sprintf(`{"id":"%d"}`, id))) _, err = w.Write(fmt.Appendf(nil, `{"id":"%d"}`, id))
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
+4 -4
View File
@@ -28,7 +28,7 @@ func newTranslationRepository(context.Context) rest.Repository {
type translationRepository struct{} type translationRepository struct{}
func (r *translationRepository) Read(id string) (interface{}, error) { func (r *translationRepository) Read(id string) (any, error) {
translations, _ := loadTranslations() translations, _ := loadTranslations()
if t, ok := translations[id]; ok { if t, ok := translations[id]; ok {
return t, nil return t, nil
@@ -43,7 +43,7 @@ func (r *translationRepository) Count(...rest.QueryOptions) (int64, error) {
} }
// ReadAll simple implementation, only returns IDs. Does not support any `options` // ReadAll simple implementation, only returns IDs. Does not support any `options`
func (r *translationRepository) ReadAll(...rest.QueryOptions) (interface{}, error) { func (r *translationRepository) ReadAll(...rest.QueryOptions) (any, error) {
translations, _ := loadTranslations() translations, _ := loadTranslations()
var result []translation var result []translation
for _, t := range translations { for _, t := range translations {
@@ -57,7 +57,7 @@ func (r *translationRepository) EntityName() string {
return "translation" return "translation"
} }
func (r *translationRepository) NewInstance() interface{} { func (r *translationRepository) NewInstance() any {
return &translation{} return &translation{}
} }
@@ -103,7 +103,7 @@ func loadTranslation(fsys fs.FS, fileName string) (translation translation, err
if err != nil { if err != nil {
return return
} }
var out map[string]interface{} var out map[string]any
if err = json.Unmarshal(data, &out); err != nil { if err = json.Unmarshal(data, &out); err != nil {
return return
} }
+2 -2
View File
@@ -24,7 +24,7 @@ var _ = Describe("Translations", func() {
filePath := filepath.Join(consts.I18nFolder, name) filePath := filepath.Join(consts.I18nFolder, name)
file, _ := fsys.Open(filePath) file, _ := fsys.Open(filePath)
data, _ := io.ReadAll(file) data, _ := io.ReadAll(file)
var out map[string]interface{} var out map[string]any
Expect(filepath.Ext(filePath)).To(Equal(".json"), filePath) Expect(filepath.Ext(filePath)).To(Equal(".json"), filePath)
Expect(json.Unmarshal(data, &out)).To(BeNil(), filePath) Expect(json.Unmarshal(data, &out)).To(BeNil(), filePath)
@@ -40,7 +40,7 @@ var _ = Describe("Translations", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(tr.ID).To(Equal("en")) Expect(tr.ID).To(Equal("en"))
Expect(tr.Name).To(Equal("English")) Expect(tr.Name).To(Equal("English"))
var out map[string]interface{} var out map[string]any
Expect(json.Unmarshal([]byte(tr.Data), &out)).To(BeNil()) Expect(json.Unmarshal([]byte(tr.Data), &out)).To(BeNil())
}) })
}) })
+3 -3
View File
@@ -39,7 +39,7 @@ func serveIndex(ds model.DataStore, fs fs.FS, shareInfo *model.Share) http.Handl
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
appConfig := map[string]interface{}{ appConfig := map[string]any{
"version": consts.Version, "version": consts.Version,
"firstTime": firstTime, "firstTime": firstTime,
"variousArtistsId": consts.VariousArtistsID, "variousArtistsId": consts.VariousArtistsID,
@@ -95,7 +95,7 @@ func serveIndex(ds model.DataStore, fs fs.FS, shareInfo *model.Share) http.Handl
if version != "dev" { if version != "dev" {
version = "v" + version version = "v" + version
} }
data := map[string]interface{}{ data := map[string]any{
"AppConfig": string(appConfigJson), "AppConfig": string(appConfigJson),
"Version": version, "Version": version,
} }
@@ -145,7 +145,7 @@ type shareTrack struct {
Duration float32 `json:"duration,omitempty"` Duration float32 `json:"duration,omitempty"`
} }
func addShareData(r *http.Request, data map[string]interface{}, shareInfo *model.Share) { func addShareData(r *http.Request, data map[string]any, shareInfo *model.Share) {
ctx := r.Context() ctx := r.Context()
if shareInfo == nil || shareInfo.ID == "" { if shareInfo == nil || shareInfo.ID == "" {
return return
+2 -2
View File
@@ -80,8 +80,8 @@ func (s *Server) Run(ctx context.Context, addr string, port int, tlsCert string,
// Create a listener based on the address type (either Unix socket or TCP) // Create a listener based on the address type (either Unix socket or TCP)
var listener net.Listener var listener net.Listener
var err error var err error
if strings.HasPrefix(addr, "unix:") { if after, ok := strings.CutPrefix(addr, "unix:"); ok {
socketPath := strings.TrimPrefix(addr, "unix:") socketPath := after
listener, err = createUnixSocketFile(socketPath, conf.Server.UnixSocketPerm) listener, err = createUnixSocketFile(socketPath, conf.Server.UnixSocketPerm)
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -319,7 +319,7 @@ func sendResponse(w http.ResponseWriter, r *http.Request, payload *responses.Sub
callback, _ := p.String("callback") callback, _ := p.String("callback")
wrapper := &responses.JsonWrapper{Subsonic: *payload} wrapper := &responses.JsonWrapper{Subsonic: *payload}
response, err = json.Marshal(wrapper) response, err = json.Marshal(wrapper)
response = []byte(fmt.Sprintf("%s(%s)", callback, response)) response = fmt.Appendf(nil, "%s(%s)", callback, response)
default: default:
w.Header().Set("Content-Type", "application/xml") w.Header().Set("Content-Type", "application/xml")
response, err = xml.Marshal(payload) response, err = xml.Marshal(payload)
+4 -4
View File
@@ -34,10 +34,10 @@ func newResponse() *responses.Subsonic {
type subError struct { type subError struct {
code int32 code int32
messages []interface{} messages []any
} }
func newError(code int32, message ...interface{}) error { func newError(code int32, message ...any) error {
return subError{ return subError{
code: code, code: code,
messages: message, messages: message,
@@ -176,8 +176,8 @@ func isClientInList(clientList, client string) bool {
if clientList == "" || client == "" { if clientList == "" || client == "" {
return false return false
} }
clients := strings.Split(clientList, ",") clients := strings.SplitSeq(clientList, ",")
for _, c := range clients { for c := range clients {
if strings.TrimSpace(c) == client { if strings.TrimSpace(c) == client {
return true return true
} }
+4 -3
View File
@@ -5,6 +5,7 @@ import (
"errors" "errors"
"io" "io"
"net/http" "net/http"
"strings"
"time" "time"
"github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/conf"
@@ -120,12 +121,12 @@ func (api *Router) GetLyrics(r *http.Request) (*responses.Subsonic, error) {
lyricsResponse.Artist = artist lyricsResponse.Artist = artist
lyricsResponse.Title = title lyricsResponse.Title = title
lyricsText := "" var lyricsText strings.Builder
for _, line := range structuredLyrics[0].Line { for _, line := range structuredLyrics[0].Line {
lyricsText += line.Value + "\n" lyricsText.WriteString(line.Value + "\n")
} }
lyricsResponse.Value = lyricsText lyricsResponse.Value = lyricsText.String()
return response, nil return response, nil
} }
+1 -1
View File
@@ -459,7 +459,7 @@ type PlayQueueByIndex struct {
} }
type Bookmark struct { type Bookmark struct {
Entry Child `xml:"entry,omitempty" json:"entry,omitempty"` Entry Child `xml:"entry,omitempty" json:"entry"`
Position int64 `xml:"position,attr,omitempty" json:"position,omitempty"` Position int64 `xml:"position,attr,omitempty" json:"position,omitempty"`
Username string `xml:"username,attr" json:"username"` Username string `xml:"username,attr" json:"username"`
Comment string `xml:"comment,attr" json:"comment"` Comment string `xml:"comment,attr" json:"comment"`
@@ -26,17 +26,17 @@ type snapshotMatcher struct {
c *cupaloy.Config c *cupaloy.Config
} }
func (matcher snapshotMatcher) Match(actual interface{}) (success bool, err error) { func (matcher snapshotMatcher) Match(actual any) (success bool, err error) {
actualJson := strings.TrimSpace(string(actual.([]byte))) actualJson := strings.TrimSpace(string(actual.([]byte)))
err = matcher.c.SnapshotWithName(ginkgo.CurrentSpecReport().FullText(), actualJson) err = matcher.c.SnapshotWithName(ginkgo.CurrentSpecReport().FullText(), actualJson)
success = err == nil success = err == nil
return return
} }
func (matcher snapshotMatcher) FailureMessage(_ interface{}) (message string) { func (matcher snapshotMatcher) FailureMessage(_ any) (message string) {
return "Expected to match saved snapshot\n" return "Expected to match saved snapshot\n"
} }
func (matcher snapshotMatcher) NegatedFailureMessage(_ interface{}) (message string) { func (matcher snapshotMatcher) NegatedFailureMessage(_ any) (message string) {
return "Expected to not match saved snapshot\n" return "Expected to not match saved snapshot\n"
} }
+1 -1
View File
@@ -30,7 +30,7 @@ var _ = Describe("Search", func() {
}) })
Context("musicFolderId parameter", func() { Context("musicFolderId parameter", func() {
assertQueryOptions := func(filter squirrel.Sqlizer, expectedQuery string, expectedArgs ...interface{}) { assertQueryOptions := func(filter squirrel.Sqlizer, expectedQuery string, expectedArgs ...any) {
GinkgoHelper() GinkgoHelper()
query, args, err := filter.ToSql() query, args, err := filter.ToSql()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
+5 -5
View File
@@ -168,7 +168,7 @@ func (m *MockLibraryRepo) Count(options ...rest.QueryOptions) (int64, error) {
return m.CountAll() return m.CountAll()
} }
func (m *MockLibraryRepo) Read(id string) (interface{}, error) { func (m *MockLibraryRepo) Read(id string) (any, error) {
idInt, _ := strconv.Atoi(id) idInt, _ := strconv.Atoi(id)
mf, err := m.Get(idInt) mf, err := m.Get(idInt)
if errors.Is(err, model.ErrNotFound) { if errors.Is(err, model.ErrNotFound) {
@@ -177,7 +177,7 @@ func (m *MockLibraryRepo) Read(id string) (interface{}, error) {
return mf, err return mf, err
} }
func (m *MockLibraryRepo) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (m *MockLibraryRepo) ReadAll(options ...rest.QueryOptions) (any, error) {
return m.GetAll() return m.GetAll()
} }
@@ -185,13 +185,13 @@ func (m *MockLibraryRepo) EntityName() string {
return "library" return "library"
} }
func (m *MockLibraryRepo) NewInstance() interface{} { func (m *MockLibraryRepo) NewInstance() any {
return &model.Library{} return &model.Library{}
} }
// REST Repository methods (string-based IDs) // REST Repository methods (string-based IDs)
func (m *MockLibraryRepo) Save(entity interface{}) (string, error) { func (m *MockLibraryRepo) Save(entity any) (string, error) {
lib := entity.(*model.Library) lib := entity.(*model.Library)
if m.Err != nil { if m.Err != nil {
return "", m.Err return "", m.Err
@@ -216,7 +216,7 @@ func (m *MockLibraryRepo) Save(entity interface{}) (string, error) {
return strconv.Itoa(lib.ID), nil return strconv.Itoa(lib.ID), nil
} }
func (m *MockLibraryRepo) Update(id string, entity interface{}, cols ...string) error { func (m *MockLibraryRepo) Update(id string, entity any, cols ...string) error {
lib := entity.(*model.Library) lib := entity.(*model.Library)
if m.Err != nil { if m.Err != nil {
return m.Err return m.Err
+3 -3
View File
@@ -218,7 +218,7 @@ func (m *MockMediaFileRepo) Count(...rest.QueryOptions) (int64, error) {
return m.CountAll() return m.CountAll()
} }
func (m *MockMediaFileRepo) Read(id string) (interface{}, error) { func (m *MockMediaFileRepo) Read(id string) (any, error) {
mf, err := m.Get(id) mf, err := m.Get(id)
if errors.Is(err, model.ErrNotFound) { if errors.Is(err, model.ErrNotFound) {
return nil, rest.ErrNotFound return nil, rest.ErrNotFound
@@ -226,7 +226,7 @@ func (m *MockMediaFileRepo) Read(id string) (interface{}, error) {
return mf, err return mf, err
} }
func (m *MockMediaFileRepo) ReadAll(...rest.QueryOptions) (interface{}, error) { func (m *MockMediaFileRepo) ReadAll(...rest.QueryOptions) (any, error) {
return m.GetAll() return m.GetAll()
} }
@@ -234,7 +234,7 @@ func (m *MockMediaFileRepo) EntityName() string {
return "mediafile" return "mediafile"
} }
func (m *MockMediaFileRepo) NewInstance() interface{} { func (m *MockMediaFileRepo) NewInstance() any {
return &model.MediaFile{} return &model.MediaFile{}
} }
+5 -5
View File
@@ -54,7 +54,7 @@ func (m *MockPluginRepo) Get(id string) (*model.Plugin, error) {
return nil, model.ErrNotFound return nil, model.ErrNotFound
} }
func (m *MockPluginRepo) Read(id string) (interface{}, error) { func (m *MockPluginRepo) Read(id string) (any, error) {
p, err := m.Get(id) p, err := m.Get(id)
if errors.Is(err, model.ErrNotFound) { if errors.Is(err, model.ErrNotFound) {
return nil, rest.ErrNotFound return nil, rest.ErrNotFound
@@ -151,21 +151,21 @@ func (m *MockPluginRepo) EntityName() string {
return "plugin" return "plugin"
} }
func (m *MockPluginRepo) NewInstance() interface{} { func (m *MockPluginRepo) NewInstance() any {
return &model.Plugin{} return &model.Plugin{}
} }
func (m *MockPluginRepo) ReadAll(options ...rest.QueryOptions) (interface{}, error) { func (m *MockPluginRepo) ReadAll(options ...rest.QueryOptions) (any, error) {
return m.GetAll() return m.GetAll()
} }
func (m *MockPluginRepo) Save(entity interface{}) (string, error) { func (m *MockPluginRepo) Save(entity any) (string, error) {
p := entity.(*model.Plugin) p := entity.(*model.Plugin)
err := m.Put(p) err := m.Put(p)
return p.ID, err return p.ID, err
} }
func (m *MockPluginRepo) Update(id string, entity interface{}, cols ...string) error { func (m *MockPluginRepo) Update(id string, entity any, cols ...string) error {
p := entity.(*model.Plugin) p := entity.(*model.Plugin)
p.ID = id p.ID = id
return m.Put(p) return m.Put(p)
+3 -3
View File
@@ -10,13 +10,13 @@ type MockShareRepo struct {
rest.Repository rest.Repository
rest.Persistable rest.Persistable
Entity interface{} Entity any
ID string ID string
Cols []string Cols []string
Error error Error error
} }
func (m *MockShareRepo) Save(entity interface{}) (string, error) { func (m *MockShareRepo) Save(entity any) (string, error) {
if m.Error != nil { if m.Error != nil {
return "", m.Error return "", m.Error
} }
@@ -28,7 +28,7 @@ func (m *MockShareRepo) Save(entity interface{}) (string, error) {
return s.ID, nil return s.ID, nil
} }
func (m *MockShareRepo) Update(id string, entity interface{}, cols ...string) error { func (m *MockShareRepo) Update(id string, entity any, cols ...string) error {
if m.Error != nil { if m.Error != nil {
return m.Error return m.Error
} }
+2 -2
View File
@@ -149,7 +149,7 @@ func (u *MockedUserRepo) Delete(id string) error {
return model.ErrNotFound return model.ErrNotFound
} }
func (u *MockedUserRepo) Save(entity interface{}) (string, error) { func (u *MockedUserRepo) Save(entity any) (string, error) {
usr := entity.(*model.User) usr := entity.(*model.User)
if err := u.Put(usr); err != nil { if err := u.Put(usr); err != nil {
return "", err return "", err
@@ -157,7 +157,7 @@ func (u *MockedUserRepo) Save(entity interface{}) (string, error) {
return usr.ID, nil return usr.ID, nil
} }
func (u *MockedUserRepo) Update(id string, entity interface{}, cols ...string) error { func (u *MockedUserRepo) Update(id string, entity any, cols ...string) error {
if u.Error != nil { if u.Error != nil {
return u.Error return u.Error
} }
+1 -1
View File
@@ -70,7 +70,7 @@ var _ = Describe("FileHaunter", func() {
func createTestFiles(c *fscache.FSCache) error { func createTestFiles(c *fscache.FSCache) error {
// Create 5 normal files and 1 empty // Create 5 normal files and 1 empty
for i := 0; i < 6; i++ { for i := range 6 {
name := fmt.Sprintf("stream-%v", i) name := fmt.Sprintf("stream-%v", i)
var r fscache.ReadAtCloser var r fscache.ReadAtCloser
if i < 5 { if i < 5 {
+1 -1
View File
@@ -57,7 +57,7 @@ var _ = Describe("HashFunc", func() {
}) })
It("does not cause race conditions", func() { It("does not cause race conditions", func() {
for i := 0; i < 1000; i++ { for i := range 1000 {
go func() { go func() {
hashFunc := hasher.HashFunc() hashFunc := hasher.HashFunc()
sum := hashFunc(strconv.Itoa(i), input) sum := hashFunc(strconv.Itoa(i), input)
+2 -2
View File
@@ -23,8 +23,8 @@ var indexGroupsRx = regexp.MustCompile(`(.+)\((.+)\)`)
func ParseIndexGroups(spec string) IndexGroups { func ParseIndexGroups(spec string) IndexGroups {
parsed := make(IndexGroups) parsed := make(IndexGroups)
split := strings.Split(spec, " ") split := strings.SplitSeq(spec, " ")
for _, g := range split { for g := range split {
sub := indexGroupsRx.FindStringSubmatch(g) sub := indexGroupsRx.FindStringSubmatch(g)
if len(sub) > 0 { if len(sub) > 0 {
for _, c := range sub[2] { for _, c := range sub[2] {
+1 -1
View File
@@ -152,7 +152,7 @@ func Tee[T any](ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
defer close(out2) defer close(out2)
for val := range ReadOrDone(ctx, in) { for val := range ReadOrDone(ctx, in) {
var out1, out2 = out1, out2 var out1, out2 = out1, out2
for i := 0; i < 2; i++ { for range 2 {
select { select {
case <-ctx.Done(): case <-ctx.Done():
case out1 <- val: case out1 <- val:
+4 -4
View File
@@ -22,7 +22,7 @@ var _ = Describe("Pipeline", func() {
Context("happy path", func() { Context("happy path", func() {
It("calls the 'transform' function and returns values and errors", func() { It("calls the 'transform' function and returns values and errors", func() {
inC := make(chan int, 4) inC := make(chan int, 4)
for i := 0; i < 4; i++ { for i := range 4 {
inC <- i inC <- i
} }
close(inC) close(inC)
@@ -48,7 +48,7 @@ var _ = Describe("Pipeline", func() {
const numJobs = 100 const numJobs = 100
It("starts multiple workers, respecting the limit", func() { It("starts multiple workers, respecting the limit", func() {
inC := make(chan int, numJobs) inC := make(chan int, numJobs)
for i := 0; i < numJobs; i++ { for i := range numJobs {
inC <- i inC <- i
} }
close(inC) close(inC)
@@ -94,7 +94,7 @@ var _ = Describe("Pipeline", func() {
BeforeEach(func() { BeforeEach(func() {
in1 = make(chan int, 4) in1 = make(chan int, 4)
in2 = make(chan int, 4) in2 = make(chan int, 4)
for i := 0; i < 4; i++ { for i := range 4 {
in1 <- i in1 <- i
in2 <- i + 4 in2 <- i + 4
} }
@@ -126,7 +126,7 @@ var _ = Describe("Pipeline", func() {
It("copies them to its output channel", func() { It("copies them to its output channel", func() {
in := make(chan int) in := make(chan int)
out := pl.ReadOrDone(context.Background(), in) out := pl.ReadOrDone(context.Background(), in)
for i := 0; i < 4; i++ { for i := range 4 {
in <- i in <- i
j := <-out j := <-out
Expect(i).To(Equal(j)) Expect(i).To(Equal(j))
+1 -1
View File
@@ -16,7 +16,7 @@ func TestRandom(t *testing.T) {
var _ = Describe("number package", func() { var _ = Describe("number package", func() {
Describe("Int64N", func() { Describe("Int64N", func() {
It("should return a random int64", func() { It("should return a random int64", func() {
for i := 0; i < 10000; i++ { for range 10000 {
Expect(random.Int64N(100)).To(BeNumerically("<", 100)) Expect(random.Int64N(100)).To(BeNumerically("<", 100))
} }
}) })
+5 -5
View File
@@ -9,7 +9,7 @@ var _ = Describe("WeightedChooser", func() {
var w *WeightedChooser[int] var w *WeightedChooser[int]
BeforeEach(func() { BeforeEach(func() {
w = NewWeightedChooser[int]() w = NewWeightedChooser[int]()
for i := 0; i < 10; i++ { for i := range 10 {
w.Add(i, i+1) w.Add(i, i+1)
} }
}) })
@@ -23,7 +23,7 @@ var _ = Describe("WeightedChooser", func() {
It("removes items", func() { It("removes items", func() {
Expect(w.Size()).To(Equal(10)) Expect(w.Size()).To(Equal(10))
for i := 0; i < 10; i++ { for range 10 {
Expect(w.Remove(0)).To(Succeed()) Expect(w.Remove(0)).To(Succeed())
} }
Expect(w.Size()).To(Equal(0)) Expect(w.Size()).To(Equal(0))
@@ -43,7 +43,7 @@ var _ = Describe("WeightedChooser", func() {
}) })
It("returns all items from the list", func() { It("returns all items from the list", func() {
for i := 0; i < 10; i++ { for range 10 {
Expect(w.Pick()).To(BeElementOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) Expect(w.Pick()).To(BeElementOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
} }
Expect(w.Size()).To(Equal(0)) Expect(w.Size()).To(Equal(0))
@@ -61,11 +61,11 @@ var _ = Describe("WeightedChooser", func() {
It("chooses based on weights", func() { It("chooses based on weights", func() {
counts := [10]int{} counts := [10]int{}
for i := 0; i < 200000; i++ { for range 200000 {
c, _ := w.weightedChoice() c, _ := w.weightedChoice()
counts[c] = counts[c] + 1 counts[c] = counts[c] + 1
} }
for i := 0; i < 9; i++ { for i := range 9 {
Expect(counts[i]).To(BeNumerically("<", counts[i+1])) Expect(counts[i]).To(BeNumerically("<", counts[i+1]))
} }
}) })
+1 -1
View File
@@ -9,7 +9,7 @@ import (
) )
var ( var (
instances = map[string]interface{}{} instances = map[string]any{}
pending = map[string]chan struct{}{} pending = map[string]chan struct{}{}
lock sync.RWMutex lock sync.RWMutex
) )
+1 -1
View File
@@ -69,7 +69,7 @@ var _ = Describe("GetInstance", func() {
done.Add(numCallsToDo) done.Add(numCallsToDo)
numInstancesCreated = 0 numInstancesCreated = 0
for i := 0; i < numCallsToDo; i++ { for range numCallsToDo {
go func() { go func() {
// This is needed to make sure the test does not hang if it fails // This is needed to make sure the test does not hang if it fails
defer GinkgoRecover() defer GinkgoRecover()

Some files were not shown because too many files have changed in this diff Show More