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;
以上是我的spotify.js 代码。我正在尝试创建一个 Web 应用程序,它接受 YouTube 链接,然后识别视频中的歌曲并使用所有 Spotify 链接创建 Spotify 播放列表。目前,我能够获取列表中的所有 Spotify 链接,但是当我将所有这些信息发送到 spotify.js 时,我收到创建播放列表的错误。我尝试查看日志并使用聊天 gpt,但无法找出错误。这应该创建播放列表并向其中添加歌曲。我已经创建了一个函数来格式化链接,所以我认为这不应该是一个问题。我可以获得一些帮助来找出潜在的错误吗?以下是用于创建播放列表的 Spotify Web API 的链接:https://developer.spotify.com/documentation/web-api/reference/create-playlist。
您可以使用
req.app.set
和 req.app.get
而不是将令牌值存储在全局范围内
此外,通过在
req.app
中存储值,可以使用 req.app.get
在任何控制器中访问
let spotifyAccessToken = ''; // Dynamically set by app.js ❌
let spotifyRefreshToken = ''; ❌
在中间件中
router.use(async (req, res, next) => {
if(!req.app.get('spotifyAccessToken')){
await refreshAccessToken(req);
}
next();
});
在控制器中
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);
}
}
这个方法很高效,因为我们不能在commonjs中使用全局await。