0
const express = require('express');
const axios = require('axios');
const querystring = require('querystring');
const router = express.Router();
require('dotenv').config();

const client_id = process.env.SPOTIFY_CLIENT_ID;
const client_secret = process.env.SPOTIFY_CLIENT_SECRET;
const userId = process.env.SPOTIFY_USER_ID;

let spotifyAccessToken = ''; // Dynamically set by app.js
let spotifyRefreshToken = ''; // Dynamically set by app.js

async function refreshAccessToken() {
    const authOptions = {
        url: 'https://accounts.spotify.com/api/token',
        form: {
            grant_type: 'refresh_token',
            refresh_token: spotifyRefreshToken
        },
        headers: {
            'Authorization': 'Basic ' + Buffer.from(client_id + ':' + client_secret).toString('base64')
        }
    };

    try {
        const response = await axios.post(authOptions.url, querystring.stringify(authOptions.form), {
            headers: authOptions.headers,
        });

        spotifyAccessToken = response.data.access_token;
        console.log('New Access Token:', spotifyAccessToken);
    } catch (error) {
        console.error('Error refreshing access token:', error);
    }
}

// Middleware to refresh the token if needed
router.use(async (req, res, next) => {
    if (!spotifyAccessToken) {
        await refreshAccessToken();
    }
    next();
});

// Function to convert Spotify track URLs to URIs
function convertUrlsToUris(urls) {
    return urls.map(url => {
        const match = url.match(/track\/([^?\/]+)$/);
        if (match) {
            return `spotify:track:${match[1]}`;
        }
        throw new Error(`Invalid URL format: ${url}`);
    });
}

router.post('/create-playlist', async (req, res) => {
    const { spotifyLinks, youtubeLink, videoTitle } = req.body;
    const playlistName = videoTitle;

    try {
        // Create a new playlist
        const createPlaylistResponse = await axios.post(
            `https://api.spotify.com/v1/users/${userId}/playlists`,
            {
                name: playlistName,
                description: 'Playlist created from YouTube video',
                public: false
            },
            {
                headers: {
                    'Authorization': `Bearer ${spotifyAccessToken}`,
                    'Content-Type': 'application/json'
                }
            }
        );

        const playlistId = createPlaylistResponse.data.id;
        console.log('Created Playlist ID:', playlistId);

        // Convert track URLs to URIs
        const trackUris = convertUrlsToUris(spotifyLinks);

        // Add tracks to the playlist
        if (trackUris && trackUris.length > 0) {
            const addTracksResponse = await axios.post(
                `https://api.spotify.com/v1/playlists/${playlistId}/tracks`,
                {
                    uris: trackUris
                },
                {
                    headers: {
                        'Authorization': `Bearer ${spotifyAccessToken}`,
                        'Content-Type': 'application/json'
                    }
                }
            );
            console.log('Tracks added to Playlist:', addTracksResponse.data);
        }

        res.json({ message: 'Playlist created successfully', playlistId });
    } catch (error) {
        console.error('Error creating playlist:', error.response ? error.response.data : error.message);
        res.status(500).json({ error: error.response ? error.response.data : 'Error creating playlist' });
    }
});

module.exports = router;

The above is my code for spotify.js. I'm trying to create a web application that takes in a youtube link and then recognizes the songs in the video and create a spotify playlist using all the spotify links. Currently I am able to get all the spotify links in a list but when I send all of that information to the spotify.js, I get an error for creating playlist. I tried looking at the logs and using chat gpt but was not able to figure out the error. This is supposed to create the playlist and add songs to it. I've made a function to format the links so I don't think that should be a problem. Can I get some help to figure out the potential error. Here is a link to spotify web API to create playlists: https://developer.spotify.com/documentation/web-api/reference/create-playlist.

1 Answer 1

0

You can use req.app.set and req.app.get instead of storing the token value in a global scope

Also by storing values in req.app can be accessed in any controller using req.app.get

let spotifyAccessToken = ''; // Dynamically set by app.js ❌
let spotifyRefreshToken = ''; ❌

In middleware

router.use(async (req, res, next) => {
    if(!req.app.get('spotifyAccessToken')){
        await refreshAccessToken(req);
    }
    next();
});

In controller

async function refreshAccessToken(req) {
    const authOptions = {
        url: 'https://accounts.spotify.com/api/token',
        form: {
            grant_type: 'refresh_token',
            refresh_token: spotifyRefreshToken
        },
        headers: {
            'Authorization': 'Basic ' + Buffer.from(client_id + ':' + client_secret).toString('base64')
        }
    };

    try {
        const response = await axios.post(authOptions.url, querystring.stringify(authOptions.form), {
            headers: authOptions.headers,
        });

        const spotifyAccessToken = response.data.access_token;

        req.app.set('spotifyAccessToken',spotifyAccessToken); // here is the magic ✅

        console.log('New Access Token:', spotifyAccessToken);
    } catch (error) {
        console.error('Error refreshing access token:', error);
    }
}

This method is efficient since we cannot use global await in commonjs.

1
  • Yeah I think that was the problem. Thank you. I actually figured before your answer
    – Whichman
    Commented Aug 13, 2024 at 3:22

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.