.fix spotify rate limit issue
This commit is contained in:
@@ -389,11 +389,15 @@ func (a *App) DownloadTrack(req DownloadRequest) (DownloadResponse, error) {
|
|||||||
close(lyricsChan)
|
close(lyricsChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
if req.Service == "qobuz" {
|
||||||
client := backend.NewSongLinkClient()
|
go func() {
|
||||||
isrc, _ := client.GetISRC(req.SpotifyID)
|
client := backend.NewSongLinkClient()
|
||||||
isrcChan <- isrc
|
isrc, _ := client.GetISRCDirect(req.SpotifyID)
|
||||||
}()
|
isrcChan <- isrc
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
close(isrcChan)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
close(lyricsChan)
|
close(lyricsChan)
|
||||||
close(isrcChan)
|
close(isrcChan)
|
||||||
|
|||||||
+4
-59
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -19,12 +18,6 @@ type AmazonDownloader struct {
|
|||||||
regions []string
|
regions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SongLinkResponse struct {
|
|
||||||
LinksByPlatform map[string]struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
} `json:"linksByPlatform"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AmazonStreamResponse struct {
|
type AmazonStreamResponse struct {
|
||||||
StreamURL string `json:"streamUrl"`
|
StreamURL string `json:"streamUrl"`
|
||||||
DecryptionKey string `json:"decryptionKey"`
|
DecryptionKey string `json:"decryptionKey"`
|
||||||
@@ -40,65 +33,17 @@ func NewAmazonDownloader() *AmazonDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmazonDownloader) GetAmazonURLFromSpotify(spotifyTrackID string) (string, error) {
|
func (a *AmazonDownloader) GetAmazonURLFromSpotify(spotifyTrackID string) (string, error) {
|
||||||
|
|
||||||
spotifyBase := "https://open.spotify.com/track/"
|
|
||||||
spotifyURL := fmt.Sprintf("%s%s", spotifyBase, spotifyTrackID)
|
|
||||||
|
|
||||||
apiBase := "https://api.song.link/v1-alpha.1/links?url="
|
|
||||||
apiURL := fmt.Sprintf("%s%s", apiBase, url.QueryEscape(spotifyURL))
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", apiURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36")
|
|
||||||
|
|
||||||
fmt.Println("Getting Amazon URL...")
|
fmt.Println("Getting Amazon URL...")
|
||||||
|
client := NewSongLinkClient()
|
||||||
resp, err := a.client.Do(req)
|
urls, err := client.GetAllURLsFromSpotify(spotifyTrackID, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get Amazon URL: %w", err)
|
return "", fmt.Errorf("failed to get Amazon URL: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
amazonURL := normalizeAmazonMusicURL(urls.AmazonURL)
|
||||||
return "", fmt.Errorf("API returned status %d", resp.StatusCode)
|
if amazonURL == "" {
|
||||||
}
|
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to read response body: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(body) == 0 {
|
|
||||||
return "", fmt.Errorf("API returned empty response")
|
|
||||||
}
|
|
||||||
|
|
||||||
var songLinkResp SongLinkResponse
|
|
||||||
if err := json.Unmarshal(body, &songLinkResp); err != nil {
|
|
||||||
|
|
||||||
bodyStr := string(body)
|
|
||||||
if len(bodyStr) > 200 {
|
|
||||||
bodyStr = bodyStr[:200] + "..."
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("failed to decode response: %w (response: %s)", err, bodyStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
amazonLink, ok := songLinkResp.LinksByPlatform["amazonMusic"]
|
|
||||||
if !ok || amazonLink.URL == "" {
|
|
||||||
return "", fmt.Errorf("amazon Music link not found")
|
return "", fmt.Errorf("amazon Music link not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
amazonURL := amazonLink.URL
|
|
||||||
|
|
||||||
if strings.Contains(amazonURL, "trackAsin=") {
|
|
||||||
parts := strings.Split(amazonURL, "trackAsin=")
|
|
||||||
if len(parts) > 1 {
|
|
||||||
trackAsin := strings.Split(parts[1], "&")[0]
|
|
||||||
amazonURL = fmt.Sprintf("https://music.amazon.com/tracks/%s?musicTerritory=US", trackAsin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Found Amazon URL: %s\n", amazonURL)
|
fmt.Printf("Found Amazon URL: %s\n", amazonURL)
|
||||||
return amazonURL, nil
|
return amazonURL, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -365,7 +365,7 @@ func (q *QobuzDownloader) DownloadTrack(spotifyID, outputDir, quality, filenameF
|
|||||||
var deezerISRC string
|
var deezerISRC string
|
||||||
if spotifyID != "" {
|
if spotifyID != "" {
|
||||||
songlinkClient := NewSongLinkClient()
|
songlinkClient := NewSongLinkClient()
|
||||||
isrc, err := songlinkClient.GetISRC(spotifyID)
|
isrc, err := songlinkClient.GetISRCDirect(spotifyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get ISRC: %v", err)
|
return "", fmt.Errorf("failed to get ISRC: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+778
-318
File diff suppressed because it is too large
Load Diff
+4
-35
@@ -8,7 +8,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -91,47 +90,17 @@ func (t *TidalDownloader) GetAvailableAPIs() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TidalDownloader) GetTidalURLFromSpotify(spotifyTrackID string) (string, error) {
|
func (t *TidalDownloader) GetTidalURLFromSpotify(spotifyTrackID string) (string, error) {
|
||||||
|
|
||||||
spotifyBase := "https://open.spotify.com/track/"
|
|
||||||
spotifyURL := fmt.Sprintf("%s%s", spotifyBase, spotifyTrackID)
|
|
||||||
|
|
||||||
apiBase := "https://api.song.link/v1-alpha.1/links?url="
|
|
||||||
apiURL := fmt.Sprintf("%s%s", apiBase, url.QueryEscape(spotifyURL))
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", apiURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36")
|
|
||||||
|
|
||||||
fmt.Println("Getting Tidal URL...")
|
fmt.Println("Getting Tidal URL...")
|
||||||
|
client := NewSongLinkClient()
|
||||||
resp, err := t.client.Do(req)
|
urls, err := client.GetAllURLsFromSpotify(spotifyTrackID, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get Tidal URL: %w", err)
|
return "", fmt.Errorf("failed to get Tidal URL: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
tidalURL := urls.TidalURL
|
||||||
return "", fmt.Errorf("API returned status %d", resp.StatusCode)
|
if tidalURL == "" {
|
||||||
}
|
|
||||||
|
|
||||||
var songLinkResp struct {
|
|
||||||
LinksByPlatform map[string]struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
} `json:"linksByPlatform"`
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&songLinkResp); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tidalLink, ok := songLinkResp.LinksByPlatform["tidal"]
|
|
||||||
if !ok || tidalLink.URL == "" {
|
|
||||||
return "", fmt.Errorf("tidal link not found")
|
return "", fmt.Errorf("tidal link not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
tidalURL := tidalLink.URL
|
|
||||||
fmt.Printf("Found Tidal URL: %s\n", tidalURL)
|
fmt.Printf("Found Tidal URL: %s\n", tidalURL)
|
||||||
return tidalURL, nil
|
return tidalURL, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
|
|||||||
</Button>
|
</Button>
|
||||||
<Button variant={activeTab === "api" ? "default" : "ghost"} size="sm" onClick={() => setActiveTab("api")} className="rounded-b-none gap-2">
|
<Button variant={activeTab === "api" ? "default" : "ghost"} size="sm" onClick={() => setActiveTab("api")} className="rounded-b-none gap-2">
|
||||||
<Router className="h-4 w-4"/>
|
<Router className="h-4 w-4"/>
|
||||||
API Status
|
Status
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user