1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

bugfixes, ui improvements

This commit is contained in:
Marek Farkaš
2025-05-30 21:28:37 +02:00
parent 1c8b16d27b
commit 9d7e4297e3
10 changed files with 265 additions and 275 deletions

View File

@@ -1,7 +1,7 @@
'use strict';
const exec = require('child_process').exec;
const fs = require('fs');
const fs = require('fs').promises; // Use the Promise-based fs API
const ffmpeg = require('ffmpeg-static');
const filePath = '/proc/asound/cards';
const platform = process.platform;
@@ -16,106 +16,97 @@ function parseAudioDevice(options, callback) {
options = null;
}
options = options || {};
const ffmpegPath = "\"" + ffmpeg.replace(/\\/g, '\\\\') + "\"";
const ffmpegPath = `"${ffmpeg.replace(/\\/g, '\\\\')}"`;
const callbackExists = typeof callback === 'function';
let inputDevice, prefix, audioSeparator, alternativeName, deviceParams;
switch (platform) {
case 'win32':
inputDevice = 'dshow';
prefix = /\[dshow/;
audioSeparator = /DirectShow\saudio\sdevices/;
alternativeName = /Alternative\sname\s*?\"(.*?)\"/;
deviceParams = /\"(.*?)\"/;
break;
case 'darwin':
inputDevice = 'avfoundation';
prefix = /^\[AVFoundation/;
audioSeparator = /AVFoundation\saudio\sdevices/;
deviceParams = /^\[AVFoundation.*?\]\s\[(\d*?)\]\s(.*)$/;
break;
case 'linux':
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error(`Error reading file: ${err.message}`);
return;
}
// Extract values between square brackets, trim whitespace, and prefix with 'hw:'
const regex = /\[([^\]]+)\]/g;
const matches = (data.match(regex) || []).map(match => 'hw:' + match.replace(/\s+/g, '').slice(1, -1));
if (matches.length > 0) {
// Process the extracted values
matches.forEach(function(match) {
if (typeof match === 'string') {
audioDevices.push({ name: match });
} else if (typeof match === 'object' && match.name) {
audioDevices.push(match);
}
});
} else {
logWarn('No audio devices have been found.');
}
});
break;
}
const searchPrefix = (line) => (line.search(prefix) > -1);
const searchAudioSeparator = (line) => isVideo && (line.search(audioSeparator) > -1);
const searchAlternativeName = (line) => (platform === 'win32') && (line.search(/Alternative\sname/) > -1);
const execute = (fulfill, reject) => {
exec(`${ffmpegPath} -f ${inputDevice} -list_devices true -i ""`, (err, stdout, stderr) => {
stderr.split("\n")
.filter(searchPrefix)
.forEach((line) => {
const deviceList = isVideo ? videoDevices : audioDevices;
if (searchAudioSeparator(line)) {
isVideo = false;
return;
const execute = async (fulfill, reject) => {
try {
if (platform === 'linux') {
try {
const data = await fs.readFile(filePath, 'utf8');
const regex = /\[([^\]]+)\]/g;
const matches = (data.match(regex) || []).map(match => 'hw:' + match.replace(/\s+/g, '').slice(1, -1));
matches.forEach(match => {
if (typeof match === 'string') {
audioDevices.push({ name: match });
}
});
} catch (err) {
console.error(`Error reading file: ${err.message}`);
}
if (searchAlternativeName(line)) {
const lastDevice = deviceList[deviceList.length - 1];
lastDevice.alternativeName = line.match(alternativeName)[1];
return;
}
const params = line.match(deviceParams);
if (params) {
let device;
switch (platform) {
case 'win32':
device = {
name: params[1]
};
break;
case 'darwin':
device = {
id: parseInt(params[1]),
name: params[2]
};
break;
case 'linux':
device = {
name: params[1]
};
break;
}
deviceList.push(device);
}
});
audioDevices = audioDevices.filter(device => device.name !== undefined);
const result = { videoDevices, audioDevices };
if (callbackExists) {
callback(result);
} else {
fulfill(result);
// Linux doesn't support the `-list_devices` ffmpeg command like macOS/Windows,
// so skip the ffmpeg exec for Linux
const result = { videoDevices: [], audioDevices };
if (callbackExists) return callback(result);
return fulfill(result);
}
});
let inputDevice, prefix, audioSeparator, alternativeName, deviceParams;
switch (platform) {
case 'win32':
inputDevice = 'dshow';
prefix = /\[dshow/;
audioSeparator = /DirectShow\saudio\sdevices/;
alternativeName = /Alternative\sname\s*?"(.*?)"/;
deviceParams = /"(.*?)"/;
break;
case 'darwin':
inputDevice = 'avfoundation';
prefix = /^\[AVFoundation/;
audioSeparator = /AVFoundation\saudio\sdevices/;
deviceParams = /^\[AVFoundation.*?]\s\[(\d+)]\s(.*)$/;
break;
}
exec(`${ffmpegPath} -f ${inputDevice} -list_devices true -i ""`, (err, stdout, stderr) => {
stderr.split("\n")
.filter(line => line.search(prefix) > -1)
.forEach(line => {
const deviceList = isVideo ? videoDevices : audioDevices;
if (line.search(audioSeparator) > -1) {
isVideo = false;
return;
}
if (platform === 'win32' && line.search(/Alternative\sname/) > -1) {
const lastDevice = deviceList[deviceList.length - 1];
const alt = line.match(alternativeName);
if (lastDevice && alt) {
lastDevice.alternativeName = alt[1];
}
return;
}
const params = line.match(deviceParams);
if (params) {
let device;
switch (platform) {
case 'win32':
device = { name: params[1] };
break;
case 'darwin':
device = { id: parseInt(params[1]), name: params[2] };
break;
}
deviceList.push(device);
}
});
audioDevices = audioDevices.filter(device => device.name !== undefined);
const result = { videoDevices, audioDevices };
if (callbackExists) return callback(result);
return fulfill(result);
});
} catch (err) {
console.error('Unexpected error:', err);
if (callbackExists) callback({ videoDevices: [], audioDevices: [] });
else reject(err);
}
};
if (callbackExists) {
execute();
} else {