Implement team name text overlays with refactored group structure

- Add createTextSource function with automatic OBS text input detection
- Implement createStreamGroup to create groups within team scenes instead of separate scenes
- Add team name text overlays positioned at top-left of each stream
- Refactor stream switching to use stream group names for cleaner organization
- Update setActive API to write stream group names to files
- Fix getActive API to return correct screen position data
- Improve team UUID assignment when adding streams
- Remove manage streams section from home page for cleaner UI
- Add vertical spacing to streams list to match teams page
- Support dynamic text input kinds (text_ft2_source_v2, text_gdiplus, etc.)

This creates a much cleaner OBS structure with 10 team scenes containing grouped
stream sources rather than 200+ individual stream scenes, while adding team
name text overlays for better stream identification.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Decobus 2025-07-20 16:59:50 -04:00
parent ece75cf2df
commit 78f4d325d8
11 changed files with 325 additions and 49 deletions

View file

@ -1,6 +1,6 @@
import { NextRequest, NextResponse } from 'next/server';
import { getDatabase } from '../../../lib/database';
import { connectToOBS, getOBSClient, disconnectFromOBS, addSourceToSwitcher, createGroupIfNotExists, addSourceToGroup } from '../../../lib/obsClient';
import { connectToOBS, getOBSClient, disconnectFromOBS, addSourceToSwitcher, createGroupIfNotExists, addSourceToGroup, createStreamGroup } from '../../../lib/obsClient';
import { open } from 'sqlite';
import sqlite3 from 'sqlite3';
import path from 'path';
@ -44,7 +44,7 @@ async function fetchTeamInfo(teamId: number) {
});
const teamInfo = await db.get(
`SELECT team_name, group_name FROM ${teamsTableName} WHERE team_id = ?`,
`SELECT team_name, group_name, group_uuid FROM ${teamsTableName} WHERE team_id = ?`,
[teamId]
);
@ -130,16 +130,53 @@ export async function POST(request: NextRequest) {
const sourceExists = inputs.some((input: OBSInput) => input.inputName === obs_source_name);
if (!sourceExists) {
// Create/ensure group exists and add source to it
await createGroupIfNotExists(groupName);
await addSourceToGroup(groupName, obs_source_name, url);
// Create stream group with text overlay
const result = await createStreamGroup(groupName, name, teamInfo.team_name, url);
// Update team with group UUID if not set
if (!teamInfo.group_uuid) {
const FILE_DIRECTORY = path.resolve(process.env.FILE_DIRECTORY || './files');
const dbPath = path.join(FILE_DIRECTORY, 'sources.db');
const db = await open({
filename: dbPath,
driver: sqlite3.Database,
});
const teamsTableName = getTableName(BASE_TABLE_NAMES.TEAMS, {
year: 2025,
season: 'summer',
suffix: 'sat'
});
try {
// Get the scene UUID for the group
const obsClient = await getOBSClient();
const { scenes } = await obsClient.call('GetSceneList');
const scene = scenes.find((s: any) => s.sceneName === groupName);
if (scene) {
await db.run(
`UPDATE ${teamsTableName} SET group_name = ?, group_uuid = ? WHERE team_id = ?`,
[groupName, scene.sceneUuid, team_id]
);
console.log(`Updated team ${team_id} with group UUID: ${scene.sceneUuid}`);
} else {
console.log(`Scene "${groupName}" not found in OBS`);
}
} catch (error) {
console.error('Error updating team group UUID:', error);
} finally {
await db.close();
}
}
console.log(`OBS source "${obs_source_name}" created.`);
for (const screen of screens) {
try {
const streamGroupName = `${name.toLowerCase().replace(/\s+/g, '_')}_stream`;
await addSourceToSwitcher(screen, [
{ hidden: false, selected: false, value: obs_source_name },
{ hidden: false, selected: false, value: streamGroupName },
]);
} catch (error) {
if (error instanceof Error) {