import { LiveChat } from "@/element/chat/live-chat"; import LiveVideoPlayer from "@/element/stream/live-video-player"; import { useCurrentStreamFeed } from "@/hooks/current-stream-feed"; import { extractStreamInfo } from "@/utils"; import { EventExt, NostrEvent, NostrLink } from "@snort/system"; import { SnortContext, useReactions } from "@snort/system-react"; import { Suspense, lazy, useContext, useEffect, useMemo, useState } from "react"; import { FormattedMessage, FormattedNumber } from "react-intl"; import { StreamTimer } from "@/element/stream/stream-time"; import { LIVE_STREAM_CHAT, LIVE_STREAM_RAID, LIVE_STREAM_CLIP, StreamState } from "@/const"; import { DashboardRaidButton } from "./button-raid"; import { DashboardZapColumn } from "./column-zaps"; import { DashboardChatList } from "./chat-list"; import { DashboardStatsCard } from "./stats-card"; import { DashboardCard } from "./card"; import { NewStreamDialog } from "@/element/new-stream"; import { DashboardSettingsButton } from "./button-settings"; import DashboardIntro from "./intro"; import { useLocation } from "react-router-dom"; import StreamKey from "@/element/provider/nostr/stream-key"; import { DefaultProvider, NostrStreamProvider, StreamProviderInfo } from "@/providers"; import { ExternalLink } from "@/element/external-link"; import BalanceTimeEstimate from "@/element/balance-time-estimate"; import { Layer1Button, WarningButton } from "@/element/buttons"; import { useLogin } from "@/hooks/login"; import AccountTopup from "@/element/provider/nostr/topup"; import classNames from "classnames"; import ManualStream from "./manual-stream"; import { unixNow } from "@snort/shared"; import { Icon } from "@/element/icon"; import ForwardingModal from "./forwarding"; import BalanceHistoryModal from "./balance-history"; const StreamSummary = lazy(() => import("@/element/summary-chart")); export function DashboardForLink({ link }: { link: NostrLink }) { const streamEvent = useCurrentStreamFeed(link, true); const location = useLocation(); const login = useLogin(); const streamLink = streamEvent ? NostrLink.fromEvent(streamEvent) : undefined; const { stream, status, image, participants, service } = extractStreamInfo(streamEvent); const [info, setInfo] = useState(); const isMyManual = streamEvent?.pubkey === login?.pubkey; const system = useContext(SnortContext); const [recording, setRecording] = useState(Boolean(localStorage.getItem("default-recording") ?? "true")); useEffect(() => { localStorage.setItem("default-recording", String(recording)); }, [recording]); const provider = useMemo(() => (service ? new NostrStreamProvider("", service) : DefaultProvider), [service]); const defaultEndpoint = useMemo(() => { return info?.endpoints.find(a => a.name == (recording ? "Best" : "Good")) ?? info?.endpoints[0]; }, [info, recording]); useEffect(() => { if (!isMyManual) { provider.info().then(setInfo); const t = setInterval(() => { provider.info().then(setInfo); }, 1000 * 60); return () => { clearInterval(t); }; } }, [isMyManual, provider]); const [maxParticipants, setMaxParticipants] = useState(0); useEffect(() => { if (participants) { setMaxParticipants(v => (v < Number(participants) ? Number(participants) : v)); } }, [participants]); const feed = useReactions( `live:${link?.id}:${streamLink?.author}:reactions`, streamLink ? [streamLink] : [], rb => { if (streamLink) { rb.withFilter().kinds([LIVE_STREAM_CHAT, LIVE_STREAM_RAID, LIVE_STREAM_CLIP]).replyToLink([streamLink]); } }, true, ); if (!streamLink && !location.search.includes("setupComplete=true")) return ; return (

{status === StreamState.Live ? ( ) : ( )}
{streamLink && status === StreamState.Live && !isMyManual && ( <>
} value={} /> } value={participants} /> } value={maxParticipants} />
{defaultEndpoint && (
), balance: , rate: defaultEndpoint.rate ?? 0, unit: defaultEndpoint.unit ?? "min", }} />
{ provider.info().then(setInfo); }} />
)}
} />
)} {streamLink && isMyManual && status === StreamState.Live && ( <>
} /> { //todo: clean this up const copy = streamEvent ? ({ ...streamEvent } as NostrEvent) : undefined; const statusTag = copy?.tags.find(a => a[0] === "status"); const endedTag = copy?.tags.find(a => a[0] === "ends"); const pub = login?.signer(); if (statusTag && copy && pub) { statusTag[1] = StreamState.Ended; if (endedTag) { endedTag[1] = String(unixNow()); } else { copy.tags.push(["ends", String(unixNow())]); } copy.created_at = unixNow(); copy.id = EventExt.createId(copy); const evPub = await pub.sign(copy); if (evPub) { await system.BroadcastEvent(evPub); } } }}>
)} {(!streamLink || status === StreamState.Ended) && ( <>
} />

{c}, }} />

setRecording(e.target.checked)} />
{defaultEndpoint && }
)}
{streamLink && status === StreamState.Live && (

)} {(!streamLink || status === StreamState.Ended) && (

)}
{streamLink && status === StreamState.Live && ( <>
{ window.open( `${window.location.protocol}//${window.location.host}/chat/${link.encode()}?chat=true`, "", "popup=true,width=400,height=800", ); }}>
)} {streamLink && status === StreamState.Ended && ( <>

)}
); }