diff --git a/app/api/addStream/route.ts b/app/api/addStream/route.ts index 9347106..4bb22d6 100644 --- a/app/api/addStream/route.ts +++ b/app/api/addStream/route.ts @@ -4,7 +4,7 @@ import { connectToOBS, getOBSClient, disconnectFromOBS, addSourceToSwitcher, cre import { open } from 'sqlite'; import sqlite3 from 'sqlite3'; import path from 'path'; -import { getTableName, BASE_TABLE_NAMES, SOURCE_SWITCHER_NAMES } from '../../../lib/constants'; +import { getTableName, BASE_TABLE_NAMES } from '../../../lib/constants'; interface OBSClient { call: (method: string, params?: Record) => Promise>; @@ -18,7 +18,15 @@ inputName: string; interface GetInputListResponse { inputs: OBSInput[]; } -const screens = SOURCE_SWITCHER_NAMES; +const screens = [ + 'ss_large', + 'ss_left', + 'ss_right', + 'ss_top_left', + 'ss_top_right', + 'ss_bottom_left', + 'ss_bottom_right', +]; async function fetchTeamInfo(teamId: number) { const FILE_DIRECTORY = path.resolve(process.env.FILE_DIRECTORY || './files'); diff --git a/app/api/getTeamName/route.ts b/app/api/getTeamName/route.ts index c4c7cd9..d364306 100644 --- a/app/api/getTeamName/route.ts +++ b/app/api/getTeamName/route.ts @@ -1,32 +1,38 @@ import { NextRequest, NextResponse } from 'next/server'; import { getDatabase } from '../../../lib/database'; -import { TABLE_NAMES } from '../../../lib/constants'; -import { createErrorResponse, createSuccessResponse, createDatabaseError, withErrorHandling } from '../../../lib/apiHelpers'; - -async function getTeamNameHandler(request: NextRequest) { - // Extract the team_id from the query string - const { searchParams } = new URL(request.url); - const teamId = searchParams.get('team_id'); - - if (!teamId) { - return createErrorResponse('Missing team_id', 400, 'team_id parameter is required'); - } +export async function GET(request: NextRequest) { try { + // Extract the team_id from the query string + const { searchParams } = new URL(request.url); + const teamId = searchParams.get('team_id'); + + if (!teamId) { + return NextResponse.json( + { error: 'Missing team_id' }, + { status: 400 } + ); + } + const db = await getDatabase(); const team = await db.get( - `SELECT team_name FROM ${TABLE_NAMES.TEAMS} WHERE team_id = ?`, + 'SELECT team_name FROM teams_2025_spring_adr WHERE team_id = ?', [teamId] ); if (!team) { - return createErrorResponse('Team not found', 404, `No team found with ID: ${teamId}`); + return NextResponse.json( + { error: 'Team not found' }, + { status: 404 } + ); } - return createSuccessResponse({ team_name: team.team_name }); + return NextResponse.json({ team_name: team.team_name }); } catch (error) { - return createDatabaseError('fetch team name', error); + console.error('Error fetching team name:', error instanceof Error ? error.message : String(error)); + return NextResponse.json( + { error: 'Failed to fetch team name' }, + { status: 500 } + ); } } - -export const GET = withErrorHandling(getTeamNameHandler); diff --git a/app/api/streams/route.ts b/app/api/streams/route.ts index ab368e3..000106f 100644 --- a/app/api/streams/route.ts +++ b/app/api/streams/route.ts @@ -2,16 +2,17 @@ import { NextResponse } from 'next/server'; import { getDatabase } from '../../../lib/database'; import { Stream } from '@/types'; import { TABLE_NAMES } from '../../../lib/constants'; -import { createSuccessResponse, createDatabaseError, withErrorHandling } from '../../../lib/apiHelpers'; -async function getStreamsHandler() { - try { +export async function GET() { +try { const db = await getDatabase(); const streams: Stream[] = await db.all(`SELECT * FROM ${TABLE_NAMES.STREAMS}`); - return createSuccessResponse(streams); - } catch (error) { - return createDatabaseError('fetch streams', error); - } + return NextResponse.json(streams); +} catch (error) { + console.error('Error fetching streams:', error); + return NextResponse.json( + { error: 'Failed to fetch streams' }, + { status: 500 } + ); +} } - -export const GET = withErrorHandling(getStreamsHandler); diff --git a/lib/constants.ts b/lib/constants.ts index e756185..c67808e 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -40,29 +40,3 @@ export const TABLE_NAMES = { TEAMS: getTableName(BASE_TABLE_NAMES.TEAMS), } as const; -// Screen position constants -export const SCREEN_POSITIONS = [ - 'large', - 'left', - 'right', - 'topLeft', - 'topRight', - 'bottomLeft', - 'bottomRight' -] as const; - -export const SOURCE_SWITCHER_NAMES = [ - 'ss_large', - 'ss_left', - 'ss_right', - 'ss_top_left', - 'ss_top_right', - 'ss_bottom_left', - 'ss_bottom_right' -] as const; - -// OBS utility functions -export function cleanObsName(name: string): string { - return name.toLowerCase().replace(/\s+/g, '_'); -} - diff --git a/lib/obsClient.js b/lib/obsClient.js index 9adfe80..4390568 100644 --- a/lib/obsClient.js +++ b/lib/obsClient.js @@ -1,5 +1,4 @@ const { OBSWebSocket } = require('obs-websocket-js'); -const { cleanObsName, SOURCE_SWITCHER_NAMES, SCREEN_POSITIONS } = require('./constants'); let obs = null; let isConnecting = false; @@ -281,7 +280,7 @@ async function createTextSource(sceneName, textSourceName, text) { inputName: colorSourceName, inputKind: 'color_source_v3', // Use v3 if available, fallback handled below inputSettings: { - color: 0xFF4B2B00, // Background color #002b4b in ABGR format + color: 0xFF002B4B, // Background color #002b4b width: 800, // Width to accommodate text height: 100 // Height for text background } @@ -293,7 +292,7 @@ async function createTextSource(sceneName, textSourceName, text) { inputName: colorSourceName, inputKind: 'color_source_v2', inputSettings: { - color: 0xFF4B2B00, + color: 0xFF002B4B, width: 800, height: 100 } @@ -305,7 +304,7 @@ async function createTextSource(sceneName, textSourceName, text) { inputName: colorSourceName, inputKind: 'color_source', inputSettings: { - color: 0xFF4B2B00, + color: 0xFF002B4B, width: 800, height: 100 } @@ -359,7 +358,7 @@ async function createTextSource(sceneName, textSourceName, text) { outline: true, outline_color: 0xFF000000, // Black outline outline_size: 4, - bk_color: 0xFF4B2B00, // Background color #002b4b in ABGR format + bk_color: 0xFF002B4B, // Background color #002b4b bk_opacity: 255 // Full opacity background }; @@ -384,11 +383,11 @@ async function createStreamGroup(groupName, streamName, teamName, url) { // Ensure team scene exists await createGroupIfNotExists(groupName); - const cleanGroupName = cleanObsName(groupName); - const cleanStreamName = cleanObsName(streamName); + const cleanGroupName = groupName.toLowerCase().replace(/\s+/g, '_'); + const cleanStreamName = streamName.toLowerCase().replace(/\s+/g, '_'); const streamGroupName = `${cleanGroupName}_${cleanStreamName}_stream`; const sourceName = `${cleanGroupName}_${cleanStreamName}`; - const textSourceName = cleanObsName(teamName) + '_text'; + const textSourceName = teamName.toLowerCase().replace(/\s+/g, '_') + '_text'; // Create a nested scene for this stream (acts as a group) try { @@ -595,11 +594,11 @@ async function deleteStreamComponents(streamName, teamName, groupName) { try { const obsClient = await getOBSClient(); - const cleanGroupName = cleanObsName(groupName); - const cleanStreamName = cleanObsName(streamName); + const cleanGroupName = groupName.toLowerCase().replace(/\s+/g, '_'); + const cleanStreamName = streamName.toLowerCase().replace(/\s+/g, '_'); const streamGroupName = `${cleanGroupName}_${cleanStreamName}_stream`; const sourceName = `${cleanGroupName}_${cleanStreamName}`; - const textSourceName = cleanObsName(teamName) + '_text'; + const textSourceName = teamName.toLowerCase().replace(/\s+/g, '_') + '_text'; console.log(`Starting comprehensive deletion for stream "${streamName}"`); console.log(`Components to delete: scene="${streamGroupName}", source="${sourceName}"`); @@ -651,7 +650,15 @@ async function deleteStreamComponents(streamName, teamName, groupName) { } // 5. Remove from all source switchers - const screens = SOURCE_SWITCHER_NAMES; + const screens = [ + 'ss_large', + 'ss_left', + 'ss_right', + 'ss_top_left', + 'ss_top_right', + 'ss_bottom_left', + 'ss_bottom_right' + ]; for (const screen of screens) { try { @@ -716,7 +723,15 @@ async function clearTextFilesForStream(streamGroupName) { try { const FILE_DIRECTORY = path.resolve(process.env.FILE_DIRECTORY || './files'); - const screens = SCREEN_POSITIONS; + const screens = [ + 'large', + 'left', + 'right', + 'topLeft', + 'topRight', + 'bottomLeft', + 'bottomRight' + ]; let clearedFiles = []; @@ -770,7 +785,7 @@ async function deleteTeamComponents(teamName, groupName) { } // 2. Delete the team text source (shared across all team streams) - const textSourceName = cleanObsName(teamName) + '_text'; + const textSourceName = teamName.toLowerCase().replace(/\s+/g, '_') + '_text'; try { const { inputs } = await obsClient.call('GetInputList'); const textSource = inputs.find(input => input.inputName === textSourceName); @@ -786,7 +801,7 @@ async function deleteTeamComponents(teamName, groupName) { // 3. Get all scenes to check for nested stream scenes try { const { scenes } = await obsClient.call('GetSceneList'); - const cleanGroupName = cleanObsName(groupName || teamName); + const cleanGroupName = (groupName || teamName).toLowerCase().replace(/\s+/g, '_'); // Find all nested stream scenes for this team const streamScenes = scenes.filter(scene => @@ -812,7 +827,7 @@ async function deleteTeamComponents(teamName, groupName) { // 4. Remove any browser sources associated with this team try { const { inputs } = await obsClient.call('GetInputList'); - const cleanGroupName = cleanObsName(groupName || teamName); + const cleanGroupName = (groupName || teamName).toLowerCase().replace(/\s+/g, '_'); // Find all browser sources for this team const teamBrowserSources = inputs.filter(input =>