mirror of
https://github.com/Dvorinka/SpotifyRecAlg.git
synced 2026-06-03 20:13:03 +00:00
106 lines
2.9 KiB
Go
106 lines
2.9 KiB
Go
package provider
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/tdvorak/spotifyrecalg/apps/backend/internal/provider/musicbrainz"
|
|
"github.com/tdvorak/spotifyrecalg/apps/backend/internal/provider/spotify"
|
|
"github.com/tdvorak/spotifyrecalg/apps/backend/internal/recommendation"
|
|
)
|
|
|
|
func mapSpotifyTrack(track spotify.Track, features spotify.AudioFeatures, mb musicbrainz.Recording, missingFeatures bool) recommendation.Track {
|
|
artist := ""
|
|
if len(track.Artists) > 0 {
|
|
artist = track.Artists[0].Name
|
|
}
|
|
|
|
spotifyURL := "https://open.spotify.com/track/" + track.ID
|
|
external := map[string]string{
|
|
"source": ProviderSpotify,
|
|
"spotify_id": track.ID,
|
|
"spotify": spotifyURL,
|
|
"spotify_url": spotifyURL,
|
|
}
|
|
if value := strings.TrimSpace(track.ExternalURLs["spotify"]); value != "" {
|
|
external["spotify"] = value
|
|
external["spotify_url"] = value
|
|
}
|
|
if isrc := strings.ToUpper(strings.TrimSpace(track.ExternalIDs["isrc"])); isrc != "" {
|
|
external["isrc"] = isrc
|
|
}
|
|
if len(track.Album.Images) > 0 && track.Album.Images[0].URL != "" {
|
|
external["image_url"] = track.Album.Images[0].URL
|
|
external["spotify_image_url"] = track.Album.Images[0].URL
|
|
}
|
|
if missingFeatures {
|
|
external["features_missing"] = "true"
|
|
}
|
|
if mb.ID != "" {
|
|
external["musicbrainz_recording_id"] = mb.ID
|
|
}
|
|
if mb.ArtistID != "" {
|
|
external["musicbrainz_artist_id"] = mb.ArtistID
|
|
}
|
|
if mb.ISRC != "" && external["isrc"] == "" {
|
|
external["isrc"] = mb.ISRC
|
|
}
|
|
|
|
genres := mergeStrings(nil, mb.Genres...)
|
|
genres = mergeStrings(genres, mb.Tags...)
|
|
|
|
return recommendation.Track{
|
|
ID: "spotify:track:" + track.ID,
|
|
Title: track.Name,
|
|
Artist: artist,
|
|
Album: track.Album.Name,
|
|
Genres: genres,
|
|
ReleaseDate: track.Album.ReleaseDate,
|
|
DurationMS: track.DurationMS,
|
|
Popularity: clamp01(float64(track.Popularity) / 100),
|
|
Explicit: track.Explicit,
|
|
Features: recommendation.AudioFeatures{
|
|
Danceability: features.Danceability,
|
|
Energy: features.Energy,
|
|
Loudness: features.Loudness,
|
|
Speechiness: features.Speechiness,
|
|
Acousticness: features.Acousticness,
|
|
Instrumentalness: features.Instrumentalness,
|
|
Liveness: features.Liveness,
|
|
Valence: features.Valence,
|
|
Tempo: features.Tempo,
|
|
TimeSignature: features.TimeSignature,
|
|
Key: features.Key,
|
|
Mode: features.Mode,
|
|
},
|
|
External: external,
|
|
DiscoveryAllowed: true,
|
|
}
|
|
}
|
|
|
|
func mergeStrings(values []string, next ...string) []string {
|
|
seen := make(map[string]struct{}, len(values)+len(next))
|
|
out := make([]string, 0, len(values)+len(next))
|
|
for _, value := range append(values, next...) {
|
|
value = strings.ToLower(strings.TrimSpace(value))
|
|
if value == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[value]; ok {
|
|
continue
|
|
}
|
|
seen[value] = struct{}{}
|
|
out = append(out, value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func clamp01(value float64) float64 {
|
|
if value < 0 {
|
|
return 0
|
|
}
|
|
if value > 1 {
|
|
return 1
|
|
}
|
|
return value
|
|
}
|