Web Player Examples
Browser-based HLS video player implementations.
Video.js Player
Basic Setup
html
<!DOCTYPE html>
<html>
<head>
<title>Lunar Stream Player</title>
<link href="https://vjs.zencdn.net/8.0.4/video-js.css" rel="stylesheet">
<style>
body { margin: 0; background: #000; }
.container { max-width: 1280px; margin: 0 auto; padding: 20px; }
.video-js { width: 100%; aspect-ratio: 16/9; }
.status { color: #fff; padding: 10px; text-align: center; }
</style>
</head>
<body>
<div class="container">
<div id="status" class="status">Loading...</div>
<video id="player" class="video-js vjs-default-skin" controls></video>
</div>
<script src="https://vjs.zencdn.net/8.0.4/video.min.js"></script>
<script>
const streamKey = new URLSearchParams(window.location.search).get('key');
const statusEl = document.getElementById('status');
async function loadStream() {
if (!streamKey) {
statusEl.textContent = 'No stream key provided. Add ?key=YOUR_STREAM_KEY to URL';
return;
}
try {
const response = await fetch(
`https://api.lunarstream.kozow.com/api/v1/livestreams/stream-info/${streamKey}`
);
const { data } = await response.json();
if (data.status === 'STARTED') {
statusEl.textContent = `Now Playing: ${data.name}`;
initPlayer(data.hlsSources);
} else {
statusEl.textContent = `Stream "${data.name}" is ${data.status}`;
}
} catch (error) {
statusEl.textContent = 'Stream not found';
}
}
function initPlayer(hlsSources) {
const player = videojs('player', {
liveui: true,
html5: { vhs: { overrideNative: true } }
});
let currentIndex = 0;
player.src({ src: hlsSources[currentIndex].url, type: 'application/x-mpegURL' });
player.on('error', () => {
currentIndex++;
if (currentIndex < hlsSources.length) {
player.src({ src: hlsSources[currentIndex].url, type: 'application/x-mpegURL' });
player.play();
}
});
player.play();
}
loadStream();
</script>
</body>
</html>HLS.js Player
html
<!DOCTYPE html>
<html>
<head>
<title>HLS.js Player</title>
<style>
body { margin: 0; background: #000; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
video { max-width: 100%; max-height: 100vh; }
</style>
</head>
<body>
<video id="video" controls></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
const video = document.getElementById('video');
const hlsUrl = 'https://stream.lunarstream.kozow.com/live/YOUR_STREAM_KEY/hls.m3u8';
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: true,
lowLatencyMode: true
});
hls.loadSource(hlsUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play();
});
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('Network error, trying to recover...');
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('Media error, trying to recover...');
hls.recoverMediaError();
break;
default:
hls.destroy();
break;
}
}
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = hlsUrl;
video.addEventListener('loadedmetadata', () => video.play());
}
</script>
</body>
</html>React Component
jsx
import React, { useEffect, useRef, useState } from 'react';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
const StreamPlayer = ({ streamKey }) => {
const videoRef = useRef(null);
const playerRef = useRef(null);
const [status, setStatus] = useState('loading');
useEffect(() => {
const loadStream = async () => {
const response = await fetch(
`https://api.lunarstream.kozow.com/api/v1/livestreams/stream-info/${streamKey}`
);
const { data } = await response.json();
if (data.status === 'STARTED' && data.hlsSources?.length > 0) {
setStatus('playing');
playerRef.current = videojs(videoRef.current, { liveui: true });
playerRef.current.src({ src: data.hlsSources[0].url, type: 'application/x-mpegURL' });
playerRef.current.play();
} else {
setStatus(data.status);
}
};
loadStream();
return () => playerRef.current?.dispose();
}, [streamKey]);
if (status === 'loading') return <div>Loading...</div>;
if (status !== 'playing') return <div>Stream is {status}</div>;
return <video ref={videoRef} className="video-js vjs-default-skin" />;
};
export default StreamPlayer;