.isrc finder fallback
This commit is contained in:
+35
-17
@@ -87,14 +87,7 @@ func (s *SongLinkClient) lookupSpotifyISRC(spotifyTrackID string) (string, error
|
|||||||
isrc, resolvedTrackID, err := s.lookupSpotifyISRCViaSpotFetchAPI(normalizedTrackID, spotFetchAPIURL)
|
isrc, resolvedTrackID, err := s.lookupSpotifyISRCViaSpotFetchAPI(normalizedTrackID, spotFetchAPIURL)
|
||||||
if err == nil && isrc != "" {
|
if err == nil && isrc != "" {
|
||||||
fmt.Printf("Found ISRC via SpotFetch API: %s\n", isrc)
|
fmt.Printf("Found ISRC via SpotFetch API: %s\n", isrc)
|
||||||
if err := PutCachedISRC(normalizedTrackID, isrc); err != nil {
|
cacheResolvedSpotifyTrackISRC(normalizedTrackID, resolvedTrackID, isrc)
|
||||||
fmt.Printf("Warning: failed to write ISRC cache: %v\n", err)
|
|
||||||
}
|
|
||||||
if resolvedTrackID != "" && resolvedTrackID != normalizedTrackID {
|
|
||||||
if err := PutCachedISRC(resolvedTrackID, isrc); err != nil {
|
|
||||||
fmt.Printf("Warning: failed to write ISRC cache for resolved track ID: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isrc, nil
|
return isrc, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -102,21 +95,46 @@ func (s *SongLinkClient) lookupSpotifyISRC(spotifyTrackID string) (string, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, err := fetchSpotifyTrackRawData(s.client, normalizedTrackID)
|
payload, metadataErr := fetchSpotifyTrackRawData(s.client, normalizedTrackID)
|
||||||
if err != nil {
|
if metadataErr == nil {
|
||||||
return "", err
|
isrc, extractErr := extractSpotifyTrackISRC(payload)
|
||||||
|
if extractErr == nil {
|
||||||
|
fmt.Printf("Found ISRC via Spotify metadata: %s\n", isrc)
|
||||||
|
cacheResolvedSpotifyTrackISRC(normalizedTrackID, "", isrc)
|
||||||
|
return isrc, nil
|
||||||
|
}
|
||||||
|
metadataErr = extractErr
|
||||||
}
|
}
|
||||||
|
|
||||||
isrc, err := extractSpotifyTrackISRC(payload)
|
if metadataErr != nil {
|
||||||
if err != nil {
|
fmt.Printf("Warning: Spotify metadata ISRC lookup failed, falling back to Soundplate: %v\n", metadataErr)
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Found ISRC via Spotify metadata: %s\n", isrc)
|
isrc, resolvedTrackID, soundplateErr := s.lookupSpotifyISRCViaSoundplate(normalizedTrackID)
|
||||||
if err := PutCachedISRC(normalizedTrackID, isrc); err != nil {
|
if soundplateErr == nil && isrc != "" {
|
||||||
|
fmt.Printf("Found ISRC via Soundplate: %s\n", isrc)
|
||||||
|
cacheResolvedSpotifyTrackISRC(normalizedTrackID, resolvedTrackID, isrc)
|
||||||
|
return isrc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadataErr != nil && soundplateErr != nil {
|
||||||
|
return "", fmt.Errorf("spotify metadata lookup failed: %v | soundplate lookup failed: %w", metadataErr, soundplateErr)
|
||||||
|
}
|
||||||
|
if soundplateErr != nil {
|
||||||
|
return "", soundplateErr
|
||||||
|
}
|
||||||
|
return "", metadataErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func cacheResolvedSpotifyTrackISRC(trackID string, resolvedTrackID string, isrc string) {
|
||||||
|
if err := PutCachedISRC(trackID, isrc); err != nil {
|
||||||
fmt.Printf("Warning: failed to write ISRC cache: %v\n", err)
|
fmt.Printf("Warning: failed to write ISRC cache: %v\n", err)
|
||||||
}
|
}
|
||||||
return isrc, nil
|
if resolvedTrackID != "" && resolvedTrackID != trackID {
|
||||||
|
if err := PutCachedISRC(resolvedTrackID, isrc); err != nil {
|
||||||
|
fmt.Printf("Warning: failed to write ISRC cache for resolved track ID: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SongLinkClient) lookupSpotifyISRCViaSpotFetchAPI(spotifyTrackID string, apiBaseURL string) (string, string, error) {
|
func (s *SongLinkClient) lookupSpotifyISRCViaSpotFetchAPI(spotifyTrackID string, apiBaseURL string) (string, string, error) {
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package backend
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
soundplateSpotifyAPIURL = "https://phpstack-822472-6184058.cloudwaysapps.com/api/spotify.php"
|
||||||
|
soundplateRefererURL = "https://phpstack-822472-6184058.cloudwaysapps.com/?"
|
||||||
|
soundplateUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
|
||||||
|
)
|
||||||
|
|
||||||
|
type soundplateSpotifyResponse struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Artist string `json:"artist"`
|
||||||
|
Album string `json:"album"`
|
||||||
|
AlbumType string `json:"album_type"`
|
||||||
|
ArtworkURL string `json:"artwork_url"`
|
||||||
|
ISRC string `json:"isrc"`
|
||||||
|
Year string `json:"year"`
|
||||||
|
SpotifyURL string `json:"spotify_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SongLinkClient) lookupSpotifyISRCViaSoundplate(spotifyTrackID string) (string, string, error) {
|
||||||
|
normalizedTrackID, err := extractSpotifyTrackID(spotifyTrackID)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
spotifyTrackURL := fmt.Sprintf("https://open.spotify.com/track/%s", normalizedTrackID)
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("q", spotifyTrackURL)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, soundplateSpotifyAPIURL+"?"+query.Encode(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to create Soundplate ISRC request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("User-Agent", soundplateUserAgent)
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
req.Header.Set("Referer", soundplateRefererURL)
|
||||||
|
req.Header.Set("Accept-Language", "en-US,en;q=0.9,id;q=0.8")
|
||||||
|
req.Header.Set("Sec-CH-UA", "\"Chromium\";v=\"146\", \"Not-A.Brand\";v=\"24\", \"Google Chrome\";v=\"146\"")
|
||||||
|
req.Header.Set("Sec-CH-UA-Mobile", "?0")
|
||||||
|
req.Header.Set("Sec-CH-UA-Platform", "\"Windows\"")
|
||||||
|
req.Header.Set("Sec-Fetch-Dest", "empty")
|
||||||
|
req.Header.Set("Sec-Fetch-Mode", "cors")
|
||||||
|
req.Header.Set("Sec-Fetch-Site", "same-origin")
|
||||||
|
req.Header.Set("Priority", "u=1, i")
|
||||||
|
|
||||||
|
resp, err := s.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("Soundplate ISRC request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to read Soundplate ISRC response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
bodyPreview := strings.TrimSpace(string(body))
|
||||||
|
if len(bodyPreview) > 256 {
|
||||||
|
bodyPreview = bodyPreview[:256]
|
||||||
|
}
|
||||||
|
return "", "", fmt.Errorf("Soundplate ISRC returned status %d (%s)", resp.StatusCode, bodyPreview)
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload soundplateSpotifyResponse
|
||||||
|
if err := json.Unmarshal(body, &payload); err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to decode Soundplate ISRC response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isrc := firstISRCMatch(payload.ISRC)
|
||||||
|
if isrc == "" {
|
||||||
|
isrc = firstISRCMatch(string(body))
|
||||||
|
}
|
||||||
|
if isrc == "" {
|
||||||
|
return "", "", fmt.Errorf("ISRC missing in Soundplate response")
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedTrackID := ""
|
||||||
|
if payload.SpotifyURL != "" {
|
||||||
|
if trackID, err := extractSpotifyTrackID(payload.SpotifyURL); err == nil {
|
||||||
|
resolvedTrackID = trackID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isrc, resolvedTrackID, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user