From cf36d2844453291ccc0da29f47f5ab980bcbcba9 Mon Sep 17 00:00:00 2001 From: afkarxyz Date: Thu, 2 Apr 2026 08:36:42 +0700 Subject: [PATCH] .separate songlink --- backend/link_resolver.go | 140 +++++++++++++++++++++++++++++++++++++++ backend/songlink.go | 63 ------------------ 2 files changed, 140 insertions(+), 63 deletions(-) create mode 100644 backend/link_resolver.go diff --git a/backend/link_resolver.go b/backend/link_resolver.go new file mode 100644 index 0000000..b614ab1 --- /dev/null +++ b/backend/link_resolver.go @@ -0,0 +1,140 @@ +package backend + +import ( + "errors" + "fmt" + "strings" +) + +type resolvedTrackLinks struct { + TidalURL string + AmazonURL string + DeezerURL string + ISRC string +} + +const ( + linkResolverProviderSongstats = "songstats" + linkResolverProviderDeezerSongLink = "deezer-songlink" +) + +func (s *SongLinkClient) resolveSpotifyTrackLinks(spotifyTrackID string, region string) (*resolvedTrackLinks, error) { + links := &resolvedTrackLinks{} + var attempts []string + + isrc, err := s.lookupSpotifyISRC(spotifyTrackID) + if err != nil { + attempts = append(attempts, fmt.Sprintf("spotify isrc: %v", err)) + } else { + links.ISRC = isrc + } + + if links.ISRC != "" { + resolvers := prioritizeProviders("link_resolver", []string{ + linkResolverProviderSongstats, + linkResolverProviderDeezerSongLink, + }) + + for _, resolver := range resolvers { + switch resolver { + case linkResolverProviderSongstats: + addedData, songstatsErr := s.resolveLinksViaSongstats(links) + if addedData { + recordProviderSuccess("link_resolver", linkResolverProviderSongstats) + } else if songstatsErr != nil { + recordProviderFailure("link_resolver", linkResolverProviderSongstats) + } + if songstatsErr != nil { + attempts = append(attempts, fmt.Sprintf("songstats: %v", songstatsErr)) + } + case linkResolverProviderDeezerSongLink: + addedData, deezerSongLinkErr := s.resolveLinksViaDeezerSongLink(links, region) + if addedData { + recordProviderSuccess("link_resolver", linkResolverProviderDeezerSongLink) + } else if deezerSongLinkErr != nil { + recordProviderFailure("link_resolver", linkResolverProviderDeezerSongLink) + } + if deezerSongLinkErr != nil { + attempts = append(attempts, fmt.Sprintf("deezer-songlink: %v", deezerSongLinkErr)) + } + } + + if links.TidalURL != "" && links.AmazonURL != "" { + return links, nil + } + } + } + + if hasAnySongLinkData(links) { + return links, nil + } + + if len(attempts) == 0 { + attempts = append(attempts, "no streaming URLs found") + } + + return links, errors.New(strings.Join(attempts, " | ")) +} + +func (s *SongLinkClient) resolveLinksViaSongstats(links *resolvedTrackLinks) (bool, error) { + if links == nil || links.ISRC == "" { + return false, fmt.Errorf("ISRC is required for Songstats resolver") + } + + before := *links + + fmt.Printf("Fetching Songstats links for ISRC %s\n", links.ISRC) + if err := s.populateLinksFromSongstats(links, links.ISRC); err != nil { + return false, err + } + + return *links != before, nil +} + +func (s *SongLinkClient) resolveLinksViaDeezerSongLink(links *resolvedTrackLinks, region string) (bool, error) { + if links == nil || links.ISRC == "" { + return false, fmt.Errorf("ISRC is required for Deezer song.link resolver") + } + + before := *links + var attempts []string + + if links.DeezerURL == "" { + fmt.Printf("Resolving Deezer track from ISRC %s\n", links.ISRC) + deezerURL, err := s.lookupDeezerTrackURLByISRC(links.ISRC) + if err != nil { + attempts = append(attempts, fmt.Sprintf("deezer isrc: %v", err)) + } else { + links.DeezerURL = deezerURL + } + } + + if links.DeezerURL != "" { + fmt.Println("Resolving streaming URLs from song.link via Deezer URL...") + deezerResp, err := s.fetchSongLinkLinksByURL(links.DeezerURL, region) + if err != nil { + attempts = append(attempts, fmt.Sprintf("song.link deezer: %v", err)) + } else { + mergeSongLinkResponse(links, deezerResp) + } + + if links.ISRC == "" { + if resolvedISRC, deezerISRCErr := getDeezerISRC(links.DeezerURL); deezerISRCErr == nil { + links.ISRC = resolvedISRC + } + } + } + + if *links != before { + if len(attempts) == 0 { + return true, nil + } + return true, errors.New(strings.Join(attempts, " | ")) + } + + if len(attempts) == 0 { + attempts = append(attempts, "no links found via deezer-songlink") + } + + return false, errors.New(strings.Join(attempts, " | ")) +} diff --git a/backend/songlink.go b/backend/songlink.go index e1a3475..919fa39 100644 --- a/backend/songlink.go +++ b/backend/songlink.go @@ -2,7 +2,6 @@ package backend import ( "encoding/json" - "errors" "fmt" "io" "net/http" @@ -48,13 +47,6 @@ type songLinkAPIResponse struct { } `json:"linksByPlatform"` } -type resolvedTrackLinks struct { - TidalURL string - AmazonURL string - DeezerURL string - ISRC string -} - func NewSongLinkClient() *SongLinkClient { return &SongLinkClient{ client: &http.Client{ @@ -276,61 +268,6 @@ func (s *SongLinkClient) GetISRCDirect(spotifyID string) (string, error) { return s.lookupSpotifyISRC(spotifyID) } -func (s *SongLinkClient) resolveSpotifyTrackLinks(spotifyTrackID string, region string) (*resolvedTrackLinks, error) { - links := &resolvedTrackLinks{} - var attempts []string - - isrc, err := s.lookupSpotifyISRC(spotifyTrackID) - if err != nil { - attempts = append(attempts, fmt.Sprintf("spotify isrc: %v", err)) - } else { - links.ISRC = isrc - } - - if links.ISRC != "" { - fmt.Printf("Fetching Songstats links for ISRC %s\n", links.ISRC) - if songstatsErr := s.populateLinksFromSongstats(links, links.ISRC); songstatsErr != nil { - attempts = append(attempts, fmt.Sprintf("songstats: %v", songstatsErr)) - } - } - - if links.ISRC != "" && links.DeezerURL == "" { - fmt.Printf("Resolving Deezer track from ISRC %s\n", links.ISRC) - deezerURL, deezerErr := s.lookupDeezerTrackURLByISRC(links.ISRC) - if deezerErr != nil { - attempts = append(attempts, fmt.Sprintf("deezer isrc: %v", deezerErr)) - } else { - links.DeezerURL = deezerURL - } - } - - if links.DeezerURL != "" { - fmt.Println("Resolving streaming URLs from song.link via Deezer URL...") - deezerResp, deezerSongLinkErr := s.fetchSongLinkLinksByURL(links.DeezerURL, region) - if deezerSongLinkErr != nil { - attempts = append(attempts, fmt.Sprintf("song.link deezer: %v", deezerSongLinkErr)) - } else { - mergeSongLinkResponse(links, deezerResp) - } - - if links.ISRC == "" { - if resolvedISRC, deezerISRCErr := getDeezerISRC(links.DeezerURL); deezerISRCErr == nil { - links.ISRC = resolvedISRC - } - } - } - - if hasAnySongLinkData(links) { - return links, nil - } - - if len(attempts) == 0 { - attempts = append(attempts, "no streaming URLs found") - } - - return links, errors.New(strings.Join(attempts, " | ")) -} - func (s *SongLinkClient) fetchSongLinkLinksByURL(rawURL string, region string) (*songLinkAPIResponse, error) { apiURL := fmt.Sprintf("https://api.song.link/v1-alpha.1/links?url=%s", url.QueryEscape(rawURL)) if region != "" {