v7.0.7
This commit is contained in:
+122
-72
@@ -47,6 +47,7 @@ type TrackMetadata struct {
|
||||
Publisher string `json:"publisher,omitempty"`
|
||||
Plays string `json:"plays,omitempty"`
|
||||
PreviewURL string `json:"preview_url,omitempty"`
|
||||
IsExplicit bool `json:"is_explicit,omitempty"`
|
||||
}
|
||||
|
||||
type ArtistSimple struct {
|
||||
@@ -79,6 +80,7 @@ type AlbumTrackMetadata struct {
|
||||
Plays string `json:"plays,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
PreviewURL string `json:"preview_url,omitempty"`
|
||||
IsExplicit bool `json:"is_explicit,omitempty"`
|
||||
}
|
||||
|
||||
type TrackResponse struct {
|
||||
@@ -198,6 +200,7 @@ type apiTrackResponse struct {
|
||||
Medium string `json:"medium"`
|
||||
Large string `json:"large"`
|
||||
} `json:"cover"`
|
||||
IsExplicit bool `json:"is_explicit"`
|
||||
}
|
||||
|
||||
type apiAlbumResponse struct {
|
||||
@@ -208,12 +211,13 @@ type apiAlbumResponse struct {
|
||||
ReleaseDate string `json:"releaseDate"`
|
||||
Count int `json:"count"`
|
||||
Tracks []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Artists string `json:"artists"`
|
||||
ArtistIds []string `json:"artistIds"`
|
||||
Duration string `json:"duration"`
|
||||
Plays string `json:"plays"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Artists string `json:"artists"`
|
||||
ArtistIds []string `json:"artistIds"`
|
||||
Duration string `json:"duration"`
|
||||
Plays string `json:"plays"`
|
||||
IsExplicit bool `json:"is_explicit"`
|
||||
} `json:"tracks"`
|
||||
}
|
||||
|
||||
@@ -240,6 +244,7 @@ type apiPlaylistResponse struct {
|
||||
AlbumArtist string `json:"albumArtist"`
|
||||
AlbumID string `json:"albumId"`
|
||||
Duration string `json:"duration"`
|
||||
IsExplicit bool `json:"is_explicit"`
|
||||
} `json:"tracks"`
|
||||
}
|
||||
|
||||
@@ -261,11 +266,13 @@ type apiArtistResponse struct {
|
||||
Gallery []string `json:"gallery"`
|
||||
Discography struct {
|
||||
All []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cover string `json:"cover"`
|
||||
Date string `json:"date"`
|
||||
Year int `json:"year"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cover string `json:"cover"`
|
||||
Date string `json:"date"`
|
||||
Year int `json:"year"`
|
||||
TotalTracks int `json:"total_tracks"`
|
||||
Type string `json:"type"`
|
||||
} `json:"all"`
|
||||
Total int `json:"total"`
|
||||
} `json:"discography"`
|
||||
@@ -274,12 +281,13 @@ type apiArtistResponse struct {
|
||||
type apiSearchResponse struct {
|
||||
Results struct {
|
||||
Tracks []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Artists string `json:"artists"`
|
||||
Album string `json:"album"`
|
||||
Duration string `json:"duration"`
|
||||
Cover string `json:"cover"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Artists string `json:"artists"`
|
||||
Album string `json:"album"`
|
||||
Duration string `json:"duration"`
|
||||
Cover string `json:"cover"`
|
||||
IsExplicit bool `json:"is_explicit"`
|
||||
} `json:"tracks"`
|
||||
Albums []struct {
|
||||
ID string `json:"id"`
|
||||
@@ -320,6 +328,7 @@ type SearchResult struct {
|
||||
Duration int `json:"duration_ms,omitempty"`
|
||||
TotalTracks int `json:"total_tracks,omitempty"`
|
||||
Owner string `json:"owner,omitempty"`
|
||||
IsExplicit bool `json:"is_explicit,omitempty"`
|
||||
}
|
||||
|
||||
type SearchResponse struct {
|
||||
@@ -464,6 +473,10 @@ func (c *SpotifyMetadataClient) fetchAlbum(ctx context.Context, albumID string)
|
||||
if err := client.Initialize(); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize spotify client: %w", err)
|
||||
}
|
||||
return c.fetchAlbumWithClient(ctx, client, albumID)
|
||||
}
|
||||
|
||||
func (c *SpotifyMetadataClient) fetchAlbumWithClient(ctx context.Context, client *SpotifyClient, albumID string) (*apiAlbumResponse, error) {
|
||||
|
||||
allItems := []interface{}{}
|
||||
offset := 0
|
||||
@@ -727,6 +740,12 @@ func (c *SpotifyMetadataClient) fetchArtistDiscography(ctx context.Context, pars
|
||||
}
|
||||
|
||||
offset += limit
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
albumsItems := []interface{}{}
|
||||
@@ -843,6 +862,7 @@ func (c *SpotifyMetadataClient) formatTrackData(raw *apiTrackResponse) TrackResp
|
||||
Copyright: raw.Copyright,
|
||||
Publisher: raw.Album.Label,
|
||||
Plays: raw.Plays,
|
||||
IsExplicit: raw.IsExplicit,
|
||||
}
|
||||
|
||||
return TrackResponse{
|
||||
@@ -904,6 +924,7 @@ func (c *SpotifyMetadataClient) formatAlbumData(raw *apiAlbumResponse) (*AlbumRe
|
||||
ArtistURL: artistURL,
|
||||
ArtistsData: artistsData,
|
||||
Plays: item.Plays,
|
||||
IsExplicit: item.IsExplicit,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -964,6 +985,7 @@ func (c *SpotifyMetadataClient) formatPlaylistData(raw *apiPlaylistResponse) Pla
|
||||
ArtistsData: artistsData,
|
||||
Plays: item.Plays,
|
||||
Status: item.Status,
|
||||
IsExplicit: item.IsExplicit,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -995,79 +1017,105 @@ func (c *SpotifyMetadataClient) formatArtistDiscographyData(ctx context.Context,
|
||||
albumList := make([]DiscographyAlbumMetadata, 0, len(raw.Discography.All))
|
||||
allTracks := make([]AlbumTrackMetadata, 0)
|
||||
|
||||
type fetchResult struct {
|
||||
tracks []AlbumTrackMetadata
|
||||
err error
|
||||
}
|
||||
|
||||
resultsChan := make(chan fetchResult, len(raw.Discography.All))
|
||||
sem := make(chan struct{}, 5)
|
||||
|
||||
sharedClient := NewSpotifyClient()
|
||||
if err := sharedClient.Initialize(); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize shared spotify client: %w", err)
|
||||
}
|
||||
|
||||
for _, alb := range raw.Discography.All {
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
||||
return &ArtistDiscographyPayload{
|
||||
ArtistInfo: info,
|
||||
AlbumList: albumList,
|
||||
TrackList: allTracks,
|
||||
}, ctx.Err()
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
albumList = append(albumList, DiscographyAlbumMetadata{
|
||||
ID: alb.ID,
|
||||
Name: alb.Name,
|
||||
AlbumType: "album",
|
||||
AlbumType: alb.Type,
|
||||
ReleaseDate: alb.Date,
|
||||
TotalTracks: 0,
|
||||
TotalTracks: alb.TotalTracks,
|
||||
Artists: raw.Name,
|
||||
Images: alb.Cover,
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/album/%s", alb.ID),
|
||||
})
|
||||
|
||||
albumData, err := c.fetchAlbum(ctx, alb.ID)
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting tracks for album %s: %v\n", alb.Name, err)
|
||||
continue
|
||||
}
|
||||
go func(albumID string, albumName string) {
|
||||
sem <- struct{}{}
|
||||
|
||||
for idx, tr := range albumData.Tracks {
|
||||
durationMS := parseDuration(tr.Duration)
|
||||
trackNumber := idx + 1
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
defer func() { <-sem }()
|
||||
|
||||
var artistID, artistURL string
|
||||
if len(tr.ArtistIds) > 0 {
|
||||
artistID = tr.ArtistIds[0]
|
||||
artistURL = fmt.Sprintf("https://open.spotify.com/artist/%s", artistID)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
resultsChan <- fetchResult{err: ctx.Err()}
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
artistsData := make([]ArtistSimple, 0, len(tr.ArtistIds))
|
||||
for _, id := range tr.ArtistIds {
|
||||
artistsData = append(artistsData, ArtistSimple{
|
||||
ID: id,
|
||||
Name: "",
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/artist/%s", id),
|
||||
albumData, err := c.fetchAlbumWithClient(ctx, sharedClient, albumID)
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting tracks for album %s: %v\n", albumName, err)
|
||||
resultsChan <- fetchResult{tracks: []AlbumTrackMetadata{}}
|
||||
return
|
||||
}
|
||||
|
||||
tracks := make([]AlbumTrackMetadata, 0, len(albumData.Tracks))
|
||||
for idx, tr := range albumData.Tracks {
|
||||
durationMS := parseDuration(tr.Duration)
|
||||
trackNumber := idx + 1
|
||||
|
||||
var artistID, artistURL string
|
||||
if len(tr.ArtistIds) > 0 {
|
||||
artistID = tr.ArtistIds[0]
|
||||
artistURL = fmt.Sprintf("https://open.spotify.com/artist/%s", artistID)
|
||||
}
|
||||
|
||||
artistsData := make([]ArtistSimple, 0, len(tr.ArtistIds))
|
||||
for _, id := range tr.ArtistIds {
|
||||
artistsData = append(artistsData, ArtistSimple{
|
||||
ID: id,
|
||||
Name: "",
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/artist/%s", id),
|
||||
})
|
||||
}
|
||||
|
||||
tracks = append(tracks, AlbumTrackMetadata{
|
||||
SpotifyID: tr.ID,
|
||||
Artists: tr.Artists,
|
||||
Name: tr.Name,
|
||||
AlbumName: albumData.Name,
|
||||
AlbumArtist: raw.Name,
|
||||
AlbumType: "album",
|
||||
DurationMS: durationMS,
|
||||
Images: albumData.Cover,
|
||||
ReleaseDate: albumData.ReleaseDate,
|
||||
TrackNumber: trackNumber,
|
||||
TotalTracks: albumData.Count,
|
||||
DiscNumber: 1,
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/track/%s", tr.ID),
|
||||
ISRC: tr.ID,
|
||||
AlbumID: albumID,
|
||||
AlbumURL: fmt.Sprintf("https://open.spotify.com/album/%s", albumID),
|
||||
ArtistID: artistID,
|
||||
ArtistURL: artistURL,
|
||||
ArtistsData: artistsData,
|
||||
Plays: tr.Plays,
|
||||
IsExplicit: tr.IsExplicit,
|
||||
})
|
||||
}
|
||||
resultsChan <- fetchResult{tracks: tracks}
|
||||
}(alb.ID, alb.Name)
|
||||
}
|
||||
|
||||
allTracks = append(allTracks, AlbumTrackMetadata{
|
||||
SpotifyID: tr.ID,
|
||||
Artists: tr.Artists,
|
||||
Name: tr.Name,
|
||||
AlbumName: albumData.Name,
|
||||
AlbumArtist: albumData.Artists,
|
||||
AlbumType: "album",
|
||||
DurationMS: durationMS,
|
||||
Images: albumData.Cover,
|
||||
ReleaseDate: albumData.ReleaseDate,
|
||||
TrackNumber: trackNumber,
|
||||
TotalTracks: albumData.Count,
|
||||
DiscNumber: 1,
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/track/%s", tr.ID),
|
||||
ISRC: tr.ID,
|
||||
AlbumID: alb.ID,
|
||||
AlbumURL: fmt.Sprintf("https://open.spotify.com/album/%s", alb.ID),
|
||||
ArtistID: artistID,
|
||||
ArtistURL: artistURL,
|
||||
ArtistsData: artistsData,
|
||||
Plays: tr.Plays,
|
||||
})
|
||||
for i := 0; i < len(raw.Discography.All); i++ {
|
||||
res := <-resultsChan
|
||||
if res.err != nil {
|
||||
return nil, res.err
|
||||
}
|
||||
allTracks = append(allTracks, res.tracks...)
|
||||
}
|
||||
|
||||
return &ArtistDiscographyPayload{
|
||||
@@ -1246,6 +1294,7 @@ func (c *SpotifyMetadataClient) Search(ctx context.Context, query string, limit
|
||||
Images: item.Cover,
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/track/%s", item.ID),
|
||||
Duration: parseDuration(item.Duration),
|
||||
IsExplicit: item.IsExplicit,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1359,6 +1408,7 @@ func (c *SpotifyMetadataClient) SearchByType(ctx context.Context, query string,
|
||||
Images: item.Cover,
|
||||
ExternalURL: fmt.Sprintf("https://open.spotify.com/track/%s", item.ID),
|
||||
Duration: parseDuration(item.Duration),
|
||||
IsExplicit: item.IsExplicit,
|
||||
})
|
||||
}
|
||||
case "album":
|
||||
|
||||
Reference in New Issue
Block a user