Announcements

Help Wizard

Step 1

NEXT STEP

FAQs

Please see below the most popular frequently asked questions.

Loading article...

Loading faqs...

VIEW ALL

Ongoing Issues

Please see below the current ongoing issues which are under investigation.

Loading issue...

Loading ongoing issues...

VIEW ALL

[Web API] Search not returning certain album

[Web API] Search not returning certain album

Plan

Premium

Country

Germany

Device

Lenovo Thinkpad T490

Operating System

Linux Manjaro

 

My Question or Issue

For prototyping I am using my laptop to emulate a bluetooth speaker and have my phone connected to the laptop over bluetooth. My plan is to use the song, album and artist name transmitted over bluetooth to get the album cover art from spotify. This works mostly quite well, except for one album, the compilation "Discography - Complete Singles Collection". There it returns multiple other albums, but never this exact one, even though my search query should match it pretty exactly. The search query works for other songs, albums and artists, except if they are from that album.

Discography - Complete Singles Collection

 

Search query
"track: Always on My Mind album: Discography - Complete Singles Collection artist: Pet Shop Boys"

 

Output Dump

https://pastebin.com/c6qGUHkm

(inconsistencies in single- and double-quotes due to VS Code not wanting to format it correctly)

 

Python Code

 

 

import dbus
import dbus.mainloop.glib
from gi.repository import GLib
import requests
from PIL import Image
from io import BytesIO
from fuzzywuzzy import fuzz
from urllib.parse import urlencode,quote

# Create a D-Bus session
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

access_token = None

def discover_devices():
    bus = dbus.SystemBus()
    manager = dbus.Interface(bus.get_object('org.bluez', '/'), 'org.freedesktop.DBus.ObjectManager')
    objects = manager.GetManagedObjects()

    discovered_devices = []
    for path, interfaces in objects.items():
        if 'org.bluez.Device1' in interfaces:
            device_props = interfaces['org.bluez.Device1']
            discovered_devices.append({
                'Path': path,
                'Address': device_props['Address']
            })

    return discovered_devices

def show_image(image_url):
    if image_url:
        
        response = requests.get(image_url)
        if response.status_code == 200:
            image_data = BytesIO(response.content)
            image = Image.open(image_data)
            image.show()
        else:
            print("Failed to download and display the image.")
    else:
        print("No album art found for the album.")

def get_access_token():
    global access_token
    if not access_token:
        url = "https://accounts.spotify.com/api/token"
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        data = {"grant_type":"client_credentials", "client_id":"","client_secret":""}

        response = requests.post(url, headers=headers, data=data)
        data=response.json()
        access_token = data['access_token']
    return access_token

def fetch_album_art(album, artist, song):
    token = get_access_token()
    #query = song + " " +album + " " +artist
    query = "track: "+(str(song).strip())+" album: "+(str(album).strip())+" artist: "+(str(artist).strip())
    #query = (str(song).strip())+(str(album).strip())+(str(artist).strip())
    url = f"https://api.spotify.com/v1/search?q={query}&type=track"
    print('')
    print(query)
    print(url)
    print('')
    print(song)
    print(album)
    print(artist)
    headers = {
        "User-Agent": "prototyping (**bleep** )",
        "Authorization": "Bearer {}".format(token),
        "Accept":"application/json"}

    response = requests.get(url, headers=headers)
    if response.status_code == 404:
        print("No cover art found")
        return None
    data = response.json()

    best_match_score = 0
    best_album_image = None

    print('')
    print(data)
    print(album, len(data['tracks']['items']))
    print('')
    for element in data['tracks']['items']:
        match_score = fuzz.token_sort_ratio(element['album']['name'], album)
        print(element['album']['name'], match_score)
        if match_score > best_match_score:
            best_match_score = match_score
            best_album_image = element['album']['images'][0]['url']
            print('Updated')
    print(best_match_score)
    if best_match_score > 0:
        return best_album_image
    else:
        return data['tracks']['items'][0]['album']['images'][0]['url']

def property_changed_handler(interface, changed_props, invalidated_props):
    if "Track" in changed_props:
        print("Track Properties Changed on Interface:", interface)
        track_properties = changed_props["Track"]
        track_changed_handler(track_properties)

def track_changed_handler(props):
    album = ""
    artist = ""
    song = ""
    if "Album" in props:
        album = props["Album"]
    if "Artist" in props:
        artist = props["Artist"]
    if "Title" in props:
        song = props["Title"]
    image_url = fetch_album_art(album, artist, song)
    if image_url:
        show_image(image_url)
    else:
        print("No image found")

def find_player_interface(bus, device_path):
    manager = dbus.Interface(bus.get_object('org.bluez', '/'), 'org.freedesktop.DBus.ObjectManager')
    objects = manager.GetManagedObjects()

    for path, interfaces in objects.items():
        if path.startswith(device_path) and 'org.bluez.MediaPlayer1' in interfaces:
            print(path)
            return bus.get_object('org.bluez', path)

    return None

def main():
    print("Discovering devices...")
    discovered_devices = discover_devices()

    print("Discovered devices:")
    for index, device in enumerate(discovered_devices):
        print(f"{index}: {device['Address']}")

    choice = int(input("Choose a device by entering its index: "))
    if choice < 0 or choice >= len(discovered_devices):
        print("Invalid choice.")
        return

    chosen_device = discovered_devices[choice]
    device_path = chosen_device['Path']
    print("Chosen Device Path:", device_path)

    bus = dbus.SystemBus()

    player = find_player_interface(bus, device_path)
    if player is None:
        print("No suitable player interface found.")
        return
    
    player_iface = dbus.Interface(player, 'org.freedesktop.DBus.Properties')
    player_iface.connect_to_signal('PropertiesChanged', property_changed_handler)

    mainloop = GLib.MainLoop()
    mainloop.run()

if __name__ == "__main__":
    main()

 

 

 

I donโ€˜t know why this problem occurs and it would be a major reliability concern for the final product.

 

 

 

 

 

Reply
2 Replies

Interestingly when making the request from the python program, while overriding the requested token with the token the spotify website uses when making the example queries, the python program manages to find the album. Is there some kind of scope limitation for API Search?

It works completely reliably if I hard code my API request to use the same spotify market as my phone uses, but I shouldn't have to do that if omitting the market parameter just requests all markets when using client credentials(so no market of any user can be used). Maybe this is even a bug with the API, because it seems like the Search endpoint only really works with US market albums when omitting the market parameter ._.

Suggested posts

Staff
Let's introduce ourselves!

Hey there you,   Yeah, you! ๐Ÿ˜   Welcome - we're glad you joined the Spotify Community!   While you here, let's have a fun game and getโ€ฆ

Staff
ModeratorStaff / Moderator/ 3 years ago  in Social & Random

Type a product name