1

I was building an app that helps me move tracks from my library to another playlist which requires me to go through the Spotify Authorisation workflow. I'm fairly certain the scopes are correct and I've managed to return the correct access and refresh tokens, but I cannot figure out how to only get the tracks from the user's library after the user has logged in and authorised their account for access.

I tried passing the authorisation flow into a function only to be called before the app gets the tracks but that didn't seem to work.

const __dirname = dirname(fileURLToPath(import.meta.url));

const app = Express();
const port = 3030;

// CLIENT_SECRET stored in Config Vars
// const apiUrl = "https://accounts.spotify.com/api/token"; // Spotify Web API URL
const client_id = '467fab359c114e719ecefafd6af299e5'; // Client id
const client_secret = 'your_client_secret' // temp client secret
// const client_secret = process.env.CLIENT_SECRET;
const redirect_uri = 'http://localhost:3030/callback/'; // Callback URL

let AT, RT; // Stores access and refresh tokens
const scope = [
  'user-read-private',
  'user-read-email',
  'user-library-read',
  'playlist-read-private',
  'playlist-modify-public',
  'playlist-modify-private'
];


/**
 * Generates a random string containing numbers and letters
 * @param  {number} length The length of the string
 * @return {string} The generated string
 */
let generateRandomString = function (length) {
  let text = '';
  let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

  for (let i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
};

let stateKey = 'spotify_auth_state';


const authorizeSpotify = () => {
  return new Promise((resolve, reject) => {
    app.get('/', function (req, res) {
      res.sendFile(__dirname + "/index.html");
      res.redirect('/login');
    });
    
    app.use(Express.static(__dirname + '/index.html'))
      .use(cors())
      .use(cookieParser());
    
    app.get('/login', function (req, res) {
    
      let state = generateRandomString(16);
      res.cookie(stateKey, state);
    
      //  app requests authorization
      res.redirect('https://accounts.spotify.com/authorize?' +
        querystring.stringify({
          response_type: 'code',
          client_id: client_id,
          scope: scope,
          redirect_uri: redirect_uri,
          state: state
        }));
    });
    
    app.get('/callback', function (req, res) {
    
      // app requests refresh and access tokens
      // after checking the state parameter
    
      let code = req.query.code || null;
      let state = req.query.state || null;
      let storedState = req.cookies ? req.cookies[stateKey] : null;
    
       console.log(state);
       console.log(storedState);
    
      if (state === null || state !== storedState) {
        res.redirect('/#' +
          querystring.stringify({
            error: 'state_mismatch'
          }));
      } else {
        res.clearCookie(stateKey);
        let authOptions = {
          url: 'https://accounts.spotify.com/api/token',
          form: {
            code: code,
            redirect_uri: redirect_uri,
            grant_type: 'authorization_code'
          },
          headers: {
            'Authorization': 'Basic ' + (Buffer.from(client_id + ':' + client_secret).toString('base64'))
          },
          json: true
        };
    
    
        request.post(authOptions, function (error, response, body) {
          if (!error && response.statusCode === 200) {
    
            console.log(body);
    
            AT = body.access_token;
            RT = body.refresh_token;
    
            let options = {
              url: 'https://api.spotify.com/v1/me',
              headers: { 'Authorization': 'Bearer ' + AT },
              json: true
            };
    
            interval = setInterval(requestToken, body.expires_in * 1000 * 0.70);
    
            previousExpires = body.expires_in;
    
            res.send("Logged in!");
          }
        });
      }
    });
    
    
    
    let interval;
    let previousExpires = 0;
    
    const requestToken = () => {
    
      const authOptions = {
        url: 'https://accounts.spotify.com/api/token',
        headers: { 'Authorization': 'Basic ' + (Buffer.from(client_id + ':' + client_secret).toString('base64')) },
        form: {
          grant_type: 'refresh_token',
          refresh_token: RT
        },
        json: true
      };
    
      request.post(authOptions, function (error, response, body) {
        if (error || response.statusCode !== 200) {
          console.error(error);
          return;
        }
    
        AT = body.access_token;
    
        if (body.refresh_token) {
          RT = body.refresh_token;
        }
    
        console.log("Access Token refreshed!");
    
        if (previousExpires != body.expires_in) {
    
          clearInterval(interval);
    
          interval = setInterval(requestToken, body.expires_in * 1000 * 0.70);
    
          previousExpires = body.expires_in;
        }
      });
    }
    resolve({AT, RT});
  });
};



// Write code for app here
// Function to get the user's library tracks
const getUserLibraryTracks = (AT) => {
  return new Promise((resolve, reject) => {
    const options = {
      url: 'https://api.spotify.com/v1/me/tracks',
      headers: { 'Authorization': 'Bearer ' + AT },
      json: true
    };

    request.get(options, (error, response, body) => {
      if (error || response.statusCode !== 200) {
        console.log('Response:', body);
        reject(error || new Error('Failed to get user library tracks'));
      } else {
        resolve(body.items.map(item => item.track));
      }
    });
  });
};

// Function to get the tracks in a playlist
const getPlaylistTracks = (AT, playlistId) => {
  return new Promise((resolve, reject) => {
    const options = {
      url: `https://api.spotify.com/v1/playlists/${playlistId}/tracks`,
      headers: { 'Authorization': 'Bearer ' + AT },
      json: true
    };

    request.get(options, (error, response, body) => {
      if (error || response.statusCode !== 200) {
        reject(error || new Error('Failed to get playlist tracks'));
      } else {
        resolve(body.items.map(item => item.track));
      }
    });
  });
};

// Function to add tracks to a playlist
const addTracksToPlaylist = (AT, playlistId, trackIds) => {
  return new Promise((resolve, reject) => {
    const options = {
      url: `https://api.spotify.com/v1/playlists/${playlistId}/tracks`,
      headers: { 'Authorization': 'Bearer ' + AT },
      json: true,
      body: { uris: trackIds }
    };

    request.post(options, (error, response, body) => {
      if (error || response.statusCode !== 201) {
        reject(error || new Error('Failed to add tracks to playlist'));
      } else {
        resolve();
      }
    });
  });
};

// Function to update the playlist with new tracks
const updatePlaylist = async (playlistId) => {
  
  try {
    const {AT, RT } = await authorizeSpotify();
    const libraryTracks = await getUserLibraryTracks(AT);
    const playlistTracks = await getPlaylistTracks(AT, playlistId);

    const trackIdsToAdd = libraryTracks
      .filter(track => !playlistTracks.some(playlistTrack => playlistTrack.id === track.id))
      .map(track => track.uri);

    await addTracksToPlaylist(AT, playlistId, trackIdsToAdd);

    console.log('Playlist updated successfully');
  } catch (error) {
    console.error('Failed to update playlist:', error);
  }
};

// Call the updatePlaylist function to update the playlist
updatePlaylist('your_playlist_id');

app.listen(port, () => console.log(`Listening on port: ${port}`));

Running the code, I keep receiving this message:

[nodemon] starting `node autoadd.js`
Listening on port: 3030
Response: { error: { status: 401, message: 'Invalid access token' } }
Failed to update playlist: Error: Failed to get user library tracks
    at Request._callback (file:///home/nero/Projects/Autoadd/autoadd.js:195:25)
    at Request.self.callback (/home/nero/Projects/Autoadd/node_modules/request/request.js:185:22)
    at Request.emit (events.js:314:20)
    at Request.<anonymous> (/home/nero/Projects/Autoadd/node_modules/request/request.js:1154:10)
    at Request.emit (events.js:314:20)
    at IncomingMessage.<anonymous> (/home/nero/Projects/Autoadd/node_modules/request/request.js:1076:12)
    at Object.onceWrapper (events.js:420:28)
    at IncomingMessage.emit (events.js:326:22)
    at endReadableNT (_stream_readable.js:1241:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)

Of course, after running the code, I browse to the localhost:3030 address and it logs in successfully with my account. The console logging this:

{
  access_token: 'BQBC1CAN2Wv3PIR1XdwTuQwgrHjQ1eCgQJqAZ0PWBNAiHGk6OKqsJFeafJEqBXBWfg1qpOvVxfEJ4SF77OHgxn9OvxS8Lg9Na0NSFlz1iWR26xztSJEq4Or-hwUKB2yE_Y-X6yPvzaScar7HDFADSQtVMxOx1Z8wq3hbi498i0bGTTnYccFTijopoSxbwfKvbfMTRxNrdUJt0z8u_w',
  token_type: 'Bearer',
  expires_in: 3600,
  refresh_token: 'AQC3bMXEM23qjQqOOXrC5Tcsvt6ijfp2umMyz466u1DCi9nNN2J9jsU0Q4ilYq2cu19xA80fhrljQSutWrFGyBzOUV3i1mytO4UBEjbbKOHuKXFXwEYV83Rxzo-7ic_-YFA',
  scope: 'playlist-modify-private'
}
Lazlo
  • 159
  • 1
  • 7

1 Answers1

1

My understanding is you want to get my tracks and adding into the playlist except for duplicated(already existing) songs.

Flow Overview enter image description here

Using express for REST server, axios for Spotify REST POST call.

Using Authorization Code Flow for getting access token

Spotify API calls

Get Playlist Items

GET /playlists/{playlist_id}/tracks

enter image description here

Get User's Saved Tracks

GET /me/tracks

enter image description here

Add Items to Playlist

POST /playlists/{playlist_id}/tracks

Demo code

Save as update_songs.js

const express = require("express")
const axios = require('axios')
const cors = require("cors");

const app = express()
app.use(cors())

CLIENT_ID = "<your client ID>"
CLIENT_SECRET = "<your client secret>"
PORT = 3030 // it is located in Spotify dashboard's Redirect URIs, my port is 3000
REDIRECT_URI = `http://localhost:${PORT}/callback` // my case is 'http://localhost:3000/callback'
PLAYLIST_ID = 'your playlist ID'
SCOPE = [
    'user-read-private',
    'user-read-email',
    'user-library-read',
    'playlist-read-private',
    'playlist-modify-public',
    'playlist-modify-private'
]

const getToken = async (code) => {
    try {
        const resp = await axios.post(
            url = 'https://accounts.spotify.com/api/token',
            data = new URLSearchParams({
                'grant_type': 'authorization_code',
                'redirect_uri': REDIRECT_URI,
                'code': code
            }),
            config = {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                auth: {
                    username: CLIENT_ID,
                    password: CLIENT_SECRET
                }
            })
        return Promise.resolve(resp.data.access_token);
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const addSongs = async (playlist_id, tracks, token) => {
    try {
        const uris = []
        for(const track of tracks) {
            if (track.new) {
                uris.push(track.uri)
            }
        }

        const chunkSize = 100;
        for (let i = 0; i < uris.length; i += chunkSize) {
            const sub_uris = uris.slice(i, i + chunkSize);
            const resp = await axios.post(
                url = `https://api.spotify.com/v1/playlists/${playlist_id}/tracks`,
                data = {
                    'uris': sub_uris
                },
                config = {
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${token}`,
                    }
                })
            }
        return Promise.resolve('OK');
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const getPlaylistTracks = async (playlist, token) => {
    try {
        let next = 1
        const tracks = []
        url = `https://api.spotify.com/v1/playlists/${playlist}`
        while (next != null) {
            const resp = await axios.get(
                url,
                config = {
                    headers: {
                        'Accept-Encoding': 'application/json',
                        'Authorization': `Bearer ${token}`,
                    }
                }
            )
            items =  []
            if (resp.data.items) {
                items = resp.data.items
            } else if (resp.data.tracks.items) {
                items = resp.data.tracks.items
            }
            for(const item of items) {
                if (item.track?.name != null) {
                    tracks.push({
                        name: item.track.name,
                        external_urls: item.track.external_urls.spotify,
                        uri: item.track.uri,
                        new: false
                    })
                }
            }
            if (resp.data.items) {
                url = resp.data.next
            } else if (resp.data.tracks.items) {
                url = resp.data.tracks.next
            } else {
                break
            }
            next = url
        }
        return Promise.resolve(tracks)
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const update_track = (arr, track) => {
    const { length } = arr;
    const id = length + 1;
    const found = arr.some(el => el.external_urls === track.external_urls);
    if (!found) {
        arr.push({ name : track.name, external_urls: track.external_urls, uri: track.uri, new: true })
    };
    return arr;
}

const updatePlaylistTracks = async (my_tracks, previous_tracks, token) => {
    try {
        new_tracks = previous_tracks.map(a => Object.assign({}, a));
        // update new playlist with my_tracks and previous_tracks
        for(const track of my_tracks) {
            new_tracks = update_track(new_tracks, track)
        }
        return Promise.resolve(new_tracks)
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const getMyTracks = async (token) => {
    try {
        let offset = 0
        let next = 1
        const limit = 50;
        const tracks = [];
        while (next != null) {
            const resp = await axios.get(
                url = `https://api.spotify.com/v1/me/tracks/?limit=${limit}&offset=${offset}`,
                config = {
                    headers: {
                        'Accept-Encoding': 'application/json',
                        'Authorization': `Bearer ${token}`,
                    }
                }
            );
            for(const item of resp.data.items) {
                if(item.track?.name != null) {
                    tracks.push({
                        name: item.track.name,
                        external_urls: item.track.external_urls.spotify,
                        uri: item.track.uri,
                        new: false,
                        added_at: item.added_at
                    })
                }
            }
            offset = offset + limit
            next = resp.data.next
        }
        return Promise.resolve(tracks)
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

app.get("/login", (request, response) => {
    const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${SCOPE}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
    response.redirect(redirect_url);
})

app.get("/callback", async (request, response) => {
    const code = request.query["code"]
    getToken(code)
        .then(access_token => {
            getMyTracks(access_token)
                .then(my_tracks => {
                    getPlaylistTracks(PLAY_LIST_ID, access_token)
                        .then(previous_tracks => {
                            updatePlaylistTracks(my_tracks, previous_tracks, access_token)
                                .then(new_tracks => {
                                    addSongs(PLAY_LIST_ID, new_tracks, access_token)
                                        .then(OK => {
                                            return response.send({ 
                                                'my tracks Total:': my_tracks.length,
                                                'my tracks': my_tracks,
                                                'previous playlist Total:': previous_tracks.length,
                                                'previous playlist': previous_tracks,
                                                'new playlist Total:': new_tracks.length,
                                                'new playlist': new_tracks,
                                                'add song result': OK });
                                        })
                                })
                        })
                })
        })
        .catch(error => {
            console.log(error.message);
        })
})

app.listen(PORT, () => {
    console.log(`Listening on :${PORT}`)
})

Install dependencies

npm install express axios cors

Run it

From terminal

node update_songs.js

By browser

http://locahost:3030/login

Result

From Browser

My library list songs: total 837 songs

enter image description here

Previous Playlist songs: total 771 songs

Before adding songs (previous playlist songs)

enter image description here

enter image description here After adding songs: total 1,591 songs

enter image description here

enter image description here

Update for checking new songs

For checking if any new songs are in my library, can see when it added_at

You need to add one line of code into getMyTracks()

                tracks.push({
                    name: item.track.name,
                    external_urls: item.track.external_urls.spotify,
                    uri: item.track.uri,
                    new: false,
                    added_at: item.added_at
                })

Update V3 for my tracks only

Step By Step, this code can get my library songs.

const express = require("express")
const axios = require('axios')
const cors = require("cors");

const app = express()
app.use(cors())

CLIENT_ID = "<your client ID>"
CLIENT_SECRET = "<your client secret>"
PORT = 3030 // it is located in Spotify dashboard's Redirect URIs
REDIRECT_URI = `http://localhost:${PORT}/callback` // my case is 'http://localhost:3000/callback'
SCOPE = [
    'user-read-private',
    'user-read-email',
    'user-library-read',
    'playlist-read-private',
    'playlist-modify-public',
    'playlist-modify-private'
]

app.get("/login", (request, response) => {
    const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${SCOPE}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
    response.redirect(redirect_url);
})

const getToken = async (code) => {
    try {
        const resp = await axios.post(
            'https://accounts.spotify.com/api/token',
            new URLSearchParams({
                'grant_type': 'authorization_code',
                'redirect_uri': REDIRECT_URI,
                'code': code
            }),
            {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                auth: {
                    username: CLIENT_ID,
                    password: CLIENT_SECRET
                }
            })
        return Promise.resolve(resp.data.access_token);
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const getMyTracks = async (token) => {
    try {
        let offset = 0
        let next = 1
        const limit = 50;
        const tracks = [];
        while (next != null) {
            const resp = await axios.get(
                url = `https://api.spotify.com/v1/me/tracks/?limit=${limit}&offset=${offset}`,
                config = {
                    headers: {
                        'Accept-Encoding': 'application/json',
                        'Authorization': `Bearer ${token}`,
                    }
                }
            );
            for(const item of resp.data.items) {
                if(item.track?.name != null) {
                    tracks.push({
                        name: item.track.name,
                        external_urls: item.track.external_urls.spotify,
                        uri: item.track.uri,
                        new: false,
                        added_at: item.added_at
                    })
                }
            }
            offset = offset + limit
            next = resp.data.next
        }
        return Promise.resolve(tracks)
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
};
app.get("/callback", async (request, response) => {
    const code = request.query["code"]
    getToken(code)
        .then(access_token => {
            getMyTracks(access_token)
                .then(my_tracks => {
                    return response.send({ 
                        'total:' : my_tracks.length,
                        'my tracks': my_tracks
                    });
                })
        })
        .catch(error => {
            console.log(error.message);
        })
    })

app.listen(PORT, () => {
    console.log(`Listening on :${PORT}`)
})

Update V3 for plylist only

Step By Step, this code can get playlist songs.

const express = require("express")
const axios = require('axios')
const cors = require("cors");

const app = express()
app.use(cors())

CLIENT_ID = "<your client ID>"
CLIENT_SECRET = "<your client secret>"
PORT = 3030 // it is located in Spotify dashboard's Redirect URIs
REDIRECT_URI = `http://localhost:${PORT}/callback` // my case is 'http://localhost:3000/callback'
PLAYLIST_ID = 'your playlist ID'
SCOPE = [
    'user-read-private',
    'user-read-email',
    'user-library-read',
    'playlist-read-private',
    'playlist-modify-public',
    'playlist-modify-private'
]

app.get("/login", (request, response) => {
    const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${SCOPE}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
    response.redirect(redirect_url);
})

const getToken = async (code) => {
    try {
        const resp = await axios.post(
            'https://accounts.spotify.com/api/token',
            new URLSearchParams({
                'grant_type': 'authorization_code',
                'redirect_uri': REDIRECT_URI,
                'code': code
            }),
            {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                auth: {
                    username: CLIENT_ID,
                    password: CLIENT_SECRET
                }
            })
        return Promise.resolve(resp.data.access_token);
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}

const getPlaylistTracks = async (playlist, token) => {
    try {
        let next = 1
        const tracks = []
        url = `https://api.spotify.com/v1/playlists/${playlist}`
        while (next != null) {
            const resp = await axios.get(
                url,
                config = {
                    headers: {
                        'Accept-Encoding': 'application/json',
                        'Authorization': `Bearer ${token}`,
                    }
                }
            )
            items =  []
            if (resp.data.items) {
                items = resp.data.items
            } else if (resp.data.tracks.items) {
                items = resp.data.tracks.items
            }
            for(const item of items) {
                if (item.track?.name != null) {
                    tracks.push({
                        name: item.track.name,
                        external_urls: item.track.external_urls.spotify,
                        uri: item.track.uri,
                        new: false
                    })
                }
            }
            if (resp.data.items) {
                url = resp.data.next
            } else if (resp.data.tracks.items) {
                url = resp.data.tracks.next
            } else {
                break
            }
            next = url
        }
        return Promise.resolve(tracks)
    } catch (err) {
        console.error(err)
        return Promise.reject(err)
    }
}
app.get("/callback", async (request, response) => {
    const code = request.query["code"]
    getToken(code)
        .then(access_token => {
            getPlaylistTracks(PLAYLIST_ID, access_token)
                .then(tracks => {
                    return response.send({ 
                        'total:' : tracks.length,
                        'playlist tracks': tracks
                    });
                })
        })
        .catch(error => {
            console.log(error.message);
        })
    })

app.listen(PORT, () => {
    console.log(`Listening on :${PORT}`)
})
Bench Vue
  • 5,257
  • 2
  • 10
  • 14
  • I...how did you...you just made the whole thing? That's impressive. I'll need a bit to go through it though, I still don't quite know how my code was failing such that it would directly hit the app code as opposed to the authorisation flow. Feel a bit silly not being able to do this now, maybe I've misunderstood awaits or the requests library isn't good at it. – Lazlo Jul 05 '23 at 04:16
  • I did whole things. it took more than 3 hours. The ChatGPT pretty good job for all areas but she can't do this kind of complicated steps and fine turning. Also without knowledge of Spotify APIs can't judge the ChatGPT's code. I used Spotify API one and a half years. The Spotify API is one of my favorite API. Good doc, wide examples, easy to test. This question is the most complicated step among my answers. The request or axios is not issue. Just My favorite HTTP call library is axios. You needs to learn async/await, express, Authorization Code Flow and Spotify API. let me know your progress. – Bench Vue Jul 05 '23 at 10:10
  • Working on it but is there any way to have it periodically check if any new songs are in the library without me needing to authorise each time or something? I'm looking to host this in Vercel so it can simply work in the background whenever I add a new song to the library. – Lazlo Jul 06 '23 at 03:26
  • Yes, you can check when it's song was added. it can check new songs or old sold by referencing your time. I updated my answer. – Bench Vue Jul 06 '23 at 03:47
  • I think I've got most of the code working and I made it until the authorise screen but upon clicking the button, it keeps loading and the console tells me that `url` isn't defined at `getToken`. – Lazlo Jul 10 '23 at 13:04
  • 1
    Can you check `axios` version by `npm list`. It should be `1.4.0`. If not that version, try `npm uninstall axios` then `npm install axios`. The `url` defined a parameter in POST() mathod in [here](https://axios-http.com/docs/api_intro) – Bench Vue Jul 10 '23 at 13:39
  • Yes, it's `axios` version `1.4.0`. Just in case, I tried to uninstall and reinstall it but still got the same error. I'm running npm version `9.5.1` if that matters at all. – Lazlo Jul 11 '23 at 16:05
  • npm version OK. what is your redirect URL, can you check develop dashboard like [this](https://stackoverflow.com/questions/76559444/issue-im-trying-to-pause-spotify-playing-using-a-python-script/76560961#76560961) - what is red circle #3 value? – Bench Vue Jul 11 '23 at 16:27
  • It's `http://localhost:3030/callback/`. The callback http call is written as `/callback/` in my app, similar to yours but I obviously just changed it to suit the one in my dashboard. – Lazlo Jul 11 '23 at 16:46
  • OK, it seems should be no problem. Are you still `url` issue in get token? – Bench Vue Jul 11 '23 at 16:50
  • This is simple code get token, can you try [this](https://stackoverflow.com/questions/76624085/new-method-required-for-adding-tracks-to-a-spotify-playlist-from-windows-comman/76645760#76645760). it will show access token in browser. – Bench Vue Jul 11 '23 at 16:53
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254444/discussion-between-lazlo-and-bench-vue). – Lazlo Jul 11 '23 at 16:54
  • I come back, can you join again upper chat? – Bench Vue Jul 11 '23 at 18:50
  • @Lazlo, OK, you can get a token, I added an update v2. It it the next step, only displaying my tracks with songs. Can you try it and let me know the result? – Bench Vue Jul 11 '23 at 23:24
  • Fell asleep, my bad. Will do it today and let you know. – Lazlo Jul 12 '23 at 03:11
  • Up to you, I will wake up next one hour. – Bench Vue Jul 12 '23 at 03:13
  • Hello, wanted to mention that I tried and made sure the redirect URIs were correct. It does return all my spotify library tracks successfully. – Lazlo Jul 19 '23 at 13:21
  • Good Job what is next target? – Bench Vue Jul 19 '23 at 13:46
  • Well, the original goal hasn't changed. I still need to check to see if those tracks are in the playlist that I specify and update the playlist if there are any new tracks in my library with those new tracks. – Lazlo Jul 19 '23 at 13:56
  • OK, you left 3 steps, #1 getPlaylistTracks(), #2 updatePlaylistTracks() and #3 addSongs(), let me know any progress. – Bench Vue Jul 19 '23 at 14:06
  • `getPlaylistTracks()` works and returns everything fine as well. It is odd though that both `getPlaylistTracks()` returns only 99 songs and `getMyTracks()` returns only 19 tracks even though both have far more songs than that. updatePlaylistTracks() uses update_track as well, so added that in but the "new_playlist" doesn't contain all of the songs from both my library and playlist (just the ones added). Also id from `update_track` is never used so I'm not sure where to use it. Haven't done `addSongs()` yet because I'd like to solve this issue first. – Lazlo Jul 21 '23 at 16:52
  • @Lazlo, I updated getPlaylistTracks() and getMyTracks() for more songs in first `update_songs.js` file, let me know the result. – Bench Vue Jul 21 '23 at 17:41
  • 404 error: https://pastebin.com/0jKmHk6K – Lazlo Jul 22 '23 at 04:44
  • Wrong URL get me API. You need to change from `https://api.spotify.com/v1/me/tracks'tracks/?limit=50&offset=0` to `https://api.spotify.com/v1/me/tracks/?limit=50&offset=0` – Bench Vue Jul 22 '23 at 10:55
  • url = `https://api.spotify.com/v1/me/tracks/?limit=${limit}&offset=${offset}` – Bench Vue Jul 22 '23 at 11:19
  • Interesting. So it's definitely reading all my library's tracks now (it's around 500 or so) but still stuck at the same number of tracks (99) for my playlist. – Lazlo Jul 23 '23 at 12:25
  • Did you use `while (next != null)` in getMyTracks()? and You did you wrong URL? – Bench Vue Jul 23 '23 at 20:05
  • If you not premium user, it may be limit to get songs number. Are you premium user? – Bench Vue Jul 24 '23 at 18:30
  • I did do `while (next != null)` in that function and I am a premium user. I checked and the URLs are `https://api.spotify.com/v1/me/tracks/?limit=${limit}&offset=${offset}` and `https://api.spotify.com/v1/playlists/${playlist}/?offset=${offset}&limit=${limit}` which should be correct. – Lazlo Jul 27 '23 at 11:36
  • 1
    Can you try tst get all playlist song from this [answer](https://stackoverflow.com/questions/75619250/python-spotify-api-unable-to-get-full-playlist-with-get-playlist-items-metho/75630754#75630754)? – Bench Vue Jul 27 '23 at 12:13
  • Working with that function, I keep running into an issue where newResponse is not defined. I think it's because it's not returning as an array for some reason (I set it as null instead of none because I'm using JS). Maybe I'm doing it wrong. Here's the code: https://pastebin.com/NzAaxMmx – Lazlo Jul 27 '23 at 14:01
  • 1
    I can't test now, I can test return home tonight. Can you vote me that [answer](https://stackoverflow.com/questions/75619250/python-spotify-api-unable-to-get-full-playlist-with-get-playlist-items-metho/75630754#75630754)? – Bench Vue Jul 27 '23 at 14:05
  • No worries, still appreciate the help. Take your time, I've already upvoted it. – Lazlo Jul 27 '23 at 14:56
  • 1
    @Lazlo, I updated all source code. It will work. My previous get playlist did not work. Now fixed it. And I tested my tracks (837 songs), playlist (771 songs). Also I added V3 two sources, one for only my track test , the second for only the playlist test. Can you test both code separately before run demo code. If you run demo code, the playlist will increase more number of song. Let me know test result and vote/accept my answer. – Bench Vue Jul 28 '23 at 02:45
  • It finally works! Thank you so much, genuinely appreciate it. It's been a long time since I was able to get this project working. Could you tell me how you figured it out? Hopefully, I can port this over to Vercel and it should automatically check my library whenever there's a new song in it and then update my playlist. – Lazlo Jul 29 '23 at 15:43
  • 1
    I am happy to hear you got it and thanks for your keep working a long time (25 days?) focus this question. I am learning a lot too from your question. I spend a lot of time to learn about Spotify from stack overflow Q/A no other secret weapon. I have no experience Vercel, good luck to convert it. – Bench Vue Jul 29 '23 at 15:48