feat(audio): support more upload and music formats
Allow the console and music page to upload common audio formats, expand music track detection and playback source selection beyond wav/dfpwm, and update station list name normalization so common extensions resolve consistently. Bump the station build to v1.0.6.
This commit is contained in:
+42
-22
@@ -43,6 +43,8 @@ const audioGeneralDir = path.join(audioRootDir, 'general');
|
||||
const audioStationDir = path.join(audioRootDir, 'station');
|
||||
const listFilePath = path.join(appRootDir, 'list.txt');
|
||||
const tempBroadcastDir = path.join(appRootDir, 'temp-broadcast');
|
||||
const STREAMABLE_AUDIO_EXTENSIONS = ['.wav', '.mp3', '.ogg', '.flac', '.m4a', '.aac', '.opus'];
|
||||
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 });
|
||||
@@ -446,10 +448,25 @@ async function sendLiveWavChunksToStation(stationName, fallbackWs, task) {
|
||||
|
||||
const stationMusicStates = new Map();
|
||||
|
||||
function hasSupportedAudioExtension(name, exts = MUSIC_AUDIO_EXTENSIONS) {
|
||||
const lower = String(name || '').trim().toLowerCase();
|
||||
return exts.some(ext => lower.endsWith(ext));
|
||||
}
|
||||
|
||||
function stripSupportedAudioExtension(name, exts = MUSIC_AUDIO_EXTENSIONS) {
|
||||
const value = String(name || '').trim();
|
||||
for (const ext of exts) {
|
||||
if (value.toLowerCase().endsWith(ext)) {
|
||||
return value.slice(0, -ext.length).trim();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function normalizeBaseName(name) {
|
||||
const s = String(name || '').trim();
|
||||
const s = stripSupportedAudioExtension(name);
|
||||
if (!s) return null;
|
||||
const base = s.replace(/\.(wav|dfpwm)$/i, '').trim();
|
||||
const base = s.trim();
|
||||
return base || null;
|
||||
}
|
||||
|
||||
@@ -470,7 +487,7 @@ function listMusicTracks() {
|
||||
if (!file || file.startsWith('.')) continue;
|
||||
const full = path.join(audioGeneralDir, file);
|
||||
if (!fs.existsSync(full) || !fs.statSync(full).isFile()) continue;
|
||||
if (!file.toLowerCase().endsWith('.wav') && !file.toLowerCase().endsWith('.dfpwm')) continue;
|
||||
if (!hasSupportedAudioExtension(file)) continue;
|
||||
const base = normalizeBaseName(file);
|
||||
if (base) out.add(base);
|
||||
}
|
||||
@@ -514,35 +531,38 @@ function getPlaybackAudioByBaseName(baseName) {
|
||||
const base = normalizeBaseName(baseName);
|
||||
if (!base) throw new Error('Invalid track name');
|
||||
|
||||
const wavCandidates = [
|
||||
path.join(audioGeneralDir, `${base}.wav`),
|
||||
path.join(audioStationDir, `${base}.wav`)
|
||||
];
|
||||
for (const p of wavCandidates) {
|
||||
if (fs.existsSync(p)) {
|
||||
const buffer = fs.readFileSync(p);
|
||||
for (const ext of STREAMABLE_AUDIO_EXTENSIONS) {
|
||||
const candidates = [
|
||||
path.join(audioGeneralDir, `${base}${ext}`),
|
||||
path.join(audioStationDir, `${base}${ext}`)
|
||||
];
|
||||
for (const p of candidates) {
|
||||
if (!fs.existsSync(p)) continue;
|
||||
let durationSec = 0;
|
||||
if (ext === '.wav') {
|
||||
const buffer = fs.readFileSync(p);
|
||||
durationSec = getWavDurationSec(buffer) || 0;
|
||||
}
|
||||
return {
|
||||
sourcePath: p,
|
||||
audioFormat: 'stream',
|
||||
streamUrl: getManagedMediaUrl(p.startsWith(audioStationDir) ? 'audio/station' : 'audio/general', path.basename(p)),
|
||||
durationSec: getWavDurationSec(buffer) || 0
|
||||
durationSec
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const dfCandidates = [
|
||||
for (const p of [
|
||||
path.join(audioGeneralDir, `${base}.dfpwm`),
|
||||
path.join(audioStationDir, `${base}.dfpwm`)
|
||||
];
|
||||
for (const p of dfCandidates) {
|
||||
if (fs.existsSync(p)) {
|
||||
const buffer = fs.readFileSync(p);
|
||||
return {
|
||||
buffer,
|
||||
audioFormat: 'dfpwm',
|
||||
durationSec: buffer.length / 6000
|
||||
};
|
||||
}
|
||||
]) {
|
||||
if (!fs.existsSync(p)) continue;
|
||||
const buffer = fs.readFileSync(p);
|
||||
return {
|
||||
buffer,
|
||||
audioFormat: 'dfpwm',
|
||||
durationSec: buffer.length / 6000
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Audio not found: ${base}`);
|
||||
|
||||
Reference in New Issue
Block a user