diff --git a/frontend/src/lib/components/StreamPlayer.svelte b/frontend/src/lib/components/StreamPlayer.svelte index 60ca496..754df2b 100644 --- a/frontend/src/lib/components/StreamPlayer.svelte +++ b/frontend/src/lib/components/StreamPlayer.svelte @@ -12,6 +12,17 @@ const STREAM_PORT = import.meta.env.VITE_STREAM_PORT || '8088'; + // Helper for dynamic host detection + function getStreamHost() { + if (!browser) return 'localhost'; + return window.location.hostname; + } + + function getStreamProtocol() { + if (!browser) return 'http'; + return window.location.protocol === 'https:' ? 'https' : 'http'; + } + let player; let playerElement; let viewerToken = null; @@ -111,10 +122,12 @@ function initializePlayer() { if (!playerElement || !window.OvenPlayer || !viewerToken || !actualStreamKey) return; + const host = getStreamHost(); + const proto = getStreamProtocol(); const sources = [ { type: 'hls', - file: `http://localhost:${STREAM_PORT}/app/${actualStreamKey}/llhls.m3u8?token=${viewerToken}`, + file: `${proto}://${host}:${STREAM_PORT}/app/${actualStreamKey}/llhls.m3u8?token=${viewerToken}`, label: 'LLHLS' } ]; diff --git a/frontend/src/lib/components/StreamTileOverlay.svelte b/frontend/src/lib/components/StreamTileOverlay.svelte index cc4d0d6..089e47f 100644 --- a/frontend/src/lib/components/StreamTileOverlay.svelte +++ b/frontend/src/lib/components/StreamTileOverlay.svelte @@ -6,6 +6,17 @@ const STREAM_PORT = import.meta.env.VITE_STREAM_PORT || '8088'; + // Helper for dynamic host detection + function getStreamHost() { + if (!browser) return 'localhost'; + return window.location.hostname; + } + + function getStreamProtocol() { + if (!browser) return 'http'; + return window.location.protocol === 'https:' ? 'https' : 'http'; + } + let players = {}; let viewerTokens = {}; let offlineStreams = {}; // Track which streams are offline @@ -127,10 +138,12 @@ const isMuted = $streamTiles.unmutedStream !== stream.streamKey; + const host = getStreamHost(); + const proto = getStreamProtocol(); const sources = [ { type: 'hls', - file: `http://localhost:${STREAM_PORT}/app/${stream.streamKey}/llhls.m3u8?token=${token}`, + file: `${proto}://${host}:${STREAM_PORT}/app/${stream.streamKey}/llhls.m3u8?token=${token}`, label: 'LLHLS' } ]; diff --git a/frontend/src/lib/stores/nakama.js b/frontend/src/lib/stores/nakama.js index a6963cb..2bda4d6 100644 --- a/frontend/src/lib/stores/nakama.js +++ b/frontend/src/lib/stores/nakama.js @@ -1,11 +1,33 @@ import { writable, derived } from 'svelte/store'; import { browser } from '$app/environment'; -// Nakama configuration from environment +// Nakama configuration - dynamically detect from browser location for production const NAKAMA_SERVER_KEY = import.meta.env.VITE_NAKAMA_SERVER_KEY || 'defaultkey'; -const NAKAMA_HOST = import.meta.env.VITE_NAKAMA_HOST || 'localhost'; -const NAKAMA_PORT = import.meta.env.VITE_NAKAMA_PORT || '80'; -const NAKAMA_USE_SSL = import.meta.env.VITE_NAKAMA_USE_SSL === 'true'; + +// Dynamically detect host/protocol from browser location +// This ensures production uses the correct domain and SSL settings +function getNakamaConfig() { + if (!browser) { + // SSR fallback - use env vars or defaults + return { + host: import.meta.env.VITE_NAKAMA_HOST || 'localhost', + port: import.meta.env.VITE_NAKAMA_PORT || '80', + useSSL: import.meta.env.VITE_NAKAMA_USE_SSL === 'true' + }; + } + // Browser: use current page's host/protocol + const isSSL = window.location.protocol === 'https:'; + return { + host: window.location.hostname, + port: isSSL ? '443' : (window.location.port || '80'), + useSSL: isSSL + }; +} + +const nakamaConfig = getNakamaConfig(); +const NAKAMA_HOST = nakamaConfig.host; +const NAKAMA_PORT = nakamaConfig.port; +const NAKAMA_USE_SSL = nakamaConfig.useSSL; // Polling interval for games lists (ms) export const GAMES_POLL_INTERVAL = 30000; diff --git a/frontend/src/lib/stores/watchSync.js b/frontend/src/lib/stores/watchSync.js index e4ba1c0..24883d7 100644 --- a/frontend/src/lib/stores/watchSync.js +++ b/frontend/src/lib/stores/watchSync.js @@ -1,7 +1,16 @@ import { writable, derived, get } from 'svelte/store'; import { browser } from '$app/environment'; -const WS_URL = import.meta.env.VITE_WS_URL || 'ws://localhost/ws'; +// Dynamically detect WebSocket URL from browser location +function getWsUrl() { + if (!browser) { + return import.meta.env.VITE_WS_URL || 'ws://localhost/ws'; + } + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + return `${protocol}//${window.location.host}/ws`; +} + +const WS_URL = getWsUrl(); const SYNC_INTERVAL = 5000; // Sync every 5 seconds (server pushes every 1s anyway) const DRIFT_THRESHOLD = 2; // Seek if drift > 2 seconds (CyTube-style tight sync) const LEAD_IN_DURATION = 3000; // 3 seconds lead-in for buffering diff --git a/frontend/src/lib/websocket.js b/frontend/src/lib/websocket.js index 0c2f941..283bc2e 100644 --- a/frontend/src/lib/websocket.js +++ b/frontend/src/lib/websocket.js @@ -1,3 +1,5 @@ +import { browser } from '$app/environment'; + let ws = null; let reconnectTimeout = null; let reconnectAttempts = 0; @@ -5,7 +7,17 @@ const MAX_RECONNECT_ATTEMPTS = 10; const BASE_RECONNECT_DELAY = 1000; // 1 second const MAX_RECONNECT_DELAY = 30000; // 30 seconds -const WS_URL = import.meta.env.VITE_WS_URL || 'ws://localhost/ws'; +// Dynamically detect WebSocket URL from browser location +// This ensures production uses wss:// and the correct host +function getWebSocketURL() { + if (!browser) { + return import.meta.env.VITE_WS_URL || 'ws://localhost/ws'; + } + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + return `${protocol}//${window.location.host}/ws`; +} + +const WS_URL = getWebSocketURL(); /** * Calculate exponential backoff delay with jitter diff --git a/frontend/src/routes/[realm]/live/+page.svelte b/frontend/src/routes/[realm]/live/+page.svelte index c47dc94..729fdaf 100644 --- a/frontend/src/routes/[realm]/live/+page.svelte +++ b/frontend/src/routes/[realm]/live/+page.svelte @@ -29,7 +29,24 @@ } const STREAM_PORT = import.meta.env.VITE_STREAM_PORT || '8088'; - + const WEBRTC_PORT = import.meta.env.VITE_WEBRTC_PORT || '3333'; + + // Helper functions for dynamic host/protocol detection + function getStreamHost() { + if (!browser) return 'localhost'; + return window.location.hostname; + } + + function getStreamProtocol(secure = false) { + if (!browser) return secure ? 'https' : 'http'; + return window.location.protocol === 'https:' ? 'https' : 'http'; + } + + function getWsProtocol() { + if (!browser) return 'ws'; + return window.location.protocol === 'https:' ? 'wss' : 'ws'; + } + let player; let realm = null; let streamKey = ''; @@ -295,23 +312,28 @@ } const sources = []; - + if (streamKey) { + // Dynamic URLs based on current page host/protocol + const host = getStreamHost(); + const httpProto = getStreamProtocol(); + const wsProto = getWsProtocol(); + // Add all sources - LLHLS first (default), then HLS, then WebRTC as fallback sources.push( { type: 'hls', - file: `http://localhost:${STREAM_PORT}/app/${streamKey}/llhls.m3u8?token=${viewerToken}`, + file: `${httpProto}://${host}:${STREAM_PORT}/app/${streamKey}/llhls.m3u8?token=${viewerToken}`, label: 'LLHLS (Low Latency)' }, { type: 'hls', - file: `http://localhost:${STREAM_PORT}/app/${streamKey}/ts:playlist.m3u8?token=${viewerToken}`, + file: `${httpProto}://${host}:${STREAM_PORT}/app/${streamKey}/ts:playlist.m3u8?token=${viewerToken}`, label: 'HLS (Standard)' }, { type: 'webrtc', - file: `ws://localhost:3333/app/${streamKey}`, + file: `${wsProto}://${host}:${WEBRTC_PORT}/app/${streamKey}`, label: 'WebRTC (Ultra Low Latency)' } ); diff --git a/frontend/src/routes/forums/[slug]/+page.svelte b/frontend/src/routes/forums/[slug]/+page.svelte index c8da091..d578667 100644 --- a/frontend/src/routes/forums/[slug]/+page.svelte +++ b/frontend/src/routes/forums/[slug]/+page.svelte @@ -244,7 +244,7 @@ const formData = new FormData(); formData.append('banner', file); - const response = await fetch(`/api/forums/${$page.params.slug}/banner`, { + const response = await fetch(`/api/forums/${forum.id}/banner`, { method: 'POST', credentials: 'include', body: formData @@ -274,7 +274,7 @@ bannerError = ''; try { - const response = await fetch(`/api/forums/${$page.params.slug}/banner`, { + const response = await fetch(`/api/forums/${forum.id}/banner`, { method: 'DELETE', credentials: 'include' }); @@ -351,7 +351,7 @@ bannerError = ''; try { - const response = await fetch(`/api/forums/${$page.params.slug}/banner/position`, { + const response = await fetch(`/api/forums/${forum.id}/banner/position`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', @@ -396,7 +396,7 @@ bannerError = ''; try { - const response = await fetch(`/api/forums/${$page.params.slug}/title-color`, { + const response = await fetch(`/api/forums/${forum.id}/title-color`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', diff --git a/frontend/src/routes/my-realms/+page.svelte b/frontend/src/routes/my-realms/+page.svelte index f01768a..286d928 100644 --- a/frontend/src/routes/my-realms/+page.svelte +++ b/frontend/src/routes/my-realms/+page.svelte @@ -1,10 +1,14 @@