diff --git a/app/api/__tests__/streams.test.ts b/app/api/__tests__/streams.test.ts index f57f060..41f6389 100644 --- a/app/api/__tests__/streams.test.ts +++ b/app/api/__tests__/streams.test.ts @@ -27,8 +27,6 @@ describe('/api/streams', () => { mockDb.all.mockResolvedValue(mockStreams); - const _response = await GET(); - expect(mockDb.all).toHaveBeenCalledWith( expect.stringContaining('SELECT * FROM') ); @@ -40,8 +38,6 @@ 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([]); }); @@ -50,8 +46,6 @@ 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' }, @@ -64,8 +58,6 @@ 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 c84747a..bd09053 100644 --- a/app/api/__tests__/teams.test.ts +++ b/app/api/__tests__/teams.test.ts @@ -46,8 +46,6 @@ describe('/api/teams', () => { mockDb.all.mockResolvedValue(mockTeams); - const _response = await GET(); - expect(mockDb.all).toHaveBeenCalledWith( expect.stringContaining('SELECT * FROM') ); @@ -59,8 +57,6 @@ 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([]); }); @@ -69,8 +65,6 @@ 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); }); @@ -80,8 +74,6 @@ 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 86a638d..a3ddc75 100644 --- a/app/api/counts/route.ts +++ b/app/api/counts/route.ts @@ -1,4 +1,3 @@ -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 a47825b..59016e9 100644 --- a/app/api/getActive/route.ts +++ b/app/api/getActive/route.ts @@ -1,4 +1,3 @@ -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 c4c7cd9..cd5bef4 100644 --- a/app/api/getTeamName/route.ts +++ b/app/api/getTeamName/route.ts @@ -1,4 +1,4 @@ -import { NextRequest, NextResponse } from 'next/server'; +import { NextRequest } 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 b52a74e..1df75ee 100644 --- a/app/api/streams/route.ts +++ b/app/api/streams/route.ts @@ -1,4 +1,3 @@ -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 96dd077..e2128a2 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 - const result = await db.run( + await db.run( `DELETE FROM ${TABLE_NAMES.TEAMS} WHERE team_id = ?`, [teamId] ); diff --git a/app/page.tsx b/app/page.tsx index 2f768aa..ee8dcf2 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,7 +1,6 @@ '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'; @@ -75,8 +74,11 @@ export default function Home() { activeRes.json() ]); - setStreams(streamsData.data); - setActiveSources(activeData.data); + // 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); } 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 2f23e7c..2e4f52f 100644 --- a/app/streams/page.tsx +++ b/app/streams/page.tsx @@ -66,9 +66,37 @@ 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; - setFormData((prev) => ({ ...prev, [name]: value })); + + // 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 })); + } // Clear validation error when user starts typing if (validationErrors[name]) { @@ -213,7 +241,7 @@ export default function AddStream() { {/* Twitch Username */}
{validationErrors.twitch_username && (
diff --git a/components/Footer.tsx b/components/Footer.tsx index b3f4b2f..9d2e03c 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -50,7 +50,9 @@ export default function Footer() { try { const response = await fetch('/api/counts'); const data = await response.json(); - setCounts(data.data); + // Handle both old and new API response formats + const countsData = data.success ? data.data : data; + setCounts(countsData); } catch (error) { console.error('Failed to fetch counts:', error); } @@ -79,12 +81,14 @@ export default function Footer() {
{/* Connection Status */}
-

OBS Studio

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

OBS Studio

+

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

+
{obsStatus && ( diff --git a/lib/__tests__/apiHelpers.test.ts b/lib/__tests__/apiHelpers.test.ts index 9bb97b4..1ad2609 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', () => { - const _response = createErrorResponse('Test Error'); + createErrorResponse('Test Error'); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ @@ -44,7 +44,7 @@ describe('apiHelpers', () => { }); it('creates error response with custom status and message', () => { - const _response = createErrorResponse('Test Error', 400, 'Custom message', { detail: 'extra' }); + 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' }; - const _response = createSuccessResponse(data); + 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' }; - const _response = createSuccessResponse(data, 201); + createSuccessResponse(data, 201); expect(NextResponse.json).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/lib/obsClient.js b/lib/obsClient.js index 4402708..26dfbe4 100644 --- a/lib/obsClient.js +++ b/lib/obsClient.js @@ -244,20 +244,6 @@ 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 { @@ -394,7 +380,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 (sceneError) { + } catch (error) { console.log(`Nested scene "${streamGroupName}" might already exist`); } @@ -457,7 +443,7 @@ async function createStreamGroup(groupName, streamName, teamName, url) { sourceName: colorSourceName }); console.log(`Added color source background "${colorSourceName}" to nested scene`); - } catch (e) { + } catch (error) { console.log('Color source background might already be in nested scene'); } @@ -467,7 +453,7 @@ async function createStreamGroup(groupName, streamName, teamName, url) { sourceName: textSourceName }); console.log(`Added text source "${textSourceName}" to nested scene`); - } catch (e) { + } catch (error) { console.log('Text source might already be in nested scene'); }