feat: embed player
This commit is contained in:
@ -6,6 +6,7 @@ import { Icon } from "./icon";
|
|||||||
import { ProgressBar } from "./progress-bar";
|
import { ProgressBar } from "./progress-bar";
|
||||||
import { Menu, MenuItem } from "@szhsin/react-menu";
|
import { Menu, MenuItem } from "@szhsin/react-menu";
|
||||||
import { StreamState } from "@/const";
|
import { StreamState } from "@/const";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
export enum VideoStatus {
|
export enum VideoStatus {
|
||||||
Online = "online",
|
Online = "online",
|
||||||
@ -251,7 +252,7 @@ export default function LiveVideoPlayer({
|
|||||||
{playerOverlay()}
|
{playerOverlay()}
|
||||||
<video
|
<video
|
||||||
{...props}
|
{...props}
|
||||||
className={props.className}
|
className={classNames(props.className, "w-full aspect-video")}
|
||||||
ref={video}
|
ref={video}
|
||||||
autoPlay={true}
|
autoPlay={true}
|
||||||
poster={poster}
|
poster={poster}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { unwrap } from "@snort/shared";
|
import { unwrap } from "@snort/shared";
|
||||||
import { NostrEvent, NostrLink, NostrPrefix, RequestBuilder, TaggedNostrEvent } from "@snort/system";
|
import { NostrEvent, NostrLink, NostrPrefix, RequestBuilder } from "@snort/system";
|
||||||
import { useRequestBuilderAdvanced } from "@snort/system-react";
|
import { useRequestBuilder } from "@snort/system-react";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { LIVE_STREAM } from "@/const";
|
import { LIVE_STREAM } from "@/const";
|
||||||
@ -27,14 +27,10 @@ export function useCurrentStreamFeed(link: NostrLink, leaveOpen = false, evPrelo
|
|||||||
return b;
|
return b;
|
||||||
}, [link.id, leaveOpen]);
|
}, [link.id, leaveOpen]);
|
||||||
|
|
||||||
const q = useRequestBuilderAdvanced(sub);
|
const q = useRequestBuilder(sub);
|
||||||
|
|
||||||
if (evPreload) {
|
|
||||||
q?.feed.add([evPreload as TaggedNostrEvent]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const hosting = q?.snapshot?.filter(
|
const hosting = [...q, ...(evPreload ? [evPreload] : [])].filter(
|
||||||
a => a.pubkey === author || a.tags.some(b => b[0] === "p" && b[1] === author && b[3] === "host")
|
a => a.pubkey === author || a.tags.some(b => b[0] === "p" && b[1] === author && b[3] === "host")
|
||||||
);
|
);
|
||||||
return [...(hosting ?? [])].sort((a, b) => (b.created_at > a.created_at ? 1 : -1)).at(0);
|
return [...(hosting ?? [])].sort((a, b) => (b.created_at > a.created_at ? 1 : -1)).at(0);
|
||||||
|
@ -26,6 +26,7 @@ import { IntlProvider } from "@/intl";
|
|||||||
import { WidgetsPage } from "@/pages/widgets";
|
import { WidgetsPage } from "@/pages/widgets";
|
||||||
import { AlertsPage } from "@/pages/alerts";
|
import { AlertsPage } from "@/pages/alerts";
|
||||||
import { StreamSummaryPage } from "@/pages/summary";
|
import { StreamSummaryPage } from "@/pages/summary";
|
||||||
|
import { EmbededPage } from "./pages/embed";
|
||||||
const DashboardPage = lazy(() => import("./pages/dashboard"));
|
const DashboardPage = lazy(() => import("./pages/dashboard"));
|
||||||
|
|
||||||
const db = new SnortSystemDb();
|
const db = new SnortSystemDb();
|
||||||
@ -126,6 +127,15 @@ const router = createBrowserRouter([
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/embed/:id",
|
||||||
|
element: <EmbededPage />,
|
||||||
|
loader: async () => {
|
||||||
|
db.ready = await db.isAvailable();
|
||||||
|
await System.Init();
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLDivElement);
|
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLDivElement);
|
||||||
root.render(
|
root.render(
|
||||||
|
37
src/pages/embed.tsx
Normal file
37
src/pages/embed.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { StreamState } from "@/const";
|
||||||
|
import LiveVideoPlayer from "@/element/live-video-player";
|
||||||
|
import { useCurrentStreamFeed } from "@/hooks/current-stream-feed";
|
||||||
|
import { useStreamLink } from "@/hooks/stream-link";
|
||||||
|
import { extractStreamInfo } from "@/utils";
|
||||||
|
import { NostrLink } from "@snort/system";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
|
export function EmbededPage() {
|
||||||
|
const link = useStreamLink();
|
||||||
|
if (link) {
|
||||||
|
return <EmbededPagePlayer link={link} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmbededPagePlayer({ link }: { link: NostrLink }) {
|
||||||
|
const ev = useCurrentStreamFeed(link, true);
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
image,
|
||||||
|
status,
|
||||||
|
stream,
|
||||||
|
recording,
|
||||||
|
} = extractStreamInfo(ev);
|
||||||
|
console.debug(ev);
|
||||||
|
return <div className="w-[100vw] h-[100vh]">
|
||||||
|
<Suspense>
|
||||||
|
<LiveVideoPlayer
|
||||||
|
title={title}
|
||||||
|
stream={status === StreamState.Live ? stream : recording}
|
||||||
|
poster={image}
|
||||||
|
status={status}
|
||||||
|
className="h-[100vh]"
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
}
|
@ -17,11 +17,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stream-page .video-content video {
|
|
||||||
width: 100%;
|
|
||||||
aspect-ratio: 16/9;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1020px) {
|
@media (max-width: 1020px) {
|
||||||
.stream-page {
|
.stream-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
Reference in New Issue
Block a user