<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>IPTV Player</title>
    <style>
        #controls {
            position: absolute;
            bottom: 10px;
            left: 10px;
            display: flex;
            gap: 10px;
            background-color: rgba(0, 0, 0, 0.5);
            padding: 10px;
            border-radius: 5px;
            transition: opacity 0.5s;
        }
        #videoContainer {
            position: relative;
            width: fit-content;
        }
        video {
            width: 100%;
            height: auto;
        }
        .control-button {
            background-color: #444;
            color: white;
            border: none;
            padding: 10px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
        }
        .control-button:hover {
            background-color: #666;
        }
        #errorMessage {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 20px;
            border-radius: 5px;
            display: none;
        }
        #loadingSpinner {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            border: 8px solid rgba(0, 0, 0, 0.1);
            border-top: 8px solid #444;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            animation: spin 1s linear infinite;
            display: none;
        }
        @keyframes spin {
            0% { transform: translate(-50%, -50%) rotate(0deg); }
            100% { transform: translate(-50%, -50%) rotate(360deg); }
        }
        #sourceList {
            width: 100%;
            display: flex;
            flex-direction: column;
            gap: 10px;
            background-color: rgba(0, 0, 0, 0.5);
            padding: 10px;
            border-radius: 5px;
            overflow: scroll;
        }
        .category {
            margin-bottom: 10px;
        }
        .category-title {
            font-size: 18px;
            color: white;
            margin-bottom: 5px;
            cursor: pointer;
        }
        .source-items {
            display: none;
            flex-direction: column;
            gap: 5px;
        }
        .source-item {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
        }
        .source-item img {
            width: 20px;
            height: 20px;
        }
    </style>
</head>
<body>
    <div id="videoContainer">
        <video id="videoPlayer"></video>
        <div id="controls">
            <button id="playButton" class="control-button">Play</button>
            <button id="pauseButton" class="control-button">Pause</button>
            <button id="stopButton" class="control-button">Stop</button>
            <button id="fullscreenButton" class="control-button">Fullscreen</button>
        </div>
        <div id="errorMessage">Не удалось загрузить видео. Пожалуйста, попробуйте позже.</div>
        <div id="loadingSpinner"></div>
    </div>
    <div id="sourceList"></div>
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script>
        async function fetchM3U(url) {
            const response = await fetch(url);
            const text = await response.text();
            const lines = text.split('\n');
            const sources = [];
            let currentSource = {};

            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
                if (line.startsWith('#EXTINF')) {
                    const info = line.split(',');
                    const attributes = info[0].split(' ');
                    const currentSource = {
                        name: info[1],
                        img: '',
                        category: 'Uncategorized'
                    };
                    attributes.forEach(attr => {
                        const [key, value] = attr.split('=');
                        if (key === 'tvg-logo') {
                            currentSource.img = value.replace(/"/g, '');
                        }
                        if (key === 'group-title') {
                            currentSource.category = value.replace(/"/g, '');
                        }
                    });
                    sources.push(currentSource);
                } else if (line && !line.startsWith('#')) {
                    sources[sources.length - 1].url = line;
                }
            }

            return sources;
        }

        if (Hls.isSupported()) {
            var video = document.getElementById('videoPlayer');
            var hls = new Hls();
            var loadingSpinner = document.getElementById('loadingSpinner');
            var errorMessage = document.getElementById('errorMessage');
            var sourceList = document.getElementById('sourceList');

            function loadSource(url) {
                hls.loadSource(url);
                hls.attachMedia(video);
                hls.on(Hls.Events.MANIFEST_PARSED, function() {
                    video.play().catch(function(error) {
                        console.error('Error playing video:', error);
                    });
                });
            }

            function populateSourceList(sources) {
                sourceList.innerHTML = '';
                const categories = {};

                sources.forEach((source, index) => {
                    if (!categories[source.category]) {
                        categories[source.category] = [];
                    }
                    categories[source.category].push(source);
                });

                for (const category in categories) {
                    const categoryDiv = document.createElement('div');
                    categoryDiv.className = 'category';
                    const categoryTitle = document.createElement('div');
                    categoryTitle.className = 'category-title';
                    categoryTitle.textContent = category;
                    categoryTitle.addEventListener('click', function() {
                        const sourceItems = categoryDiv.querySelector('.source-items');
                        sourceItems.style.display = sourceItems.style.display === 'none' ? 'flex' : 'none';
                    });
                    categoryDiv.appendChild(categoryTitle);

                    const sourceItemsDiv = document.createElement('div');
                    sourceItemsDiv.className = 'source-items';

                    categories[category].forEach((source, index) => {
                        var sourceItem = document.createElement('div');
                        sourceItem.className = 'source-item';
                        sourceItem.setAttribute('data-url', source.url);
                        sourceItem.innerHTML = `<img src="${source.img}" alt="Icon ${index + 1}"><span>${source.name}</span>`;
                        sourceItem.addEventListener('click', function() {
                            loadSource(source.url);
                        });
                        sourceItemsDiv.appendChild(sourceItem);
                    });

                    categoryDiv.appendChild(sourceItemsDiv);
                    sourceList.appendChild(categoryDiv);
                }
            }

            fetchM3U('https://m3u.work/cGkexz').then(sources => {
                if (sources.length > 0) {
                    populateSourceList(sources);
                    loadSource(sources[0].url);
                } else {
                    errorMessage.style.display = 'block';
                    console.error('No valid URLs found in the m3u file.');
                }
            }).catch(error => {
                errorMessage.style.display = 'block';
                console.error('Error fetching m3u file:', error);
            });

            // Show loading spinner while buffering
            video.addEventListener('waiting', function() {
                loadingSpinner.style.display = 'block';
            });

            // Hide loading spinner when playing
            video.addEventListener('playing', function() {
                loadingSpinner.style.display = 'none';
            });

            // Disable seeking
            video.addEventListener('seeking', function() {
                video.currentTime = video.startTime;
            });

            // Play button
            document.getElementById('playButton').addEventListener('click', function() {
                video.play().catch(function(error) {
                    console.error('Error playing video:', error);
                });
            });

            // Pause button
            document.getElementById('pauseButton').addEventListener('click', function() {
                video.pause();
            });

            // Stop button
            document.getElementById('stopButton').addEventListener('click', function() {
                video.pause();
                video.currentTime = 0;
            });

            // Fullscreen button
            document.getElementById('fullscreenButton').addEventListener('click', function() {
                if (video.requestFullscreen) {
                    video.requestFullscreen();
                } else if (video.mozRequestFullScreen) { // Firefox
                    video.mozRequestFullScreen();
                } else if (video.webkitRequestFullscreen) { // Chrome, Safari and Opera
                    video.webkitRequestFullscreen();
                } else if (video.msRequestFullscreen) { // IE/Edge
                    video.msRequestFullscreen();
                }
            });

            // Hide controls after 3 seconds of inactivity
            let controls = document.getElementById('controls');
            let timeout;
            document.getElementById('videoContainer').addEventListener('mousemove', function() {
                controls.style.opacity = 1;
                clearTimeout(timeout);
                timeout = setTimeout(function() {
                    controls.style.opacity = 0;
                }, 3000); }); } 
				
			</script> 
		</body> 
	</html>