navidrome/persistence/sql_participations.go
Deluan 20297c2aea fix(server): send artist mbids when scrobbling to ListenBrainz
Signed-off-by: Deluan <deluan@navidrome.org>
2025-02-23 13:30:39 -05:00

87 lines
2.6 KiB
Go

package persistence
import (
"encoding/json"
"fmt"
. "github.com/Masterminds/squirrel"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/utils/slice"
)
type participant struct {
ID string `json:"id"`
Name string `json:"name"`
SubRole string `json:"subRole,omitempty"`
}
func marshalParticipants(participants model.Participants) string {
dbParticipants := make(map[model.Role][]participant)
for role, artists := range participants {
for _, artist := range artists {
dbParticipants[role] = append(dbParticipants[role], participant{ID: artist.ID, SubRole: artist.SubRole, Name: artist.Name})
}
}
res, _ := json.Marshal(dbParticipants)
return string(res)
}
func unmarshalParticipants(data string) (model.Participants, error) {
var dbParticipants map[model.Role][]participant
err := json.Unmarshal([]byte(data), &dbParticipants)
if err != nil {
return nil, fmt.Errorf("parsing participants: %w", err)
}
participants := make(model.Participants, len(dbParticipants))
for role, participantList := range dbParticipants {
artists := slice.Map(participantList, func(p participant) model.Participant {
return model.Participant{Artist: model.Artist{ID: p.ID, Name: p.Name}, SubRole: p.SubRole}
})
participants[role] = artists
}
return participants, nil
}
func (r sqlRepository) updateParticipants(itemID string, participants model.Participants) error {
ids := participants.AllIDs()
sqd := Delete(r.tableName + "_artists").Where(And{Eq{r.tableName + "_id": itemID}, NotEq{"artist_id": ids}})
_, err := r.executeSQL(sqd)
if err != nil {
return err
}
if len(participants) == 0 {
return nil
}
sqi := Insert(r.tableName+"_artists").
Columns(r.tableName+"_id", "artist_id", "role", "sub_role").
Suffix(fmt.Sprintf("on conflict (artist_id, %s_id, role, sub_role) do nothing", r.tableName))
for role, artists := range participants {
for _, artist := range artists {
sqi = sqi.Values(itemID, artist.ID, role.String(), artist.SubRole)
}
}
_, err = r.executeSQL(sqi)
return err
}
func (r *sqlRepository) getParticipants(m *model.MediaFile) (model.Participants, error) {
ar := NewArtistRepository(r.ctx, r.db)
ids := m.Participants.AllIDs()
artists, err := ar.GetAll(model.QueryOptions{Filters: Eq{"id": ids}})
if err != nil {
return nil, fmt.Errorf("getting participants: %w", err)
}
artistMap := slice.ToMap(artists, func(a model.Artist) (string, model.Artist) {
return a.ID, a
})
p := m.Participants
for role, artistList := range p {
for idx, artist := range artistList {
if a, ok := artistMap[artist.ID]; ok {
p[role][idx].Artist = a
}
}
}
return p, nil
}