Spaces:
Runtime error
Runtime error
| const express = require('express'); | |
| const mm = require('music-metadata'); | |
| const util = require('util'); | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const sharp = require('sharp'); | |
| const app = express(); | |
| const PORT = process.env.PORT || 7860; | |
| app.use(express.static('public')); | |
| app.use('/music', express.static('music')); | |
| const SUPPORTED_FORMATS = ['.mp3', '.mp4', '.wav', '.flac', '.ogg', '.opus']; // Add or remove formats as needed | |
| function isSupportedFormat(filename) { | |
| const ext = path.extname(filename).toLowerCase(); | |
| return SUPPORTED_FORMATS.includes(ext); | |
| } | |
| app.get('/tracks', async (req, res) => { | |
| const searchQuery = (req.query.search || '').toLowerCase(); | |
| const pageNumber = parseInt(req.query.page) || 1; | |
| const pageSize = 5; | |
| fs.readdir('music', async (err, files) => { | |
| if (err) { | |
| console.error('Error reading music directory', err); | |
| return res.sendStatus(500); | |
| } | |
| // If there's a search query, filter files by it | |
| let filteredFiles = files.filter(file => isSupportedFormat(file)); | |
| if (searchQuery) { | |
| filteredFiles = filteredFiles.filter(file => file.toLowerCase().includes(searchQuery)); | |
| } | |
| const pageStart = (pageNumber - 1) * pageSize; | |
| const pageEnd = pageStart + pageSize; | |
| // Slice files for pagination after filtering, ONLY if not searching. If searching, ignore pagination and send first 5 results. | |
| const pagedFiles = filteredFiles.slice(searchQuery ? 0 : pageStart, searchQuery ? pageSize : pageEnd); | |
| const trackDetails = []; | |
| for (const file of pagedFiles) { | |
| const filePath = path.join(__dirname, 'music', file); | |
| try { | |
| const metadata = await mm.parseFile(filePath, { native: true }); | |
| let artwork = ''; | |
| // Fallback path for default icon | |
| const fallbackIconPath = path.join(__dirname, 'music', 'icon.png'); | |
| try { | |
| let imageBuffer; | |
| if (metadata.common.picture && metadata.common.picture[0]) { | |
| imageBuffer = await sharp(metadata.common.picture[0].data) | |
| .resize(256, 256, { fit: 'inside' }) | |
| .toBuffer(); | |
| } else { | |
| // Use the default icon if no album art is present | |
| imageBuffer = await sharp(fallbackIconPath) | |
| .resize(256, 256, { fit: 'inside' }) | |
| .toBuffer(); | |
| } | |
| // Determine the image format | |
| const imageFormat = metadata.common.picture && metadata.common.picture[0] ? metadata.common.picture[0].format : 'image/png'; | |
| artwork = `data:${imageFormat};base64,${imageBuffer.toString('base64')}`; | |
| } catch (e) { | |
| console.error(`Error processing artwork for file: ${file}`, e); | |
| } | |
| trackDetails.push({filename: file, artwork}); | |
| } catch (error) { | |
| console.error(`Error reading metadata for file: ${file}`, error); | |
| } | |
| } | |
| res.json({tracks: trackDetails, total: filteredFiles.length}); | |
| }); | |
| }); | |
| app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); |