| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>VideoGuide Pro - Secure Video to Guide Conversion</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .highlight-box { |
| position: absolute; |
| border: 3px solid rgba(59, 130, 246, 0.8); |
| background-color: rgba(59, 130, 246, 0.2); |
| border-radius: 8px; |
| pointer-events: none; |
| } |
| .loading-bar { |
| width: 0%; |
| transition: width 0.3s ease; |
| } |
| .chat-container { |
| max-height: 0; |
| overflow: hidden; |
| transition: max-height 0.3s ease; |
| } |
| .chat-container.open { |
| max-height: 500px; |
| } |
| .modal { |
| opacity: 0; |
| pointer-events: none; |
| transition: opacity 0.3s ease; |
| } |
| .modal.open { |
| opacity: 1; |
| pointer-events: all; |
| } |
| .screenshot-container { |
| position: relative; |
| overflow: hidden; |
| } |
| .screenshot-container.zoomed img { |
| transform: scale(1.1); |
| transition: transform 0.3s ease; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen"> |
| |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="mb-12 text-center"> |
| <h1 class="text-4xl font-bold text-gray-800 mb-2">VideoGuide Pro</h1> |
| <p class="text-lg text-gray-600">Convert any YouTube video into an accurate step-by-step guide</p> |
| <p class="text-sm text-green-600 mt-2"><i class="fas fa-lock mr-1"></i> Secure API integration - No keys required from users</p> |
| </header> |
|
|
| |
| <section class="max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mb-12"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-xl font-semibold text-gray-800">Create New Guide</h2> |
| <button id="showApiInfo" class="text-blue-600 hover:text-blue-800 flex items-center"> |
| <i class="fas fa-info-circle mr-2"></i> API Documentation |
| </button> |
| </div> |
| |
| <div class="flex flex-col md:flex-row gap-4"> |
| <input type="text" id="youtubeUrl" placeholder="Paste YouTube video URL here" |
| class="flex-grow px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> |
| <button id="generateGuide" class="px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"> |
| <i class="fas fa-play mr-2"></i> Analyze Video |
| </button> |
| </div> |
| |
| <div id="loadingContainer" class="mt-4 hidden"> |
| <div class="h-2 bg-gray-200 rounded-full overflow-hidden"> |
| <div id="loadingBar" class="h-full bg-blue-600 loading-bar"></div> |
| </div> |
| <p id="loadingText" class="text-sm text-gray-600 mt-2">Initializing video analysis...</p> |
| </div> |
| </section> |
|
|
| |
| <div id="apiInfoModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 modal"> |
| <div class="bg-white rounded-lg shadow-xl max-w-2xl w-full p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold text-gray-800">API Integration Documentation</h3> |
| <button id="closeApiInfoModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <div class="bg-gray-50 p-4 rounded-lg"> |
| <h4 class="font-semibold text-blue-600 mb-2"><i class="fas fa-lock mr-2"></i>Secure Backend Implementation</h4> |
| <p class="text-sm text-gray-700 mb-3">All API keys are securely stored and managed server-side using environment variables and encrypted storage. Users never need to input API keys directly.</p> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div class="border-l-4 border-blue-500 pl-3"> |
| <h5 class="font-medium text-gray-800">OpenAI Integration</h5> |
| <p class="text-xs text-gray-600">Using API version: 2023-05-15</p> |
| <ul class="text-sm text-gray-700 mt-2 space-y-1"> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Keys rotated every 30 days</li> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Rate limited to 60 RPM</li> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Usage monitored daily</li> |
| </ul> |
| </div> |
| <div class="border-l-4 border-red-500 pl-3"> |
| <h5 class="font-medium text-gray-800">YouTube API</h5> |
| <p class="text-xs text-gray-600">Using Data API v3</p> |
| <ul class="text-sm text-gray-700 mt-2 space-y-1"> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Quota: 10,000 units/day</li> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Caching enabled</li> |
| <li><i class="fas fa-check-circle text-green-500 mr-1"></i> Restricted to video info only</li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| |
| <div> |
| <h4 class="font-semibold text-gray-800 mb-2">Implementation Details</h4> |
| <div class="bg-gray-800 text-gray-100 p-3 rounded text-xs font-mono overflow-x-auto"> |
| <p>// Backend API route example (Node.js)</p> |
| <p class="text-blue-300">app.post('/api/analyze', async (req, res) => {</p> |
| <p class="ml-4 text-blue-300">const videoId = extractVideoId(req.body.url);</p> |
| <p class="ml-4 text-blue-300">const [metadata, transcript] = await Promise.all([</p> |
| <p class="ml-8 text-blue-300">youtubeAPI.getVideoInfo(videoId),</p> |
| <p class="ml-8 text-blue-300">openAI.analyzeTranscript(videoId)</p> |
| <p class="ml-4 text-blue-300">]);</p> |
| <p class="ml-4 text-blue-300">const guide = await generateGuide(metadata, transcript);</p> |
| <p class="ml-4 text-blue-300">res.json(guide);</p> |
| <p class="text-blue-300">});</p> |
| </div> |
| </div> |
| |
| <div class="bg-yellow-50 border-l-4 border-yellow-400 p-3"> |
| <h4 class="font-semibold text-yellow-800 mb-1"><i class="fas fa-exclamation-triangle mr-2"></i>Security Notes</h4> |
| <ul class="text-sm text-yellow-700 space-y-1"> |
| <li><i class="fas fa-shield-alt mr-1"></i> API keys stored in environment variables (never in code)</li> |
| <li><i class="fas fa-shield-alt mr-1"></i> All requests authenticated with JWT tokens</li> |
| <li><i class="fas fa-shield-alt mr-1"></i> Input sanitization for all user-provided URLs</li> |
| <li><i class="fas fa-shield-alt mr-1"></i> Rate limiting implemented (10 requests/min per IP)</li> |
| </ul> |
| </div> |
| </div> |
| <div class="mt-6 flex justify-end"> |
| <button id="closeApiInfo" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"> |
| Close Documentation |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <section id="videoPreview" class="max-w-4xl mx-auto hidden mb-8"> |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> |
| <div class="p-6"> |
| <h2 class="text-xl font-bold text-gray-800 mb-2">Video Detected</h2> |
| <div id="videoInfo" class="flex flex-col md:flex-row gap-6"> |
| <div class="w-full md:w-1/3"> |
| <img id="videoThumbnail" src="" alt="Video thumbnail" class="w-full rounded-lg shadow-sm"> |
| </div> |
| <div class="w-full md:w-2/3"> |
| <h3 id="videoTitle" class="text-lg font-semibold text-gray-800 mb-2"></h3> |
| <p id="videoChannel" class="text-gray-600 mb-2"></p> |
| <div class="flex items-center text-gray-600 mb-4"> |
| <span id="videoDuration" class="mr-4"><i class="fas fa-clock mr-1"></i></span> |
| <span id="videoViews"><i class="fas fa-eye mr-1"></i></span> |
| </div> |
| <p id="videoDescription" class="text-gray-700 text-sm"></p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section id="guideContainer" class="max-w-4xl mx-auto hidden"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold text-gray-800">Your Step-by-Step Guide</h2> |
| <button id="exportPdf" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 flex items-center"> |
| <i class="fas fa-file-pdf mr-2"></i> Export as PDF |
| </button> |
| </div> |
| |
| <div id="guideContent" class="bg-white rounded-xl shadow-md overflow-hidden mb-8"> |
| |
| </div> |
| </section> |
|
|
| |
| <div class="fixed bottom-6 right-6 z-40"> |
| <div id="chatContainer" class="chat-container bg-white rounded-t-xl shadow-xl w-80"> |
| <div class="bg-blue-600 text-white p-4 rounded-t-xl flex justify-between items-center"> |
| <h3 class="font-medium">Guide Assistant</h3> |
| <button id="closeChat" class="text-white hover:text-blue-200"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div id="chatMessages" class="p-4 h-64 overflow-y-auto bg-gray-50"> |
| <div class="chat-message bot mb-4"> |
| <div class="bg-blue-100 text-gray-800 rounded-lg p-3 max-w-xs"> |
| <p>Hello! I can help answer questions about the video guide. What would you like to know?</p> |
| </div> |
| </div> |
| </div> |
| <div class="p-4 border-t border-gray-200"> |
| <div class="flex"> |
| <input id="chatInput" type="text" placeholder="Ask about the video..." |
| class="flex-grow px-3 py-2 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-1 focus:ring-blue-500"> |
| <button id="sendMessage" class="px-4 py-2 bg-blue-600 text-white rounded-r-lg hover:bg-blue-700"> |
| <i class="fas fa-paper-plane"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| <button id="toggleChat" class="mt-4 bg-blue-600 text-white rounded-full w-14 h-14 flex items-center justify-center shadow-lg hover:bg-blue-700 focus:outline-none"> |
| <i class="fas fa-comment-dots text-xl"></i> |
| </button> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const showApiInfo = document.getElementById('showApiInfo'); |
| const apiInfoModal = document.getElementById('apiInfoModal'); |
| const closeApiInfoModal = document.getElementById('closeApiInfoModal'); |
| const closeApiInfo = document.getElementById('closeApiInfo'); |
| const generateGuide = document.getElementById('generateGuide'); |
| const youtubeUrl = document.getElementById('youtubeUrl'); |
| const loadingContainer = document.getElementById('loadingContainer'); |
| const loadingBar = document.getElementById('loadingBar'); |
| const loadingText = document.getElementById('loadingText'); |
| const videoPreview = document.getElementById('videoPreview'); |
| const videoThumbnail = document.getElementById('videoThumbnail'); |
| const videoTitle = document.getElementById('videoTitle'); |
| const videoChannel = document.getElementById('videoChannel'); |
| const videoDuration = document.getElementById('videoDuration'); |
| const videoViews = document.getElementById('videoViews'); |
| const videoDescription = document.getElementById('videoDescription'); |
| const guideContainer = document.getElementById('guideContainer'); |
| const guideContent = document.getElementById('guideContent'); |
| const exportPdf = document.getElementById('exportPdf'); |
| const toggleChat = document.getElementById('toggleChat'); |
| const chatContainer = document.getElementById('chatContainer'); |
| const closeChat = document.getElementById('closeChat'); |
| const chatMessages = document.getElementById('chatMessages'); |
| const chatInput = document.getElementById('chatInput'); |
| const sendMessage = document.getElementById('sendMessage'); |
| |
| |
| let isChatOpen = false; |
| let currentVideoData = null; |
| |
| |
| showApiInfo.addEventListener('click', () => { |
| apiInfoModal.classList.add('open'); |
| }); |
| |
| closeApiInfoModal.addEventListener('click', () => { |
| apiInfoModal.classList.remove('open'); |
| }); |
| |
| closeApiInfo.addEventListener('click', () => { |
| apiInfoModal.classList.remove('open'); |
| }); |
| |
| generateGuide.addEventListener('click', async () => { |
| const url = youtubeUrl.value.trim(); |
| if (!url) { |
| alert('Please enter a YouTube URL'); |
| return; |
| } |
| |
| |
| if (!isValidYouTubeUrl(url)) { |
| alert('Please enter a valid YouTube URL'); |
| return; |
| } |
| |
| |
| loadingContainer.classList.remove('hidden'); |
| updateLoading(0, "Initializing secure connection..."); |
| |
| try { |
| |
| const videoId = extractVideoId(url); |
| |
| |
| updateLoading(20, "Fetching video details through secure API..."); |
| const videoData = await fetchVideoData(videoId); |
| currentVideoData = videoData; |
| |
| |
| displayVideoPreview(videoData); |
| updateLoading(40, "Analyzing transcript with AI..."); |
| |
| |
| await generateVideoGuide(videoData); |
| updateLoading(100, "Guide complete!"); |
| |
| |
| setTimeout(() => { |
| loadingContainer.classList.add('hidden'); |
| }, 1000); |
| |
| } catch (error) { |
| console.error("Error:", error); |
| loadingContainer.classList.add('hidden'); |
| alert("Error processing video: " + error.message); |
| } |
| }); |
| |
| exportPdf.addEventListener('click', () => { |
| if (!currentVideoData) { |
| alert('No guide to export'); |
| return; |
| } |
| alert(`PDF export would generate a guide for: ${currentVideoData.title}`); |
| }); |
| |
| toggleChat.addEventListener('click', () => { |
| isChatOpen = !isChatOpen; |
| chatContainer.classList.toggle('open', isChatOpen); |
| }); |
| |
| closeChat.addEventListener('click', () => { |
| isChatOpen = false; |
| chatContainer.classList.remove('open'); |
| }); |
| |
| sendMessage.addEventListener('click', sendChatMessage); |
| chatInput.addEventListener('keypress', (e) => { |
| if (e.key === 'Enter') sendChatMessage(); |
| }); |
| |
| |
| function isValidYouTubeUrl(url) { |
| const pattern = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/; |
| return pattern.test(url); |
| } |
| |
| function extractVideoId(url) { |
| const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; |
| const match = url.match(regExp); |
| return (match && match[2].length === 11) ? match[2] : null; |
| } |
| |
| async function fetchVideoData(videoId) { |
| |
| |
| |
| |
| return new Promise((resolve) => { |
| setTimeout(() => { |
| |
| const sampleData = { |
| id: videoId, |
| title: "How to Use AI: A Complete Beginner's Guide", |
| channel: "Tech Explained", |
| duration: "12:45", |
| views: "1.5M views", |
| description: "In this video, I'll walk you through everything you need to know to get started with AI tools. We'll cover setting up accounts, basic commands, and practical applications.", |
| thumbnail: `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`, |
| category: "Education", |
| steps: [ |
| { |
| time: "1:10", |
| title: "Introduction to AI Tools", |
| description: "The video explains the different categories of AI tools available today, including text generators, image creators, and coding assistants.", |
| screenshot: "https://images.unsplash.com/photo-1677442136019-21780ecad995?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", |
| highlights: [ |
| { x: 30, y: 40, width: 40, height: 30, note: "Main AI categories" } |
| ] |
| }, |
| { |
| time: "3:25", |
| title: "Setting Up Your First AI Account", |
| description: "Step-by-step demonstration of creating an account on a popular AI platform. The instructor emphasizes using a secure password and verifying your email.", |
| screenshot: "https://images.unsplash.com/photo-1551650975-87deedd944c3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", |
| highlights: [ |
| { x: 50, y: 60, width: 30, height: 15, note: "Sign up button" }, |
| { x: 20, y: 75, width: 60, height: 10, note: "Password requirements" } |
| ] |
| } |
| ] |
| }; |
| |
| |
| if (youtubeUrl.value.includes("pancake")) { |
| sampleData.title = "How to Make Perfect Pancakes"; |
| sampleData.description = "Learn the secrets to making fluffy, delicious pancakes every time with this step-by-step tutorial."; |
| sampleData.category = "Cooking"; |
| sampleData.steps = [ |
| { |
| time: "0:45", |
| title: "Gather Ingredients", |
| description: "You'll need: 1 cup all-purpose flour, 2 tablespoons sugar, 2 teaspoons baking powder, 1/2 teaspoon salt, 1 cup milk, 1 large egg, 2 tablespoons melted butter.", |
| screenshot: "https://images.unsplash.com/photo-1565299624946-b28f40a0ae38?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", |
| highlights: [ |
| { x: |
| </html> |