{"id":551,"date":"2026-07-20T14:39:47","date_gmt":"2026-07-20T14:39:47","guid":{"rendered":"https:\/\/freewebtools.co.in\/?page_id=551"},"modified":"2026-07-20T14:39:47","modified_gmt":"2026-07-20T14:39:47","slug":"streaming","status":"publish","type":"page","link":"https:\/\/freewebtools.co.in\/index.php\/streaming\/","title":{"rendered":"Streaming"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"dark\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>YouTube Playlist Manager<\/title>\n    <style>\n        :root {\n            --bg-color: #0f0f0f;\n            --card-bg: #212121;\n            --text-color: #f1f1f1;\n            --text-secondary: #aaa;\n            --border-color: #3f3f3f;\n            --accent-color: #ff0000;\n            --accent-hover: #cc0000;\n            --input-bg: #121212;\n            --hover-bg: #2d2d2d;\n            --active-bg: #383838;\n            --shadow: 0 4px 12px rgba(0,0,0,0.5);\n        }\n\n        [data-theme=\"light\"] {\n            --bg-color: #f9f9f9;\n            --card-bg: #ffffff;\n            --text-color: #0f0f0f;\n            --text-secondary: #606060;\n            --border-color: #e5e5e5;\n            --accent-color: #cc0000;\n            --accent-hover: #990000;\n            --input-bg: #f1f1f1;\n            --hover-bg: #f2f2f2;\n            --active-bg: #e5e5e5;\n            --shadow: 0 4px 12px rgba(0,0,0,0.08);\n        }\n\n        * {\n            box-sizing: border-box;\n            margin: 0;\n            padding: 0;\n            font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n            transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;\n        }\n\n        body {\n            background-color: var(--bg-color);\n            color: var(--text-color);\n            min-height: 100vh;\n            display: flex;\n            flex-direction: column;\n            padding: 20px;\n        }\n\n        \/* Top Bar *\/\n        header {\n            max-width: 1400px;\n            width: 100%;\n            margin: 0 auto 20px auto;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            background: var(--card-bg);\n            padding: 12px 24px;\n            border-radius: 12px;\n            box-shadow: var(--shadow);\n            border: 1px solid var(--border-color);\n        }\n\n        .logo-area {\n            display: flex;\n            align-items: center;\n            gap: 12px;\n        }\n\n        .logo-area svg {\n            width: 32px;\n            height: 32px;\n            fill: var(--accent-color);\n        }\n\n        .playlist-title-input {\n            font-size: 20px;\n            font-weight: 700;\n            background: transparent;\n            border: 1px solid transparent;\n            color: var(--text-color);\n            padding: 4px 8px;\n            border-radius: 6px;\n            width: 300px;\n        }\n\n        .playlist-title-input:hover, .playlist-title-input:focus {\n            border-color: var(--border-color);\n            background: var(--input-bg);\n            outline: none;\n        }\n\n        .header-actions {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n        }\n\n        button {\n            background-color: var(--card-bg);\n            color: var(--text-color);\n            border: 1px solid var(--border-color);\n            padding: 8px 14px;\n            border-radius: 8px;\n            cursor: pointer;\n            font-weight: 600;\n            font-size: 13px;\n            display: flex;\n            align-items: center;\n            gap: 6px;\n        }\n\n        button:hover {\n            background-color: var(--hover-bg);\n        }\n\n        button.primary {\n            background-color: var(--accent-color);\n            color: white;\n            border-color: var(--accent-color);\n        }\n\n        button.primary:hover {\n            background-color: var(--accent-hover);\n        }\n\n        \/* Main Container Layout *\/\n        .main-container {\n            max-width: 1400px;\n            width: 100%;\n            margin: 0 auto;\n            display: grid;\n            grid-template-columns: 1.6fr 1fr;\n            gap: 20px;\n            flex: 1;\n        }\n\n        @media (max-width: 1024px) {\n            .main-container {\n                grid-template-columns: 1fr;\n            }\n        }\n\n        \/* Left Column: Player & Add Form *\/\n        .left-column {\n            display: flex;\n            flex-direction: column;\n            gap: 20px;\n        }\n\n        .player-card {\n            background: var(--card-bg);\n            border-radius: 12px;\n            overflow: hidden;\n            box-shadow: var(--shadow);\n            border: 1px solid var(--border-color);\n        }\n\n        .video-wrapper {\n            position: relative;\n            width: 100%;\n            padding-top: 56.25%; \/* 16:9 Aspect Ratio *\/\n            background: #000;\n        }\n\n        .video-wrapper iframe {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            border: none;\n        }\n\n        .player-fallback {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            gap: 10px;\n            color: var(--text-secondary);\n            padding: 20px;\n            text-align: center;\n        }\n\n        .now-playing-info {\n            padding: 16px 20px;\n            border-top: 1px solid var(--border-color);\n        }\n\n        .now-playing-title {\n            font-size: 16px;\n            font-weight: 600;\n            margin-bottom: 4px;\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n        }\n\n        .now-playing-author {\n            font-size: 13px;\n            color: var(--text-secondary);\n        }\n\n        \/* Controls Toolbar under player *\/\n        .player-controls-bar {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 12px 20px;\n            background: var(--input-bg);\n            border-top: 1px solid var(--border-color);\n        }\n\n        .playback-toggles {\n            display: flex;\n            gap: 8px;\n        }\n\n        .playback-toggles button.active {\n            background: var(--accent-color);\n            color: white;\n            border-color: var(--accent-color);\n        }\n\n        \/* Add Video Section *\/\n        .add-card {\n            background: var(--card-bg);\n            padding: 20px;\n            border-radius: 12px;\n            box-shadow: var(--shadow);\n            border: 1px solid var(--border-color);\n        }\n\n        .add-card h3 {\n            font-size: 15px;\n            margin-bottom: 12px;\n            font-weight: 600;\n        }\n\n        .add-form-group {\n            display: flex;\n            gap: 10px;\n            margin-bottom: 8px;\n        }\n\n        input[type=\"text\"] {\n            flex: 1;\n            background: var(--input-bg);\n            border: 1px solid var(--border-color);\n            padding: 10px 14px;\n            border-radius: 8px;\n            color: var(--text-color);\n            font-size: 14px;\n        }\n\n        input[type=\"text\"]:focus {\n            outline: none;\n            border-color: var(--accent-color);\n        }\n\n        .add-optional-row {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n        }\n\n        .add-optional-row input {\n            max-width: 120px;\n        }\n\n        .error-msg {\n            color: var(--accent-color);\n            font-size: 12px;\n            margin-top: 6px;\n            min-height: 16px;\n        }\n\n        \/* Right Column: Playlist Management *\/\n        .right-column {\n            background: var(--card-bg);\n            border-radius: 12px;\n            box-shadow: var(--shadow);\n            border: 1px solid var(--border-color);\n            display: flex;\n            flex-direction: column;\n            max-height: calc(100vh - 120px);\n            overflow: hidden;\n        }\n\n        .playlist-header {\n            padding: 16px 20px;\n            border-bottom: 1px solid var(--border-color);\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n        }\n\n        .playlist-stats {\n            font-size: 13px;\n            color: var(--text-secondary);\n        }\n\n        .playlist-items {\n            flex: 1;\n            overflow-y: auto;\n            padding: 10px;\n            display: flex;\n            flex-direction: column;\n            gap: 8px;\n        }\n\n        .playlist-item {\n            display: flex;\n            align-items: center;\n            gap: 12px;\n            padding: 8px;\n            border-radius: 8px;\n            background: transparent;\n            cursor: pointer;\n            border: 1px solid transparent;\n            position: relative;\n        }\n\n        .playlist-item:hover {\n            background: var(--hover-bg);\n        }\n\n        .playlist-item.active {\n            background: var(--active-bg);\n            border-color: var(--border-color);\n        }\n\n        .item-thumb-wrapper {\n            position: relative;\n            width: 90px;\n            height: 50px;\n            border-radius: 6px;\n            overflow: hidden;\n            flex-shrink: 0;\n            background: #000;\n        }\n\n        .item-thumb-wrapper img {\n            width: 100%;\n            height: 100%;\n            object-fit: cover;\n        }\n\n        .item-duration-badge {\n            position: absolute;\n            bottom: 3px;\n            right: 3px;\n            background: rgba(0, 0, 0, 0.8);\n            color: white;\n            font-size: 10px;\n            padding: 1px 4px;\n            border-radius: 4px;\n        }\n\n        .item-details {\n            flex: 1;\n            min-width: 0;\n        }\n\n        .item-title {\n            font-size: 13px;\n            font-weight: 600;\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            margin-bottom: 3px;\n        }\n\n        .item-author {\n            font-size: 11px;\n            color: var(--text-secondary);\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n        }\n\n        .item-actions {\n            display: flex;\n            flex-direction: column;\n            gap: 2px;\n            opacity: 0.4;\n            transition: opacity 0.2s;\n        }\n\n        .playlist-item:hover .item-actions {\n            opacity: 1;\n        }\n\n        .item-actions button {\n            background: transparent;\n            border: none;\n            padding: 2px;\n            font-size: 11px;\n            color: var(--text-secondary);\n            cursor: pointer;\n        }\n\n        .item-actions button:hover {\n            color: var(--text-color);\n            background: var(--border-color);\n            border-radius: 4px;\n        }\n\n        .empty-playlist {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            padding: 60px 20px;\n            color: var(--text-secondary);\n            text-align: center;\n            gap: 10px;\n        }\n\n        \/* Toast notification *\/\n        #toast {\n            position: fixed;\n            bottom: 20px;\n            right: 20px;\n            background: var(--card-bg);\n            color: var(--text-color);\n            border: 1px solid var(--border-color);\n            padding: 12px 20px;\n            border-radius: 8px;\n            box-shadow: var(--shadow);\n            font-size: 13px;\n            opacity: 0;\n            transform: translateY(20px);\n            transition: opacity 0.3s ease, transform 0.3s ease;\n            pointer-events: none;\n            z-index: 1000;\n        }\n        #toast.show {\n            opacity: 1;\n            transform: translateY(0);\n        }\n\n        \/* Hidden file input for import *\/\n        #import-file-input {\n            display: none;\n        }\n    <\/style>\n<\/head>\n<body>\n\n    <!-- Top Header -->\n    <header>\n        <div class=\"logo-area\">\n            <svg viewBox=\"0 0 24 24\"><path d=\"M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z\"\/><\/svg>\n            <input type=\"text\" id=\"playlist-name-input\" class=\"playlist-title-input\" value=\"My Favorite Videos\" oninput=\"savePlaylistMetadata()\">\n        <\/div>\n        <div class=\"header-actions\">\n            <button onclick=\"triggerImport()\" title=\"Import Playlist JSON\">\n                <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"><\/path><polyline points=\"7 10 12 15 17 10\"><\/polyline><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"><\/line><\/svg>\n                Import\n            <\/button>\n            <input type=\"file\" id=\"import-file-input\" accept=\".json\" onchange=\"importPlaylist(event)\">\n            <button onclick=\"exportPlaylist()\" title=\"Export Playlist JSON\">\n                <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"><\/path><polyline points=\"17 8 12 3 7 8\"><\/polyline><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"><\/line><\/svg>\n                Export\n            <\/button>\n            <button onclick=\"toggleTheme()\" id=\"theme-toggle-btn\" title=\"Toggle Theme\">\n                \ud83c\udf13 Theme\n            <\/button>\n        <\/div>\n    <\/header>\n\n    <!-- Main Workspace -->\n    <div class=\"main-container\">\n        \n        <!-- Left Column -->\n        <div class=\"left-column\">\n            \n            <!-- Video Player Card -->\n            <div class=\"player-card\">\n                <div class=\"video-wrapper\">\n                    <div id=\"youtube-player\"><\/div>\n                    <div id=\"player-fallback\" class=\"player-fallback\" style=\"display: none;\">\n                        <p>Embedded player unavailable or blocked.<\/p>\n                        <a id=\"fallback-link\" href=\"#\" target=\"_blank\" style=\"color: var(--accent-color);\">Watch directly on YouTube<\/a>\n                    <\/div>\n                <\/div>\n                \n                <div class=\"now-playing-info\">\n                    <div id=\"now-playing-title\" class=\"now-playing-title\">Select a video to start playing<\/div>\n                    <div id=\"now-playing-author\" class=\"now-playing-author\">&#8211;<\/div>\n                <\/div>\n\n                <div class=\"player-controls-bar\">\n                    <div class=\"playback-toggles\">\n                        <button id=\"btn-autoplay\" onclick=\"toggleAutoplay()\" title=\"Autoplay next video\">Autoplay<\/button>\n                        <button id=\"btn-shuffle\" onclick=\"toggleShuffle()\" title=\"Shuffle playlist\">Shuffle<\/button>\n                        <button id=\"btn-repeat\" onclick=\"toggleRepeat()\" title=\"Repeat mode\">Repeat: Off<\/button>\n                    <\/div>\n                    <div>\n                        <button onclick=\"playNext()\" title=\"Next video\">Next \u23ed<\/button>\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- Add Video Form -->\n            <div class=\"add-card\">\n                <h3>Add Video to Playlist<\/h3>\n                <div class=\"add-form-group\">\n                    <input type=\"text\" id=\"video-url-input\" placeholder=\"Paste YouTube URL (e.g., https:\/\/www.youtube.com\/watch?v=...)\" onkeypress=\"if(event.key === 'Enter') addVideoFromInput()\">\n                    <button class=\"primary\" onclick=\"addVideoFromInput()\">Add Video<\/button>\n                <\/div>\n                <div class=\"add-optional-row\">\n                    <input type=\"text\" id=\"video-duration-input\" placeholder=\"Duration (e.g. 3:45)\" maxlength=\"10\">\n                    <span style=\"font-size: 12px; color: var(--text-secondary);\">Optional duration label<\/span>\n                <\/div>\n                <div id=\"add-error-msg\" class=\"error-msg\"><\/div>\n            <\/div>\n\n        <\/div>\n\n        <!-- Right Column: Playlist Management -->\n        <div class=\"right-column\">\n            <div class=\"playlist-header\">\n                <div>\n                    <strong>Playlist Queue<\/strong>\n                    <div id=\"playlist-stats\" class=\"playlist-stats\">0 videos<\/div>\n                <\/div>\n                <div>\n                    <button onclick=\"clearPlaylist()\" style=\"color: var(--accent-color); border-color: rgba(255,0,0,0.3);\">Clear All<\/button>\n                <\/div>\n            <\/div>\n\n            <div id=\"playlist-items-container\" class=\"playlist-items\">\n                <!-- Dynamically populated playlist items -->\n            <\/div>\n        <\/div>\n\n    <\/div>\n\n    <!-- Toast Notification -->\n    <div id=\"toast\"><\/div>\n\n    <!-- YouTube IFrame API Script Loader -->\n    <script>\n        \/\/ State & Configuration\n        let playlist = [];\n        let currentIndex = -1;\n        let player = null;\n        let isAPIReady = false;\n        \n        \/\/ Playback Preferences\n        let autoplayEnabled = true;\n        let shuffleEnabled = false;\n        let repeatMode = 0; \/\/ 0: Off, 1: All, 2: One\n        let currentVolume = 100;\n\n        \/\/ Load State on Startup\n        window.addEventListener(\"DOMContentLoaded\", () => {\n            loadFromLocalStorage();\n            applyTheme();\n            updateUIControlsState();\n            \n            \/\/ If playlist exists, setup first item selection (without auto-playing on load)\n            if (playlist.length > 0 && currentIndex === -1) {\n                currentIndex = 0;\n            }\n        });\n\n        \/\/ --- YouTube API Integration ---\n        const tag = document.createElement('script');\n        tag.src = \"https:\/\/www.youtube.com\/iframe_api\";\n        const firstScriptTag = document.getElementsByTagName('script')[0];\n        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n\n        function onYouTubeIframeAPIReady() {\n            isAPIReady = true;\n            initPlayer();\n        }\n\n        function initPlayer() {\n            if (!isAPIReady) return;\n            \n            const videoId = (currentIndex >= 0 && playlist[currentIndex]) ? playlist[currentIndex].id : '';\n\n            if (player) {\n                if (videoId) {\n                    player.loadVideoById(videoId);\n                } else {\n                    player.stopVideo();\n                }\n                return;\n            }\n\n            try {\n                player = new YT.Player('youtube-player', {\n                    height: '100%',\n                    width: '100%',\n                    videoId: videoId,\n                    playerVars: {\n                        'playsinline': 1,\n                        'autoplay': 0,\n                        'controls': 1\n                    },\n                    events: {\n                        'onReady': onPlayerReady,\n                        'onStateChange': onPlayerStateChange,\n                        'onError': onPlayerError\n                    }\n                });\n            } catch (e) {\n                showFallbackPlayer(videoId);\n            }\n        }\n\n        function onPlayerReady(event) {\n            if (currentVolume) {\n                event.target.setVolume(currentVolume);\n            }\n            if (currentIndex >= 0 && playlist[currentIndex]) {\n                updateNowPlayingDisplay();\n            }\n        }\n\n        function onPlayerStateChange(event) {\n            \/\/ YT.PlayerState.ENDED = 0\n            if (event.data === YT.PlayerState.ENDED) {\n                handleVideoEnded();\n            }\n        }\n\n        function onPlayerError(event) {\n            showToast(\"Error playing video. Skipping...\");\n            playNext();\n        }\n\n        function showFallbackPlayer(videoId) {\n            document.getElementById('youtube-player').style.display = 'none';\n            const fallback = document.getElementById('player-fallback');\n            fallback.style.display = 'flex';\n            if (videoId) {\n                document.getElementById('fallback-link').href = `https:\/\/www.youtube.com\/watch?v=${videoId}`;\n            }\n        }\n\n        \/\/ --- Video Operations & oEmbed Fetching ---\n        function extractYouTubeID(url) {\n            if (!url) return null;\n            const regExp = \/^.*(youtu.be\\\/|v\\\/|u\\\/\\w\\\/|embed\\\/|watch\\?v=|\\&v=)([^#\\&\\?]*).*\/;\n            const match = url.match(regExp);\n            return (match && match[2].length === 11) ? match[2] : null;\n        }\n\n        async function addVideoFromInput() {\n            const urlInput = document.getElementById(\"video-url-input\");\n            const durationInput = document.getElementById(\"video-duration-input\");\n            const errorMsg = document.getElementById(\"add-error-msg\");\n            errorMsg.textContent = \"\";\n\n            const url = urlInput.value.trim();\n            const videoId = extractYouTubeID(url);\n\n            if (!videoId) {\n                errorMsg.textContent = \"Invalid YouTube URL format.\";\n                return;\n            }\n\n            \/\/ Check if already in playlist\n            if (playlist.some(item => item.id === videoId)) {\n                errorMsg.textContent = \"Video is already in the playlist.\";\n                return;\n            }\n\n            \/\/ Fetch oEmbed metadata\n            try {\n                const oembedUrl = `https:\/\/www.youtube.com\/oembed?url=https:\/\/www.youtube.com\/watch?v=${videoId}&format=json`;\n                const response = await fetch(oembedUrl);\n                \n                if (!response.ok) {\n                    throw new Error(\"Failed to fetch video details\");\n                }\n\n                const data = await response.json();\n                \n                const newItem = {\n                    id: videoId,\n                    title: data.title || \"Untitled Video\",\n                    author: data.author_name || \"Unknown Channel\",\n                    thumbnail: data.thumbnail_url || `https:\/\/img.youtube.com\/vi\/${videoId}\/hqdefault.jpg`,\n                    duration: durationInput.value.trim() || \"N\/A\"\n                };\n\n                playlist.push(newItem);\n                saveToLocalStorage();\n                renderPlaylist();\n\n                \/\/ If first video, select it\n                if (playlist.length === 1) {\n                    selectVideo(0, false);\n                }\n\n                urlInput.value = \"\";\n                durationInput.value = \"\";\n                showToast(\"Video added successfully!\");\n\n            } catch (err) {\n                \/\/ Fallback metadata if oembed CORS or network issue arises\n                const newItem = {\n                    id: videoId,\n                    title: `YouTube Video (${videoId})`,\n                    author: \"YouTube Channel\",\n                    thumbnail: `https:\/\/img.youtube.com\/vi\/${videoId}\/hqdefault.jpg`,\n                    duration: durationInput.value.trim() || \"N\/A\"\n                };\n                playlist.push(newItem);\n                saveToLocalStorage();\n                renderPlaylist();\n                if (playlist.length === 1) {\n                    selectVideo(0, false);\n                }\n                urlInput.value = \"\";\n                durationInput.value = \"\";\n                showToast(\"Video added with basic details.\");\n            }\n        }\n\n        function removeVideo(index, event) {\n            event.stopPropagation();\n            playlist.splice(index, 1);\n\n            if (playlist.length === 0) {\n                currentIndex = -1;\n                if (player && typeof player.stopVideo === 'function') {\n                    player.stopVideo();\n                }\n                document.getElementById('now-playing-title').textContent = \"Select a video to start playing\";\n                document.getElementById('now-playing-author').textContent = \"-\";\n            } else if (index === currentIndex) {\n                currentIndex = Math.min(index, playlist.length - 1);\n                selectVideo(currentIndex, true);\n            } else if (index < currentIndex) {\n                currentIndex--;\n            }\n\n            saveToLocalStorage();\n            renderPlaylist();\n            showToast(\"Video removed\");\n        }\n\n        function moveVideo(index, direction, event) {\n            event.stopPropagation();\n            const targetIndex = index + direction;\n            if (targetIndex < 0 || targetIndex >= playlist.length) return;\n\n            const temp = playlist[index];\n            playlist[index] = playlist[targetIndex];\n            playlist[targetIndex] = temp;\n\n            \/\/ Adjust currentIndex tracker if moved\n            if (currentIndex === index) {\n                currentIndex = targetIndex;\n            } else if (currentIndex === targetIndex) {\n                currentIndex = index;\n            }\n\n            saveToLocalStorage();\n            renderPlaylist();\n        }\n\n        function clearPlaylist() {\n            if (playlist.length === 0) return;\n            if (confirm(\"Are you sure you want to clear the entire playlist?\")) {\n                playlist = [];\n                currentIndex = -1;\n                if (player && typeof player.stopVideo === 'function') {\n                    player.stopVideo();\n                }\n                document.getElementById('now-playing-title').textContent = \"Select a video to start playing\";\n                document.getElementById('now-playing-author').textContent = \"-\";\n                saveToLocalStorage();\n                renderPlaylist();\n                showToast(\"Playlist cleared\");\n            }\n        }\n\n        \/\/ --- Playback & Navigation Logic ---\n        function selectVideo(index, autoPlay = true) {\n            if (index < 0 || index >= playlist.length) return;\n            currentIndex = index;\n            renderPlaylist();\n            updateNowPlayingDisplay();\n\n            const video = playlist[currentIndex];\n            if (player && typeof player.loadVideoById === 'function') {\n                document.getElementById('youtube-player').style.display = 'block';\n                document.getElementById('player-fallback').style.display = 'none';\n                if (autoPlay) {\n                    player.loadVideoById(video.id);\n                } else {\n                    player.cueVideoById(video.id);\n                }\n            } else {\n                showFallbackPlayer(video.id);\n            }\n            saveToLocalStorage();\n        }\n\n        function updateNowPlayingDisplay() {\n            if (currentIndex >= 0 && playlist[currentIndex]) {\n                const item = playlist[currentIndex];\n                document.getElementById('now-playing-title').textContent = item.title;\n                document.getElementById('now-playing-author').textContent = item.author;\n            }\n        }\n\n        function handleVideoEnded() {\n            if (repeatMode === 2) {\n                \/\/ Repeat One\n                selectVideo(currentIndex, true);\n                return;\n            }\n\n            if (!autoplayEnabled) return;\n\n            if (shuffleEnabled) {\n                if (playlist.length > 1) {\n                    let nextIdx;\n                    do {\n                        nextIdx = Math.floor(Math.random() * playlist.length);\n                    } while (nextIdx === currentIndex);\n                    selectVideo(nextIdx, true);\n                } else if (playlist.length === 1 && repeatMode === 1) {\n                    selectVideo(0, true);\n                }\n                return;\n            }\n\n            \/\/ Normal sequential order\n            if (currentIndex < playlist.length - 1) {\n                selectVideo(currentIndex + 1, true);\n            } else if (repeatMode === 1) {\n                \/\/ Repeat All\n                selectVideo(0, true);\n            }\n        }\n\n        function playNext() {\n            if (playlist.length === 0) return;\n            let nextIdx;\n            if (shuffleEnabled) {\n                nextIdx = Math.floor(Math.random() * playlist.length);\n            } else {\n                nextIdx = (currentIndex + 1) % playlist.length;\n            }\n            selectVideo(nextIdx, true);\n        }\n\n        \/\/ --- Toggle Controls ---\n        function toggleAutoplay() {\n            autoplayEnabled = !autoplayEnabled;\n            updateUIControlsState();\n            saveToLocalStorage();\n            showToast(`Autoplay ${autoplayEnabled ? 'Enabled' : 'Disabled'}`);\n        }\n\n        function toggleShuffle() {\n            shuffleEnabled = !shuffleEnabled;\n            updateUIControlsState();\n            saveToLocalStorage();\n            showToast(`Shuffle ${shuffleEnabled ? 'Enabled' : 'Disabled'}`);\n        }\n\n        function toggleRepeat() {\n            \/\/ 0: Off, 1: All, 2: One\n            repeatMode = (repeatMode + 1) % 3;\n            updateUIControlsState();\n            saveToLocalStorage();\n            const labels = [\"Off\", \"All\", \"One\"];\n            showToast(`Repeat: ${labels[repeatMode]}`);\n        }\n\n        function updateUIControlsState() {\n            const btnAuto = document.getElementById(\"btn-autoplay\");\n            const btnShuffle = document.getElementById(\"btn-shuffle\");\n            const btnRepeat = document.getElementById(\"btn-repeat\");\n\n            if (autoplayEnabled) btnAuto.classList.add(\"active\");\n            else btnAuto.classList.remove(\"active\");\n\n            if (shuffleEnabled) btnShuffle.classList.add(\"active\");\n            else btnShuffle.classList.remove(\"active\");\n\n            const repeatLabels = [\"Repeat: Off\", \"Repeat: All\", \"Repeat: One\"];\n            btnRepeat.textContent = repeatLabels[repeatMode];\n            if (repeatMode > 0) btnRepeat.classList.add(\"active\");\n            else btnRepeat.classList.remove(\"active\");\n        }\n\n        \/\/ --- UI Rendering ---\n        function renderPlaylist() {\n            const container = document.getElementById(\"playlist-items-container\");\n            const stats = document.getElementById(\"playlist-stats\");\n            container.innerHTML = \"\";\n\n            stats.textContent = `${playlist.length} video${playlist.length === 1 ? '' : 's'}`;\n\n            if (playlist.length === 0) {\n                container.innerHTML = `\n                    <div class=\"empty-playlist\">\n                        <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><circle cx=\"12\" cy=\"12\" r=\"10\"><\/circle><polygon points=\"10 8 16 12 10 16 10 8\"><\/polygon><\/svg>\n                        <p>Your playlist is empty.<br>Add videos using the form above.<\/p>\n                    <\/div>\n                `;\n                return;\n            }\n\n            playlist.forEach((item, index) => {\n                const el = document.createElement(\"div\");\n                el.className = `playlist-item ${index === currentIndex ? 'active' : ''}`;\n                el.onclick = () => selectVideo(index, true);\n\n                el.innerHTML = `\n                    <div class=\"item-thumb-wrapper\">\n                        <img decoding=\"async\" src=\"${item.thumbnail}\" alt=\"Thumbnail\">\n                        <div class=\"item-duration-badge\">${item.duration}<\/div>\n                    <\/div>\n                    <div class=\"item-details\">\n                        <div class=\"item-title\" title=\"${item.escapeAttr ? '' : item.title}\">${item.title}<\/div>\n                        <div class=\"item-author\">${item.author}<\/div>\n                    <\/div>\n                    <div class=\"item-actions\">\n                        <button onclick=\"moveVideo(${index}, -1, event)\" title=\"Move Up\">\u25b2<\/button>\n                        <button onclick=\"moveVideo(${index}, 1, event)\" title=\"Move Down\">\u25bc<\/button>\n                        <button onclick=\"removeVideo(${index}, event)\" title=\"Remove\">\u2715<\/button>\n                    <\/div>\n                `;\n                container.appendChild(el);\n            });\n        }\n\n        \/\/ --- Theme Management ---\n        function toggleTheme() {\n            const html = document.documentElement;\n            const currentTheme = html.getAttribute(\"data-theme\");\n            const newTheme = currentTheme === \"dark\" ? \"light\" : \"dark\";\n            html.setAttribute(\"data-theme\", newTheme);\n            localStorage.setItem(\"yt_playlist_theme\", newTheme);\n        }\n\n        function applyTheme() {\n            const savedTheme = localStorage.getItem(\"yt_playlist_theme\") || \"dark\";\n            document.documentElement.setAttribute(\"data-theme\", savedTheme);\n        }\n\n        \/\/ --- Export \/ Import ---\n        function exportPlaylist() {\n            if (playlist.length === 0) {\n                showToast(\"Playlist is empty, nothing to export.\");\n                return;\n            }\n            const playlistName = document.getElementById(\"playlist-name-input\").value.trim() || \"YouTube_Playlist\";\n            const dataObj = {\n                name: playlistName,\n                playlist: playlist\n            };\n            const dataStr = \"data:text\/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(dataObj, null, 2));\n            const dlAnchor = document.createElement('a');\n            dlAnchor.setAttribute(\"href\", dataStr);\n            dlAnchor.setAttribute(\"download\", `${playlistName.replace(\/[^a-z0-9]\/gi, '_').toLowerCase()}.json`);\n            document.body.appendChild(dlAnchor);\n            dlAnchor.click();\n            dlAnchor.remove();\n            showToast(\"Playlist exported successfully!\");\n        }\n\n        function triggerImport() {\n            document.getElementById(\"import-file-input\").click();\n        }\n\n        function importPlaylist(event) {\n            const file = event.target.files[0];\n            if (!file) return;\n\n            const reader = new FileReader();\n            reader.onload = function(e) {\n                try {\n                    const parsed = JSON.parse(e.target.result);\n                    if (Array.isArray(parsed)) {\n                        playlist = parsed;\n                    } else if (parsed && Array.isArray(parsed.playlist)) {\n                        playlist = parsed.playlist;\n                        if (parsed.name) {\n                            document.getElementById(\"playlist-name-input\").value = parsed.name;\n                        }\n                    } else {\n                        throw new Error(\"Invalid format\");\n                    }\n\n                    currentIndex = playlist.length > 0 ? 0 : -1;\n                    saveToLocalStorage();\n                    renderPlaylist();\n                    if (currentIndex >= 0) {\n                        selectVideo(0, false);\n                    }\n                    showToast(\"Playlist imported successfully!\");\n                } catch (err) {\n                    showToast(\"Failed to parse JSON file.\");\n                }\n                event.target.value = \"\"; \/\/ Reset file input\n            };\n            reader.readAsText(file);\n        }\n\n        \/\/ --- LocalStorage Persistence ---\n        function saveToLocalStorage() {\n            const name = document.getElementById(\"playlist-name-input\").value;\n            const state = {\n                name: name,\n                playlist: playlist,\n                currentIndex: currentIndex,\n                autoplay: autoplayEnabled,\n                shuffle: shuffleEnabled,\n                repeat: repeatMode\n            };\n            localStorage.setItem(\"yt_playlist_manager_state\", JSON.stringify(state));\n        }\n\n        function savePlaylistMetadata() {\n            saveToLocalStorage();\n        }\n\n        function loadFromLocalStorage() {\n            const saved = localStorage.getItem(\"yt_playlist_manager_state\");\n            if (saved) {\n                try {\n                    const state = JSON.parse(saved);\n                    if (state.name) {\n                        document.getElementById(\"playlist-name-input\").value = state.name;\n                    }\n                    if (Array.isArray(state.playlist)) {\n                        playlist = state.playlist;\n                    }\n                    if (typeof state.currentIndex === 'number') {\n                        currentIndex = state.currentIndex;\n                    }\n                    if (typeof state.autoplay === 'boolean') {\n                        autoplayEnabled = state.autoplay;\n                    }\n                    if (typeof state.shuffle === 'boolean') {\n                        shuffleEnabled = state.shuffle;\n                    }\n                    if (typeof state.repeat === 'number') {\n                        repeatMode = state.repeat;\n                    }\n                } catch (e) {\n                    console.error(\"Error loading local state\", e);\n                }\n            } else {\n                \/\/ Default sample video if entirely fresh load\n                playlist = [\n                    {\n                        id: \"dQw4w9WgXcQ\",\n                        title: \"Rick Astley - Never Gonna Give You Up (Official Music Video)\",\n                        author: \"RickAstleyVEVO\",\n                        thumbnail: \"https:\/\/img.youtube.com\/vi\/dQw4w9WgXcQ\/hqdefault.jpg\",\n                        duration: \"3:33\"\n                    }\n                ];\n                currentIndex = 0;\n            }\n            renderPlaylist();\n        }\n\n        \/\/ --- Toast Utility ---\n        function showToast(message) {\n            const toast = document.getElementById(\"toast\");\n            toast.textContent = message;\n            toast.classList.add(\"show\");\n            setTimeout(() => {\n                toast.classList.remove(\"show\");\n            }, 3000);\n        }\n    <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>YouTube Playlist Manager Import Export \ud83c\udf13 Theme Embedded player unavailable or blocked. Watch directly on YouTube Select a video to start playing &#8211; Autoplay Shuffle Repeat: Off Next \u23ed Add Video to Playlist Add Video Optional duration label Playlist Queue 0 videos Clear All<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-551","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/551","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/comments?post=551"}],"version-history":[{"count":1,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/551\/revisions"}],"predecessor-version":[{"id":552,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/551\/revisions\/552"}],"wp:attachment":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=551"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}