document.addEventListener('DOMContentLoaded', async function() { const player = document.getElementById('player'); const playerOverlay = document.getElementById('player-overlay'); const channelList = document.getElementById('channel-list'); const currentChannel = document.getElementById('current-channel'); const currentProgram = document.getElementById('current-program'); // Default M3U URL const m3uUrl = 'https://iptv-org.github.io/iptv/languages/mal.m3u'; playerOverlay.classList.remove('hidden'); // Load channels from M3U file async function loadChannels() { try { const response = await fetch(m3uUrl); const text = await response.text(); const channels = parseM3U(text); channelList.innerHTML = ''; channels.forEach(channel => { const channelItem = document.createElement('div'); channelItem.className = 'channel-item bg-gray-700 hover:bg-gray-600 rounded-lg p-3 cursor-pointer flex items-center transition-all'; channelItem.innerHTML = `

${channel.name}

${channel.group || 'General'}

`; channelItem.addEventListener('click', () => { playChannel(channel); }); channelList.appendChild(channelItem); }); feather.replace(); } catch (error) { console.error('Error loading channels:', error); channelList.innerHTML = `

Failed to load channels. Please try again later.

`; feather.replace(); } } // Parse M3U file content function parseM3U(content) { const lines = content.split('\n'); const channels = []; for (let i = 0; i < lines.length; i++) { if (lines[i].startsWith('#EXTINF:')) { const infoLine = lines[i]; const urlLine = lines[i + 1]; if (urlLine && !urlLine.startsWith('#')) { const channel = { name: extractName(infoLine), group: extractGroup(infoLine), url: urlLine.trim() }; channels.push(channel); i++; } } } return channels; } // Extract channel name from EXTINF line function extractName(extinfLine) { const match = extinfLine.match(/tvg-name="([^"]*)"/i); if (match && match[1]) { return match[1]; } // Fallback to last part after comma const parts = extinfLine.split(','); return parts[parts.length - 1].trim(); } // Extract channel group from EXTINF line function extractGroup(extinfLine) { const match = extinfLine.match(/group-title="([^"]*)"/i); return match && match[1] ? match[1] : null; } // Play selected channel function playChannel(channel) { playerOverlay.classList.add('hidden'); currentChannel.textContent = channel.name; currentProgram.textContent = channel.group ? `Category: ${channel.group}` : 'Live Stream'; player.pause(); // Check if HLS.js is needed if (channel.url.endsWith('.m3u8')) { if (typeof Hls === 'undefined') { loadHlsJs().then(() => { setupHlsPlayer(channel.url); }); } else { setupHlsPlayer(channel.url); } } else { // Direct video source player.src = channel.url; player.play(); } // Highlight selected channel const channelItems = document.querySelectorAll('.channel-item'); channelItems.forEach(item => { item.classList.remove('bg-rose-500', 'text-white'); item.classList.add('bg-gray-700', 'hover:bg-gray-600'); }); // Find and highlight the clicked channel const selectedChannel = [...channelItems].find(item => item.querySelector('h3').textContent === channel.name ); if (selectedChannel) { selectedChannel.classList.remove('bg-gray-700', 'hover:bg-gray-600'); selectedChannel.classList.add('bg-rose-500', 'text-white'); } } // Load HLS.js dynamically function loadHlsJs() { return new Promise((resolve, reject) => { if (typeof Hls !== 'undefined') { resolve(); return; } const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/hls.js@latest'; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } // Setup HLS player function setupHlsPlayer(url) { if (Hls.isSupported()) { const hls = new Hls(); hls.loadSource(url); hls.attachMedia(player); hls.on(Hls.Events.MANIFEST_PARSED, function() { player.play(); }); } else if (player.canPlayType('application/vnd.apple.mpegurl')) { // For Safari player.src = url; player.play(); } else { alert('Error: Your browser does not support HLS streaming.'); } } // Initialize the app loadChannels(); // Handle volume change from player controls document.addEventListener('volumechange', (e) => { player.volume = e.detail.volume; }); // Handle play/pause from player controls document.addEventListener('playpause', () => { if (player.paused) { player.play(); } else { player.pause(); } }); // Handle fullscreen from player controls document.addEventListener('fullscreen', () => { if (player.requestFullscreen) { player.requestFullscreen(); } else if (player.webkitRequestFullscreen) { player.webkitRequestFullscreen(); } else if (player.msRequestFullscreen) { player.msRequestFullscreen(); } }); // Channel navigation let currentChannelIndex = -1; let channels = []; document.addEventListener('prevchannel', () => { if (channels.length === 0) return; currentChannelIndex = (currentChannelIndex - 1 + channels.length) % channels.length; playChannel(channels[currentChannelIndex]); }); document.addEventListener('nextchannel', () => { if (channels.length === 0) return; currentChannelIndex = (currentChannelIndex + 1) % channels.length; playChannel(channels[currentChannelIndex]); }); // Modified loadChannels to store channels globally async function loadChannels() { try { const response = await fetch(m3uUrl); const text = await response.text(); channels = parseM3U(text); channelList.innerHTML = ''; channels.forEach((channel, index) => { const channelItem = document.createElement('div'); channelItem.className = 'channel-item bg-gray-700 hover:bg-gray-600 rounded-lg p-3 cursor-pointer flex items-center transition-all'; channelItem.innerHTML = `

${channel.name}

${channel.group || 'General'}

`; channelItem.addEventListener('click', () => { currentChannelIndex = index; playChannel(channel); }); channelList.appendChild(channelItem); }); });