- Add group_name column to teams table for mapping teams to OBS groups - Create API endpoints for group creation (/api/createGroup) and bulk sync (/api/syncGroups) - Update teams UI with group status display and creation buttons - Implement automatic group assignment when adding streams - Add comprehensive OBS setup documentation (docs/OBS_SETUP.md) - Fix team list spacing issue with explicit margins - Update OBS client with group management functions - Add database migration script for existing deployments 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
203 lines
No EOL
5.5 KiB
JavaScript
203 lines
No EOL
5.5 KiB
JavaScript
const { OBSWebSocket } = require('obs-websocket-js');
|
|
|
|
let obs = null;
|
|
let isConnecting = false;
|
|
let connectionPromise = null;
|
|
|
|
async function ensureConnected() {
|
|
// If already connected, return the existing client
|
|
if (obs && obs.identified) {
|
|
return obs;
|
|
}
|
|
|
|
// If already in the process of connecting, wait for it
|
|
if (isConnecting && connectionPromise) {
|
|
return connectionPromise;
|
|
}
|
|
|
|
// Start new connection
|
|
isConnecting = true;
|
|
connectionPromise = connectToOBS();
|
|
|
|
try {
|
|
await connectionPromise;
|
|
return obs;
|
|
} finally {
|
|
isConnecting = false;
|
|
connectionPromise = null;
|
|
}
|
|
}
|
|
|
|
async function connectToOBS() {
|
|
const OBS_HOST = process.env.OBS_WEBSOCKET_HOST || '127.0.0.1';
|
|
const OBS_PORT = process.env.OBS_WEBSOCKET_PORT || '4455';
|
|
const OBS_PASSWORD = process.env.OBS_WEBSOCKET_PASSWORD || '';
|
|
|
|
// Create new client if needed
|
|
if (!obs) {
|
|
obs = new OBSWebSocket();
|
|
|
|
// Set up event handlers for connection management
|
|
obs.on('ConnectionClosed', () => {
|
|
console.log('OBS WebSocket connection closed');
|
|
obs = null;
|
|
});
|
|
|
|
obs.on('ConnectionError', (err) => {
|
|
console.error('OBS WebSocket connection error:', err);
|
|
obs = null;
|
|
});
|
|
|
|
obs.on('Identified', () => {
|
|
console.log('OBS WebSocket successfully identified');
|
|
});
|
|
}
|
|
|
|
try {
|
|
console.log('Connecting to OBS WebSocket...');
|
|
console.log('Host:', OBS_HOST);
|
|
console.log('Port:', OBS_PORT);
|
|
console.log('Password:', OBS_PASSWORD ? '***' : '(none)');
|
|
|
|
await obs.connect(`ws://${OBS_HOST}:${OBS_PORT}`, OBS_PASSWORD);
|
|
console.log('Connected to OBS WebSocket.');
|
|
return obs;
|
|
} catch (err) {
|
|
console.error('Failed to connect to OBS WebSocket:', err.message);
|
|
obs = null;
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async function getOBSClient() {
|
|
return await ensureConnected();
|
|
}
|
|
|
|
function getConnectionStatus() {
|
|
return {
|
|
connected: obs && obs.identified,
|
|
client: obs
|
|
};
|
|
}
|
|
|
|
async function disconnectFromOBS() {
|
|
if (obs) {
|
|
try {
|
|
await obs.disconnect();
|
|
console.log('Disconnected from OBS WebSocket.');
|
|
} catch (err) {
|
|
console.error('Error disconnecting from OBS:', err.message);
|
|
} finally {
|
|
obs = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
async function addSourceToSwitcher(inputName, newSources) {
|
|
try {
|
|
const obsClient = await getOBSClient();
|
|
|
|
// Step 1: Get current input settings
|
|
const { inputSettings } = await obsClient.call('GetInputSettings', { inputName });
|
|
// console.log('Current Settings:', inputSettings);
|
|
|
|
// Step 2: Add new sources to the sources array
|
|
const updatedSources = [...inputSettings.sources, ...newSources];
|
|
|
|
// Step 3: Update the settings with the new sources array
|
|
await obsClient.call('SetInputSettings', {
|
|
inputName,
|
|
inputSettings: {
|
|
...inputSettings,
|
|
sources: updatedSources,
|
|
},
|
|
});
|
|
|
|
console.log('Updated settings successfully for', inputName);
|
|
} catch (error) {
|
|
console.error('Error updating settings:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function createGroupIfNotExists(groupName) {
|
|
try {
|
|
const obsClient = await getOBSClient();
|
|
|
|
// Check if the group (scene) exists
|
|
const { scenes } = await obsClient.call('GetSceneList');
|
|
const groupExists = scenes.some((scene) => scene.sceneName === groupName);
|
|
|
|
if (!groupExists) {
|
|
console.log(`Creating group "${groupName}"`);
|
|
await obsClient.call('CreateScene', { sceneName: groupName });
|
|
return { created: true, message: `Group "${groupName}" created successfully` };
|
|
} else {
|
|
console.log(`Group "${groupName}" already exists`);
|
|
return { created: false, message: `Group "${groupName}" already exists` };
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating group:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function addSourceToGroup(groupName, sourceName, url) {
|
|
try {
|
|
const obsClient = await getOBSClient();
|
|
|
|
// Ensure group exists
|
|
await createGroupIfNotExists(groupName);
|
|
|
|
// Check if source already exists in the group
|
|
const { sceneItems } = await obsClient.call('GetSceneItemList', { sceneName: groupName });
|
|
const sourceExists = sceneItems.some(item => item.sourceName === sourceName);
|
|
|
|
if (!sourceExists) {
|
|
// Create the browser source in the group
|
|
console.log(`Adding source "${sourceName}" to group "${groupName}"`);
|
|
await obsClient.call('CreateInput', {
|
|
sceneName: groupName,
|
|
inputName: sourceName,
|
|
inputKind: 'browser_source',
|
|
inputSettings: {
|
|
width: 1600,
|
|
height: 900,
|
|
url,
|
|
control_audio: true,
|
|
},
|
|
});
|
|
|
|
// Ensure audio control is enabled
|
|
await obsClient.call('SetInputSettings', {
|
|
inputName: sourceName,
|
|
inputSettings: {
|
|
control_audio: true,
|
|
},
|
|
overlay: true,
|
|
});
|
|
|
|
console.log(`Source "${sourceName}" successfully added to group "${groupName}"`);
|
|
return { success: true, message: `Source added to group successfully` };
|
|
} else {
|
|
console.log(`Source "${sourceName}" already exists in group "${groupName}"`);
|
|
return { success: false, message: `Source already exists in group` };
|
|
}
|
|
} catch (error) {
|
|
console.error('Error adding source to group:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
|
|
// Export all functions
|
|
module.exports = {
|
|
connectToOBS,
|
|
getOBSClient,
|
|
disconnectFromOBS,
|
|
addSourceToSwitcher,
|
|
ensureConnected,
|
|
getConnectionStatus,
|
|
createGroupIfNotExists,
|
|
addSourceToGroup
|
|
}; |