📺 IPTV IPTV Website Source Code Built with JavaScript & Tailwind CSS

Responsive IPTV web application designed using JavaScript and Tailwind CSS. Ideal for streaming live channels or VOD content. When hosted, it works seamlessly on Smart TVs, offering a user-friendly interface optimized for large screens.

Thanks to the contributor who shared the IPTV M3U8 links.



Preview:

1754467832844.webp




HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IPTV Player</title>
  
    <!-- Tailwind CSS for styling -->
    <script src="https://cdn.tailwindcss.com"></script>
  
    <!-- HLS.js for playing M3U8 streams -->
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  
    <!-- Google Fonts: Inter -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
  
    <!-- Icon Library (for Play button, etc.) -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">

    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #0c0c0c;
            color: #fff;
        }

        .hero-gradient {
            background-image: linear-gradient(to right, rgba(0,0,0,0.8) 20%, rgba(0,0,0,0.2) 60%, transparent 100%);
        }

        .row-container::-webkit-scrollbar { display: none; } /* Hide scrollbar */
        .row-container { -ms-overflow-style: none; scrollbar-width: none; }

        .channel-tile {
            transition: transform 0.2s ease-out, box-shadow 0.2s ease-out;
            flex-shrink: 0;
        }

        .channel-tile:hover, .channel-tile:focus {
            transform: scale(1.08);
            z-index: 20;
            box-shadow: 0 10px 20px rgba(0,0,0,0.5);
        }
      
        .channel-tile:focus {
             outline: 3px solid white;
        }
      
        .row-arrow {
            opacity: 0;
            transition: opacity 0.2s ease-in-out;
            background-color: rgba(0,0,0,0.5);
        }
      
        /* Use group-hover to show arrows on desktop */
        .row:hover .row-arrow {
            opacity: 1;
        }

        .loader {
            border: 5px solid #4b5563;
            border-top: 5px solid #e50914;
            border-radius: 50%;
            width: 60px;
            height: 60px;
            animation: spin 1.2s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .view {
            transition: opacity 0.3s ease-in-out;
        }
        .view.hidden {
            opacity: 0;
            pointer-events: none;
        }
    </style>
</head>
<body class="overflow-x-hidden">

    <!-- Main Browse View -->
    <div id="browseView" class="view">
        <!-- Hero Section -->
        <section id="hero" class="relative h-[60vh] min-h-[400px] w-full flex items-center text-white bg-cover bg-center bg-no-repeat" style="background-image: url('https://placehold.co/1920x1080/1a202c/718096?text=IPTV+Player');">
            <div class="hero-gradient absolute inset-0"></div>
            <div class="relative z-10 p-8 md:p-16 max-w-2xl">
                <h1 id="heroChannelName" class="text-4xl md:text-6xl font-extrabold drop-shadow-lg">Channel Name</h1>
                <p class="mt-4 text-lg max-w-prose text-gray-200 drop-shadow-md">
                    Welcome to your modern IPTV experience. Select a channel from the rows below or press play to start the featured channel.
                </p>
                <div class="mt-8 flex space-x-4">
                    <button id="heroPlayButton" class="flex items-center justify-center bg-white text-black font-bold py-3 px-8 rounded-md hover:bg-gray-200 transition-colors">
                        <i class="fas fa-play mr-2"></i> Play
                    </button>
                </div>
            </div>
        </section>

        <!-- Channel Rows Container -->
        <main id="rowsContainer" class="p-8 md:p-12 -mt-16 relative z-10">
            <!-- Rows will be dynamically inserted here -->
        </main>
    </div>

    <!-- Player View -->
    <div id="playerView" class="view hidden fixed inset-0 bg-black flex items-center justify-center z-50">
        <video id="videoPlayer" class="w-full h-full" controls autoplay></video>
        <div id="loading" class="loader absolute hidden"></div>
        <button id="backToBrowse" class="absolute top-5 left-5 z-50 bg-black bg-opacity-50 rounded-full w-12 h-12 flex items-center justify-center text-2xl hover:bg-opacity-75 transition-all">
            <i class="fas fa-arrow-left"></i>
        </button>
    </div>

    <script>
    document.addEventListener('DOMContentLoaded', () => {
        // --- DOM Elements ---
        const browseView = document.getElementById('browseView');
        const playerView = document.getElementById('playerView');
        const video = document.getElementById('videoPlayer');
        const loading = document.getElementById('loading');
        const backToBrowseBtn = document.getElementById('backToBrowse');
        const rowsContainer = document.getElementById('rowsContainer');
        const heroSection = document.getElementById('hero');
        const heroChannelName = document.getElementById('heroChannelName');
        const heroPlayButton = document.getElementById('heroPlayButton');

        let hls = null;
        let featuredChannel = null;

        // --- Channel Data & Categorization ---
        const channels = new Map([
            ['Star Movies HD', 'https://starofvenus.dpdns.org/starmovieshd/playlist.m3u8'], ['Movies Now HD', 'https://starofvenus.dpdns.org/moviesnowhd/playlist.m3u8'], ['HBO Family', 'https://starofvenus.dpdns.org/hbofamily/playlist.m3u8'], ['HBO HD', 'https://starofvenus.dpdns.org/hbohd/playlist.m3u8'], ['HBO Signature', 'https://starofvenus.dpdns.org/hbosignature/playlist.m3u8'], ['HBO Hits', 'https://starofvenus.dpdns.org/hbohits/playlist.m3u8'], ['Cinemax', 'https://starofvenus.dpdns.org/cinemax/playlist.m3u8'], ['Hits Movies', 'https://starofvenus.dpdns.org/hitsmovies/playlist.m3u8'], ['tvN Movies', 'https://starofvenus.dpdns.org/tvnmovies/playlist.m3u8'], ['Celestial Classic', 'https://starofvenus.dpdns.org/celestialclassic/playlist.m3u8'], ['Celestial Movies HD', 'https://starofvenus.dpdns.org/celestialmovieshd/playlist.m3u8'], ['Thrill', 'https://starofvenus.dpdns.org/thrill/playlist.m3u8'], ['Rock Actions', 'https://starofvenus.dpdns.org/rockactions/playlist.m3u8'],
            ['Animax', 'https://starofvenus.dpdns.org/animax/playlist.m3u8'], ['Dreamworks', 'https://starofvenus.dpdns.org/dreamworks/playlist.m3u8'], ['Warner TV', 'https://starofvenus.dpdns.org/warnertv/playlist.m3u8'], ['AXN HD', 'https://starofvenus.dpdns.org/axnhd/playlist.m3u8'], ['Hits', 'https://starofvenus.dpdns.org/hits/playlist.m3u8'], ['One', 'https://starofvenus.dpdns.org/one/playlist.m3u8'], ['Paramount Network', 'https://starofvenus.dpdns.org/paramountnetwork/playlist.m3u8'], ['Rock Entertainment', 'https://starofvenus.dpdns.org/rockentertainment/playlist.m3u8'], ['SCM', 'https://starofvenus.dpdns.org/scm/playlist.m3u8'], ['Kplus', 'https://starofvenus.dpdns.org/kplus/playlist.m3u8'],
            ['NatGeo HD', 'https://starofvenus.dpdns.org/natgeohd/playlist.m3u8'], ['NatGeo Wild HD', 'https://starofvenus.dpdns.org/natgeowild/playlist.m3u8'], ['Animal Planet', 'https://starofvenus.dpdns.org/animalplanet/playlist.m3u8'], ['Discovery Asia', 'https://starofvenus.dpdns.org/discoveryasia/playlist.m3u8'], ['Discovery HD', 'https://starofvenus.dpdns.org/discoveryhd/playlist.m3u8'], ['History', 'https://starofvenus.dpdns.org/history/playlist.m3u8'], ['BBC Earth HD', 'https://starofvenus.dpdns.org/bbcearthhd/playlist.m3u8'], ['Crime Investigation', 'https://starofvenus.dpdns.org/ci/playlist.m3u8'],
            ['BBC Lifestyle', 'https://starofvenus.dpdns.org/bbclifestyle/playlist.m3u8'], ['TLC', 'https://starofvenus.dpdns.org/tlc/playlist.m3u8'], ['Food Network HD', 'https://starofvenus.dpdns.org/foodnetworkhd/playlist.m3u8'], ['HGTV', 'https://starofvenus.dpdns.org/hgtv/playlist.m3u8'], ['Fashion TV', 'https://starofvenus.dpdns.org/fashiontv/playlist.m3u8']
        ]);

        const categories = {
            "Movies": ['movie', 'hbo', 'cinemax', 'hits', 'thrill', 'celestial', 'tvn'],
            "Entertainment": ['axn', 'warner', 'one', 'paramount', 'rock', 'animax', 'dreamworks', 'scm', 'kplus'],
            "Documentaries": ['natgeo', 'discovery', 'history', 'animal planet', 'bbc earth', 'crime'],
            "Lifestyle": ['lifestyle', 'tlc', 'food', 'hgtv', 'fashion']
        };

        function categorizeChannels() {
            const categorized = {};
            for (const category in categories) {
                categorized[category] = [];
            }

            channels.forEach((url, name) => {
                let found = false;
                const lowerCaseName = name.toLowerCase();
                for (const category in categories) {
                    if (categories[category].some(keyword => lowerCaseName.includes(keyword))) {
                        categorized[category].push({ name, url });
                        found = true;
                        break;
                    }
                }
            });
            return categorized;
        }

        // --- UI Rendering ---
      
        function createChannelTile(channel) {
            const tile = document.createElement('div');
            tile.className = 'channel-tile w-60 h-36 bg-gray-800 rounded-md flex items-center justify-center p-3 cursor-pointer text-center relative overflow-hidden';
            tile.tabIndex = 0;
            tile.innerHTML = `<span class="relative z-10 font-bold text-lg">${channel.name}</span><div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>`;
          
            tile.addEventListener('click', () => {
                loadChannel(channel.url, channel.name);
                showPlayerView();
            });
            return tile;
        }

        function createRow(category, channels) {
            const rowWrapper = document.createElement('div');
            // Added 'group' class for hover effects on children
            rowWrapper.className = 'mb-8 row group';

            const title = document.createElement('h2');
            title.className = 'text-2xl font-bold mb-4';
            title.textContent = category;

            const rowContainer = document.createElement('div');
            rowContainer.className = 'relative';

            const rowContent = document.createElement('div');
            rowContent.className = 'row-container flex items-center space-x-4 overflow-x-auto pb-4';
          
            channels.forEach(channel => rowContent.appendChild(createChannelTile(channel)));

            // --- NEW: Scroll Arrow Buttons ---
            const leftArrow = document.createElement('button');
            leftArrow.className = 'row-arrow absolute left-0 top-0 bottom-0 px-4 z-20 hover:bg-black/75';
            leftArrow.innerHTML = '<i class="fas fa-chevron-left"></i>';
            leftArrow.addEventListener('click', () => {
                const scrollAmount = rowContent.clientWidth * 0.8;
                rowContent.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
            });

            const rightArrow = document.createElement('button');
            rightArrow.className = 'row-arrow absolute right-0 top-0 bottom-0 px-4 z-20 hover:bg-black/75';
            rightArrow.innerHTML = '<i class="fas fa-chevron-right"></i>';
            rightArrow.addEventListener('click', () => {
                const scrollAmount = rowContent.clientWidth * 0.8;
                rowContent.scrollBy({ left: scrollAmount, behavior: 'smooth' });
            });
            // --- End of New Code ---

            rowContainer.append(leftArrow, rightArrow, rowContent);
            rowWrapper.append(title, rowContainer);
            return rowWrapper;
        }

        function renderUI() {
            const categorized = categorizeChannels();
            rowsContainer.innerHTML = '';
            for (const category in categorized) {
                if (categorized[category].length > 0) {
                    rowsContainer.appendChild(createRow(category, categorized[category]));
                }
            }
          
            // Set up hero section
            const movieChannels = categorized["Movies"] || [];
            if (movieChannels.length > 0) {
                featuredChannel = movieChannels[Math.floor(Math.random() * movieChannels.length)];
                heroChannelName.textContent = featuredChannel.name;
                const placeholderImageUrl = `https://placehold.co/1920x1080/1f2937/a0aec0?text=${encodeURIComponent(featuredChannel.name)}`;
                heroSection.style.backgroundImage = `url('${placeholderImageUrl}')`;
            }
        }

        // --- View & Player Logic ---

        function showPlayerView() {
            browseView.classList.add('hidden');
            playerView.classList.remove('hidden');
        }

        function showBrowseView() {
            playerView.classList.add('hidden');
            browseView.classList.remove('hidden');
            if (hls) hls.destroy();
            video.pause();
            video.src = "";
        }

        function loadChannel(url, name) {
            loading.classList.remove('hidden');
            if (hls) hls.destroy();

            if (Hls.isSupported()) {
                hls = new Hls({
                    startLevel: -1,
                    capLevelToPlayerSize: true,
                });
                hls.loadSource(url);
                hls.attachMedia(video);
                hls.on(Hls.Events.MANIFEST_PARSED, () => {
                    video.play().catch(e => console.error("Autoplay prevented:", e));
                    loading.classList.add('hidden');
                });
                hls.on(Hls.Events.ERROR, (event, data) => {
                    if (data.fatal) {
                        loading.classList.add('hidden');
                        alert(`Error loading channel: ${name}. Stream may be offline.`);
                        showBrowseView();
                    }
                });
            } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
                video.src = url;
                video.addEventListener('loadedmetadata', () => {
                    video.play().catch(e => console.error("Autoplay prevented:", e));
                    loading.classList.add('hidden');
                });
            } else {
                alert("Your browser does not support HLS streaming.");
                loading.classList.add('hidden');
                showBrowseView();
            }
        }

        // --- Event Listeners ---
        backToBrowseBtn.addEventListener('click', showBrowseView);
        heroPlayButton.addEventListener('click', () => {
            if (featuredChannel) {
                loadChannel(featuredChannel.url, featuredChannel.name);
                showPlayerView();
            }
        });

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && !playerView.classList.contains('hidden')) {
                showBrowseView();
            }
        });

        // --- Initialization ---
        renderUI();
    });
    </script>
</body>
</html>




1754467832844.webp
 

About this Thread

  • 9
    Replies
  • 520
    Views
  • 8
    Participants
Last reply from:
PrincessRaiven

Online now

Members online
1,331
Guests online
6,783
Total visitors
8,114

Forum statistics

Threads
2,329,929
Posts
29,250,886
Members
1,154,711
Latest member
Kenshiro123T
Back
Top