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

moonlightK

Forum Expert
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
  • 512
    Views
  • 8
    Participants
Last reply from:
PrincessRaiven

Trending Topics

Online now

Members online
882
Guests online
4,585
Total visitors
5,467

Forum statistics

Threads
2,313,102
Posts
29,171,809
Members
1,184,605
Latest member
visionpix
Back
Top