adc370a598
Implement NIP-53 staleness heuristic (24h threshold) to mark abandoned status=live streams as ended. Fetch all streams globally and filter follows client-side (including p-tag participants for streaming services). Add Live/Planned/Past pill tabs to the streams strip on /videos. Also fix pre-existing bug where the volume icon showed unmuted while the video was actually muted (autoplay requires muted), by syncing the initial muted state from the media element in usePlayerControls. Closes #88
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
import type { NostrEvent } from '@nostrify/nostrify';
|
|
|
|
/**
|
|
* Staleness threshold in seconds.
|
|
*
|
|
* NIP-53 suggests 1 hour, but in practice relays often serve older versions
|
|
* of addressable events (different `created_at` depending on query filters),
|
|
* which causes false positives at short thresholds. 24 hours is lenient
|
|
* enough to avoid misclassifying genuinely live streams while still catching
|
|
* streams that were abandoned without setting `status=ended`.
|
|
*/
|
|
const STALE_THRESHOLD_SECONDS = 24 * 3600; // 24 hours
|
|
|
|
/**
|
|
* Returns the effective stream status for a kind 30311 event, applying
|
|
* a staleness heuristic inspired by NIP-53: a `status=live` event whose
|
|
* `created_at` is older than 24 hours is treated as `ended`.
|
|
*
|
|
* When no status tag is present the event is treated as `ended`.
|
|
*/
|
|
export function getEffectiveStreamStatus(event: NostrEvent): string {
|
|
const status = event.tags.find(([n]) => n === 'status')?.[1] ?? 'ended';
|
|
|
|
if (status === 'live') {
|
|
const now = Math.floor(Date.now() / 1000);
|
|
if (now - event.created_at > STALE_THRESHOLD_SECONDS) {
|
|
return 'ended';
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|