From 36c0ec8b13398883ef261b2f52058aeb9eda263b Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 3 Mar 2024 21:29:50 -0500 Subject: [PATCH] Update DAB to include dynamic settings - Settings will now get the active device(s) available on Linux (UNTESTED) - Added CLI handler for interacting with the CLI - Added wrapper for extracting values with regex - --- client/discordAudioBot/dab.mjs | 3 +- client/discordAudioBot/dabSettings.mjs | 18 ++++++++++++ client/modules/baseUtils.mjs | 15 +++++++++- client/modules/cliHandler.mjs | 39 ++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 client/discordAudioBot/dabSettings.mjs create mode 100644 client/modules/cliHandler.mjs diff --git a/client/discordAudioBot/dab.mjs b/client/discordAudioBot/dab.mjs index ce2781b..f3bf84d 100644 --- a/client/discordAudioBot/dab.mjs +++ b/client/discordAudioBot/dab.mjs @@ -17,7 +17,8 @@ import { Client, Events, ActivityType } from 'discord.js'; import prism_media from 'prism-media'; const { FFmpeg } = prism_media; -const device = "VoiceMeeter VAIO3 Output (VB-Audio VoiceMeeter VAIO3)", maxTransmissionGap = 500, type = "dshow"; +// Import the DAB settings from the dynamic settings file +import {device, maxTransmissionGap, type} from './dabSettings.mjs' const player = createAudioPlayer({ behaviors: { diff --git a/client/discordAudioBot/dabSettings.mjs b/client/discordAudioBot/dabSettings.mjs new file mode 100644 index 0000000..8b41507 --- /dev/null +++ b/client/discordAudioBot/dabSettings.mjs @@ -0,0 +1,18 @@ +import { executeCommand } from '../modules/cliHandler.mjs'; +import { extractValue } from '../modules/baseUtils.mjs'; +import os from 'os'; + +// Defaults to Windows values for testing +let device = "VoiceMeeter VAIO3 Output (VB-Audio VoiceMeeter VAIO3)"; +let maxTransmissionGap = 500; +let type = "dshow"; + +// Set Linux values for use in production +if (os.platform() === 'linux') { + await executeCommand("pactl", ['list', 'short', 'sources']).then(cliOutput => { + device = extractValue(cliOutput, '(?:\d[ ]{4,12}(.+?)[ ]{4,12}(?:.+?[ ]{4,12}){2,4}RUNNING)') + }); + type = "pulse"; // Replace with appropriate type for Linux +} + +export { device, maxTransmissionGap, type }; diff --git a/client/modules/baseUtils.mjs b/client/modules/baseUtils.mjs index 0f02f4c..b58c4a2 100644 --- a/client/modules/baseUtils.mjs +++ b/client/modules/baseUtils.mjs @@ -61,4 +61,17 @@ export const generateUniqueID = () => { .digest('hex'); return uniqueID; -} \ No newline at end of file +} + + +/** + * Extracts the value after a specific pattern from a string using regular expressions. + * @param {string} input - The input string. + * @param {string} pattern - The pattern to match. + * @returns {string|null} The value found after the pattern, or null if not found. + */ +export const extractValue = (input, pattern) => { + const regex = new RegExp(`${pattern}\\s+(\\S+)`); + const match = input.match(regex); + return match ? match[1] : null; +}; \ No newline at end of file diff --git a/client/modules/cliHandler.mjs b/client/modules/cliHandler.mjs new file mode 100644 index 0000000..4e11548 --- /dev/null +++ b/client/modules/cliHandler.mjs @@ -0,0 +1,39 @@ +import { spawn } from "child_process"; + +/** + * Executes a command and retrieves its output. + * @param {string} command - The command to execute. + * @param {string[]} args - The arguments to pass to the command. + * @returns {Promise} A promise that resolves with the output of the command. + */ +export const executeCommand = (command, args) => { + return new Promise((resolve, reject) => { + const childProcess = spawn(command, args); + + let commandOutput = ''; + + childProcess.stdout.on('data', (data) => { + commandOutput += data.toString(); + }); + + childProcess.stderr.on('data', (data) => { + // Log any errors to stderr + console.error(data.toString()); + }); + + childProcess.on('error', (error) => { + // Reject the promise if there's an error executing the command + reject(error); + }); + + childProcess.on('close', (code) => { + if (code === 0) { + // Resolve the promise with the command output if it exits successfully + resolve(commandOutput.trim()); + } else { + // Reject the promise if the command exits with a non-zero code + reject(new Error(`Command '${command}' exited with code ${code}`)); + } + }); + }); +};