diff --git a/frontend/package.json b/frontend/package.json index 5e5ee4b..59fa117 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,7 @@ "dependencies": { "@mapbox/point-geometry": "^1.1.0", "framer-motion": "^12.34.3", + "hls.js": "^1.6.15", "lucide-react": "^0.575.0", "maplibre-gl": "^4.7.1", "next": "16.1.6", @@ -33,4 +34,4 @@ "tailwindcss": "^4", "typescript": "^5" } -} \ No newline at end of file +} diff --git a/frontend/src/components/NewsFeed.tsx b/frontend/src/components/NewsFeed.tsx index 01e847a..85f2a81 100644 --- a/frontend/src/components/NewsFeed.tsx +++ b/frontend/src/components/NewsFeed.tsx @@ -3,9 +3,43 @@ import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { AlertTriangle, Clock, ChevronDown, ChevronUp } from 'lucide-react'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useCallback } from 'react'; +import Hls from 'hls.js'; import WikiImage from '@/components/WikiImage'; +// HLS video player — uses hls.js on Chrome/Firefox, native on Safari +function HlsVideo({ url, className }: { url: string; className?: string }) { + const videoRef = useRef(null); + + useEffect(() => { + const video = videoRef.current; + if (!video || !url) return; + + let hls: Hls | null = null; + + if (Hls.isSupported()) { + hls = new Hls({ enableWorker: false, lowLatencyMode: true }); + hls.loadSource(url); + hls.attachMedia(video); + } else if (video.canPlayType('application/vnd.apple.mpegurl')) { + // Safari native HLS + video.src = url; + } + + return () => { hls?.destroy(); }; + }, [url]); + + return ( +