feat(console): split audio files into music and beep folders
Add an Audio/music path for uploaded music, keep the existing general audio directory as the Beep group, and update the console and music page so the file manager now shows Configuration, Music, Beep, and Station with matching upload and preview routes.
This commit is contained in:
+59
-12
@@ -39,6 +39,7 @@ if (!fs.existsSync(localHlsDir)) fs.mkdirSync(localHlsDir, { recursive: true });
|
||||
|
||||
const uploadDir = path.join(__dirname, 'public', 'uploads');
|
||||
const audioRootDir = path.join(appRootDir, 'Audio');
|
||||
const audioMusicDir = path.join(audioRootDir, 'music');
|
||||
const audioGeneralDir = path.join(audioRootDir, 'general');
|
||||
const audioStationDir = path.join(audioRootDir, 'station');
|
||||
const listFilePath = path.join(appRootDir, 'list.txt');
|
||||
@@ -48,6 +49,7 @@ const MUSIC_AUDIO_EXTENSIONS = [...STREAMABLE_AUDIO_EXTENSIONS, '.dfpwm'];
|
||||
|
||||
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
|
||||
if (!fs.existsSync(audioRootDir)) fs.mkdirSync(audioRootDir, { recursive: true });
|
||||
if (!fs.existsSync(audioMusicDir)) fs.mkdirSync(audioMusicDir, { recursive: true });
|
||||
if (!fs.existsSync(audioGeneralDir)) fs.mkdirSync(audioGeneralDir, { recursive: true });
|
||||
if (!fs.existsSync(audioStationDir)) fs.mkdirSync(audioStationDir, { recursive: true });
|
||||
if (!fs.existsSync(tempBroadcastDir)) fs.mkdirSync(tempBroadcastDir, { recursive: true });
|
||||
@@ -57,6 +59,8 @@ const storage = multer.diskStorage({
|
||||
destination: function (req, file, cb) {
|
||||
if (file.fieldname === 'listFile') {
|
||||
cb(null, appRootDir);
|
||||
} else if (file.fieldname === 'musicAudioFiles') {
|
||||
cb(null, audioMusicDir);
|
||||
} else if (file.fieldname === 'generalAudioFiles') {
|
||||
cb(null, audioGeneralDir);
|
||||
} else if (file.fieldname === 'stationAudioFiles') {
|
||||
@@ -106,6 +110,10 @@ app.get('/media/audio/general/:file', (req, res) => {
|
||||
const name = path.basename(String(req.params.file || ''));
|
||||
sendBinaryFile(res, path.join(audioGeneralDir, name));
|
||||
});
|
||||
app.get('/media/audio/music/:file', (req, res) => {
|
||||
const name = path.basename(String(req.params.file || ''));
|
||||
sendBinaryFile(res, path.join(audioMusicDir, name));
|
||||
});
|
||||
|
||||
app.get('/media/audio/station/:file', (req, res) => {
|
||||
const name = path.basename(String(req.params.file || ''));
|
||||
@@ -122,6 +130,7 @@ app.get('/media', (req, res) => {
|
||||
success: true,
|
||||
message: 'Use a concrete media path',
|
||||
routes: [
|
||||
'/media/audio/music/:file',
|
||||
'/media/audio/general/:file',
|
||||
'/media/audio/station/:file',
|
||||
'/media/temp/:file'
|
||||
@@ -481,15 +490,21 @@ function getManagedMediaUrl(kind, fileName) {
|
||||
|
||||
function listMusicTracks() {
|
||||
const out = new Set();
|
||||
if (!fs.existsSync(audioGeneralDir)) return [];
|
||||
const scanDirs = [audioMusicDir];
|
||||
if (fs.existsSync(audioMusicDir) && fs.readdirSync(audioMusicDir).length === 0) {
|
||||
scanDirs.push(audioGeneralDir);
|
||||
}
|
||||
|
||||
for (const file of fs.readdirSync(audioGeneralDir)) {
|
||||
if (!file || file.startsWith('.')) continue;
|
||||
const full = path.join(audioGeneralDir, file);
|
||||
if (!fs.existsSync(full) || !fs.statSync(full).isFile()) continue;
|
||||
if (!hasSupportedAudioExtension(file)) continue;
|
||||
const base = normalizeBaseName(file);
|
||||
if (base) out.add(base);
|
||||
for (const dir of scanDirs) {
|
||||
if (!fs.existsSync(dir)) continue;
|
||||
for (const file of fs.readdirSync(dir)) {
|
||||
if (!file || file.startsWith('.')) continue;
|
||||
const full = path.join(dir, file);
|
||||
if (!fs.existsSync(full) || !fs.statSync(full).isFile()) continue;
|
||||
if (!hasSupportedAudioExtension(file)) continue;
|
||||
const base = normalizeBaseName(file);
|
||||
if (base) out.add(base);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(out).sort((a, b) => a.localeCompare(b));
|
||||
@@ -533,6 +548,7 @@ function getPlaybackAudioByBaseName(baseName) {
|
||||
|
||||
for (const ext of STREAMABLE_AUDIO_EXTENSIONS) {
|
||||
const candidates = [
|
||||
path.join(audioMusicDir, `${base}${ext}`),
|
||||
path.join(audioGeneralDir, `${base}${ext}`),
|
||||
path.join(audioStationDir, `${base}${ext}`)
|
||||
];
|
||||
@@ -546,13 +562,18 @@ function getPlaybackAudioByBaseName(baseName) {
|
||||
return {
|
||||
sourcePath: p,
|
||||
audioFormat: 'stream',
|
||||
streamUrl: getManagedMediaUrl(p.startsWith(audioStationDir) ? 'audio/station' : 'audio/general', path.basename(p)),
|
||||
streamUrl: getManagedMediaUrl(
|
||||
p.startsWith(audioStationDir) ? 'audio/station' :
|
||||
(p.startsWith(audioMusicDir) ? 'audio/music' : 'audio/general'),
|
||||
path.basename(p)
|
||||
),
|
||||
durationSec
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (const p of [
|
||||
path.join(audioMusicDir, `${base}.dfpwm`),
|
||||
path.join(audioGeneralDir, `${base}.dfpwm`),
|
||||
path.join(audioStationDir, `${base}.dfpwm`)
|
||||
]) {
|
||||
@@ -725,7 +746,9 @@ function resolveManagedPath(inputPath) {
|
||||
}
|
||||
|
||||
const prefixes = [
|
||||
{ prefix: 'Audio/music/', baseDir: audioMusicDir, logicalPrefix: 'Audio/music/' },
|
||||
{ prefix: 'Audio/general/', baseDir: audioGeneralDir, logicalPrefix: 'Audio/general/' },
|
||||
{ prefix: 'uploads/audio/music/', baseDir: audioMusicDir, logicalPrefix: 'Audio/music/' },
|
||||
{ prefix: 'uploads/audio/general/', baseDir: audioGeneralDir, logicalPrefix: 'Audio/general/' },
|
||||
{ prefix: 'Audio/station/', baseDir: audioStationDir, logicalPrefix: 'Audio/station/' },
|
||||
{ prefix: 'uploads/audio/station/', baseDir: audioStationDir, logicalPrefix: 'Audio/station/' }
|
||||
@@ -758,6 +781,24 @@ function getManagedFiles() {
|
||||
});
|
||||
}
|
||||
|
||||
if (fs.existsSync(audioMusicDir)) {
|
||||
fs.readdirSync(audioMusicDir).forEach(file => {
|
||||
if (file.endsWith('.dfpwm')) {
|
||||
const wavName = file.replace(/\.dfpwm$/, '.wav');
|
||||
if (fs.existsSync(path.join(audioMusicDir, wavName))) return;
|
||||
}
|
||||
const filePath = path.join(audioMusicDir, file);
|
||||
const stats = fs.statSync(filePath);
|
||||
files.push({
|
||||
name: file,
|
||||
path: `Audio/music/${file}`,
|
||||
type: 'music',
|
||||
size: stats.size,
|
||||
mtime: stats.mtimeMs
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (fs.existsSync(audioGeneralDir)) {
|
||||
fs.readdirSync(audioGeneralDir).forEach(file => {
|
||||
if (file.endsWith('.dfpwm')) {
|
||||
@@ -769,7 +810,7 @@ function getManagedFiles() {
|
||||
files.push({
|
||||
name: file,
|
||||
path: `Audio/general/${file}`,
|
||||
type: 'general',
|
||||
type: 'beep',
|
||||
size: stats.size,
|
||||
mtime: stats.mtimeMs
|
||||
});
|
||||
@@ -1847,8 +1888,14 @@ app.post('/api/upload/list', upload.single('listFile'), (req, res) => {
|
||||
|
||||
app.post('/api/upload/general-audio', upload.array('generalAudioFiles'), (req, res) => {
|
||||
const files = req.files || [];
|
||||
log('SUCCESS', `Uploaded ${files.length} general audio files`);
|
||||
res.json({ success: true, message: `${files.length} general audio files uploaded` });
|
||||
log('SUCCESS', `Uploaded ${files.length} beep audio files`);
|
||||
res.json({ success: true, message: `${files.length} beep audio files uploaded` });
|
||||
});
|
||||
|
||||
app.post('/api/upload/music-audio', upload.array('musicAudioFiles'), (req, res) => {
|
||||
const files = req.files || [];
|
||||
log('SUCCESS', `Uploaded ${files.length} music audio files`);
|
||||
res.json({ success: true, message: `${files.length} music audio files uploaded` });
|
||||
});
|
||||
|
||||
app.post('/api/upload/station-audio', upload.array('stationAudioFiles'), (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user