This commit is contained in:
afkarxyz
2026-02-24 18:42:22 +07:00
parent 1314c14c59
commit 9ef24f5a91
26 changed files with 904 additions and 635 deletions
+75 -7
View File
@@ -1,7 +1,6 @@
package backend
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
@@ -38,6 +37,17 @@ type LyricsResponse struct {
Lines []LyricsLine `json:"lines"`
}
type SpotifyLyricsLine struct {
TimeTag string `json:"timeTag"`
Words string `json:"words"`
}
type SpotifyLyricsAPIResponse struct {
Error bool `json:"error"`
SyncType string `json:"syncType"`
Lines []SpotifyLyricsLine `json:"lines"`
}
type LyricsDownloadRequest struct {
SpotifyID string `json:"spotify_id"`
TrackName string `json:"track_name"`
@@ -73,9 +83,7 @@ func NewLyricsClient() *LyricsClient {
func (c *LyricsClient) FetchLyricsWithMetadata(trackName, artistName string, duration int) (*LyricsResponse, error) {
apiBase, _ := base64.StdEncoding.DecodeString("aHR0cHM6Ly9scmNsaWIubmV0L2FwaS9nZXQ/YXJ0aXN0X25hbWU9")
apiURL := fmt.Sprintf("%s%s&track_name=%s",
string(apiBase),
apiURL := fmt.Sprintf("https://lrclib.net/api/get?artist_name=%s&track_name=%s",
url.QueryEscape(artistName),
url.QueryEscape(trackName))
@@ -167,8 +175,7 @@ func lrcTimestampToMs(timestamp string) int64 {
func (c *LyricsClient) FetchLyricsFromLRCLibSearch(trackName, artistName string) (*LyricsResponse, error) {
query := fmt.Sprintf("%s %s", artistName, trackName)
apiBase, _ := base64.StdEncoding.DecodeString("aHR0cHM6Ly9scmNsaWIubmV0L2FwaS9zZWFyY2g/cT0=")
apiURL := fmt.Sprintf("%s%s", string(apiBase), url.QueryEscape(query))
apiURL := fmt.Sprintf("https://lrclib.net/api/search?q=%s", url.QueryEscape(query))
resp, err := c.httpClient.Get(apiURL)
if err != nil {
@@ -212,6 +219,61 @@ func (c *LyricsClient) FetchLyricsFromLRCLibSearch(trackName, artistName string)
return c.convertLRCLibToLyricsResponse(best), nil
}
func (c *LyricsClient) FetchLyricsFromSpotifyAPI(spotifyID string) (*LyricsResponse, error) {
if spotifyID == "" {
return nil, fmt.Errorf("spotify ID is empty")
}
apiURL := fmt.Sprintf("https://spotify-lyrics-api-pi.vercel.app/?trackid=%s&format=lrc", spotifyID)
resp, err := c.httpClient.Get(apiURL)
if err != nil {
return nil, fmt.Errorf("failed to fetch from Spotify Lyrics API: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("Spotify Lyrics API returned status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read Spotify Lyrics API response: %v", err)
}
var apiResp SpotifyLyricsAPIResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("failed to parse Spotify Lyrics API response: %v", err)
}
if apiResp.Error {
return nil, fmt.Errorf("Spotify Lyrics API returned error")
}
result := &LyricsResponse{
Error: false,
SyncType: apiResp.SyncType,
Lines: []LyricsLine{},
}
for _, line := range apiResp.Lines {
if line.TimeTag == "" && line.Words == "" {
continue
}
ms := lrcTimestampToMs(line.TimeTag)
result.Lines = append(result.Lines, LyricsLine{
StartTimeMs: fmt.Sprintf("%d", ms),
Words: line.Words,
})
}
if len(result.Lines) == 0 {
return nil, fmt.Errorf("Spotify Lyrics API returned empty lines")
}
return result, nil
}
func simplifyTrackName(name string) string {
if idx := strings.Index(name, "("); idx > 0 {
@@ -226,7 +288,13 @@ func simplifyTrackName(name string) string {
func (c *LyricsClient) FetchLyricsAllSources(spotifyID, trackName, artistName string, duration int) (*LyricsResponse, string, error) {
resp, err := c.FetchLyricsWithMetadata(trackName, artistName, duration)
resp, err := c.FetchLyricsFromSpotifyAPI(spotifyID)
if err == nil && resp != nil && !resp.Error && len(resp.Lines) > 0 {
return resp, "Spotify", nil
}
fmt.Printf(" Spotify Lyrics API: %v\n", err)
resp, err = c.FetchLyricsWithMetadata(trackName, artistName, duration)
if err == nil && resp != nil && !resp.Error && len(resp.Lines) > 0 {
return resp, "LRCLIB", nil
}