1
votes

I'm trying to upload a custom image to my playlist on Spotify. Here's what happens: I make a request to the API to create a playlist using AJAX (this works) and then I want to upload a custom image to that newly made playlist also using AJAX. I've been following Spotify's guide on how to do that and believe that the headers, scopes, content type, etc... are all correct. Here is the code for uploading the image:

var playlistId = "newly_created_playlist_id_here";
var token = "access_token_here";

var url = c.toDataURL({   // encodes canvas image (declared as "c" in another file) to base64 jpeg format
        format: 'jpeg',   // file where "url" is declared is imported via the import / export method
        quality: 0.8      // canvas is successfully encoded to jpeg base64
});

$.ajax({
    url: "https://api.spotify.com/v1/playlists/" + playlistId +"/images",
    type: 'PUT',
    body: url,
    headers: {
        "Authorization": "Bearer " + token,
        "Content-Type": "image/jpeg; charset=utf-8"
     },
     contentType: "image/jpeg",
     error: function(err) { 
         console.log('Error: ' + err); 
     },
     success: function(data) {
         alert('Load was performed.');
     }
});

I however receive a error 400 from Spotify as seen below:

PUT https://api.spotify.com/v1/playlists/my_playlist_id/images 
400

Here is the HTTP header file contents:

Request URL: https://api.spotify.com/v1/playlists/my_playlist_id/images
Request Method: PUT
Status Code: 400 
Remote Address: 35.186.224.25:443
Referrer Policy: no-referrer-when-downgrade
access-control-allow-credentials: true
access-control-allow-headers: Accept, App-Platform, Authorization, Content-Type, Origin, Retry-After, Spotify-App-Version, X-Cloud-Trace-Context
access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
access-control-allow-origin: *
access-control-max-age: 604800
alt-svc: clear
cache-control: private, max-age=0
content-encoding: gzip
content-length: 86
content-type: application/json
date: Mon, 15 Jun 2020 09:53:52 GMT
server: envoy
status: 400
strict-transport-security: max-age=31536000
via: HTTP/2 edgeproxy, 1.1 google
x-content-type-options: nosniff
x-robots-tag: noindex, nofollow
:authority: api.spotify.com
:method: PUT
:path: /v1/playlists/my_playlist_id/images
:scheme: https
accept: application/json, text/javascript, */*; q=0.01
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
authorization: Bearer my_access_token
content-length: 0
content-type: image/jpeg
origin: http://127.0.0.1:5500
referer: http://127.0.0.1:5500/index.html
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36

Just to re-iterate what I've said earlier for clarification, The playlist is created with no errors and the image is encoded to base64 jpeg successfully too however when I try to upload the image to the new playlist, I receive the error 400. A new access token is also generated successfully.

I am using the following scopes when requesting access from the user:

ugc-image-upload
playlist-modify-public
playlist-modify-private

which are needed as described in the Spotify documentation.

I have no idea what I'm doing wrong here and I haven't found any other questions across the internet that answer my problem so any help is greatly appreciated!

1

1 Answers

1
votes

This caused me a similar headache - it does work but the encoding of the image must be exact:

  • No newlines or spaces
  • Nothing like data:image/jpeg at the start of the string (see this answer)

While not relevant to the OP, the main issue in my case was my editor (VScode) adding a new line to the end of the text file with the encoded image when it was saved, which caused it to be rejected by the Spotify API.

For anyone else looking at this, I got it working by starting with a very basic base64 encoded image (see below) and then building up to the functionality I needed.

iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==

(A red dot, taken from this question.)