Search code examples
pythonspotify

Failed to fetch Music Recommendation. Status Code: 404


I am trying to build a system that curates music based on emotions or that is the idea for now, it was working perfectly fine for a while but suddenly whenever I want to retrieve recommendations based on emotions, I am getting a 404 status code error. I am really not able to pinpoint the problem

I'll share a few codes which is like the core concept, If I could get to know the exact solution to the problem or where the problem lies it would be helpful

Music.py

import requests
import random
from ai_ml.src.utils import get_spotify_access_token
from ai_ml.src.config import CONFIG

def get_music_recommendation(emotion, market=None):
    try:
        access_token = get_spotify_access_token()
    except Exception as e:
        print(f"Error retrieving access token: {e}")
        return []

    emotion_to_genre = {
    "happy": [
        "acoustic", "afrobeat", "alt-rock", "alternative", "ambient", "blues", 
        "bossa nova", "brazil", "chill", "classical", "club", "comedy", "dance", 
        "disco", "drum-and-bass", "edm", "electro", "electronic", "folk", "funk", 
        "garage", "gospel", "groove", "grunge", "happy", "house", "idm", "indie", 
        "indie-pop", "industrial", "j-dance", "j-idol", "j-pop", "j-rock", "jazz", 
        "k-pop", "kids", "latin", "latino", "pop", "pop-film", "post-dubstep", 
        "power-pop", "progressive-house", "reggae", "reggaeton", "rock", "rock-n-roll", 
        "salsa", "samba", "show-tunes", "singer-songwriter", "ska", "summer", 
        "swedish", "synth-pop", "tango", "techno", "trance", "world-music"
    ],
    "sad": [
        "blues", "classical", "emo", "folk", "indie-pop", "jazz", "latin", "latino", 
        "metalcore", "post-dubstep", "punk", "r-n-b", "rainy-day", "rock", "sad", 
        "singer-songwriter", "soul"
    ],
    "angry": [
        "black-metal", "death-metal", "grindcore", "hardcore", "heavy-metal", 
        "industrial", "metal", "metal-misc", "metalcore", "punk-rock", "punk"
    ],
    "surprise": [
        "anime", "electro", "experimental", "idm", "j-dance", "j-idol", "j-pop", 
        "j-rock", "post-dubstep", "psych-rock", "trip-hop", "turkish"
    ],
    "neutral": [
        "acoustic", "ambient", "chill", "classical", "country", "dancehall", "deep-house", 
        "detroit-techno", "dub", "dubstep", "edm", "electro", "electronic", "folk", 
        "french", "groove", "hard-rock", "honky-tonk", "house", "idm", "indie", 
        "indie-pop", "industrial", "j-pop", "kids", "latin", "mpb", "new-age", 
        "new-release", "opera", "party", "pop", "reggae", "reggaeton", "rockabilly", 
        "singer-songwriter", "soul", "soundtracks", "study", "synth-pop", "techno"
    ]
}


    genre = emotion_to_genre.get(emotion.lower(), "pop")

    headers = {
        "Authorization": f"Bearer {access_token}"
    }

    available_markets = [
        "AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
        "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR",
        "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM",
        "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU",
        "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW",
        "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH",
        "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO",
        "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PR", "PS", "PT", "PW", "PY", "QA", "RO", "RS",
        "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH",
        "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU",
        "WS", "XK", "ZA", "ZM", "ZW"
    ]

    selected_market = market if market in available_markets else random.choice(available_markets)


    params = {
        "seed_genres": genre,
        "limit": 25,
        "market": selected_market
    }

    if emotion == "happy":
        params["target_valence"] = 0.8
        params["target_energy"] = 0.7
    elif emotion == "sad":
        params["target_valence"] = 0.2
        params["target_energy"] = 0.2
    elif emotion == "angry":
        params["target_valence"] = 0.2
        params["target_energy"] = 0.9
    elif emotion == "surprise":
        params["target_valence"] = 0.6
        params["target_energy"] = 0.8
    else:
        params["target_valence"] = 0.5
        params["target_energy"] = 0.5

    response = requests.get("https://api.spotify.com/v1/recommendations", headers=headers, params=params)

    if response.status_code == 401:
        print("Access token expired. Please refresh the token.")
        return []
    elif response.status_code != 200:
        print(f"Failed to fetch music recommendations. Status code: {response.status_code}")
        return []

    tracks = response.json().get("tracks", [])
    recommended_tracks = [
        {
            "name": track["name"],
            "artist": ", ".join([artist["name"] for artist in track["artists"]]),
            "preview_url": track.get("preview_url"),
            "external_url": track.get("external_urls", {}).get("spotify"),
            "image_url": next((img["url"] for img in track["album"]["images"]), None),
            "album_name": track["album"]["name"],
            "release_date": track["album"].get("release_date"),
            "track_duration": track.get("duration_ms") // 1000 if track.get("duration_ms") else None,
            "popularity": track.get("popularity"),
            "explicit": track.get("explicit"),  
        }
        for track in tracks
    ]

    if not recommended_tracks:
        print(f"No tracks found for genre: {genre}")

    return recommended_tracks`

utils.py

import base64
import requests
from ai_ml.src.config import CONFIG

def get_spotify_access_token():
    client_id = CONFIG["spotify_client_id"]
    client_secret = CONFIG["spotify_client_secret"]
    token_url = "https://accounts.spotify.com/api/token"

    # Create the authorization header
    auth_header = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()

    headers = {
        "Authorization": f"Basic {auth_header}"
    }

    data = {
        "grant_type": "client_credentials"
    }

    response = requests.post(token_url, headers=headers, data=data)

    if response.status_code != 200:
        raise Exception("Failed to retrieve Spotify access token")

    return response.json().get("access_token")

config is a separate python script with my client and client_secret id


Solution

  • This is because the API was deprecated on November 27, 2024.