diff --git a/package.json b/package.json index 652ea16..cd471a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "odo-stream", - "version": "1.2.0", + "version": "1.2.1", "scripts": { "dev": "next dev", "build": "next build", diff --git a/src/app/api/live/route.ts b/src/app/api/live/route.ts index a76290e..c317da1 100644 --- a/src/app/api/live/route.ts +++ b/src/app/api/live/route.ts @@ -10,8 +10,13 @@ export async function GET(): Promise { `${process.env.RS_URL}/hls/live.stream.m3u8`, ) - // return response - return new NextResponse(response.body) + return new NextResponse(response.body, { + headers: { + 'Content-Type': + response.headers.get('Content-Type') || + 'application/vnd.apple.mpegurl', + }, + }) } catch (e: any) { throw new Error(`Failed to fetch playlist: ${e.message}`, { cause: e, diff --git a/src/app/api/segment/route.ts b/src/app/api/segment/route.ts index 5078d68..1449a7c 100644 --- a/src/app/api/segment/route.ts +++ b/src/app/api/segment/route.ts @@ -12,7 +12,12 @@ export async function GET(request: NextRequest): Promise { `${process.env.RS_URL}/hls${requestUrl.pathname}`, ) - return new NextResponse(response.body) + return new NextResponse(response.body, { + headers: { + 'Content-Type': + response.headers.get('Content-Type') || 'application/octet-stream', + }, + }) } catch (e: any) { throw new Error(`Failed to fetch segment: ${e.message}`, { cause: e, diff --git a/src/app/page.tsx b/src/app/page.tsx index edeeeb8..929787b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -20,7 +20,7 @@ async function getOnline() { const res: Response = await fetch(`${process.env.RS_URL}/v1/states`) const data = await res.json() - return data?.repeat_to_local_nginx?.type !== 'disconnected' + return data?.repeat_to_local_nginx?.type === 'connected' } catch (e: any) { throw new Error(`Failed to fetch stream state: ${e.message}`, { cause: e, diff --git a/src/components/player.tsx b/src/components/player.tsx index dae07b2..60977e1 100644 --- a/src/components/player.tsx +++ b/src/components/player.tsx @@ -11,8 +11,19 @@ export type PlayerProps = { } const hlsConfig = { - liveDurationInfinity: true, - lowLatencyMode: true, + autoStartLoad: true, // auto play on load + backBufferLength: 0, // eliminate back buffer + enableWorker: true, // use workers + initialLiveManifestSize: 2, // preload 2 chunks before autostart + liveDurationInfinity: true, // instructs browser that video is live + liveMaxLatencyDuration: 10, // if higher than this, adujst to liveSyncDuration + liveSyncDuration: 3, // how close to live to target? shorter than 3sec causes frequent buffering issues + lowLatencyMode: true, // enable low latency mode + maxBufferLength: 10, // limit forward buffer + maxLiveSyncPlaybackRate: 2, // if running behind, speed up video + nudgeMaxRetry: 5, // increase retries before buffer stalled + progressive: true, // use fetch instead of xhr + testBandwidth: false, // disable auto bandwidth estimation } export function Player({ className, src }: PlayerProps): React.ReactNode { diff --git a/src/middleware.ts b/src/middleware.ts index fb25f88..99b46d5 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -4,11 +4,15 @@ export async function middleware(request: NextRequest) { const requestUrl = new URL(request.url) const response: NextResponse = NextResponse.next() - // add CORS + // CORS response.headers.set('Access-Control-Allow-Credentials', 'true') response.headers.set('Access-Control-Allow-Origin', requestUrl.origin) response.headers.set('Access-Control-Allow-Methods', 'GET') + // Cache + response.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate') + response.headers.set('Pragma', 'no-cache') + return response }