const express = require('express'); const router = express.Router(); const fs = require('fs'); const path = require('path'); const multer = require('multer'); const AUDIO_DIR = path.join(__dirname, '../../Audio'); // Ensure directory exists if (!fs.existsSync(AUDIO_DIR)) fs.mkdirSync(AUDIO_DIR, { recursive: true }); // Configure Multer const storage = multer.diskStorage({ destination: (req, file, cb) => { // Access target path from body (requires path field to be sent BEFORE file in FormData) const targetPath = req.body.path || ''; const safePath = targetPath.replace(/\.\./g, ''); const targetDir = path.join(AUDIO_DIR, safePath); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir, { recursive: true }); } cb(null, targetDir); }, filename: (req, file, cb) => { // Decode latin1 to utf8 for original filename handling const originalName = Buffer.from(file.originalname, 'latin1').toString('utf8'); cb(null, originalName); } }); const upload = multer({ storage }); // List Files router.get('/', (req, res) => { try { const requestPath = req.query.path || ''; const recursive = req.query.recursive === 'true'; // Prevent directory traversal if (requestPath.includes('..')) return res.status(400).json({ error: 'Invalid path' }); const targetDir = path.join(AUDIO_DIR, requestPath); if (!fs.existsSync(targetDir)) { return res.status(404).json({ error: 'Directory not found' }); } if (recursive) { // Recursive list for Lua client sync const getAllFiles = (dir, fileList = [], relativePath = '') => { const files = fs.readdirSync(dir); files.forEach(file => { const filePath = path.join(dir, file); const fileStat = fs.statSync(filePath); const fileRelativePath = path.join(relativePath, file).replace(/\\/g, '/'); if (fileStat.isDirectory()) { getAllFiles(filePath, fileList, fileRelativePath); } else { fileList.push({ name: fileRelativePath, size: fileStat.size, mtime: fileStat.mtime, isDirectory: false }); } }); return fileList; }; const files = getAllFiles(AUDIO_DIR); return res.json(files); } // Standard list for Web UI const items = fs.readdirSync(targetDir).map(name => { const p = path.join(targetDir, name); const stat = fs.statSync(p); return { name, path: path.join(requestPath, name).replace(/\\/g, '/'), // Relative path from AUDIO_DIR size: stat.size, mtime: stat.mtime, isDirectory: stat.isDirectory() }; }); // Sort directories first, then files items.sort((a, b) => { if (a.isDirectory === b.isDirectory) return a.name.localeCompare(b.name); return a.isDirectory ? -1 : 1; }); res.json(items); } catch (e) { res.status(500).json({ error: e.message }); } }); // Create Folder router.post('/folder', (req, res) => { try { const { path: parentPath, name } = req.body; if (!name || name.includes('..') || name.includes('/') || name.includes('\\')) { return res.status(400).json({ error: 'Invalid folder name' }); } const safeParentPath = (parentPath || '').replace(/\.\./g, ''); const newDirPath = path.join(AUDIO_DIR, safeParentPath, name); if (fs.existsSync(newDirPath)) { return res.status(400).json({ error: 'Folder already exists' }); } fs.mkdirSync(newDirPath, { recursive: true }); res.json({ ok: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); // Upload File router.post('/', (req, res) => { const uploadMiddleware = upload.single('file'); uploadMiddleware(req, res, (err) => { if (err) return res.status(500).json({ error: err.message }); if (!req.file) return res.status(400).json({ error: 'No file uploaded' }); // File is already saved to the correct directory by Multer diskStorage // No database storage needed as requested. const relativePath = path.relative(AUDIO_DIR, req.file.path).replace(/\\/g, '/'); res.json({ ok: true, file: relativePath }); }); }); // Delete File or Folder router.delete('/', (req, res) => { const targetPath = req.query.path; if (!targetPath || targetPath.includes('..')) return res.status(400).json({ error: 'Invalid path' }); const p = path.join(AUDIO_DIR, targetPath); if (fs.existsSync(p)) { try { const stat = fs.statSync(p); if (stat.isDirectory()) { fs.rmSync(p, { recursive: true, force: true }); } else { fs.unlinkSync(p); } res.json({ ok: true }); } catch (e) { res.status(500).json({ error: e.message }); } } else { res.status(404).json({ error: 'Not found' }); } }); module.exports = router;