Kyouka commited on
Commit
af33dcf
·
verified ·
1 Parent(s): be24b2f

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +148 -12
index.js CHANGED
@@ -6,6 +6,7 @@ const bytes = require('bytes')
6
  const sharp = require('sharp')
7
  const morgan = require('morgan')
8
  const express = require('express')
 
9
  const cp = require('child_process')
10
  const PDFDocument = require('pdfkit')
11
  const playwright = require('playwright-extra')
@@ -49,6 +50,14 @@ function getFrontendUri(req) {
49
  return `https://${req.get('host')}`;
50
  }
51
 
 
 
 
 
 
 
 
 
52
  app.use('/file', express.static(tmpFolder))
53
 
54
  app.all('/', (req, res) => {
@@ -102,7 +111,13 @@ app.get('/spotify', (req, res) => {
102
  const FRONTEND_URI = getFrontendUri(req);
103
  const REDIRECT_URI = `${FRONTEND_URI}/callback`;
104
 
105
- const scopes = ['user-read-recently-played'];
 
 
 
 
 
 
106
  const queryParams = querystring.stringify({
107
  response_type: 'code',
108
  client_id: CLIENT_ID,
@@ -127,7 +142,7 @@ app.get('/callback', async (req, res) => {
127
  }
128
 
129
  try {
130
- // Dapatkan tokens
131
  const authResponse = await axios.post('https://accounts.spotify.com/api/token',
132
  querystring.stringify({
133
  grant_type: 'authorization_code',
@@ -142,7 +157,10 @@ app.get('/callback', async (req, res) => {
142
 
143
  const { access_token, refresh_token, expires_in } = authResponse.data;
144
 
145
- // Simpan tokens di cookie
 
 
 
146
  res.cookie('spotify_access', access_token, {
147
  httpOnly: true,
148
  secure: process.env.NODE_ENV === 'production',
@@ -153,29 +171,44 @@ app.get('/callback', async (req, res) => {
153
  httpOnly: true,
154
  secure: process.env.NODE_ENV === 'production'
155
  });
 
 
 
 
 
 
 
 
156
 
157
- // Redirect ke endpoint JSON
158
- res.redirect(`${FRONTEND_URI}/api/recently-played/json`);
159
  } catch (err) {
160
  console.error('Callback Error:', err);
161
  res.redirect(`${FRONTEND_URI}/error?message=${encodeURIComponent('Authentication failed')}`);
162
  }
163
  });
164
 
165
- // 3. Recently Played JSON endpoint
166
  app.get('/api/recently-played/json', async (req, res) => {
167
  const FRONTEND_URI = getFrontendUri(req);
168
  const accessToken = req.cookies.spotify_access;
 
169
 
170
- if (!accessToken) {
171
  return res.redirect('/');
172
  }
173
 
174
  try {
175
- // Get recently played tracks
176
  const limit = parseInt(req.query.limit) || 20;
 
 
 
 
 
 
 
177
  const response = await axios.get('https://api.spotify.com/v1/me/player/recently-played', {
178
- params: { limit },
179
  headers: { 'Authorization': `Bearer ${accessToken}` },
180
  });
181
 
@@ -198,16 +231,18 @@ app.get('/api/recently-played/json', async (req, res) => {
198
 
199
  res.json({
200
  status: 'success',
 
 
 
 
 
201
  data: tracks,
202
  count: tracks.length
203
  });
204
  } catch (error) {
205
  if (error.response?.status === 401) {
206
- // Token expired, redirect ke login
207
  return res.redirect('/');
208
  }
209
-
210
- console.error('Recently Played Error:', error);
211
  res.status(500).json({
212
  error: 'Failed to fetch recently played tracks',
213
  details: error.response?.data || error.message
@@ -215,6 +250,107 @@ app.get('/api/recently-played/json', async (req, res) => {
215
  }
216
  });
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  // Error handler
219
  app.use((err, req, res, next) => {
220
  console.error('Server Error:', err);
 
6
  const sharp = require('sharp')
7
  const morgan = require('morgan')
8
  const express = require('express')
9
+ const { Buffer } = require('buffer');
10
  const cp = require('child_process')
11
  const PDFDocument = require('pdfkit')
12
  const playwright = require('playwright-extra')
 
50
  return `https://${req.get('host')}`;
51
  }
52
 
53
+ async function getUserData(accessToken) {
54
+ const response = await axios.get('https://api.spotify.com/v1/me', {
55
+ headers: { 'Authorization': `Bearer ${accessToken}` }
56
+ });
57
+ return response.data;
58
+ }
59
+
60
+
61
  app.use('/file', express.static(tmpFolder))
62
 
63
  app.all('/', (req, res) => {
 
111
  const FRONTEND_URI = getFrontendUri(req);
112
  const REDIRECT_URI = `${FRONTEND_URI}/callback`;
113
 
114
+ const scopes = [
115
+ 'user-read-recently-played',
116
+ 'user-read-playback-state',
117
+ 'user-read-private',
118
+ 'user-read-email'
119
+ ];
120
+
121
  const queryParams = querystring.stringify({
122
  response_type: 'code',
123
  client_id: CLIENT_ID,
 
142
  }
143
 
144
  try {
145
+ // Get tokens
146
  const authResponse = await axios.post('https://accounts.spotify.com/api/token',
147
  querystring.stringify({
148
  grant_type: 'authorization_code',
 
157
 
158
  const { access_token, refresh_token, expires_in } = authResponse.data;
159
 
160
+ // Get user data to store in session
161
+ const userData = await getUserData(access_token);
162
+
163
+ // Store tokens and user data in cookies
164
  res.cookie('spotify_access', access_token, {
165
  httpOnly: true,
166
  secure: process.env.NODE_ENV === 'production',
 
171
  httpOnly: true,
172
  secure: process.env.NODE_ENV === 'production'
173
  });
174
+
175
+ res.cookie('spotify_user', JSON.stringify({
176
+ id: userData.id,
177
+ country: userData.country,
178
+ display_name: userData.display_name
179
+ }), {
180
+ secure: process.env.NODE_ENV === 'production'
181
+ });
182
 
183
+ // Redirect to recently played with user ID
184
+ res.redirect(`${FRONTEND_URI}/api/recently-played/json?user=${userData.id}`);
185
  } catch (err) {
186
  console.error('Callback Error:', err);
187
  res.redirect(`${FRONTEND_URI}/error?message=${encodeURIComponent('Authentication failed')}`);
188
  }
189
  });
190
 
191
+ // 3. Recently Played JSON endpoint with market from user country
192
  app.get('/api/recently-played/json', async (req, res) => {
193
  const FRONTEND_URI = getFrontendUri(req);
194
  const accessToken = req.cookies.spotify_access;
195
+ const userData = req.cookies.spotify_user ? JSON.parse(req.cookies.spotify_user) : null;
196
 
197
+ if (!accessToken || !userData) {
198
  return res.redirect('/');
199
  }
200
 
201
  try {
 
202
  const limit = parseInt(req.query.limit) || 20;
203
+ const params = { limit };
204
+
205
+ // Add market parameter from user's country if available
206
+ if (userData.country) {
207
+ params.market = userData.country;
208
+ }
209
+
210
  const response = await axios.get('https://api.spotify.com/v1/me/player/recently-played', {
211
+ params,
212
  headers: { 'Authorization': `Bearer ${accessToken}` },
213
  });
214
 
 
231
 
232
  res.json({
233
  status: 'success',
234
+ user: {
235
+ id: userData.id,
236
+ display_name: userData.display_name,
237
+ country: userData.country
238
+ },
239
  data: tracks,
240
  count: tracks.length
241
  });
242
  } catch (error) {
243
  if (error.response?.status === 401) {
 
244
  return res.redirect('/');
245
  }
 
 
246
  res.status(500).json({
247
  error: 'Failed to fetch recently played tracks',
248
  details: error.response?.data || error.message
 
250
  }
251
  });
252
 
253
+ // 4. Current Playback State endpoint
254
+ app.get('/api/current-playback', async (req, res) => {
255
+ const accessToken = req.cookies.spotify_access;
256
+ const userData = req.cookies.spotify_user ? JSON.parse(req.cookies.spotify_user) : null;
257
+
258
+ if (!accessToken || !userData) {
259
+ return res.status(401).json({ error: 'Not authenticated' });
260
+ }
261
+
262
+ try {
263
+ const params = {};
264
+ if (userData.country) {
265
+ params.market = userData.country;
266
+ }
267
+
268
+ const response = await axios.get('https://api.spotify.com/v1/me/player', {
269
+ params,
270
+ headers: { 'Authorization': `Bearer ${accessToken}` },
271
+ });
272
+
273
+ if (response.status === 204) {
274
+ return res.json({ status: 'success', data: null, message: 'No active playback' });
275
+ }
276
+
277
+ const playbackData = {
278
+ device: response.data.device,
279
+ item: {
280
+ id: response.data.item.id,
281
+ name: response.data.item.name,
282
+ artists: response.data.item.artists.map(a => ({ id: a.id, name: a.name })),
283
+ album: {
284
+ id: response.data.item.album.id,
285
+ name: response.data.item.album.name,
286
+ images: response.data.item.album.images
287
+ },
288
+ duration_ms: response.data.item.duration_ms,
289
+ progress_ms: response.data.progress_ms
290
+ },
291
+ is_playing: response.data.is_playing,
292
+ shuffle_state: response.data.shuffle_state,
293
+ repeat_state: response.data.repeat_state
294
+ };
295
+
296
+ res.json({
297
+ status: 'success',
298
+ user: {
299
+ id: userData.id,
300
+ display_name: userData.display_name
301
+ },
302
+ data: playbackData
303
+ });
304
+ } catch (error) {
305
+ if (error.response?.status === 401) {
306
+ return res.status(401).json({ error: 'Session expired' });
307
+ }
308
+ res.status(500).json({
309
+ error: 'Failed to fetch playback state',
310
+ details: error.response?.data || error.message
311
+ });
312
+ }
313
+ });
314
+
315
+ // 5. User Profile endpoint
316
+ app.get('/api/user-profile', async (req, res) => {
317
+ const accessToken = req.cookies.spotify_access;
318
+ const userData = req.cookies.spotify_user ? JSON.parse(req.cookies.spotify_user) : null;
319
+
320
+ if (!accessToken || !userData) {
321
+ return res.status(401).json({ error: 'Not authenticated' });
322
+ }
323
+
324
+ try {
325
+ const response = await axios.get('https://api.spotify.com/v1/me', {
326
+ headers: { 'Authorization': `Bearer ${accessToken}` },
327
+ });
328
+
329
+ const profileData = {
330
+ id: response.data.id,
331
+ display_name: response.data.display_name,
332
+ email: response.data.email,
333
+ country: response.data.country,
334
+ followers: response.data.followers.total,
335
+ product: response.data.product,
336
+ images: response.data.images
337
+ };
338
+
339
+ res.json({
340
+ status: 'success',
341
+ data: profileData
342
+ });
343
+ } catch (error) {
344
+ if (error.response?.status === 401) {
345
+ return res.status(401).json({ error: 'Session expired' });
346
+ }
347
+ res.status(500).json({
348
+ error: 'Failed to fetch user profile',
349
+ details: error.response?.data || error.message
350
+ });
351
+ }
352
+ });
353
+
354
  // Error handler
355
  app.use((err, req, res, next) => {
356
  console.error('Server Error:', err);