refactor: cache since, dont dedupe by host

This commit is contained in:
2023-08-01 07:58:12 +02:00
parent 5026f6a008
commit 58c55f17b6
4 changed files with 32 additions and 57 deletions

View File

@ -11,9 +11,10 @@ import { useMemo } from "react";
import { LIVE_STREAM_CHAT } from "const"; import { LIVE_STREAM_CHAT } from "const";
export function useLiveChatFeed(link: NostrLink, eZaps?: Array<string>) { export function useLiveChatFeed(link: NostrLink, eZaps?: Array<string>) {
const since = useMemo(() => const since = useMemo(
unixNow() - (60 * 60 * 24 * 7), // 7-days of zaps () => unixNow() - 60 * 60 * 24 * 7, // 7-days of zaps
[link.id]); [link.id],
);
const sub = useMemo(() => { const sub = useMemo(() => {
const rb = new RequestBuilder(`live:${link.id}:${link.author}`); const rb = new RequestBuilder(`live:${link.id}:${link.author}`);
rb.withOptions({ rb.withOptions({
@ -57,7 +58,7 @@ export function useLiveChatFeed(link: NostrLink, eZaps?: Array<string>) {
const reactionsSub = useRequestBuilder<FlatNoteStore>( const reactionsSub = useRequestBuilder<FlatNoteStore>(
System, System,
FlatNoteStore, FlatNoteStore,
esub esub,
); );
const reactions = reactionsSub.data ?? []; const reactions = reactionsSub.data ?? [];

View File

@ -6,26 +6,22 @@ import { useRequestBuilder } from "@snort/system-react";
import { unixNow } from "@snort/shared"; import { unixNow } from "@snort/shared";
import { LIVE_STREAM } from "const"; import { LIVE_STREAM } from "const";
import { System, StreamState } from "index"; import { System, StreamState } from "index";
import { findTag, dedupeByHost } from "utils"; import { findTag } from "utils";
export function useStreamsFeed(tag?: string) { export function useStreamsFeed(tag?: string) {
const since = useMemo(() => unixNow() - 86400, [tag]);
const rb = useMemo(() => { const rb = useMemo(() => {
const rb = new RequestBuilder(tag ? `streams:${tag}` : "streams"); const rb = new RequestBuilder(tag ? `streams:${tag}` : "streams");
rb.withOptions({ rb.withOptions({
leaveOpen: true, leaveOpen: true,
}); });
if (tag) { if (tag) {
rb.withFilter() rb.withFilter().kinds([LIVE_STREAM]).tag("t", [tag]).since(since);
.kinds([LIVE_STREAM])
.tag("t", [tag])
.since(unixNow() - 86400);
} else { } else {
rb.withFilter() rb.withFilter().kinds([LIVE_STREAM]).since(since);
.kinds([LIVE_STREAM])
.since(unixNow() - 86400);
} }
return rb; return rb;
}, [tag]); }, [tag, since]);
const feed = useRequestBuilder<NoteCollection>(System, NoteCollection, rb); const feed = useRequestBuilder<NoteCollection>(System, NoteCollection, rb);
const feedSorted = useMemo(() => { const feedSorted = useMemo(() => {
@ -45,19 +41,17 @@ export function useStreamsFeed(tag?: string) {
return []; return [];
}, [feed.data]); }, [feed.data]);
const live = dedupeByHost( const live = feedSorted.filter(
feedSorted.filter((a) => findTag(a, "status") === StreamState.Live), (a) => findTag(a, "status") === StreamState.Live,
); );
const planned = dedupeByHost( const planned = feedSorted.filter(
feedSorted.filter((a) => findTag(a, "status") === StreamState.Planned), (a) => findTag(a, "status") === StreamState.Planned,
);
const ended = dedupeByHost(
feedSorted.filter((a) => {
const hasEnded = findTag(a, "status") === StreamState.Ended;
const recording = findTag(a, "recording");
return hasEnded && recording?.length > 0;
}),
); );
const ended = feedSorted.filter((a) => {
const hasEnded = findTag(a, "status") === StreamState.Ended;
const recording = findTag(a, "recording");
return hasEnded && recording?.length > 0;
});
return { live, planned, ended }; return { live, planned, ended };
} }

View File

@ -3,25 +3,26 @@ import type { NostrEvent } from "@snort/system";
import { VideoTile } from "element/video-tile"; import { VideoTile } from "element/video-tile";
import { useLogin } from "hooks/login"; import { useLogin } from "hooks/login";
import { getHost, getTagValues, dedupeByHost } from "utils"; import { getHost, getTagValues } from "utils";
import { useStreamsFeed } from "hooks/live-streams"; import { useStreamsFeed } from "hooks/live-streams";
export function RootPage() { export function RootPage() {
const login = useLogin(); const login = useLogin();
const { live, planned, ended } = useStreamsFeed(); const { live, planned, ended } = useStreamsFeed();
const mutedHosts = getTagValues(login?.muted.tags ?? [], "p"); const mutedHosts = new Set(getTagValues(login?.muted.tags ?? [], "p"));
const followsHost = (ev: NostrEvent) => { const followsHost = (ev: NostrEvent) => {
return login?.follows.tags?.find((t) => t.at(1) === getHost(ev)); return login?.follows.tags?.find((t) => t.at(1) === getHost(ev));
}; };
const hashtags = getTagValues(login?.follows.tags ?? [], "t"); const hashtags = getTagValues(login?.follows.tags ?? [], "t");
const following = dedupeByHost(live.filter(followsHost)); const following = live.filter(followsHost);
const liveNow = dedupeByHost(live.filter((e) => !following.includes(e))); const liveNow = live.filter((e) => !following.includes(e));
const hasFollowingLive = following.length > 0; const hasFollowingLive = following.length > 0;
const plannedEvents = planned const plannedEvents = planned
.filter((e) => !mutedHosts.includes(getHost(e))) .filter((e) => !mutedHosts.has(getHost(e)))
.filter(followsHost); .filter(followsHost);
const endedEvents = ended.filter((e) => !mutedHosts.has(getHost(e)));
return ( return (
<div className="homepage"> <div className="homepage">
@ -35,7 +36,7 @@ export function RootPage() {
{!hasFollowingLive && ( {!hasFollowingLive && (
<div className="video-grid"> <div className="video-grid">
{live {live
.filter((e) => !mutedHosts.includes(getHost(e))) .filter((e) => !mutedHosts.has(getHost(e)))
.map((e) => ( .map((e) => (
<VideoTile ev={e} key={e.id} /> <VideoTile ev={e} key={e.id} />
))} ))}
@ -46,7 +47,7 @@ export function RootPage() {
<h2 className="divider line one-line">#{t}</h2> <h2 className="divider line one-line">#{t}</h2>
<div className="video-grid"> <div className="video-grid">
{live {live
.filter((e) => !mutedHosts.includes(getHost(e))) .filter((e) => !mutedHosts.has(getHost(e)))
.filter((e) => { .filter((e) => {
const evTags = getTagValues(e.tags, "t"); const evTags = getTagValues(e.tags, "t");
return evTags.includes(t); return evTags.includes(t);
@ -62,7 +63,7 @@ export function RootPage() {
<h2 className="divider line one-line">Live</h2> <h2 className="divider line one-line">Live</h2>
<div className="video-grid"> <div className="video-grid">
{liveNow {liveNow
.filter((e) => !mutedHosts.includes(getHost(e))) .filter((e) => !mutedHosts.has(getHost(e)))
.map((e) => ( .map((e) => (
<VideoTile ev={e} key={e.id} /> <VideoTile ev={e} key={e.id} />
))} ))}
@ -79,15 +80,13 @@ export function RootPage() {
</div> </div>
</> </>
)} )}
{ended.length > 0 && ( {endedEvents.length > 0 && (
<> <>
<h2 className="divider line one-line">Ended</h2> <h2 className="divider line one-line">Ended</h2>
<div className="video-grid"> <div className="video-grid">
{ended {endedEvents.map((e) => (
.filter((e) => !mutedHosts.includes(getHost(e))) <VideoTile ev={e} key={e.id} />
.map((e) => ( ))}
<VideoTile ev={e} key={e.id} />
))}
</div> </div>
</> </>
)} )}

View File

@ -94,22 +94,3 @@ export async function openFile(): Promise<File | undefined> {
export function getTagValues(tags: Array<string[]>, tag: string) { export function getTagValues(tags: Array<string[]>, tag: string) {
return tags.filter((t) => t.at(0) === tag).map((t) => t.at(1)); return tags.filter((t) => t.at(0) === tag).map((t) => t.at(1));
} }
export function dedupeByHost(events: Array<NostrEvent>) {
const { result } = events.reduce(
({ result, seen }, ev) => {
const host = getHost(ev);
if (seen.has(host)) {
return { result, seen };
}
result.push(ev);
seen.add(host);
return { result, seen };
},
{
result: [],
seen: new Set(),
},
);
return result;
}