mirror of
https://github.com/navidrome/navidrome.git
synced 2026-02-20 08:04:43 -05:00
Compare commits
2 Commits
custom-col
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08a71320ea | ||
|
|
44a5482493 |
9
db/db.go
9
db/db.go
@@ -6,9 +6,7 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/maruel/natural"
|
|
||||||
"github.com/mattn/go-sqlite3"
|
"github.com/mattn/go-sqlite3"
|
||||||
"github.com/navidrome/navidrome/conf"
|
"github.com/navidrome/navidrome/conf"
|
||||||
_ "github.com/navidrome/navidrome/db/migrations"
|
_ "github.com/navidrome/navidrome/db/migrations"
|
||||||
@@ -33,12 +31,7 @@ func Db() *sql.DB {
|
|||||||
return singleton.GetInstance(func() *sql.DB {
|
return singleton.GetInstance(func() *sql.DB {
|
||||||
sql.Register(Driver, &sqlite3.SQLiteDriver{
|
sql.Register(Driver, &sqlite3.SQLiteDriver{
|
||||||
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||||
if err := conn.RegisterFunc("SEEDEDRAND", hasher.HashFunc(), false); err != nil {
|
return conn.RegisterFunc("SEEDEDRAND", hasher.HashFunc(), false)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return conn.RegisterCollation("NATURALSORT", func(a, b string) int {
|
|
||||||
return natural.Compare(strings.ToLower(a), strings.ToLower(b))
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Path = conf.Server.DbPath
|
Path = conf.Server.DbPath
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
|
|
||||||
-- Change order_*/sort_* column collation from NOCASE to NATURALSORT.
|
|
||||||
-- This way bare ORDER BY on these columns automatically uses natural sorting,
|
|
||||||
-- without needing explicit COLLATE NATURALSORT in every query.
|
|
||||||
PRAGMA writable_schema = ON;
|
|
||||||
UPDATE sqlite_master
|
|
||||||
SET sql = replace(sql, 'collate NOCASE', 'collate NATURALSORT')
|
|
||||||
WHERE type = 'table' AND name IN ('artist', 'album', 'media_file', 'playlist', 'radio');
|
|
||||||
PRAGMA writable_schema = OFF;
|
|
||||||
|
|
||||||
-- Recreate indexes on order_* and sort expression fields to use NATURALSORT collation.
|
|
||||||
-- This enables natural number ordering (e.g., "Album 2" before "Album 10").
|
|
||||||
|
|
||||||
-- Artist indexes
|
|
||||||
drop index if exists artist_order_artist_name;
|
|
||||||
create index artist_order_artist_name
|
|
||||||
on artist (order_artist_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists artist_sort_name;
|
|
||||||
create index artist_sort_name
|
|
||||||
on artist (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NATURALSORT);
|
|
||||||
|
|
||||||
-- Album indexes
|
|
||||||
drop index if exists album_order_album_name;
|
|
||||||
create index album_order_album_name
|
|
||||||
on album (order_album_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists album_order_album_artist_name;
|
|
||||||
create index album_order_album_artist_name
|
|
||||||
on album (order_album_artist_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists album_alphabetical_by_artist;
|
|
||||||
create index album_alphabetical_by_artist
|
|
||||||
on album (compilation, order_album_artist_name collate NATURALSORT, order_album_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists album_sort_name;
|
|
||||||
create index album_sort_name
|
|
||||||
on album (coalesce(nullif(sort_album_name,''),order_album_name) collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists album_sort_album_artist_name;
|
|
||||||
create index album_sort_album_artist_name
|
|
||||||
on album (coalesce(nullif(sort_album_artist_name,''),order_album_artist_name) collate NATURALSORT);
|
|
||||||
|
|
||||||
-- Media file indexes
|
|
||||||
drop index if exists media_file_order_title;
|
|
||||||
create index media_file_order_title
|
|
||||||
on media_file (order_title collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists media_file_order_album_name;
|
|
||||||
create index media_file_order_album_name
|
|
||||||
on media_file (order_album_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists media_file_order_artist_name;
|
|
||||||
create index media_file_order_artist_name
|
|
||||||
on media_file (order_artist_name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_title;
|
|
||||||
create index media_file_sort_title
|
|
||||||
on media_file (coalesce(nullif(sort_title,''),order_title) collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_artist_name;
|
|
||||||
create index media_file_sort_artist_name
|
|
||||||
on media_file (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_album_name;
|
|
||||||
create index media_file_sort_album_name
|
|
||||||
on media_file (coalesce(nullif(sort_album_name,''),order_album_name) collate NATURALSORT);
|
|
||||||
|
|
||||||
-- Playlist and radio indexes: recreate to match new NATURALSORT column collation
|
|
||||||
drop index if exists playlist_name;
|
|
||||||
create index playlist_name
|
|
||||||
on playlist (name collate NATURALSORT);
|
|
||||||
|
|
||||||
drop index if exists radio_name;
|
|
||||||
create index radio_name
|
|
||||||
on radio (name collate NATURALSORT);
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
|
|
||||||
-- Restore NOCASE column collation
|
|
||||||
PRAGMA writable_schema = ON;
|
|
||||||
UPDATE sqlite_master
|
|
||||||
SET sql = replace(sql, 'collate NATURALSORT', 'collate NOCASE')
|
|
||||||
WHERE type = 'table' AND name IN ('artist', 'album', 'media_file', 'playlist', 'radio');
|
|
||||||
PRAGMA writable_schema = OFF;
|
|
||||||
|
|
||||||
-- Restore NOCASE collation indexes
|
|
||||||
|
|
||||||
-- Artist indexes
|
|
||||||
drop index if exists artist_order_artist_name;
|
|
||||||
create index artist_order_artist_name
|
|
||||||
on artist (order_artist_name);
|
|
||||||
|
|
||||||
drop index if exists artist_sort_name;
|
|
||||||
create index artist_sort_name
|
|
||||||
on artist (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NOCASE);
|
|
||||||
|
|
||||||
-- Album indexes
|
|
||||||
drop index if exists album_order_album_name;
|
|
||||||
create index album_order_album_name
|
|
||||||
on album (order_album_name);
|
|
||||||
|
|
||||||
drop index if exists album_order_album_artist_name;
|
|
||||||
create index album_order_album_artist_name
|
|
||||||
on album (order_album_artist_name);
|
|
||||||
|
|
||||||
drop index if exists album_alphabetical_by_artist;
|
|
||||||
create index album_alphabetical_by_artist
|
|
||||||
on album (compilation, order_album_artist_name, order_album_name);
|
|
||||||
|
|
||||||
drop index if exists album_sort_name;
|
|
||||||
create index album_sort_name
|
|
||||||
on album (coalesce(nullif(sort_album_name,''),order_album_name) collate NOCASE);
|
|
||||||
|
|
||||||
drop index if exists album_sort_album_artist_name;
|
|
||||||
create index album_sort_album_artist_name
|
|
||||||
on album (coalesce(nullif(sort_album_artist_name,''),order_album_artist_name) collate NOCASE);
|
|
||||||
|
|
||||||
-- Media file indexes
|
|
||||||
drop index if exists media_file_order_title;
|
|
||||||
create index media_file_order_title
|
|
||||||
on media_file (order_title);
|
|
||||||
|
|
||||||
drop index if exists media_file_order_album_name;
|
|
||||||
create index media_file_order_album_name
|
|
||||||
on media_file (order_album_name);
|
|
||||||
|
|
||||||
drop index if exists media_file_order_artist_name;
|
|
||||||
create index media_file_order_artist_name
|
|
||||||
on media_file (order_artist_name);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_title;
|
|
||||||
create index media_file_sort_title
|
|
||||||
on media_file (coalesce(nullif(sort_title,''),order_title) collate NOCASE);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_artist_name;
|
|
||||||
create index media_file_sort_artist_name
|
|
||||||
on media_file (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NOCASE);
|
|
||||||
|
|
||||||
drop index if exists media_file_sort_album_name;
|
|
||||||
create index media_file_sort_album_name
|
|
||||||
on media_file (coalesce(nullif(sort_album_name,''),order_album_name) collate NOCASE);
|
|
||||||
|
|
||||||
-- Restore playlist and radio indexes
|
|
||||||
drop index if exists playlist_name;
|
|
||||||
create index playlist_name
|
|
||||||
on playlist (name);
|
|
||||||
|
|
||||||
drop index if exists radio_name;
|
|
||||||
create index radio_name
|
|
||||||
on radio (name);
|
|
||||||
@@ -17,45 +17,45 @@ import (
|
|||||||
var _ = Describe("Collation", func() {
|
var _ = Describe("Collation", func() {
|
||||||
conn := db.Db()
|
conn := db.Db()
|
||||||
DescribeTable("Column collation",
|
DescribeTable("Column collation",
|
||||||
func(table, column, expectedCollation string) {
|
func(table, column string) {
|
||||||
Expect(checkCollation(conn, table, column, expectedCollation)).To(Succeed())
|
Expect(checkCollation(conn, table, column)).To(Succeed())
|
||||||
},
|
},
|
||||||
Entry("artist.order_artist_name", "artist", "order_artist_name", "NATURALSORT"),
|
Entry("artist.order_artist_name", "artist", "order_artist_name"),
|
||||||
Entry("artist.sort_artist_name", "artist", "sort_artist_name", "NATURALSORT"),
|
Entry("artist.sort_artist_name", "artist", "sort_artist_name"),
|
||||||
Entry("album.order_album_name", "album", "order_album_name", "NATURALSORT"),
|
Entry("album.order_album_name", "album", "order_album_name"),
|
||||||
Entry("album.order_album_artist_name", "album", "order_album_artist_name", "NATURALSORT"),
|
Entry("album.order_album_artist_name", "album", "order_album_artist_name"),
|
||||||
Entry("album.sort_album_name", "album", "sort_album_name", "NATURALSORT"),
|
Entry("album.sort_album_name", "album", "sort_album_name"),
|
||||||
Entry("album.sort_album_artist_name", "album", "sort_album_artist_name", "NATURALSORT"),
|
Entry("album.sort_album_artist_name", "album", "sort_album_artist_name"),
|
||||||
Entry("media_file.order_title", "media_file", "order_title", "NATURALSORT"),
|
Entry("media_file.order_title", "media_file", "order_title"),
|
||||||
Entry("media_file.order_album_name", "media_file", "order_album_name", "NATURALSORT"),
|
Entry("media_file.order_album_name", "media_file", "order_album_name"),
|
||||||
Entry("media_file.order_artist_name", "media_file", "order_artist_name", "NATURALSORT"),
|
Entry("media_file.order_artist_name", "media_file", "order_artist_name"),
|
||||||
Entry("media_file.sort_title", "media_file", "sort_title", "NATURALSORT"),
|
Entry("media_file.sort_title", "media_file", "sort_title"),
|
||||||
Entry("media_file.sort_album_name", "media_file", "sort_album_name", "NATURALSORT"),
|
Entry("media_file.sort_album_name", "media_file", "sort_album_name"),
|
||||||
Entry("media_file.sort_artist_name", "media_file", "sort_artist_name", "NATURALSORT"),
|
Entry("media_file.sort_artist_name", "media_file", "sort_artist_name"),
|
||||||
Entry("playlist.name", "playlist", "name", "NATURALSORT"),
|
Entry("playlist.name", "playlist", "name"),
|
||||||
Entry("radio.name", "radio", "name", "NATURALSORT"),
|
Entry("radio.name", "radio", "name"),
|
||||||
Entry("user.name", "user", "name", "NOCASE"),
|
Entry("user.name", "user", "name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
DescribeTable("Index collation",
|
DescribeTable("Index collation",
|
||||||
func(table, column string) {
|
func(table, column string) {
|
||||||
Expect(checkIndexUsage(conn, table, column)).To(Succeed())
|
Expect(checkIndexUsage(conn, table, column)).To(Succeed())
|
||||||
},
|
},
|
||||||
Entry("artist.order_artist_name", "artist", "order_artist_name collate NATURALSORT"),
|
Entry("artist.order_artist_name", "artist", "order_artist_name collate nocase"),
|
||||||
Entry("artist.sort_artist_name", "artist", "coalesce(nullif(sort_artist_name,''),order_artist_name) collate NATURALSORT"),
|
Entry("artist.sort_artist_name", "artist", "coalesce(nullif(sort_artist_name,''),order_artist_name) collate nocase"),
|
||||||
Entry("album.order_album_name", "album", "order_album_name collate NATURALSORT"),
|
Entry("album.order_album_name", "album", "order_album_name collate nocase"),
|
||||||
Entry("album.order_album_artist_name", "album", "order_album_artist_name collate NATURALSORT"),
|
Entry("album.order_album_artist_name", "album", "order_album_artist_name collate nocase"),
|
||||||
Entry("album.sort_album_name", "album", "coalesce(nullif(sort_album_name,''),order_album_name) collate NATURALSORT"),
|
Entry("album.sort_album_name", "album", "coalesce(nullif(sort_album_name,''),order_album_name) collate nocase"),
|
||||||
Entry("album.sort_album_artist_name", "album", "coalesce(nullif(sort_album_artist_name,''),order_album_artist_name) collate NATURALSORT"),
|
Entry("album.sort_album_artist_name", "album", "coalesce(nullif(sort_album_artist_name,''),order_album_artist_name) collate nocase"),
|
||||||
Entry("media_file.order_title", "media_file", "order_title collate NATURALSORT"),
|
Entry("media_file.order_title", "media_file", "order_title collate nocase"),
|
||||||
Entry("media_file.order_album_name", "media_file", "order_album_name collate NATURALSORT"),
|
Entry("media_file.order_album_name", "media_file", "order_album_name collate nocase"),
|
||||||
Entry("media_file.order_artist_name", "media_file", "order_artist_name collate NATURALSORT"),
|
Entry("media_file.order_artist_name", "media_file", "order_artist_name collate nocase"),
|
||||||
Entry("media_file.sort_title", "media_file", "coalesce(nullif(sort_title,''),order_title) collate NATURALSORT"),
|
Entry("media_file.sort_title", "media_file", "coalesce(nullif(sort_title,''),order_title) collate nocase"),
|
||||||
Entry("media_file.sort_album_name", "media_file", "coalesce(nullif(sort_album_name,''),order_album_name) collate NATURALSORT"),
|
Entry("media_file.sort_album_name", "media_file", "coalesce(nullif(sort_album_name,''),order_album_name) collate nocase"),
|
||||||
Entry("media_file.sort_artist_name", "media_file", "coalesce(nullif(sort_artist_name,''),order_artist_name) collate NATURALSORT"),
|
Entry("media_file.sort_artist_name", "media_file", "coalesce(nullif(sort_artist_name,''),order_artist_name) collate nocase"),
|
||||||
Entry("media_file.path", "media_file", "path collate nocase"),
|
Entry("media_file.path", "media_file", "path collate nocase"),
|
||||||
Entry("playlist.name", "playlist", "name collate NATURALSORT"),
|
Entry("playlist.name", "playlist", "name collate nocase"),
|
||||||
Entry("radio.name", "radio", "name collate NATURALSORT"),
|
Entry("radio.name", "radio", "name collate nocase"),
|
||||||
Entry("user.user_name", "user", "user_name collate nocase"),
|
Entry("user.user_name", "user", "user_name collate nocase"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -91,7 +91,7 @@ order by %[2]s`, table, column))
|
|||||||
return errors.New("no rows returned")
|
return errors.New("no rows returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCollation(conn *sql.DB, table, column, expectedCollation string) error {
|
func checkCollation(conn *sql.DB, table string, column string) error {
|
||||||
rows, err := conn.Query(fmt.Sprintf("SELECT sql FROM sqlite_master WHERE type='table' AND tbl_name='%s'", table))
|
rows, err := conn.Query(fmt.Sprintf("SELECT sql FROM sqlite_master WHERE type='table' AND tbl_name='%s'", table))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -113,12 +113,12 @@ func checkCollation(conn *sql.DB, table, column, expectedCollation string) error
|
|||||||
if !re.MatchString(res) {
|
if !re.MatchString(res) {
|
||||||
return fmt.Errorf("column '%s' not found in table '%s'", column, table)
|
return fmt.Errorf("column '%s' not found in table '%s'", column, table)
|
||||||
}
|
}
|
||||||
re = regexp.MustCompile(fmt.Sprintf(`(?i)\b%s\b.*collate\s+%s`, column, expectedCollation))
|
re = regexp.MustCompile(fmt.Sprintf(`(?i)\b%s\b.*collate\s+NOCASE`, column))
|
||||||
if re.MatchString(res) {
|
if re.MatchString(res) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("table '%s' not found", table)
|
return fmt.Errorf("table '%s' not found", table)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("column '%s' in table '%s' does not have %s collation", column, table, expectedCollation)
|
return fmt.Errorf("column '%s' in table '%s' does not have NOCASE collation", column, table)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ func (e existsCond) ToSql() (string, []any, error) {
|
|||||||
|
|
||||||
var sortOrderRegex = regexp.MustCompile(`order_([a-z_]+)`)
|
var sortOrderRegex = regexp.MustCompile(`order_([a-z_]+)`)
|
||||||
|
|
||||||
// mapSortOrder converts order_* columns to an expression using sort_* columns with NATURALSORT collation. Example:
|
// Convert the order_* columns to an expression using sort_* columns. Example:
|
||||||
// order_album_name -> (coalesce(nullif(sort_album_name,”),order_album_name) collate NATURALSORT)
|
// sort_album_name -> (coalesce(nullif(sort_album_name,”),order_album_name) collate nocase)
|
||||||
// It finds order column names anywhere in the substring
|
// It finds order column names anywhere in the substring
|
||||||
func mapSortOrder(tableName, order string) string {
|
func mapSortOrder(tableName, order string) string {
|
||||||
order = strings.ToLower(order)
|
order = strings.ToLower(order)
|
||||||
repl := fmt.Sprintf("(coalesce(nullif(%[1]s.sort_$1,''),%[1]s.order_$1) collate NATURALSORT)", tableName)
|
repl := fmt.Sprintf("(coalesce(nullif(%[1]s.sort_$1,''),%[1]s.order_$1) collate nocase)", tableName)
|
||||||
return sortOrderRegex.ReplaceAllString(order, repl)
|
return sortOrderRegex.ReplaceAllString(order, repl)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,13 +94,13 @@ var _ = Describe("Helpers", func() {
|
|||||||
sort := "ORDER_ALBUM_NAME asc"
|
sort := "ORDER_ALBUM_NAME asc"
|
||||||
mapped := mapSortOrder("album", sort)
|
mapped := mapSortOrder("album", sort)
|
||||||
Expect(mapped).To(Equal(`(coalesce(nullif(album.sort_album_name,''),album.order_album_name)` +
|
Expect(mapped).To(Equal(`(coalesce(nullif(album.sort_album_name,''),album.order_album_name)` +
|
||||||
` collate NATURALSORT) asc`))
|
` collate nocase) asc`))
|
||||||
})
|
})
|
||||||
It("changes multiple order columns to sort expressions", func() {
|
It("changes multiple order columns to sort expressions", func() {
|
||||||
sort := "compilation, order_title asc, order_album_artist_name desc, year desc"
|
sort := "compilation, order_title asc, order_album_artist_name desc, year desc"
|
||||||
mapped := mapSortOrder("album", sort)
|
mapped := mapSortOrder("album", sort)
|
||||||
Expect(mapped).To(Equal(`compilation, (coalesce(nullif(album.sort_title,''),album.order_title) collate NATURALSORT) asc,` +
|
Expect(mapped).To(Equal(`compilation, (coalesce(nullif(album.sort_title,''),album.order_title) collate nocase) asc,` +
|
||||||
` (coalesce(nullif(album.sort_album_artist_name,''),album.order_album_artist_name) collate NATURALSORT) desc, year desc`))
|
` (coalesce(nullif(album.sort_album_artist_name,''),album.order_album_artist_name) collate nocase) desc, year desc`))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ func (r *sqlRepository) registerModel(instance any, filters map[string]filterFun
|
|||||||
//
|
//
|
||||||
// If PreferSortTags is enabled, it will map the order fields to the corresponding sort expression,
|
// If PreferSortTags is enabled, it will map the order fields to the corresponding sort expression,
|
||||||
// which gives precedence to sort tags.
|
// which gives precedence to sort tags.
|
||||||
// Ex: order_title => (coalesce(nullif(sort_title,""), order_title) collate NATURALSORT)
|
// Ex: order_title => (coalesce(nullif(sort_title,”),order_title) collate nocase)
|
||||||
// To avoid performance issues, indexes should be created for these sort expressions.
|
// To avoid performance issues, indexes should be created for these sort expressions
|
||||||
//
|
//
|
||||||
// NOTE: if an individual item has spaces, it should be wrapped in parentheses. For example,
|
// NOTE: if an individual item has spaces, it should be wrapped in parentheses. For example,
|
||||||
// you should write "(lyrics != '[]')". This prevents the item being split unexpectedly.
|
// you should write "(lyrics != '[]')". This prevents the item being split unexpectedly.
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ type Broker interface {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
keepAliveFrequency = 15 * time.Second
|
keepAliveFrequency = 15 * time.Second
|
||||||
writeTimeOut = 5 * time.Second
|
// The timeout must be higher than the keepAliveFrequency, or the lack of activity will cause the channel to close.
|
||||||
bufferSize = 1
|
writeTimeOut = keepAliveFrequency + 5*time.Second
|
||||||
|
bufferSize = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
@@ -97,6 +97,16 @@ export default {
|
|||||||
boxShadow: '3px 3px 5px #3c3836',
|
boxShadow: '3px 3px 5px #3c3836',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiSwitch: {
|
||||||
|
colorSecondary: {
|
||||||
|
'&$checked': {
|
||||||
|
color: '#458588',
|
||||||
|
},
|
||||||
|
'&$checked + $track': {
|
||||||
|
backgroundColor: '#458588',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
NDMobileArtistDetails: {
|
NDMobileArtistDetails: {
|
||||||
bgContainer: {
|
bgContainer: {
|
||||||
background:
|
background:
|
||||||
|
|||||||
Reference in New Issue
Block a user