Show video loading speed and quality indicators
Add detailed bitrate and download speed monitoring to the video player, along with visual indicators for buffering and quality levels. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 11420304-80a9-4ef2-adff-cbdaa418ffa8 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/11420304-80a9-4ef2-adff-cbdaa418ffa8/Qpg7dKb
This commit is contained in:
parent
3b648347cd
commit
8e8c07f34c
@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Signal } from "lucide-react";
|
||||
import { Signal, Activity, Wifi } from "lucide-react";
|
||||
|
||||
interface QualityIndicatorProps {
|
||||
hlsInstance: any;
|
||||
@ -8,8 +8,11 @@ interface QualityIndicatorProps {
|
||||
|
||||
export default function QualityIndicator({ hlsInstance, className = "" }: QualityIndicatorProps) {
|
||||
const [currentQuality, setCurrentQuality] = useState<string>("");
|
||||
const [currentBitrate, setCurrentBitrate] = useState<number>(0);
|
||||
const [networkType, setNetworkType] = useState<string>("");
|
||||
const [bufferHealth, setBufferHealth] = useState<"good" | "medium" | "poor">("good");
|
||||
const [downloadSpeed, setDownloadSpeed] = useState<number>(0);
|
||||
const [isBuffering, setIsBuffering] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hlsInstance) return;
|
||||
@ -18,6 +21,8 @@ export default function QualityIndicator({ hlsInstance, className = "" }: Qualit
|
||||
const handleLevelSwitch = (event: any, data: any) => {
|
||||
const level = hlsInstance.levels[data.level];
|
||||
setCurrentQuality(`${level.height}p`);
|
||||
setCurrentBitrate(Math.round(level.bitrate / 1000)); // Convert to kbps
|
||||
console.log(`Preklopil na: ${level.height}p @ ${Math.round(level.bitrate/1000)}kbps`);
|
||||
};
|
||||
|
||||
// Monitor buffer health
|
||||
@ -35,8 +40,29 @@ export default function QualityIndicator({ hlsInstance, className = "" }: Qualit
|
||||
}
|
||||
};
|
||||
|
||||
// Monitor loading progress and speed
|
||||
const handleFragLoaded = (event: any, data: any) => {
|
||||
const stats = data.stats;
|
||||
if (stats) {
|
||||
const speed = (stats.total * 8) / (stats.loading.end - stats.loading.start); // bits per ms
|
||||
const speedKbps = Math.round(speed); // Convert to kbps
|
||||
setDownloadSpeed(speedKbps);
|
||||
console.log(`Download hitrost: ${speedKbps} kbps`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWaiting = () => setIsBuffering(true);
|
||||
const handlePlaying = () => setIsBuffering(false);
|
||||
|
||||
hlsInstance.on('hlsLevelSwitched', handleLevelSwitch);
|
||||
hlsInstance.on('hlsBufferAppending', handleBufferAppending);
|
||||
hlsInstance.on('hlsFragLoaded', handleFragLoaded);
|
||||
|
||||
const video = hlsInstance.media;
|
||||
if (video) {
|
||||
video.addEventListener('waiting', handleWaiting);
|
||||
video.addEventListener('playing', handlePlaying);
|
||||
}
|
||||
|
||||
// Detect network connection
|
||||
const connection = (navigator as any).connection;
|
||||
@ -58,6 +84,11 @@ export default function QualityIndicator({ hlsInstance, className = "" }: Qualit
|
||||
if (hlsInstance) {
|
||||
hlsInstance.off('hlsLevelSwitched', handleLevelSwitch);
|
||||
hlsInstance.off('hlsBufferAppending', handleBufferAppending);
|
||||
hlsInstance.off('hlsFragLoaded', handleFragLoaded);
|
||||
}
|
||||
if (video) {
|
||||
video.removeEventListener('waiting', handleWaiting);
|
||||
video.removeEventListener('playing', handlePlaying);
|
||||
}
|
||||
};
|
||||
}, [hlsInstance]);
|
||||
@ -74,11 +105,37 @@ export default function QualityIndicator({ hlsInstance, className = "" }: Qualit
|
||||
if (!currentQuality) return null;
|
||||
|
||||
return (
|
||||
<div className={`flex items-center gap-2 text-sm text-white bg-black/50 px-2 py-1 rounded ${className}`}>
|
||||
<Signal className={`w-4 h-4 ${getSignalColor()}`} />
|
||||
<span>{currentQuality}</span>
|
||||
<div className={`flex flex-col gap-1 text-xs text-white bg-black/70 px-3 py-2 rounded ${className}`}>
|
||||
{/* Quality and Signal */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Signal className={`w-3 h-3 ${getSignalColor()}`} />
|
||||
<span className="font-semibold">{currentQuality}</span>
|
||||
{isBuffering && (
|
||||
<Activity className="w-3 h-3 text-yellow-400 animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bitrate */}
|
||||
{currentBitrate > 0 && (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="opacity-75">Bitrate:</span>
|
||||
<span>{currentBitrate} kbps</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Download Speed */}
|
||||
{downloadSpeed > 0 && (
|
||||
<div className="flex items-center gap-1">
|
||||
<Wifi className="w-3 h-3" />
|
||||
<span>{downloadSpeed} kbps</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Network Type */}
|
||||
{networkType && (
|
||||
<span className="text-xs opacity-75">({networkType})</span>
|
||||
<div className="opacity-75">
|
||||
Omrežje: {networkType}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -132,25 +132,43 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
console.log('HLS manifest loaded - Available qualities:',
|
||||
data.levels.map(l => `${l.height}p @ ${Math.round(l.bitrate/1000)}kbps`));
|
||||
|
||||
// Log bitrate analysis
|
||||
console.log('BITRATE ANALIZA:');
|
||||
data.levels.forEach((level, index) => {
|
||||
console.log(`Nivo ${index}: ${level.width}x${level.height} @ ${Math.round(level.bitrate/1000)}kbps`);
|
||||
});
|
||||
|
||||
// Set initial quality based on connection
|
||||
const connection = (navigator as any).connection;
|
||||
if (connection) {
|
||||
const effectiveType = connection.effectiveType;
|
||||
console.log('Network type detected:', effectiveType);
|
||||
const downlink = connection.downlink; // Mbps
|
||||
console.log(`Omrežje: ${effectiveType}, hitrost: ${downlink} Mbps`);
|
||||
|
||||
// Adjust starting level based on network
|
||||
if (effectiveType === 'slow-2g' || effectiveType === '2g') {
|
||||
hls.startLevel = 0; // Start with lowest quality
|
||||
} else if (effectiveType === '3g') {
|
||||
// More aggressive quality selection for slow connections
|
||||
if (effectiveType === 'slow-2g' || effectiveType === '2g' || downlink < 1) {
|
||||
hls.startLevel = 0; // Lowest quality
|
||||
console.log('Nastavljam najnižjo kakovost zaradi počasne povezave');
|
||||
} else if (effectiveType === '3g' || downlink < 3) {
|
||||
hls.startLevel = Math.min(1, data.levels.length - 1);
|
||||
console.log('Nastavljam nizko kakovost zaradi 3G povezave');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Quality level monitoring
|
||||
// Quality level monitoring with detailed stats
|
||||
hls.on(Hls.Events.LEVEL_SWITCHED, (event, data) => {
|
||||
const level = hls.levels[data.level];
|
||||
console.log(`Kakovost preklopljena na: ${level.height}p @ ${Math.round(level.bitrate/1000)}kbps`);
|
||||
console.log(`PREKLOPIL KAKOVOST: ${level.height}p @ ${Math.round(level.bitrate/1000)}kbps`);
|
||||
console.log('Razlog preklopa: adaptivni algoritem na podlagi omrežne hitrosti');
|
||||
});
|
||||
|
||||
// Fragment loading stats
|
||||
hls.on(Hls.Events.FRAG_LOADED, (event, data) => {
|
||||
const stats = data.stats;
|
||||
const loadTime = stats.loading.end - stats.loading.start;
|
||||
const speed = (stats.total * 8) / loadTime; // bits per ms = kbps
|
||||
console.log(`Fragment naložen v ${loadTime}ms, hitrost: ${Math.round(speed)} kbps`);
|
||||
});
|
||||
|
||||
// Buffer monitoring for dynamic adjustment
|
||||
|
||||
Loading…
Reference in New Issue
Block a user