package data import ( "strconv" "gitea.elara.ws/Hazel/music-kraken/internal/common" ) type MusicObject interface { Compile() MusicObject GetIndices() []string Merge(other MusicObject) MusicObject } func dedupeMusicObjects[T MusicObject](inputMusicObjects []T) []T { indexMapping := map[string]int{} deduped := []T{} for _, musicObject := range inputMusicObjects { musicObject = musicObject.Compile().(T) indices := musicObject.GetIndices() // Check if we've seen any of these indices before found := false var existingIndex int for _, index := range indices { if idx, exists := indexMapping[index]; exists { found = true existingIndex = idx break } } if found { // Merge with existing object existing := deduped[existingIndex] merged := existing.Merge(musicObject).(T) deduped[existingIndex] = merged // Update indices for the merged object newIndices := merged.GetIndices() for _, index := range newIndices { indexMapping[index] = existingIndex } } else { // Add new object deduped = append(deduped, musicObject) newIndex := len(deduped) - 1 // Register all indices for this object for _, index := range indices { indexMapping[index] = newIndex } } } return deduped } type Song struct { Id int Name string UnifiedName string Album Album Artists []Artist Sources []Source } func (m Song) GetIndices() []string { res := sourceIndices(m.Sources) if m.UnifiedName != "" { res = append(res, "name"+m.UnifiedName) } if m.Id != 0 { res = append(res, "id"+strconv.Itoa(m.Id)) } return res } func (m Song) Merge(other MusicObject) MusicObject { otherSong, ok := other.(Song) if !ok { return m } if m.Id == 0 && otherSong.Id != 0 { m.Id = otherSong.Id } if m.Name == "" && otherSong.Name != "" { m.Name = otherSong.Name m.UnifiedName = otherSong.UnifiedName } m.Album = m.Album.Merge(otherSong.Album).(Album) m.Sources = dedupeSources(append(m.Sources, otherSong.Sources...)) return m } func (m Song) Compile() MusicObject { m.Sources = dedupeSources(m.Sources) m.UnifiedName = common.Unify(m.Name) m.Artists = dedupeMusicObjects(m.Artists) return m } type Album struct { Id int Name string UnifiedName string Songs []Song Artists []Artist Sources []Source } func (m Album) GetIndices() []string { res := sourceIndices(m.Sources) if m.UnifiedName != "" { res = append(res, "name"+m.UnifiedName) } if m.Id != 0 { res = append(res, "id"+strconv.Itoa(m.Id)) } return res } func (m Album) Merge(other MusicObject) MusicObject { otherAlbum, ok := other.(Album) if !ok { return m } if m.Id == 0 && otherAlbum.Id != 0 { m.Id = otherAlbum.Id } if m.Name == "" && otherAlbum.Name != "" { m.Name = otherAlbum.Name m.UnifiedName = otherAlbum.UnifiedName } m.Songs = dedupeMusicObjects(append(m.Songs, otherAlbum.Songs...)) m.Artists = dedupeMusicObjects(append(m.Artists, otherAlbum.Artists...)) m.Sources = dedupeSources(append(m.Sources, otherAlbum.Sources...)) return m } func (m Album) Compile() MusicObject { m.Sources = dedupeSources(m.Sources) m.UnifiedName = common.Unify(m.Name) m.Songs = dedupeMusicObjects(m.Songs) m.Artists = dedupeMusicObjects(m.Artists) return m } type Artist struct { Id int Name string UnifiedName string Albums []Album Sources []Source } func (m Artist) Merge(other MusicObject) MusicObject { otherArtist, ok := other.(Artist) if !ok { return m } if m.Id == 0 && otherArtist.Id != 0 { m.Id = otherArtist.Id } if m.Name == "" && otherArtist.Name != "" { m.Name = otherArtist.Name m.UnifiedName = otherArtist.UnifiedName } m.Albums = dedupeMusicObjects(append(m.Albums, otherArtist.Albums...)) m.Sources = dedupeSources(append(m.Sources, otherArtist.Sources...)) return m } func (m Artist) GetIndices() []string { res := sourceIndices(m.Sources) if m.UnifiedName != "" { res = append(res, "name"+m.UnifiedName) } if m.Id != 0 { res = append(res, "id"+strconv.Itoa(m.Id)) } return res } func (m Artist) Compile() MusicObject { m.Sources = dedupeSources(m.Sources) m.UnifiedName = common.Unify(m.Name) m.Albums = dedupeMusicObjects(m.Albums) return m }