Kyouka commited on
Commit
40ab32b
·
verified ·
1 Parent(s): fbb24d8

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +136 -0
index.js CHANGED
@@ -9,6 +9,9 @@ const express = require('express')
9
  const cp = require('child_process')
10
  const PDFDocument = require('pdfkit')
11
  const playwright = require('playwright-extra')
 
 
 
12
  // const stealth = require('puppeteer-extra-plugin-stealth')
13
  // playwright.chromium.use(stealth())
14
  const { NinexbuddySource, NinexbuddyScraper } = require("./lib/buddy.js")
@@ -18,6 +21,10 @@ const kyou = new NinexbuddyScraper()
18
  const app = express()
19
  app.set('json spaces', 4)
20
  app.use(morgan('dev'))
 
 
 
 
21
 
22
  const limitSize = '500mb'
23
  app.use(express.json({ limit: limitSize }))
@@ -37,6 +44,11 @@ app.use((req, res, next) => {
37
  next()
38
  })
39
 
 
 
 
 
 
40
  app.use('/file', express.static(tmpFolder))
41
 
42
  app.all('/', (req, res) => {
@@ -85,6 +97,130 @@ app.get('/proxy', async (req, res) => {
85
  }
86
  });
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  app.get('/pages', async (req, res) => {
89
  const targetUrl = req.query.url;
90
 
 
9
  const cp = require('child_process')
10
  const PDFDocument = require('pdfkit')
11
  const playwright = require('playwright-extra')
12
+ const cookieParser = require('cookie-parser');
13
+ const { Buffer } = require('buffer');
14
+ const querystring = require('querystring');
15
  // const stealth = require('puppeteer-extra-plugin-stealth')
16
  // playwright.chromium.use(stealth())
17
  const { NinexbuddySource, NinexbuddyScraper } = require("./lib/buddy.js")
 
21
  const app = express()
22
  app.set('json spaces', 4)
23
  app.use(morgan('dev'))
24
+ app.use(cookieParser());
25
+
26
+ const CLIENT_ID = process.env.CLIENT_ID || 'your_client_id';
27
+ const CLIENT_SECRET = process.env.CLIENT_SECRET || 'your_client_secret';
28
 
29
  const limitSize = '500mb'
30
  app.use(express.json({ limit: limitSize }))
 
44
  next()
45
  })
46
 
47
+
48
+ function getFrontendUri(req) {
49
+ return `${req.protocol}://${req.get('host')}`;
50
+ }
51
+
52
  app.use('/file', express.static(tmpFolder))
53
 
54
  app.all('/', (req, res) => {
 
97
  }
98
  });
99
 
100
+ // 1. Root route - redirect ke Spotify login
101
+ 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,
109
+ scope: scopes.join(' '),
110
+ redirect_uri: REDIRECT_URI,
111
+ show_dialog: false,
112
+ });
113
+
114
+ res.redirect(`https://accounts.spotify.com/authorize?${queryParams}`);
115
+ });
116
+
117
+ // 2. Callback route
118
+ app.get('/callback', async (req, res) => {
119
+ const FRONTEND_URI = getFrontendUri(req);
120
+ const REDIRECT_URI = `${FRONTEND_URI}/callback`;
121
+
122
+ const { code, error } = req.query;
123
+
124
+ if (error) {
125
+ console.error('Spotify Auth Error:', error);
126
+ return res.redirect(`${FRONTEND_URI}/error?message=${encodeURIComponent(error)}`);
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',
134
+ code,
135
+ redirect_uri: REDIRECT_URI,
136
+ }), {
137
+ headers: {
138
+ 'Content-Type': 'application/x-www-form-urlencoded',
139
+ 'Authorization': 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'),
140
+ },
141
+ });
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',
149
+ maxAge: expires_in * 1000
150
+ });
151
+
152
+ res.cookie('spotify_refresh', refresh_token, {
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
+
182
+ const tracks = response.data.items.map(item => ({
183
+ played_at: item.played_at,
184
+ track: {
185
+ id: item.track.id,
186
+ name: item.track.name,
187
+ artists: item.track.artists.map(a => ({ id: a.id, name: a.name })),
188
+ album: {
189
+ id: item.track.album.id,
190
+ name: item.track.album.name,
191
+ images: item.track.album.images,
192
+ release_date: item.track.album.release_date
193
+ },
194
+ duration_ms: item.track.duration_ms,
195
+ preview_url: item.track.preview_url
196
+ }
197
+ }));
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
214
+ });
215
+ }
216
+ });
217
+
218
+ // Error handler
219
+ app.use((err, req, res, next) => {
220
+ console.error('Server Error:', err);
221
+ res.status(500).json({ error: 'Internal server error' });
222
+ });
223
+
224
  app.get('/pages', async (req, res) => {
225
  const targetUrl = req.query.url;
226