diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7b74a5a..95a8c5c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -37,11 +37,7 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max platforms: linux/amd64 - build-args: | - BUILDKIT_INLINE_CACHE=1 - name: Emit a webhook to the server env: diff --git a/next.config.mjs b/next.config.mjs index 2e60bec..b0202a2 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -12,7 +12,8 @@ const nextConfig = { }, env: { LIVE_SERVER_URL: process.env.NODE_ENV === 'production' ? 'https://backend.hctv.srizan.dev' : 'http://localhost:8888', - } + }, + reactStrictMode: false, }; export default nextConfig; diff --git a/src/app/(protected)/api/stream/chat/[username]/route.ts b/src/app/(protected)/api/stream/chat/[username]/route.ts index f2330dd..0a3c6c0 100644 --- a/src/app/(protected)/api/stream/chat/[username]/route.ts +++ b/src/app/(protected)/api/stream/chat/[username]/route.ts @@ -1,4 +1,5 @@ import { lucia } from '@/lib/auth'; +import prisma from '@/lib/db'; import { resolveUserPersonalChannel } from '@/lib/db/resolve'; import type { WebSocket } from 'ws'; @@ -54,6 +55,40 @@ export async function SOCKET( } }); }); + + await prisma.streamInfo.update({ + where: { + username, + }, + data: { + viewers: { + increment: 1, + }, + }, + }); + + client.on('close', async () => { + console.log('client disconnected'); + const { viewers } = (await prisma.streamInfo.findUnique({ + where: { + username, + }, + select: { + viewers: true, + }, + }))!; + await prisma.streamInfo.update({ + where: { + username, + }, + data: { + viewers: { + decrement: viewers > 0 ? 1 : 0, + set: viewers === 0 ? 0 : undefined, + }, + }, + }); + }); } function parseCookieString(cookie: string) { @@ -66,4 +101,4 @@ function parseCookieString(cookie: string) { interface ExtendedWebSocket extends WebSocket { targetUsername: string; -} \ No newline at end of file +} diff --git a/src/app/(public)/auth/slack/callback/route.ts b/src/app/(public)/auth/slack/callback/route.ts index 7def0a8..2216efd 100644 --- a/src/app/(public)/auth/slack/callback/route.ts +++ b/src/app/(public)/auth/slack/callback/route.ts @@ -11,6 +11,7 @@ export async function GET(request: Request): Promise { const state = url.searchParams.get("state"); const storedState = cookies.get("slack_oauth_state")?.value ?? null; if (!code || !state || !storedState || state !== storedState) { + console.log('invalid state stuff'); return new Response(null, { status: 400 }); diff --git a/src/components/app/Sidebar/Sidebar.tsx b/src/components/app/Sidebar/Sidebar.tsx index 3b36f99..a9436c9 100644 --- a/src/components/app/Sidebar/Sidebar.tsx +++ b/src/components/app/Sidebar/Sidebar.tsx @@ -22,11 +22,6 @@ export default function Sidebar({ ...props }: React.ComponentProps { - console.log('stream info', stream); - }, [stream]); - if (isLoading) return ; const liveStreamers = stream?.filter((s) => s.isLive) || []; @@ -97,7 +92,7 @@ function StreamerItem({ streamer }: { streamer: StreamInfoResponse[0] }) {

{streamer.username}

{streamer.category}

- {false && streamer.isLive && ( + {streamer.isLive && (

{streamer.viewers} viewer{streamer.viewers === 1 ? '' : 's'}

diff --git a/src/components/app/UserInfoCard/UserInfoCard.tsx b/src/components/app/UserInfoCard/UserInfoCard.tsx index 12ca04a..b9ef144 100644 --- a/src/components/app/UserInfoCard/UserInfoCard.tsx +++ b/src/components/app/UserInfoCard/UserInfoCard.tsx @@ -2,6 +2,7 @@ import { Avatar, AvatarImage } from '@/components/ui/avatar'; import type { StreamInfo, User } from '@prisma/client'; import FollowButton from './follow'; import FollowCountText from './followCount'; +import ViewerCount from './viewerCount'; export default function UserInfoCard(props: Props) { return ( @@ -17,23 +18,12 @@ export default function UserInfoCard(props: Props) {
- +
+ + +

markdown description here

- {/*
-
- - 1.2K viewers -
- - -
*/} ); } diff --git a/src/components/app/UserInfoCard/viewerCount.tsx b/src/components/app/UserInfoCard/viewerCount.tsx new file mode 100644 index 0000000..f00361b --- /dev/null +++ b/src/components/app/UserInfoCard/viewerCount.tsx @@ -0,0 +1,17 @@ +import { useStreams } from "@/lib/providers/StreamInfoProvider"; +import { User } from "lucide-react"; + +export default function ViewerCount() { + const streamInfo = useStreams(); + + if (streamInfo.isLoading) return null; + + const viewerCount = streamInfo.stream!.reduce((acc, stream) => acc + stream.viewers, 0); + + return ( +
+ + {viewerCount} +
+ ); +} \ No newline at end of file diff --git a/src/lib/instrumentation/streamInfo.ts b/src/lib/instrumentation/streamInfo.ts index b475f30..62522dc 100644 --- a/src/lib/instrumentation/streamInfo.ts +++ b/src/lib/instrumentation/streamInfo.ts @@ -60,7 +60,6 @@ export async function syncStream() { const data = await response.json(); const httpFlv = data['http-flv'] as HttpFlv; - // Handle case where the RTMP server is not available or doesn't have the expected data structure if (!httpFlv?.servers?.[0]?.applications) { return; } @@ -68,12 +67,10 @@ export async function syncStream() { const channelLiveApp = httpFlv.servers[0].applications.find(app => app.name === 'channel-live'); const activeStreams = channelLiveApp?.live?.streams || []; - // Get all streams that are currently marked as live in the database const currentLiveStreams = await prisma.streamInfo.findMany({ where: { isLive: true }, }); - - // Create a map of active streams from the RTMP server + const activeStreamMap = new Map(); for (const stream of activeStreams) { activeStreamMap.set(stream.name, { @@ -82,12 +79,10 @@ export async function syncStream() { }); } - // Update all streams for (const dbStream of currentLiveStreams) { const streamStats = activeStreamMap.get(dbStream.username); if (!streamStats || !streamStats.isLive) { - // Stream is no longer active, mark it as offline await prisma.streamInfo.update({ where: { username: dbStream.username }, data: { @@ -96,18 +91,9 @@ export async function syncStream() { startedAt: new Date(0), }, }); - } else { - // Stream is still active, update viewers - await prisma.streamInfo.update({ - where: { username: dbStream.username }, - data: { - viewers: streamStats.viewers, - }, - }); } } - // Process new streams that aren't in the database yet for (const stream of activeStreams) { if (stream.active) { const existingStream = await prisma.streamInfo.findUnique({ @@ -115,13 +101,11 @@ export async function syncStream() { }); if (existingStream && !existingStream.isLive) { - // Stream just went live await prisma.streamInfo.update({ where: { username: stream.name }, data: { isLive: true, startedAt: new Date(), - viewers: stream.clients.filter(c => !c.publishing).length, }, }); }