Initial CarPlay audio server implementation with file management, playlists, and album/single classification
This commit is contained in:
92
src/routes/upload.js
Normal file
92
src/routes/upload.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import express from 'express';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { parseFile } from 'music-metadata';
|
||||
import crypto from 'crypto';
|
||||
import { run } from '../database/db.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const uploadPath = path.join(process.cwd(), 'audio_library', 'uploads');
|
||||
cb(null, uploadPath);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = `${Date.now()}-${file.originalname}`;
|
||||
cb(null, uniqueName);
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
fileFilter: (req, file, cb) => {
|
||||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
if (['.mp3', '.m4a', '.flac', '.wav', '.aac'].includes(ext)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error('Only audio files are allowed'));
|
||||
}
|
||||
},
|
||||
limits: { fileSize: 100 * 1024 * 1024 } // 100MB limit
|
||||
});
|
||||
|
||||
router.post('/', upload.single('audio'), async (req, res) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ error: 'No file uploaded' });
|
||||
}
|
||||
|
||||
const { isSingle } = req.body;
|
||||
const filePath = req.file.path;
|
||||
const metadata = await parseFile(filePath);
|
||||
|
||||
const id = crypto.createHash('md5').update(filePath).digest('hex');
|
||||
const relativePath = path.relative(path.join(process.cwd(), 'audio_library'), filePath);
|
||||
|
||||
const track = {
|
||||
id,
|
||||
title: metadata.common.title || path.basename(req.file.originalname, path.extname(req.file.originalname)),
|
||||
artist: metadata.common.artist || 'Unknown Artist',
|
||||
album: metadata.common.album || (isSingle === 'true' ? 'Singles' : 'Unknown Album'),
|
||||
album_artist: metadata.common.albumartist || metadata.common.artist,
|
||||
track_number: metadata.common.track?.no || null,
|
||||
year: metadata.common.year || null,
|
||||
genre: metadata.common.genre?.[0] || null,
|
||||
duration: metadata.format.duration || 0,
|
||||
file_path: relativePath,
|
||||
file_size: req.file.size,
|
||||
format: metadata.format.container || path.extname(req.file.originalname).slice(1),
|
||||
is_single: isSingle === 'true' ? 1 : 0,
|
||||
folder_path: 'uploads'
|
||||
};
|
||||
|
||||
await run(`
|
||||
INSERT INTO tracks (
|
||||
id, title, artist, album, album_artist, track_number,
|
||||
year, genre, duration, file_path, file_size, format,
|
||||
is_single, folder_path
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, [
|
||||
track.id, track.title, track.artist, track.album, track.album_artist,
|
||||
track.track_number, track.year, track.genre, track.duration,
|
||||
track.file_path, track.file_size, track.format, track.is_single,
|
||||
track.folder_path
|
||||
]);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: 'File uploaded successfully',
|
||||
track: {
|
||||
id: track.id,
|
||||
title: track.title,
|
||||
artist: track.artist,
|
||||
album: track.album
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user