fix(scanner): keep album tag order from the files instead of alphabetical (#5872)

Album-level tags were ordered by frequency and then alphabetically by value.
Album.Genre is just the first genre in that list, so any album whose genres tie
on frequency, which is the normal case, displayed the alphabetically first genre
rather than the first one in the file. A file tagged
"Native American New Age; Indigenous American Traditional Music; Ambient"
showed up as "Ambient".

Break frequency ties on order of appearance instead. This affects all
album-level tags, so mood tagged "Happy; Chill" now keeps that order too.
MediaFiles.ToAlbum already sorts the files by path before flattening their tags,
so the aggregated order stays deterministic across scans.

Only album genre was affected; media_file tags already preserved file order.
This commit is contained in:
Deluan Quintão 2026-08-25 10:58:58 -04:00 committed by GitHub
parent 3da2b590e7
commit cb0a6cedd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 11 additions and 7 deletions

View File

@ -218,11 +218,11 @@ var _ = Describe("MediaFiles", func() {
{Tags: Tags{"genre": []string{"Alternative", "Rock"}}},
}
})
It("sets the correct Genre, sorted by frequency, then alphabetically", func() {
It("sets the correct Genre, sorted by frequency, then by order of appearance", func() {
album := mfs.ToAlbum()
Expect(album.Tags).To(HaveLen(2))
Expect(album.Tags).To(HaveKeyWithValue(TagGenre, []string{"Rock", "Alternative", "Punk"}))
Expect(album.Tags).To(HaveKeyWithValue(TagMood, []string{"Chill", "Happy"}))
Expect(album.Tags).To(HaveKeyWithValue(TagGenre, []string{"Rock", "Punk", "Alternative"}))
Expect(album.Tags).To(HaveKeyWithValue(TagMood, []string{"Happy", "Chill"}))
})
})
When("we have tags with mismatching case", func() {

View File

@ -24,13 +24,17 @@ type TagList []Tag
func (l TagList) GroupByFrequency() Tags {
grouped := map[string]map[string]int{}
values := map[string]string{}
for _, t := range l {
firstSeen := map[string]int{}
for i, t := range l {
if m, ok := grouped[string(t.TagName)]; !ok {
grouped[string(t.TagName)] = map[string]int{t.ID: 1}
} else {
m[t.ID]++
}
values[t.ID] = t.TagValue
if _, ok := firstSeen[t.ID]; !ok {
firstSeen[t.ID] = i
}
}
tags := Tags{}
@ -42,7 +46,7 @@ func (l TagList) GroupByFrequency() Tags {
slices.SortFunc(idList, func(a, b string) int {
return cmp.Or(
cmp.Compare(counts[b], counts[a]),
cmp.Compare(values[a], values[b]),
cmp.Compare(firstSeen[a], firstSeen[b]),
)
})
tags[TagName(name)] = slice.Map(idList, func(id string) string { return values[id] })

View File

@ -93,7 +93,7 @@ var _ = Describe("Tag", func() {
Expect(groupedTags).To(HaveKeyWithValue(TagName("artist"), []string{"The Beatles", "The Rolling Stones"}))
})
It("should sort tags by name when frequency is the same", func() {
It("should keep the order the values appeared in when frequency is the same", func() {
tagList := TagList{
NewTag("genre", "Jazz"),
NewTag("genre", "Rock"),
@ -103,7 +103,7 @@ var _ = Describe("Tag", func() {
groupedTags := tagList.GroupByFrequency()
Expect(groupedTags).To(HaveKeyWithValue(TagName("genre"), []string{"Alternative", "Jazz", "Pop", "Rock"}))
Expect(groupedTags).To(HaveKeyWithValue(TagName("genre"), []string{"Jazz", "Rock", "Alternative", "Pop"}))
})
It("should normalize casing", func() {
tagList := TagList{