diff --git a/app/api/streams/route.ts b/app/api/streams/route.ts index ab368e3..b52a74e 100644 --- a/app/api/streams/route.ts +++ b/app/api/streams/route.ts @@ -1,13 +1,20 @@ import { NextResponse } from 'next/server'; import { getDatabase } from '../../../lib/database'; -import { Stream } from '@/types'; +import { StreamWithTeam } from '@/types'; import { TABLE_NAMES } from '../../../lib/constants'; import { createSuccessResponse, createDatabaseError, withErrorHandling } from '../../../lib/apiHelpers'; async function getStreamsHandler() { try { const db = await getDatabase(); - const streams: Stream[] = await db.all(`SELECT * FROM ${TABLE_NAMES.STREAMS}`); + const streams: StreamWithTeam[] = await db.all(` + SELECT + s.*, + t.team_name, + t.group_name + FROM ${TABLE_NAMES.STREAMS} s + LEFT JOIN ${TABLE_NAMES.TEAMS} t ON s.team_id = t.team_id + `); return createSuccessResponse(streams); } catch (error) { return createDatabaseError('fetch streams', error); diff --git a/app/page.tsx b/app/page.tsx index d8d9eae..9b6422d 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -7,17 +7,12 @@ import { useToast } from '@/lib/useToast'; import { ToastContainer } from '@/components/Toast'; import { useActiveSourceLookup, useDebounce, PerformanceMonitor } from '@/lib/performance'; -type Stream = { - id: number; - name: string; - obs_source_name: string; - url: string; -}; +import { StreamWithTeam } from '@/types'; type ScreenType = 'large' | 'left' | 'right' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'; export default function Home() { - const [streams, setStreams] = useState([]); + const [streams, setStreams] = useState([]); const [activeSources, setActiveSources] = useState>({ large: null, left: null, diff --git a/lib/performance.ts b/lib/performance.ts index 4355393..8e71fca 100644 --- a/lib/performance.ts +++ b/lib/performance.ts @@ -38,13 +38,17 @@ export function useThrottle unknown>( } // Memoized stream lookup utilities -export function createStreamLookupMaps(streams: Array<{ id: number; obs_source_name: string; name: string }>) { +export function createStreamLookupMaps(streams: Array<{ id: number; obs_source_name: string; name: string; team_name?: string; group_name?: string | null }>) { const sourceToIdMap = new Map(); - const idToStreamMap = new Map(); + const idToStreamMap = new Map(); streams.forEach(stream => { // Generate stream group name to match what's written to files - const streamGroupName = `${stream.name.toLowerCase().replace(/\s+/g, '_')}_stream`; + // Format: {team_name}_{stream_name}_stream (matching obsClient.js logic) + const cleanTeamName = stream.team_name ? stream.team_name.toLowerCase().replace(/\s+/g, '_') : 'unknown'; + const cleanStreamName = stream.name.toLowerCase().replace(/\s+/g, '_'); + const streamGroupName = `${cleanTeamName}_${cleanStreamName}_stream`; + sourceToIdMap.set(streamGroupName, stream.id); idToStreamMap.set(stream.id, stream); }); @@ -53,7 +57,7 @@ export function createStreamLookupMaps(streams: Array<{ id: number; obs_source_n } // Hook version for React components -export function useStreamLookupMaps(streams: Array<{ id: number; obs_source_name: string; name: string }>) { +export function useStreamLookupMaps(streams: Array<{ id: number; obs_source_name: string; name: string; team_name?: string; group_name?: string | null }>) { return useMemo(() => { return createStreamLookupMaps(streams); }, [streams]); @@ -61,7 +65,7 @@ export function useStreamLookupMaps(streams: Array<{ id: number; obs_source_name // Efficient active source lookup export function useActiveSourceLookup( - streams: Array<{ id: number; obs_source_name: string; name: string }>, + streams: Array<{ id: number; obs_source_name: string; name: string; team_name?: string; group_name?: string | null }>, activeSources: Record ) { const { sourceToIdMap } = useStreamLookupMaps(streams);