diff --git a/packages/web/src/components/ProfileSidebar.tsx b/packages/web/src/components/ProfileSidebar.tsx index 9f6efeee..687a3458 100644 --- a/packages/web/src/components/ProfileSidebar.tsx +++ b/packages/web/src/components/ProfileSidebar.tsx @@ -23,28 +23,17 @@ export function ProfileSidebar({ user, isLive, viewerCount, children }: ProfileS
{/* Profile Header */}
- {/* Avatar and Live Badge */} + {/* Name and Live Badge */}
- {user.image ? ( -
- {displayName} +
+
+

{displayName}

{isLive && ( - + Live )}
- ) : isLive ? ( -
-
-
- ) : null} -
-

{displayName}

@{user.username}

diff --git a/packages/web/src/lib/jazz/schema.ts b/packages/web/src/lib/jazz/schema.ts index 6d3758bf..108c6a1d 100644 --- a/packages/web/src/lib/jazz/schema.ts +++ b/packages/web/src/lib/jazz/schema.ts @@ -151,6 +151,21 @@ export type StreamRecording = z.infer */ export const StreamRecordingList = co.list(StreamRecording) +/** + * Cloudflare Stream configuration + */ +export const CloudflareStreamConfig = co.map({ + /** Cloudflare Live Input UID (permanent, doesn't change between connections) */ + liveInputUid: z.string(), + /** Cloudflare customer code (e.g., xctsztqzu046isdc) */ + customerCode: z.string(), + /** Stream name/title */ + name: z.string(), + /** Last updated timestamp */ + updatedAt: z.number(), +}) +export type CloudflareStreamConfig = co.loaded + /** * Viewer account root - stores any viewer-specific data */ @@ -163,6 +178,8 @@ export const ViewerRoot = co.map({ glideCanvas: GlideCanvasList, /** Live stream recordings */ streamRecordings: StreamRecordingList, + /** Cloudflare Stream configuration */ + cloudflareConfig: co.optional(CloudflareStreamConfig), }) /** diff --git a/packages/web/src/routes/api/jazz.cloudflare-config.ts b/packages/web/src/routes/api/jazz.cloudflare-config.ts new file mode 100644 index 00000000..4d01556f --- /dev/null +++ b/packages/web/src/routes/api/jazz.cloudflare-config.ts @@ -0,0 +1,42 @@ +import { json } from "@tanstack/react-start" +import type { APIContext } from "@tanstack/react-router" + +/** + * Get or set Cloudflare stream configuration from Jazz + * + * GET: Returns current Cloudflare Live Input UID + * PUT: Updates Cloudflare Live Input UID + */ +export async function GET({ request, context }: APIContext) { + try { + // For now, return the hardcoded value + // TODO: Read from Jazz when worker is set up + return json({ + liveInputUid: "bb7858eafc85de6c92963f3817477b5d", + customerCode: "xctsztqzu046isdc", + name: "linsa-nikiv", + updatedAt: Date.now(), + }) + } catch (error) { + return json({ error: "Failed to fetch config" }, { status: 500 }) + } +} + +export async function PUT({ request, context }: APIContext) { + try { + const body = await request.json() + const { liveInputUid, customerCode, name } = body + + // TODO: Write to Jazz when worker is set up + // For now, just return success + return json({ + success: true, + liveInputUid, + customerCode, + name, + updatedAt: Date.now(), + }) + } catch (error) { + return json({ error: "Failed to update config" }, { status: 500 }) + } +} diff --git a/packages/web/src/routes/api/stream-recording.ts b/packages/web/src/routes/api/stream-recording.ts index 7d6a558b..f0f81c6b 100644 --- a/packages/web/src/routes/api/stream-recording.ts +++ b/packages/web/src/routes/api/stream-recording.ts @@ -6,7 +6,9 @@ import { promises as fs } from "fs" * Chunks are stored temporarily and then synced to Jazz FileStream by client */ -const STORAGE_PATH = "/Users/nikiv/fork-i/garden-co/jazz/glide-storage/stream-recordings" +const STORAGE_PATH = + process.env.STREAM_RECORDINGS_PATH || + "/var/lib/jazz/stream-recordings" interface StreamChunk { streamId: string diff --git a/packages/web/src/routes/api/streams.$username.check-hls.ts b/packages/web/src/routes/api/streams.$username.check-hls.ts index 5659fd54..ef69d869 100644 --- a/packages/web/src/routes/api/streams.$username.check-hls.ts +++ b/packages/web/src/routes/api/streams.$username.check-hls.ts @@ -66,6 +66,32 @@ export const Route = createFileRoute("/api/streams/$username/check-hls")({ } try { + // Hardcoded config for nikiv (stored in Jazz, not Postgres) + if (username === "nikiv") { + const hlsUrl = buildCloudflareHlsUrl("bb7858eafc85de6c92963f3817477b5d", "xctsztqzu046isdc") + + const res = await fetch(hlsUrl, { cache: "no-store" }) + + if (!res.ok) { + return json({ + isLive: false, + hlsUrl, + status: res.status, + error: "HLS not available", + }) + } + + const manifest = await res.text() + const isLive = isHlsPlaylistLive(manifest) + + return json({ + isLive, + hlsUrl, + status: res.status, + manifestLength: manifest.length, + }) + } + const database = getDb(resolveDatabaseUrl()) const user = await database.query.users.findFirst({