diff --git a/app/api/__tests__/streams.test.ts b/app/api/__tests__/streams.test.ts index 41f6389..f57f060 100644 --- a/app/api/__tests__/streams.test.ts +++ b/app/api/__tests__/streams.test.ts @@ -27,6 +27,8 @@ describe('/api/streams', () => { mockDb.all.mockResolvedValue(mockStreams); + const _response = await GET(); + expect(mockDb.all).toHaveBeenCalledWith( expect.stringContaining('SELECT * FROM') ); @@ -38,6 +40,8 @@ describe('/api/streams', () => { it('returns empty array when no streams exist', async () => { mockDb.all.mockResolvedValue([]); + const _response = await GET(); + const { NextResponse } = require('next/server'); expect(NextResponse.json).toHaveBeenCalledWith([]); }); @@ -46,6 +50,8 @@ describe('/api/streams', () => { const dbError = new Error('Database connection failed'); mockDb.all.mockRejectedValue(dbError); + const _response = await GET(); + const { NextResponse } = require('next/server'); expect(NextResponse.json).toHaveBeenCalledWith( { error: 'Failed to fetch streams' }, @@ -58,6 +64,8 @@ describe('/api/streams', () => { const { getDatabase } = require('@/lib/database'); getDatabase.mockRejectedValue(connectionError); + const _response = await GET(); + const { NextResponse } = require('next/server'); expect(NextResponse.json).toHaveBeenCalledWith( { error: 'Failed to fetch streams' }, diff --git a/app/api/__tests__/teams.test.ts b/app/api/__tests__/teams.test.ts index bd09053..c84747a 100644 --- a/app/api/__tests__/teams.test.ts +++ b/app/api/__tests__/teams.test.ts @@ -46,6 +46,8 @@ describe('/api/teams', () => { mockDb.all.mockResolvedValue(mockTeams); + const _response = await GET(); + expect(mockDb.all).toHaveBeenCalledWith( expect.stringContaining('SELECT * FROM') ); @@ -57,6 +59,8 @@ describe('/api/teams', () => { it('returns empty array when no teams exist', async () => { mockDb.all.mockResolvedValue([]); + const _response = await GET(); + const { createSuccessResponse } = require('@/lib/apiHelpers'); expect(createSuccessResponse).toHaveBeenCalledWith([]); }); @@ -65,6 +69,8 @@ describe('/api/teams', () => { const dbError = new Error('Table does not exist'); mockDb.all.mockRejectedValue(dbError); + const _response = await GET(); + const { createDatabaseError } = require('@/lib/apiHelpers'); expect(createDatabaseError).toHaveBeenCalledWith('fetch teams', dbError); }); @@ -74,6 +80,8 @@ describe('/api/teams', () => { const { getDatabase } = require('@/lib/database'); getDatabase.mockRejectedValue(connectionError); + const _response = await GET(); + const { createDatabaseError } = require('@/lib/apiHelpers'); expect(createDatabaseError).toHaveBeenCalledWith('fetch teams', connectionError); }); diff --git a/app/api/counts/route.ts b/app/api/counts/route.ts index a3ddc75..86a638d 100644 --- a/app/api/counts/route.ts +++ b/app/api/counts/route.ts @@ -1,3 +1,4 @@ +import { NextResponse } from 'next/server'; import { getDatabase } from '../../../lib/database'; import { TABLE_NAMES } from '../../../lib/constants'; import { createSuccessResponse, createDatabaseError, withErrorHandling } from '../../../lib/apiHelpers'; diff --git a/app/api/getActive/route.ts b/app/api/getActive/route.ts index 59016e9..a47825b 100644 --- a/app/api/getActive/route.ts +++ b/app/api/getActive/route.ts @@ -1,3 +1,4 @@ +import { NextResponse } from 'next/server'; import fs from 'fs'; import path from 'path'; import { createSuccessResponse, createErrorResponse, withErrorHandling } from '../../../lib/apiHelpers'; diff --git a/app/api/getTeamName/route.ts b/app/api/getTeamName/route.ts index cd5bef4..c4c7cd9 100644 --- a/app/api/getTeamName/route.ts +++ b/app/api/getTeamName/route.ts @@ -1,4 +1,4 @@ -import { NextRequest } from 'next/server'; +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'; diff --git a/app/api/streams/route.ts b/app/api/streams/route.ts index 1df75ee..b52a74e 100644 --- a/app/api/streams/route.ts +++ b/app/api/streams/route.ts @@ -1,3 +1,4 @@ +import { NextResponse } from 'next/server'; import { getDatabase } from '../../../lib/database'; import { StreamWithTeam } from '@/types'; import { TABLE_NAMES } from '../../../lib/constants'; diff --git a/app/api/teams/[teamId]/route.ts b/app/api/teams/[teamId]/route.ts index e2128a2..96dd077 100644 --- a/app/api/teams/[teamId]/route.ts +++ b/app/api/teams/[teamId]/route.ts @@ -126,7 +126,7 @@ export async function DELETE( ); // Delete the team - await db.run( + const result = await db.run( `DELETE FROM ${TABLE_NAMES.TEAMS} WHERE team_id = ?`, [teamId] ); diff --git a/app/page.tsx b/app/page.tsx index ee8dcf2..2f768aa 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect, useMemo, useCallback } from 'react'; +import Link from 'next/link'; import Dropdown from '@/components/Dropdown'; import { useToast } from '@/lib/useToast'; import { ToastContainer } from '@/components/Toast'; @@ -74,11 +75,8 @@ export default function Home() { activeRes.json() ]); - // Handle both old and new API response formats - const streams = streamsData.success ? streamsData.data : streamsData; - const activeSources = activeData.success ? activeData.data : activeData; - setStreams(streams); - setActiveSources(activeSources); + setStreams(streamsData.data); + setActiveSources(activeData.data); } catch (error) { console.error('Error fetching data:', error); showError('Failed to Load Data', 'Could not fetch streams. Please refresh the page.'); diff --git a/app/streams/page.tsx b/app/streams/page.tsx index 2e4f52f..2f23e7c 100644 --- a/app/streams/page.tsx +++ b/app/streams/page.tsx @@ -66,37 +66,9 @@ export default function AddStream() { }, [fetchData]); - const extractTwitchUsername = (input: string): string => { - const trimmed = input.trim(); - - // If it's a URL, extract username - const urlPatterns = [ - /^https?:\/\/(www\.)?twitch\.tv\/([a-zA-Z0-9_]+)\/?$/, - /^(www\.)?twitch\.tv\/([a-zA-Z0-9_]+)\/?$/, - /^twitch\.tv\/([a-zA-Z0-9_]+)\/?$/ - ]; - - for (const pattern of urlPatterns) { - const match = trimmed.match(pattern); - if (match) { - return match[match.length - 1]; // Last capture group is always the username - } - } - - // Otherwise assume it's just a username - return trimmed; - }; - const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; - - // Special handling for twitch_username to extract from URL if needed - if (name === 'twitch_username') { - const username = extractTwitchUsername(value); - setFormData((prev) => ({ ...prev, [name]: username })); - } else { - setFormData((prev) => ({ ...prev, [name]: value })); - } + setFormData((prev) => ({ ...prev, [name]: value })); // Clear validation error when user starts typing if (validationErrors[name]) { @@ -241,7 +213,7 @@ export default function AddStream() { {/* Twitch Username */}
{validationErrors.twitch_username && (
diff --git a/components/Footer.tsx b/components/Footer.tsx index 9d2e03c..b3f4b2f 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -50,9 +50,7 @@ export default function Footer() { try { const response = await fetch('/api/counts'); const data = await response.json(); - // Handle both old and new API response formats - const countsData = data.success ? data.data : data; - setCounts(countsData); + setCounts(data.data); } catch (error) { console.error('Failed to fetch counts:', error); } @@ -81,14 +79,12 @@ export default function Footer() {
{/* Connection Status */}
-
+

OBS Studio

+
-
-

OBS Studio

-

- {obsStatus?.connected ? 'Connected' : 'Disconnected'} -

-
+ + {obsStatus?.connected ? 'Connected' : 'Disconnected'} +
{obsStatus && ( diff --git a/lib/__tests__/apiHelpers.test.ts b/lib/__tests__/apiHelpers.test.ts index 1ad2609..9bb97b4 100644 --- a/lib/__tests__/apiHelpers.test.ts +++ b/lib/__tests__/apiHelpers.test.ts @@ -32,7 +32,7 @@ describe('apiHelpers', () => { describe('createErrorResponse', () => { it('creates error response with default status 500', () => { - createErrorResponse('Test Error'); + const _response = createErrorResponse('Test Error'); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ @@ -44,7 +44,7 @@ describe('apiHelpers', () => { }); it('creates error response with custom status and message', () => { - createErrorResponse('Test Error', 400, 'Custom message', { detail: 'extra' }); + const _response = createErrorResponse('Test Error', 400, 'Custom message', { detail: 'extra' }); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ @@ -81,7 +81,7 @@ describe('apiHelpers', () => { describe('createSuccessResponse', () => { it('creates success response with default status 200', () => { const data = { test: 'data' }; - createSuccessResponse(data); + const _response = createSuccessResponse(data); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ @@ -95,7 +95,7 @@ describe('apiHelpers', () => { it('creates success response with custom status', () => { const data = { id: 1, name: 'test' }; - createSuccessResponse(data, 201); + const _response = createSuccessResponse(data, 201); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/lib/obsClient.js b/lib/obsClient.js index 26dfbe4..4402708 100644 --- a/lib/obsClient.js +++ b/lib/obsClient.js @@ -244,6 +244,20 @@ async function getAvailableTextInputKind() { } } +async function inspectTextSourceProperties(inputKind) { + try { + const obsClient = await getOBSClient(); + + // Get the default properties for this input kind + const { inputProperties } = await obsClient.call('GetInputDefaultSettings', { inputKind }); + console.log(`Default properties for ${inputKind}:`, JSON.stringify(inputProperties, null, 2)); + + return inputProperties; + } catch (error) { + console.error('Error inspecting text source properties:', error.message); + return null; + } +} async function createTextSource(sceneName, textSourceName, text) { try { @@ -380,7 +394,7 @@ async function createStreamGroup(groupName, streamName, teamName, url) { try { await obsClient.call('CreateScene', { sceneName: streamGroupName }); console.log(`Created nested scene "${streamGroupName}" for stream grouping`); - } catch (error) { + } catch (sceneError) { console.log(`Nested scene "${streamGroupName}" might already exist`); } @@ -443,7 +457,7 @@ async function createStreamGroup(groupName, streamName, teamName, url) { sourceName: colorSourceName }); console.log(`Added color source background "${colorSourceName}" to nested scene`); - } catch (error) { + } catch (e) { console.log('Color source background might already be in nested scene'); } @@ -453,7 +467,7 @@ async function createStreamGroup(groupName, streamName, teamName, url) { sourceName: textSourceName }); console.log(`Added text source "${textSourceName}" to nested scene`); - } catch (error) { + } catch (e) { console.log('Text source might already be in nested scene'); }