This commit is contained in:
afkarxyz
2026-01-13 22:45:08 +07:00
parent 0f2174bf80
commit 46a7777698
16 changed files with 649 additions and 447 deletions
+19
View File
@@ -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
View File
@@ -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
View File
@@ -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
}