feat: pubkey stream loading

chore: faster stream navigation
This commit is contained in:
2023-08-01 16:54:06 +01:00
parent 74c1a383b6
commit 90a7d2ca7e
7 changed files with 72 additions and 18 deletions

View File

@ -31,7 +31,9 @@ function NewStream({ ev, onFinish }: StreamEditorProps) {
onFinish={(ex) => { onFinish={(ex) => {
currentProvider.updateStreamInfo(ex); currentProvider.updateStreamInfo(ex);
if (!ev) { if (!ev) {
navigate(eventLink(ex)); navigate(`/${eventLink(ex)}`, {
state: ev
});
} else { } else {
onFinish?.(ev); onFinish?.(ev);
} }

View File

@ -43,6 +43,7 @@ export function VideoTile({
to={`/${link}`} to={`/${link}`}
className={`video-tile${contentWarning ? " nsfw" : ""}`} className={`video-tile${contentWarning ? " nsfw" : ""}`}
ref={ref} ref={ref}
state={ev}
> >
<div <div
style={{ style={{

View File

@ -1,16 +1,22 @@
import { unwrap } from "@snort/shared"; import { unwrap } from "@snort/shared";
import { import {
NostrEvent,
NostrLink, NostrLink,
NostrPrefix, NostrPrefix,
NoteCollection, NoteCollection,
RequestBuilder, RequestBuilder,
TaggedRawEvent,
} from "@snort/system"; } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react"; import { useRequestBuilder } from "@snort/system-react";
import { LIVE_STREAM } from "const"; import { LIVE_STREAM } from "const";
import { System } from "index"; import { System } from "index";
import { useMemo } from "react"; import { useMemo } from "react";
export function useCurrentStreamFeed(link: NostrLink, leaveOpen = false) { export function useCurrentStreamFeed(
link: NostrLink,
leaveOpen = false,
evPreload?: NostrEvent
) {
const author = const author =
link.type === NostrPrefix.Address ? unwrap(link.author) : link.id; link.type === NostrPrefix.Address ? unwrap(link.author) : link.id;
const sub = useMemo(() => { const sub = useMemo(() => {
@ -38,6 +44,10 @@ export function useCurrentStreamFeed(link: NostrLink, leaveOpen = false) {
const q = useRequestBuilder(System, NoteCollection, sub); const q = useRequestBuilder(System, NoteCollection, sub);
if (evPreload) {
q.add(evPreload as TaggedRawEvent);
}
return useMemo(() => { return useMemo(() => {
const hosting = q.data?.filter( const hosting = q.data?.filter(
(a) => (a) =>

View File

@ -15,6 +15,7 @@ import { ChatPopout } from "pages/chat-popout";
import { LoginStore } from "login"; import { LoginStore } from "login";
import { StreamProvidersPage } from "pages/providers"; import { StreamProvidersPage } from "pages/providers";
import { defaultRelays } from "const"; import { defaultRelays } from "const";
import { CatchAllRoutePage } from "pages/catch-all";
export enum StreamState { export enum StreamState {
Live = "live", Live = "live",
@ -58,6 +59,10 @@ const router = createBrowserRouter([
path: "/providers/:id?", path: "/providers/:id?",
element: <StreamProvidersPage />, element: <StreamProvidersPage />,
}, },
{
path: "*",
element: <CatchAllRoutePage />
}
], ],
}, },
{ {

6
src/pages/catch-all.tsx Normal file
View File

@ -0,0 +1,6 @@
export function CatchAllRoutePage() {
//const { ["*"]: param } = useParams();
return <b className="error">Not found :(</b>
}

View File

@ -1,14 +1,13 @@
import "./stream-page.css"; import "./stream-page.css";
import { parseNostrLink, TaggedRawEvent } from "@snort/system"; import { parseNostrLink, TaggedRawEvent } from "@snort/system";
import { useNavigate, useParams } from "react-router-dom"; import { useLocation, useNavigate, useParams } from "react-router-dom";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { LiveVideoPlayer } from "element/live-video-player"; import { LiveVideoPlayer } from "element/live-video-player";
import { findTag, getHost } from "utils"; import { createNostrLink, findTag, getEventFromLocationState, getHost } from "utils";
import { Profile, getName } from "element/profile"; import { Profile, getName } from "element/profile";
import { LiveChat } from "element/live-chat"; import { LiveChat } from "element/live-chat";
import AsyncButton from "element/async-button"; import AsyncButton from "element/async-button";
import useEventFeed from "hooks/event-feed";
import { useLogin } from "hooks/login"; import { useLogin } from "hooks/login";
import { useZapGoal } from "hooks/goals"; import { useZapGoal } from "hooks/goals";
import { StreamState, System } from "index"; import { StreamState, System } from "index";
@ -26,6 +25,7 @@ import {
ContentWarningOverlay, ContentWarningOverlay,
isContentWarningAccepted, isContentWarningAccepted,
} from "element/content-warning"; } from "element/content-warning";
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) { function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
const login = useLogin(); const login = useLogin();
@ -107,8 +107,10 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
export function StreamPage() { export function StreamPage() {
const params = useParams(); const params = useParams();
const location = useLocation();
const evPreload = getEventFromLocationState(location.state);
const link = parseNostrLink(params.id!); const link = parseNostrLink(params.id!);
const { data: ev } = useEventFeed(link, true); const ev = useCurrentStreamFeed(link, true, evPreload);
const host = getHost(ev); const host = getHost(ev);
const goal = useZapGoal(host, link, true); const goal = useZapGoal(host, link, true);
@ -151,7 +153,7 @@ export function StreamPage() {
<ProfileInfo ev={ev} goal={goal} /> <ProfileInfo ev={ev} goal={goal} />
<StreamCards host={host} /> <StreamCards host={host} />
</div> </div>
<LiveChat link={link} ev={ev} goal={goal} /> <LiveChat link={createNostrLink(ev) ?? link} ev={ev} goal={goal} />
</div> </div>
); );
} }

View File

@ -1,7 +1,14 @@
import { NostrEvent, NostrPrefix, encodeTLV } from "@snort/system"; import {
NostrEvent,
NostrPrefix,
TaggedRawEvent,
encodeTLV,
parseNostrLink,
} from "@snort/system";
import * as utils from "@noble/curves/abstract/utils"; import * as utils from "@noble/curves/abstract/utils";
import { bech32 } from "@scure/base"; import { bech32 } from "@scure/base";
import type { Tag, Tags } from "types"; import type { Tag, Tags } from "types";
import { LIVE_STREAM } from "const";
export function toAddress(e: NostrEvent): string { export function toAddress(e: NostrEvent): string {
if (e.kind && e.kind >= 30000 && e.kind <= 40000) { if (e.kind && e.kind >= 30000 && e.kind <= 40000) {
@ -70,16 +77,28 @@ export function splitByUrl(str: string) {
return str.split(urlRegex); return str.split(urlRegex);
} }
export function eventLink(ev: NostrEvent) { export function eventLink(ev: NostrEvent | TaggedRawEvent) {
const d = findTag(ev, "d") ?? ""; if (ev.kind && ev.kind >= 30000 && ev.kind <= 40000) {
const naddr = encodeTLV( const d = findTag(ev, "d") ?? "";
NostrPrefix.Address, return encodeTLV(
d, NostrPrefix.Address,
undefined, d,
ev.kind, "relays" in ev ? ev.relays : undefined,
ev.pubkey ev.kind,
); ev.pubkey
return `/${naddr}`; );
} else {
return encodeTLV(
NostrPrefix.Event,
ev.id,
"relays" in ev ? ev.relays : undefined
);
}
}
export function createNostrLink(ev?: NostrEvent) {
if (!ev) return;
return parseNostrLink(eventLink(ev));
} }
export function getHost(ev?: NostrEvent) { export function getHost(ev?: NostrEvent) {
@ -113,3 +132,12 @@ export function getTagValues(tags: Tags, tag: string): Array<string> {
.filter((t) => t) .filter((t) => t)
.map((t) => t as string); .map((t) => t as string);
} }
export function getEventFromLocationState(state: unknown | undefined | null) {
return state &&
typeof state === "object" &&
"kind" in state &&
state.kind === LIVE_STREAM
? (state as NostrEvent)
: undefined;
}