{"id":540,"date":"2026-07-18T12:21:24","date_gmt":"2026-07-18T12:21:24","guid":{"rendered":"https:\/\/freewebtools.co.in\/?page_id=540"},"modified":"2026-07-28T16:52:18","modified_gmt":"2026-07-28T16:52:18","slug":"video-stream","status":"publish","type":"page","link":"https:\/\/freewebtools.co.in\/index.php\/video-stream\/","title":{"rendered":"Streaming"},"content":{"rendered":"\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>YouTube Online Streamer<\/title>\n<style>\n    :root {\n        --ytps-primary: #ff0000;\n        --ytps-bg: #f8fafc;\n        --ytps-card-bg: #ffffff;\n        --ytps-text: #1e293b;\n        --ytps-text-light: #64748b;\n        --ytps-accent: #3b82f6;\n        --ytps-radius: 12px;\n        --ytps-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n    }\n\n    .ytps-container {\n        font-family: system-ui, -apple-system, sans-serif;\n        background: var(--ytps-bg);\n        color: var(--ytps-text);\n        padding: 20px;\n        max-width: 1200px;\n        margin: 0 auto;\n        border-radius: var(--ytps-radius);\n        box-shadow: var(--ytps-shadow);\n        box-sizing: border-box;\n    }\n\n    .ytps-container *, .ytps-container *::before, .ytps-container *::after {\n        box-sizing: inherit;\n    }\n\n    .ytps-input-group {\n        display: flex;\n        gap: 10px;\n        margin-top: 10px;\n    }\n\n    .ytps-input-group input, .ytps-sidebar input {\n        flex: 1;\n        padding: 12px 16px;\n        border: 1px solid #cbd5e1;\n        border-radius: var(--ytps-radius);\n        font-size: 14px;\n        outline: none;\n        background: var(--ytps-card-bg);\n        color: var(--ytps-text);\n    }\n\n    .ytps-sidebar input {\n        width: 100%;\n        margin-bottom: 12px;\n    }\n\n    \/* Player Wrapper *\/\n    .ytps-player-frame {\n        position: relative;\n        padding-bottom: 56.25%;\n        height: 0;\n        overflow: hidden;\n        border-radius: var(--ytps-radius);\n        background: #000;\n        box-shadow: var(--ytps-shadow);\n    }\n\n    .ytps-player-frame iframe {\n        position: absolute;\n        top: 0;\n        left: 0;\n        width: 100%;\n        height: 100%;\n        border: none;\n    }\n\n    \/* Controls *\/\n    .ytps-controls {\n        display: flex;\n        gap: 10px;\n        margin: 20px 0;\n        flex-wrap: wrap;\n    }\n\n    .ytps-btn {\n        padding: 10px 20px;\n        border: none;\n        border-radius: var(--ytps-radius);\n        cursor: pointer;\n        background: var(--ytps-primary);\n        color: white;\n        font-weight: 600;\n        transition: transform 0.2s, opacity 0.2s;\n    }\n\n    .ytps-btn:hover { opacity: 0.9; transform: translateY(-2px); }\n\n    \/* Playlist Styles *\/\n    .ytps-playlist-container {\n        display: grid;\n        grid-template-columns: 1fr 350px;\n        gap: 20px;\n    }\n\n    .ytps-video-list {\n        list-style: none;\n        padding: 0;\n        margin: 0;\n        max-height: 540px;\n        overflow-y: auto;\n        background: var(--ytps-card-bg);\n        border-radius: var(--ytps-radius);\n        border: 1px solid #e2e8f0;\n    }\n\n    .ytps-video-item {\n        display: flex;\n        align-items: center;\n        gap: 12px;\n        padding: 10px;\n        border-bottom: 1px solid #e2e8f0;\n        cursor: pointer;\n        transition: background 0.2s;\n    }\n\n    .ytps-video-item:last-child { border-bottom: none; }\n    .ytps-video-item:hover { background: rgba(0,0,0,0.03); }\n    .ytps-video-item.ytps-active { border-left: 4px solid var(--ytps-primary); background: rgba(255,0,0,0.05); }\n\n    .ytps-thumbnail { \n        width: 100px; \n        height: 60px;\n        object-fit: cover;\n        border-radius: 6px; \n        background: #cbd5e1;\n        flex-shrink: 0;\n    }\n\n    .ytps-video-info {\n        min-width: 0;\n        flex: 1;\n    }\n\n    .ytps-video-info h4 {\n        font-size: 13px;\n        margin: 0 0 4px 0;\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n    }\n\n    .ytps-video-info p {\n        font-size: 11px;\n        color: var(--ytps-text-light);\n        margin: 0;\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n    }\n\n    @media (max-width: 768px) {\n        .ytps-playlist-container { grid-template-columns: 1fr; }\n    }\n<\/style>\n\n<div id=\"ytps-app\" class=\"ytps-container\">\n    <header style=\"margin-bottom: 20px;\">\n        <h1 style=\"margin: 0 0 10px 0; font-size: 24px;\">YouTube Online Streamer<\/h1>\n        <div class=\"ytps-input-group\">\n            <input type=\"text\" id=\"ytps-playlist-input\" placeholder=\"Paste any YouTube video link here...\">\n            <button id=\"ytps-load-btn\" class=\"ytps-btn\">Stream Link<\/button>\n        <\/div>\n    <\/header>\n\n    <div class=\"ytps-playlist-container\">\n        <section class=\"ytps-main-view\">\n            <div id=\"ytps-player\" class=\"ytps-player-frame\"><\/div>\n            <div class=\"ytps-controls\">\n                <button id=\"ytps-prev\" class=\"ytps-btn\">Previous<\/button>\n                <button id=\"ytps-next\" class=\"ytps-btn\">Next<\/button>\n            <\/div>\n        <\/section>\n        \n        <aside class=\"ytps-sidebar\">\n            <input type=\"text\" id=\"ytps-search\" placeholder=\"Search queue...\">\n            <ul id=\"ytps-video-list\" class=\"ytps-video-list\"><\/ul>\n        <\/aside>\n    <\/div>\n<\/div>\n\n<script>\n(function() {\n    'use strict';\n\n    const ytps = {\n        player: null,\n        playlist: [\n            { id: 'dQw4w9WgXcQ', title: 'Rick Astley - Never Gonna Give You Up', channel: 'RickAstleyVEVO' },\n            { id: '3JZ_D3ELwOQ', title: 'Carly Rae Jepsen - Call Me Maybe', channel: 'CarlyRaeJepsenVEVO' }\n        ],\n        filteredPlaylist: [],\n        currentIndex: 0,\n        els: {},\n        isApiReady: false,\n        pendingVideoId: null,\n\n        init() {\n            this.filteredPlaylist = [...this.playlist];\n            this.els = {\n                player: document.getElementById('ytps-player'),\n                loadBtn: document.getElementById('ytps-load-btn'),\n                input: document.getElementById('ytps-playlist-input'),\n                list: document.getElementById('ytps-video-list'),\n                next: document.getElementById('ytps-next'),\n                prev: document.getElementById('ytps-prev'),\n                search: document.getElementById('ytps-search')\n            };\n\n            this.loadYouTubeIframeAPI();\n            this.addListeners();\n            this.renderPlaylist();\n        },\n\n        loadYouTubeIframeAPI() {\n            if (window.YT && window.YT.Player) {\n                this.onApiReady();\n                return;\n            }\n\n            if (!window.onYouTubeIframeAPIReady) {\n                window.onYouTubeIframeAPIReady = () => {\n                    this.onApiReady();\n                };\n            }\n\n            if (!document.getElementById('yt-iframe-api')) {\n                const tag = document.createElement('script');\n                tag.id = 'yt-iframe-api';\n                tag.src = \"https:\/\/www.youtube.com\/iframe_api\";\n                const firstScriptTag = document.getElementsByTagName('script')[0];\n                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n            }\n        },\n\n        onApiReady() {\n            this.isApiReady = true;\n            this.setupPlayer();\n        },\n\n        setupPlayer() {\n            if (this.player || !this.isApiReady) return;\n            \n            try {\n                this.player = new YT.Player('ytps-player', {\n                    height: '100%',\n                    width: '100%',\n                    videoId: this.playlist[this.currentIndex].id,\n                    playerVars: { 'autoplay': 1, 'modestbranding': 1, 'rel': 0 },\n                    events: {\n                        'onReady': () => {\n                            if (this.pendingVideoId) {\n                                const idToPlay = this.pendingVideoId;\n                                this.pendingVideoId = null;\n                                this.player.loadVideoById(idToPlay);\n                            }\n                        },\n                        'onStateChange': (e) => { \n                            if(e.data === YT.PlayerState.ENDED) {\n                                this.playNext(); \n                            }\n                        }\n                    }\n                });\n            } catch(e) {\n                console.error(\"Error creating YouTube player instance:\", e);\n            }\n        },\n\n        addListeners() {\n            this.els.loadBtn.addEventListener('click', () => this.handleUserLink(this.els.input.value));\n            this.els.input.addEventListener('keydown', (e) => {\n                if (e.key === 'Enter') {\n                    this.handleUserLink(this.els.input.value);\n                }\n            });\n\n            this.els.next.addEventListener('click', () => this.playNext());\n            this.els.prev.addEventListener('click', () => this.playPrev());\n            \n            this.els.search.addEventListener('input', (e) => {\n                const query = e.target.value.toLowerCase().trim();\n                this.filteredPlaylist = this.playlist.filter(video => \n                    video.title.toLowerCase().includes(query) || video.channel.toLowerCase().includes(query)\n                );\n                this.renderPlaylist();\n            });\n            \n            document.addEventListener('keydown', (e) => {\n                if(e.code === 'Space' && document.activeElement.tagName !== 'INPUT') {\n                    e.preventDefault();\n                    if(this.player && typeof this.player.getPlayerState === 'function') {\n                        const state = this.player.getPlayerState();\n                        if (state === YT.PlayerState.PLAYING) {\n                            this.player.pauseVideo();\n                        } else {\n                            this.player.playVideo();\n                        }\n                    }\n                }\n            });\n        },\n\n        extractVideoId(url) {\n            if (!url) return null;\n            const cleanedUrl = url.trim();\n            const regExp = \/^.*(youtu.be\\\/|v\\\/|u\\\/\\w\\\/|embed\\\/|shorts\\\/|watch\\?v=|\\&v=)([^#\\&\\?]*).*\/;\n            const match = cleanedUrl.match(regExp);\n            if (match && match[2].length === 11) {\n                return match[2];\n            }\n            if (cleanedUrl.length === 11) {\n                return cleanedUrl;\n            }\n            return null;\n        },\n\n        async handleUserLink(inputVal) {\n            const videoId = this.extractVideoId(inputVal);\n            if (!videoId) {\n                alert(\"Please enter a valid YouTube video link or 11-character video ID.\");\n                return;\n            }\n\n            const existingIndex = this.playlist.findIndex(v => v.id === videoId);\n            if (existingIndex !== -1) {\n                this.currentIndex = existingIndex;\n                this.loadVideo();\n                this.renderPlaylist();\n                this.els.input.value = '';\n                return;\n            }\n\n            let videoTitle = `Streamed Video (${videoId})`;\n            let channelName = 'Live Online Stream';\n\n            try {\n                const res = await fetch(`https:\/\/noembed.com\/embed?url=https:\/\/www.youtube.com\/watch?v=${videoId}`);\n                if (res.ok) {\n                    const data = await res.json();\n                    if (data && !data.error) {\n                        videoTitle = data.title || videoTitle;\n                        channelName = data.author_name || channelName;\n                    }\n                }\n            } catch (err) {\n                console.warn(\"External metadata fetch bypassed, using default info.\", err);\n            }\n\n            const newVideo = {\n                id: videoId,\n                title: videoTitle,\n                channel: channelName\n            };\n\n            this.playlist.push(newVideo);\n            this.currentIndex = this.playlist.length - 1;\n            \n            const searchQuery = this.els.search.value.toLowerCase().trim();\n            if (searchQuery) {\n                this.filteredPlaylist = this.playlist.filter(video => \n                    video.title.toLowerCase().includes(searchQuery) || video.channel.toLowerCase().includes(searchQuery)\n                );\n            } else {\n                this.filteredPlaylist = [...this.playlist];\n            }\n            \n            this.loadVideo();\n            this.renderPlaylist();\n            this.els.input.value = '';\n        },\n\n        renderPlaylist() {\n            this.els.list.innerHTML = '';\n            if (this.filteredPlaylist.length === 0) {\n                this.els.list.innerHTML = '<li style=\"padding: 15px; text-align: center; color: var(--ytps-text-light);\">No items in queue<\/li>';\n                return;\n            }\n\n            this.filteredPlaylist.forEach((video) => {\n                const originalIndex = this.playlist.findIndex(v => v.id === video.id);\n                const li = document.createElement('li');\n                li.className = `ytps-video-item ${originalIndex === this.currentIndex ? 'ytps-active' : ''}`;\n                \n                li.innerHTML = `\n                    <img decoding=\"async\" class=\"ytps-thumbnail\" src=\"https:\/\/img.youtube.com\/vi\/${video.id}\/mqdefault.jpg\" alt=\"Thumb\">\n                    <div class=\"ytps-video-info\">\n                        <h4>${video.title}<\/h4>\n                        <p>${video.channel}<\/p>\n                    <\/div>\n                `;\n                \n                li.addEventListener('click', () => {\n                    this.currentIndex = originalIndex;\n                    this.loadVideo();\n                    this.renderPlaylist();\n                });\n                \n                this.els.list.appendChild(li);\n            });\n        },\n\n        playNext() {\n            if (this.playlist.length === 0) return;\n            this.currentIndex = (this.currentIndex + 1) % this.playlist.length;\n            this.loadVideo();\n            this.renderPlaylist();\n        },\n\n        playPrev() {\n            if (this.playlist.length === 0) return;\n            this.currentIndex = (this.currentIndex - 1 + this.playlist.length) % this.playlist.length;\n            this.loadVideo();\n            this.renderPlaylist();\n        },\n\n        loadVideo() {\n            const currentVideo = this.playlist[this.currentIndex];\n            if (!currentVideo) return;\n\n            if (this.player && typeof this.player.loadVideoById === 'function') {\n                try {\n                    this.player.loadVideoById(currentVideo.id);\n                } catch(e) {\n                    this.pendingVideoId = currentVideo.id;\n                    this.setupPlayer();\n                }\n            } else {\n                this.pendingVideoId = currentVideo.id;\n                this.loadYouTubeIframeAPI();\n            }\n            this.renderPlaylist();\n        }\n    };\n\n    ytps.init();\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>YouTube Online Streamer YouTube Online Streamer Stream Link Previous Next<\/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-540","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/540","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=540"}],"version-history":[{"count":8,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/540\/revisions"}],"predecessor-version":[{"id":768,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/540\/revisions\/768"}],"wp:attachment":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}