.remove spotfetch api

This commit is contained in:
afkarxyz
2026-04-13 22:50:45 +07:00
parent e23fa2a48e
commit 7997f7e264
9 changed files with 9 additions and 428 deletions
-19
View File
@@ -50,25 +50,6 @@ func LoadConfigSettings() (map[string]interface{}, error) {
return settings, nil
}
func GetSpotFetchAPISettings() (bool, string) {
settings, err := LoadConfigSettings()
if err != nil || settings == nil {
return false, ""
}
useAPI, _ := settings["useSpotFetchAPI"].(bool)
if !useAPI {
return false, ""
}
apiURL, _ := settings["spotFetchAPIUrl"].(string)
if apiURL == "" {
apiURL = "https://sp.afkarxyz.qzz.io/api"
}
return true, apiURL
}
func GetRedownloadWithSuffixSetting() bool {
settings, err := LoadConfigSettings()
if err != nil || settings == nil {
-89
View File
@@ -52,20 +52,6 @@ type SpotifyTrackIdentifiers struct {
UPC string `json:"upc,omitempty"`
}
type spotFetchIdentifierResponse struct {
Input string `json:"input"`
TrackID string `json:"track_id"`
GID string `json:"gid"`
CanonicalURI string `json:"canonical_uri"`
Name string `json:"name"`
Artists []string `json:"artists"`
AlbumName string `json:"album_name"`
ReleaseDate string `json:"release_date"`
Label string `json:"label"`
ISRC string `json:"isrc"`
UPC string `json:"upc"`
}
func GetSpotifyTrackIdentifiersDirect(spotifyTrackID string) (SpotifyTrackIdentifiers, error) {
normalizedTrackID, err := extractSpotifyTrackID(spotifyTrackID)
if err != nil {
@@ -82,23 +68,6 @@ func GetSpotifyTrackIdentifiersDirect(spotifyTrackID string) (SpotifyTrackIdenti
identifiers.ISRC = cachedISRC
}
useSpotFetchAPI, spotFetchAPIURL := GetSpotFetchAPISettings()
if useSpotFetchAPI {
apiIdentifiers, resolvedTrackID, err := lookupSpotifyTrackIdentifiersViaSpotFetchAPI(normalizedTrackID, spotFetchAPIURL)
if err == nil {
mergeSpotifyTrackIdentifiers(&identifiers, apiIdentifiers)
if identifiers.ISRC != "" {
fmt.Printf("Found identifiers via SpotFetch API: isrc=%s upc=%s\n", identifiers.ISRC, identifiers.UPC)
cacheResolvedSpotifyTrackISRC(normalizedTrackID, resolvedTrackID, identifiers.ISRC)
}
if identifiers.ISRC != "" && identifiers.UPC != "" {
return identifiers, nil
}
} else {
fmt.Printf("Warning: SpotFetch identifier lookup failed, falling back to Spotify metadata: %v\n", err)
}
}
httpClient := &http.Client{Timeout: 30 * time.Second}
payload, metadataErr := fetchSpotifyTrackRawData(httpClient, normalizedTrackID)
@@ -172,18 +141,6 @@ func cacheResolvedSpotifyTrackISRC(trackID string, resolvedTrackID string, isrc
}
}
func (s *SongLinkClient) lookupSpotifyISRCViaSpotFetchAPI(spotifyTrackID string, apiBaseURL string) (string, string, error) {
identifiers, resolvedTrackID, err := lookupSpotifyTrackIdentifiersViaSpotFetchAPI(spotifyTrackID, apiBaseURL)
if err != nil {
return "", "", err
}
if identifiers.ISRC == "" {
return "", "", fmt.Errorf("ISRC missing in SpotFetch identifier response")
}
return identifiers.ISRC, resolvedTrackID, nil
}
func mergeSpotifyTrackIdentifiers(target *SpotifyTrackIdentifiers, incoming SpotifyTrackIdentifiers) {
if incoming.ISRC != "" {
target.ISRC = strings.TrimSpace(incoming.ISRC)
@@ -193,52 +150,6 @@ func mergeSpotifyTrackIdentifiers(target *SpotifyTrackIdentifiers, incoming Spot
}
}
func lookupSpotifyTrackIdentifiersViaSpotFetchAPI(spotifyTrackID string, apiBaseURL string) (SpotifyTrackIdentifiers, string, error) {
normalizedTrackID := strings.TrimSpace(spotifyTrackID)
baseURL := strings.TrimRight(strings.TrimSpace(apiBaseURL), "/")
if normalizedTrackID == "" {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("spotify track ID is required")
}
if baseURL == "" {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("spotfetch api url is required")
}
requestURL := fmt.Sprintf("%s/identifier/%s", baseURL, url.PathEscape(normalizedTrackID))
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("failed to create SpotFetch identifier request: %w", err)
}
req.Header.Set("User-Agent", songLinkUserAgent)
req.Header.Set("Accept", "application/json")
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Do(req)
if err != nil {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("SpotFetch identifier request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
bodyPreview, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("SpotFetch identifier returned status %d (%s)", resp.StatusCode, strings.TrimSpace(string(bodyPreview)))
}
var payload spotFetchIdentifierResponse
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("failed to decode SpotFetch identifier response: %w", err)
}
identifiers := SpotifyTrackIdentifiers{
ISRC: firstISRCMatch(payload.ISRC),
UPC: strings.TrimSpace(payload.UPC),
}
if identifiers.ISRC == "" && identifiers.UPC == "" {
return SpotifyTrackIdentifiers{}, "", fmt.Errorf("identifiers missing in SpotFetch response")
}
return identifiers, strings.TrimSpace(payload.TrackID), nil
}
func lookupSpotifyAlbumUPC(albumID string) (string, error) {
normalizedAlbumID := strings.TrimSpace(albumID)
if normalizedAlbumID == "" {
-197
View File
@@ -1,197 +0,0 @@
package backend
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"regexp"
"strings"
"time"
)
func streamTrackListChunks(ctx context.Context, tracks []AlbumTrackMetadata, callback MetadataCallback) error {
if callback == nil || len(tracks) == 0 {
return nil
}
const chunkSize = 25
for start := 0; start < len(tracks); start += chunkSize {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
end := start + chunkSize
if end > len(tracks) {
end = len(tracks)
}
callback(tracks[start:end])
if end < len(tracks) {
time.Sleep(15 * time.Millisecond)
}
}
return nil
}
func GetSpotifyDataWithAPI(ctx context.Context, spotifyURL string, useAPI bool, apiBaseURL string, batch bool, delay time.Duration, separator string, callback MetadataCallback) (interface{}, error) {
if !useAPI || apiBaseURL == "" {
return GetFilteredSpotifyData(ctx, spotifyURL, batch, delay, separator, callback)
}
spotifyType, id := parseSpotifyURLToTypeAndID(spotifyURL)
if spotifyType == "" || id == "" {
return nil, fmt.Errorf("invalid Spotify URL: %s", spotifyURL)
}
if spotifyType == "artist" {
return GetFilteredSpotifyData(ctx, spotifyURL, batch, delay, separator, callback)
}
apiURL := fmt.Sprintf("%s/%s/%s", strings.TrimSuffix(apiBaseURL, "/"), spotifyType, id)
req, err := http.NewRequestWithContext(ctx, "GET", apiURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create API request: %w", err)
}
client := &http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("SpotFetch API request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("SpotFetch API error: HTTP %d", resp.StatusCode)
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read API response: %w", err)
}
var data interface{}
switch spotifyType {
case "track":
var trackResp TrackResponse
if err := json.Unmarshal(bodyBytes, &trackResp); err != nil {
return nil, fmt.Errorf("failed to decode track response: %w", err)
}
trackID := strings.TrimSpace(trackResp.Track.SpotifyID)
if trackID == "" {
trackID = strings.TrimSpace(id)
}
if trackID != "" {
if identifiers, _, err := lookupSpotifyTrackIdentifiersViaSpotFetchAPI(trackID, apiBaseURL); err == nil {
if identifiers.UPC != "" {
trackResp.Track.UPC = identifiers.UPC
}
}
}
data = trackResp
case "album":
var albumResp AlbumResponsePayload
if err := json.Unmarshal(bodyBytes, &albumResp); err != nil {
return nil, fmt.Errorf("failed to decode album response: %w", err)
}
data = &albumResp
if callback != nil {
callback(&AlbumResponsePayload{
AlbumInfo: albumResp.AlbumInfo,
TrackList: []AlbumTrackMetadata{},
})
if err := streamTrackListChunks(ctx, albumResp.TrackList, callback); err != nil {
return nil, err
}
}
case "playlist":
var playlistResp PlaylistResponsePayload
if err := json.Unmarshal(bodyBytes, &playlistResp); err != nil {
return nil, fmt.Errorf("failed to decode playlist response: %w", err)
}
data = playlistResp
if callback != nil {
callback(PlaylistResponsePayload{
PlaylistInfo: playlistResp.PlaylistInfo,
TrackList: []AlbumTrackMetadata{},
})
if err := streamTrackListChunks(ctx, playlistResp.TrackList, callback); err != nil {
return nil, err
}
}
case "artist":
var artistResp ArtistDiscographyPayload
if err := json.Unmarshal(bodyBytes, &artistResp); err != nil {
return nil, fmt.Errorf("failed to decode artist response: %w", err)
}
data = &artistResp
if callback != nil {
callback(&ArtistDiscographyPayload{
ArtistInfo: artistResp.ArtistInfo,
AlbumList: artistResp.AlbumList,
TrackList: []AlbumTrackMetadata{},
})
if err := streamTrackListChunks(ctx, artistResp.TrackList, callback); err != nil {
return nil, err
}
}
default:
return nil, fmt.Errorf("unsupported Spotify type: %s", spotifyType)
}
if callback != nil {
switch payload := data.(type) {
case TrackResponse:
t := payload.Track
callback([]AlbumTrackMetadata{{
SpotifyID: t.SpotifyID,
Artists: t.Artists,
Name: t.Name,
AlbumName: t.AlbumName,
AlbumArtist: t.AlbumArtist,
DurationMS: t.DurationMS,
Images: t.Images,
ReleaseDate: t.ReleaseDate,
TrackNumber: t.TrackNumber,
TotalTracks: t.TotalTracks,
DiscNumber: t.DiscNumber,
TotalDiscs: t.TotalDiscs,
ExternalURL: t.ExternalURL,
UPC: t.UPC,
Plays: t.Plays,
PreviewURL: t.PreviewURL,
IsExplicit: t.IsExplicit,
}})
}
}
return data, nil
}
func parseSpotifyURLToTypeAndID(url string) (string, string) {
if strings.HasPrefix(url, "spotify:") {
parts := strings.Split(url, ":")
if len(parts) >= 3 {
return parts[1], parts[2]
}
}
re := regexp.MustCompile(`spotify\.com/(track|album|playlist|artist)/([a-zA-Z0-9]+)`)
matches := re.FindStringSubmatch(url)
if len(matches) == 3 {
return matches[1], matches[2]
}
return "", ""
}