-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
224 lines (182 loc) · 6.7 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import express from 'express';
import sqlite3 from 'sqlite3';
import path from 'path';
import cors from 'cors';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import admin from 'firebase-admin';
import { getApps, initializeApp as adminInitializeApp } from 'firebase-admin/app';
import { getStorage } from 'firebase-admin/storage';
// Resolve __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Initialize Express
const server = express();
const port = 5000;
// Enable CORS
server.use(cors());
server.use(express.json());
// Initialize Firebase Admin if not already initialized
if (!getApps().length) {
const serviceAccount = JSON.parse(fs.readFileSync('./serviceAccountKey.json', 'utf8'));
adminInitializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: 'vimusic4abshetty.appspot.com',
});
}
// Firebase Admin Storage Bucket
const bucket = getStorage().bucket();
// FUNCTIONS BEGIN =======================================================================================================
// Ensure 'public/database' directory exists, create if not
const ensureDatabaseDirExists = () => {
const databaseDir = path.join(__dirname, 'public', 'database');
if (!fs.existsSync(databaseDir)) {
fs.mkdirSync(databaseDir, { recursive: true });
console.log(`Created directory: ${databaseDir}`);
}
};
// Function to dynamically create a SQLite connection based on user status
const getDatabaseConnection = (userEmail = null) => {
const defaultDbPath = path.join(__dirname, 'public', 'database', 'vimusic.db');
const dbPath = userEmail
? path.join(__dirname, 'public', 'database', `${userEmail}.db`)
: defaultDbPath;
console.log(`Connecting to database: ${dbPath}`);
const db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('Error opening database:', err);
} else {
console.log(`Connected to database: ${dbPath}`);
}
});
return db;
};
// Set the default connection to vimusic.db (guest mode)
let dbConnection = getDatabaseConnection(); // This is global
// Function to download and save the user-specific database file to server's "public/database" folder
const downloadDatabaseToServer = async (userEmail) => {
ensureDatabaseDirExists(); // Ensure directory exists
const filePath = `databases/${userEmail}.db`;
const destinationPath = path.join(__dirname, 'public', 'database', `${userEmail}.db`);
try {
// Firebase Admin method to download the file to the specified path
await bucket.file(filePath).download({ destination: destinationPath });
console.log(`Database file saved to ${destinationPath}`);
// Now switch to the user-specific database
dbConnection = getDatabaseConnection(userEmail);
console.log(`Switched to user-specific database for ${userEmail}`);
} catch (error) {
console.error('Error downloading and saving database:', error);
}
};
// ROUTES BEGIN ========================================================================================================
// Route to trigger the database download for a user
server.get('/download-database/:email', async (req, res) => {
const userEmail = req.params.email;
// Call the function to download and save the database file
await downloadDatabaseToServer(userEmail);
res.send('Database download initiated.');
});
// Route to delete the user's database file after sign-out
server.post('/logout/:email', async (req, res) => {
const userEmail = req.params.email;
const filePath = path.join(__dirname, 'public', 'database', `${userEmail}.db`);
try {
// Close the user-specific database connection first
if (dbConnection) {
dbConnection.close((err) => {
if (err) {
console.error('Error closing database connection:', err);
return res.status(500).send('Error closing database connection.');
}
console.log('Database connection closed successfully.');
// Add a small delay to ensure the file is released properly
setTimeout(() => {
// Now attempt to delete the database file
if (fs.existsSync(filePath)) {
try {
fs.unlinkSync(filePath); // Delete the file
console.log(`Database file ${filePath} deleted.`);
} catch (unlinkError) {
console.error('Error deleting database file:', unlinkError);
return res.status(500).send('Error deleting database file.');
}
} else {
console.log(`Database file ${filePath} not found.`);
}
// Reset the connection to the default guest database
dbConnection = getDatabaseConnection();
console.log('Switched back to the default guest database.');
res.send('User signed out and database deleted.');
}, 500); // Delay of 500ms to ensure file is released
});
} else {
res.status(500).send('No database connection found.');
}
} catch (error) {
console.error('Error during logout process:', error);
res.status(500).send('Error during logout process.');
}
});
// Fetch songs
server.get('/api/songs', (req, res) => {
const sql = "SELECT * FROM song ORDER BY totalPlayTimeMs DESC LIMIT 100";
dbConnection.all(sql, [], (err, rows) => {
if (err) {
res.status(400).json({ error: err.message });
return;
}
res.json({ songs: rows });
});
});
// Fetch all playlists
server.get('/api/playlists', (req, res) => {
const sql = 'SELECT * FROM Playlist';
dbConnection.all(sql, [], (err, rows) => {
if (err) {
res.status(400).json({ error: err.message });
return;
}
res.json({ playlists: rows });
});
});
// Fetch songs for a specific playlist
server.get('/api/playlists/:playlistId/songs', (req, res) => {
const { playlistId } = req.params;
const sql = `
SELECT s.*
FROM Song s
INNER JOIN SongPlaylistMap spm ON s.id = spm.songId
WHERE spm.playlistId = ?
ORDER BY spm.position ASC
`;
dbConnection.all(sql, [playlistId], (err, rows) => {
if (err) {
res.status(400).json({ error: err.message });
return;
}
res.json({ songs: rows });
});
});
// Fetch favorite songs
server.get('/api/favorites', (req, res) => {
const sql = `
SELECT * FROM Song
WHERE likedAt IS NOT NULL
ORDER BY likedAt DESC
`;
dbConnection.all(sql, [], (err, rows) => {
if (err) {
res.status(400).json({ error: err.message });
return;
}
res.json({ songs: rows });
});
});
// Serve static files (for your frontend)
server.use(express.static(path.join(__dirname, 'public')));
// Start the server
server.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});