初始提交
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user