mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-06-09 07:43:59 +02:00
668ce16dc7
Gate messages now propagate via the Infonet hashchain as encrypted blobs — every node syncs them through normal chain sync while only Gate members with MLS keys can decrypt. Added mesh reputation system, peer push workers, voluntary Wormhole opt-in for node participation, fork recovery, killwormhole scripts, obfuscated terminology, and hardened the self-updater to protect encryption keys and chain state during updates. New features: Shodan search, train tracking, Sentinel Hub imagery, 8 new intelligence layers, CCTV expansion to 11,000+ cameras across 6 countries, Mesh Terminal CLI, prediction markets, desktop-shell scaffold, and comprehensive mesh test suite (215 frontend + backend tests passing). Community contributors: @wa1id, @AlborzNazari, @adust09, @Xpirix, @imqdcr, @csysp, @suranyami, @chr0n1x, @johan-martensson, @singularfailure, @smithbh, @OrfeoTerkuci, @deuza, @tm-const, @Elhard1, @ttulttul
67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
|
|
|
|
export interface HlsVideoHandle {
|
|
play(): void;
|
|
pause(): void;
|
|
get paused(): boolean;
|
|
}
|
|
|
|
const HlsVideo = forwardRef<HlsVideoHandle, { url: string; className?: string; onError?: () => void }>(
|
|
({ url, className, onError }, ref) => {
|
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
play: () => videoRef.current?.play(),
|
|
pause: () => videoRef.current?.pause(),
|
|
get paused() {
|
|
return videoRef.current?.paused ?? true;
|
|
},
|
|
}));
|
|
|
|
useEffect(() => {
|
|
const video = videoRef.current;
|
|
if (!video || !url) return;
|
|
|
|
let hlsInstance: { destroy(): void } | null = null;
|
|
let cancelled = false;
|
|
|
|
(async () => {
|
|
const { default: Hls } = await import('hls.js');
|
|
if (cancelled) return;
|
|
if (Hls.isSupported()) {
|
|
const hls = new Hls({ enableWorker: false, lowLatencyMode: true });
|
|
hls.on(Hls.Events.ERROR, (_e: unknown, data: { fatal?: boolean }) => {
|
|
if (data.fatal) onError?.();
|
|
});
|
|
hls.loadSource(url);
|
|
hls.attachMedia(video);
|
|
hlsInstance = hls;
|
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
video.src = url;
|
|
}
|
|
})();
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
hlsInstance?.destroy();
|
|
};
|
|
}, [url, onError]);
|
|
|
|
return (
|
|
<video
|
|
ref={videoRef}
|
|
autoPlay
|
|
muted
|
|
playsInline
|
|
onError={() => onError?.()}
|
|
className={className}
|
|
/>
|
|
);
|
|
},
|
|
);
|
|
|
|
HlsVideo.displayName = 'HlsVideo';
|
|
export default HlsVideo;
|