v7.0.5
This commit is contained in:
@@ -403,6 +403,25 @@ func (c *LyricsClient) DownloadLyrics(req LyricsDownloadRequest) (*LyricsDownloa
|
||||
outputDir = NormalizePath(outputDir)
|
||||
}
|
||||
|
||||
safeArtist := sanitizeFilename(req.AlbumArtist)
|
||||
if safeArtist == "" {
|
||||
safeArtist = sanitizeFilename(req.ArtistName)
|
||||
}
|
||||
safeAlbum := sanitizeFilename(req.AlbumName)
|
||||
|
||||
if safeArtist != "" && safeAlbum != "" {
|
||||
artistAlbumPath := filepath.Join(outputDir, safeArtist, safeAlbum)
|
||||
if info, err := os.Stat(artistAlbumPath); err == nil && info.IsDir() {
|
||||
outputDir = artistAlbumPath
|
||||
} else {
|
||||
|
||||
artistPath := filepath.Join(outputDir, safeArtist)
|
||||
if info, err := os.Stat(artistPath); err == nil && info.IsDir() {
|
||||
outputDir = artistPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
return &LyricsDownloadResponse{
|
||||
Success: false,
|
||||
|
||||
+21
-10
@@ -1049,6 +1049,7 @@ func FilterPlaylist(data map[string]interface{}) map[string]interface{} {
|
||||
albumData := getMap(trackData, "albumOfTrack")
|
||||
albumName := ""
|
||||
albumID := ""
|
||||
albumArtistsString := ""
|
||||
var trackCover interface{}
|
||||
|
||||
if len(albumData) > 0 {
|
||||
@@ -1069,19 +1070,29 @@ func FilterPlaylist(data map[string]interface{}) map[string]interface{} {
|
||||
trackCover = getString(coverObj, "large")
|
||||
}
|
||||
}
|
||||
|
||||
albumArtists := extractArtists(getMap(albumData, "artists"))
|
||||
if len(albumArtists) > 0 {
|
||||
albumArtistNames := []string{}
|
||||
for _, artist := range albumArtists {
|
||||
albumArtistNames = append(albumArtistNames, getString(artist, "name"))
|
||||
}
|
||||
albumArtistsString = strings.Join(albumArtistNames, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
trackInfo := map[string]interface{}{
|
||||
"id": trackID,
|
||||
"cover": trackCover,
|
||||
"title": getString(trackData, "name"),
|
||||
"artist": artistsString,
|
||||
"artistIds": artistIDs,
|
||||
"plays": rank,
|
||||
"status": status,
|
||||
"album": albumName,
|
||||
"albumId": albumID,
|
||||
"duration": durationString,
|
||||
"id": trackID,
|
||||
"cover": trackCover,
|
||||
"title": getString(trackData, "name"),
|
||||
"artist": artistsString,
|
||||
"artistIds": artistIDs,
|
||||
"plays": rank,
|
||||
"status": status,
|
||||
"album": albumName,
|
||||
"albumArtist": albumArtistsString,
|
||||
"albumId": albumID,
|
||||
"duration": durationString,
|
||||
}
|
||||
tracks = append(tracks, trackInfo)
|
||||
}
|
||||
|
||||
+50
-11
@@ -5,8 +5,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -44,6 +46,7 @@ type TrackMetadata struct {
|
||||
Copyright string `json:"copyright,omitempty"`
|
||||
Publisher string `json:"publisher,omitempty"`
|
||||
Plays string `json:"plays,omitempty"`
|
||||
PreviewURL string `json:"preview_url,omitempty"`
|
||||
}
|
||||
|
||||
type ArtistSimple struct {
|
||||
@@ -75,6 +78,7 @@ type AlbumTrackMetadata struct {
|
||||
ArtistsData []ArtistSimple `json:"artists_data,omitempty"`
|
||||
Plays string `json:"plays,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
PreviewURL string `json:"preview_url,omitempty"`
|
||||
}
|
||||
|
||||
type TrackResponse struct {
|
||||
@@ -225,16 +229,17 @@ type apiPlaylistResponse struct {
|
||||
Count int `json:"count"`
|
||||
Followers int `json:"followers"`
|
||||
Tracks []struct {
|
||||
ID string `json:"id"`
|
||||
Cover string `json:"cover"`
|
||||
Title string `json:"title"`
|
||||
Artist string `json:"artist"`
|
||||
ArtistIds []string `json:"artistIds"`
|
||||
Plays string `json:"plays"`
|
||||
Status string `json:"status"`
|
||||
Album string `json:"album"`
|
||||
AlbumID string `json:"albumId"`
|
||||
Duration string `json:"duration"`
|
||||
ID string `json:"id"`
|
||||
Cover string `json:"cover"`
|
||||
Title string `json:"title"`
|
||||
Artist string `json:"artist"`
|
||||
ArtistIds []string `json:"artistIds"`
|
||||
Plays string `json:"plays"`
|
||||
Status string `json:"status"`
|
||||
Album string `json:"album"`
|
||||
AlbumArtist string `json:"albumArtist"`
|
||||
AlbumID string `json:"albumId"`
|
||||
Duration string `json:"duration"`
|
||||
} `json:"tracks"`
|
||||
}
|
||||
|
||||
@@ -942,7 +947,7 @@ func (c *SpotifyMetadataClient) formatPlaylistData(raw *apiPlaylistResponse) Pla
|
||||
Artists: item.Artist,
|
||||
Name: item.Title,
|
||||
AlbumName: item.Album,
|
||||
AlbumArtist: item.Artist,
|
||||
AlbumArtist: item.AlbumArtist,
|
||||
DurationMS: durationMS,
|
||||
Images: item.Cover,
|
||||
ReleaseDate: "",
|
||||
@@ -1400,3 +1405,37 @@ func SearchSpotifyByType(ctx context.Context, query string, searchType string, l
|
||||
client := NewSpotifyMetadataClient()
|
||||
return client.SearchByType(ctx, query, searchType, limit, offset)
|
||||
}
|
||||
|
||||
func GetPreviewURL(trackID string) (string, error) {
|
||||
if trackID == "" {
|
||||
return "", errors.New("track ID cannot be empty")
|
||||
}
|
||||
|
||||
embedURL := fmt.Sprintf("https://open.spotify.com/embed/track/%s", trackID)
|
||||
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Get(embedURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to fetch embed page: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("embed page returned status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
html := string(body)
|
||||
re := regexp.MustCompile(`https://p\.scdn\.co/mp3-preview/[a-zA-Z0-9]+`)
|
||||
match := re.FindString(html)
|
||||
|
||||
if match == "" {
|
||||
return "", errors.New("preview URL not found")
|
||||
}
|
||||
|
||||
return match, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user