feat: implement authentication context and hooks for user management
- Add AuthContext to manage user authentication state and token storage. - Create hooks for login, registration, and logout functionalities. - Implement dashboard layout with authentication check and loading state. - Enhance dashboard page with channel management features including create, edit, and delete channels. - Integrate API calls for channel operations and current broadcast retrieval. - Add stream URL resolution via server-side API route to handle redirects. - Update TV page to utilize new hooks for channel and broadcast management. - Refactor components for better organization and user experience. - Update application metadata for improved branding.
This commit is contained in:
56
k-tv-frontend/app/api/stream/[channelId]/route.ts
Normal file
56
k-tv-frontend/app/api/stream/[channelId]/route.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
// Server-side URL of the K-TV backend (never exposed to the browser).
|
||||
// Falls back to the public URL if the internal one isn't set.
|
||||
const API_URL =
|
||||
process.env.API_URL ??
|
||||
process.env.NEXT_PUBLIC_API_URL ??
|
||||
"http://localhost:4000/api/v1";
|
||||
|
||||
/**
|
||||
* GET /api/stream/[channelId]?token=<bearer>
|
||||
*
|
||||
* Resolves the backend's 307 stream redirect and returns the final
|
||||
* Jellyfin URL as JSON. Browsers can't read the Location header from a
|
||||
* redirected fetch, so this server-side route does it for them.
|
||||
*
|
||||
* Returns:
|
||||
* 200 { url: string } — stream URL ready to use as <video src>
|
||||
* 204 — channel is in a gap (no-signal)
|
||||
* 401 — missing token
|
||||
* 502 — backend error
|
||||
*/
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ channelId: string }> },
|
||||
) {
|
||||
const { channelId } = await params;
|
||||
const token = request.nextUrl.searchParams.get("token");
|
||||
|
||||
if (!token) {
|
||||
return new Response(null, { status: 401 });
|
||||
}
|
||||
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch(`${API_URL}/channels/${channelId}/stream`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
redirect: "manual",
|
||||
});
|
||||
} catch {
|
||||
return new Response(null, { status: 502 });
|
||||
}
|
||||
|
||||
if (res.status === 204) {
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
if (res.status === 307 || res.status === 302 || res.status === 301) {
|
||||
const location = res.headers.get("Location");
|
||||
if (location) {
|
||||
return Response.json({ url: location });
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(null, { status: 502 });
|
||||
}
|
||||
Reference in New Issue
Block a user