StreamAI / index.html
privateuserh's picture
Update index.html
b754c39 verified
raw
history blame
72.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>StreamAI - Personalized Streaming Recommendations</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>
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.floating {
animation: float 6s ease-in-out infinite;
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.chat-bubble {
border-radius: 20px;
position: relative;
max-width: 80%;
}
.user-bubble {
background-color: #4f46e5;
color: white;
margin-left: auto;
border-bottom-right-radius: 5px;
}
.ai-bubble {
background-color: #f3f4f6;
color: #1f2937;
margin-right: auto;
border-bottom-left-radius: 5px;
}
.typing-indicator span {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #9ca3af;
margin: 0 2px;
}
.typing-indicator span:nth-child(1) {
animation: bounce 1s infinite;
}
.typing-indicator span:nth-child(2) {
animation: bounce 1s infinite 0.2s;
}
.typing-indicator span:nth-child(3) {
animation: bounce 1s infinite 0.4s;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.stream-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.notification {
position: fixed;
bottom: 20px;
right: 20px;
background: #4f46e5;
color: white;
padding: 15px 25px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transform: translateX(120%);
transition: transform 0.3s ease-out;
z-index: 1000;
}
.notification.show {
transform: translateX(0);
}
.production-button {
position: fixed;
bottom: 30px;
right: 30px;
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #ff5e62 0%, #ff9966 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 10px 25px rgba(255, 94, 98, 0.3);
cursor: pointer;
z-index: 999;
transition: all 0.3s ease;
}
.production-button:hover {
transform: scale(1.1);
box-shadow: 0 15px 30px rgba(255, 94, 98, 0.4);
}
.production-panel {
position: fixed;
bottom: 110px;
right: 30px;
width: 350px;
background: white;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
padding: 20px;
z-index: 998;
transform: translateY(20px);
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
}
.production-panel.open {
transform: translateY(0);
opacity: 1;
pointer-events: all;
}
.recording-indicator {
position: absolute;
top: -10px;
right: -10px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #ff5e62;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 94, 98, 0.7); }
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(255, 94, 98, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 94, 98, 0); }
}
.clip-item {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #eee;
cursor: pointer;
}
.clip-item:hover {
background-color: #f9fafb;
}
.clip-item:last-child {
border-bottom: none;
}
.clip-preview {
width: 100%;
height: 180px;
background-color: #f3f4f6;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
position: relative;
overflow: hidden;
}
.clip-preview video {
width: 100%;
height: 100%;
object-fit: cover;
}
.clip-preview-placeholder {
text-align: center;
color: #6b7280;
}
.clip-preview-placeholder i {
font-size: 40px;
margin-bottom: 10px;
display: block;
}
.progress-bar {
height: 4px;
background-color: #e5e7eb;
border-radius: 2px;
overflow: hidden;
margin-top: 10px;
}
.progress-fill {
height: 100%;
background-color: #4f46e5;
width: 0%;
transition: width 0.3s ease;
}
.tab {
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
margin-right: 8px;
}
.tab.active {
background-color: #4f46e5;
color: white;
}
.tab.inactive {
background-color: #f3f4f6;
color: #6b7280;
}
.rank-badge {
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: bold;
margin-left: 8px;
}
.rank-1 {
background-color: #f59e0b;
color: white;
}
.rank-2 {
background-color: #6b7280;
color: white;
}
.rank-3 {
background-color: #92400e;
color: white;
}
.bluetooth-connected {
color: #3b82f6;
animation: pulse 2s infinite;
}
.bluetooth-disconnected {
color: #6b7280;
}
.user-tag {
background-color: #e5e7eb;
color: #4b5563;
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
margin-left: 4px;
}
.category-tag {
background-color: #dbeafe;
color: #1e40af;
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
margin-left: 4px;
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<!-- Notification -->
<div id="notification" class="notification hidden">
<div class="flex items-center">
<i class="fas fa-bell text-yellow-300 mr-3"></i>
<div>
<p class="font-semibold" id="notification-title">Reminder Set!</p>
<p class="text-sm" id="notification-message">We'll notify you when this show is about to broadcast.</p>
</div>
</div>
</div>
<!-- Production Button & Panel -->
<div class="production-button" id="production-button">
<i class="fas fa-video"></i>
<div class="recording-indicator hidden" id="recording-indicator"></div>
</div>
<div class="production-panel" id="production-panel">
<div class="flex mb-4">
<div class="tab active" id="record-tab">Record</div>
<div class="tab inactive" id="edit-tab">Edit</div>
<div class="tab inactive" id="share-tab">Share</div>
<div class="tab inactive" id="rank-tab">Rankings</div>
</div>
<div id="record-section">
<h3 class="font-bold text-lg mb-4">Create Video Clips</h3>
<p class="text-sm text-gray-600 mb-4">Record your screen and audio to create short clips for your production. Perfect for capturing highlights or creating content snippets.</p>
<div class="clip-preview" id="clip-preview">
<div class="clip-preview-placeholder">
<i class="fas fa-video"></i>
<p>Preview will appear here</p>
</div>
</div>
<div class="mb-4">
<button id="start-recording" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-full text-sm font-medium transition">
<i class="fas fa-circle mr-1"></i> Start Recording (5s clips)
</button>
<button id="stop-recording" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-full text-sm font-medium transition ml-2 hidden">
<i class="fas fa-stop mr-1"></i> Stop
</button>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
<div id="clips-container" class="mb-4 max-h-40 overflow-y-auto">
<p class="text-gray-500 text-sm">Clips will appear here when recorded...</p>
</div>
</div>
<div id="edit-section" class="hidden">
<h3 class="font-bold text-lg mb-4">Edit Your Production</h3>
<p class="text-sm text-gray-600 mb-4">Combine your clips, add transitions, and create a polished final video.</p>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Video Title</label>
<input type="text" id="video-title" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" placeholder="My Awesome Video">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Select Transition</label>
<select id="video-transition" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
<option value="none">No Transition</option>
<option value="fade">Fade</option>
<option value="slide">Slide</option>
<option value="zoom">Zoom</option>
</select>
</div>
</div>
<div id="share-section" class="hidden">
<h3 class="font-bold text-lg mb-4">Share with Bluetooth Group</h3>
<p class="text-sm text-gray-600 mb-4">Connect with nearby devices and share your clips with the group.</p>
<div class="flex items-center mb-4">
<button id="bluetooth-connect" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-full text-sm font-medium transition">
<i class="fas fa-bluetooth-b mr-1"></i> Connect Devices
</button>
<div id="connection-status" class="ml-3 text-sm">
<i class="fas fa-circle bluetooth-disconnected mr-1"></i>
<span>Not connected</span>
</div>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Your Username</label>
<input type="text" id="username" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" placeholder="Enter a username">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Content Category</label>
<select id="content-category" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
<option value="general">General</option>
<option value="gaming">Gaming</option>
<option value="education">Education</option>
<option value="entertainment">Entertainment</option>
<option value="news">News</option>
</select>
</div>
<button id="share-clips" class="w-full bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-full text-sm font-medium transition mb-4">
<i class="fas fa-share-alt mr-1"></i> Share Selected Clips
</button>
<div id="shared-clips-container" class="max-h-40 overflow-y-auto">
<p class="text-gray-500 text-sm">Shared clips will appear here...</p>
</div>
</div>
<div id="rank-section" class="hidden">
<h3 class="font-bold text-lg mb-4">Group Rankings</h3>
<p class="text-sm text-gray-600 mb-4">See how your clips rank against others in your group.</p>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Ranking Algorithm</label>
<select id="ranking-algorithm" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
<option value="engagement">Engagement Score</option>
<option value="quality">Quality Score</option>
<option value="consistency">Consistency Score</option>
<option value="composite">Composite Score</option>
</select>
</div>
<div id="rankings-container" class="max-h-60 overflow-y-auto">
<p class="text-gray-500 text-sm">Rankings will appear here when available...</p>
</div>
</div>
<div class="flex space-x-2">
<button id="generate-video" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-full text-sm font-medium transition flex-1">
<i class="fas fa-magic mr-1"></i> Generate Video
</button>
<button id="clear-clips" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-full text-sm font-medium transition">
<i class="fas fa-trash mr-1"></i>
</button>
</div>
</div>
<!-- Header -->
<header class="gradient-bg text-white shadow-lg">
<div class="container mx-auto px-4 py-6">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-3">
<i class="fas fa-stream text-3xl"></i>
<h1 class="text-2xl font-bold">StreamAI</h1>
</div>
<nav class="hidden md:flex space-x-6">
<a href="#" class="hover:text-indigo-200 transition">Home</a>
<a href="#" class="hover:text-indigo-200 transition">Features</a>
<a href="#" class="hover:text-indigo-200 transition">About</a>
<a href="#" class="hover:text-indigo-200 transition">Contact</a>
</nav>
<button class="md:hidden text-xl">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</header>
<!-- Hero Section -->
<section class="gradient-bg text-white py-16">
<div class="container mx-auto px-4 flex flex-col md:flex-row items-center">
<div class="md:w-1/2 mb-10 md:mb-0">
<h2 class="text-4xl md:text-5xl font-bold mb-4">AI-Powered Streaming Recommendations</h2>
<p class="text-xl mb-8 text-indigo-100">Get personalized streaming suggestions powered by Cloudflare Workers AI.</p>
<div class="flex space-x-4">
<button class="bg-white text-indigo-600 px-6 py-3 rounded-full font-semibold hover:bg-indigo-100 transition">
Try It Now
</button>
<button class="border-2 border-white text-white px-6 py-3 rounded-full font-semibold hover:bg-white hover:text-indigo-600 transition">
How It Works
</button>
</div>
</div>
<div class="md:w-1/2 flex justify-center">
<div class="relative w-64 h-64 md:w-80 md:h-80">
<div class="absolute inset-0 bg-indigo-500 rounded-full opacity-20 floating"></div>
<div class="absolute inset-4 bg-indigo-400 rounded-full opacity-30 floating" style="animation-delay: 0.5s;"></div>
<div class="absolute inset-8 bg-indigo-300 rounded-full opacity-40 floating" style="animation-delay: 1s;"></div>
<div class="absolute inset-12 bg-white rounded-full flex items-center justify-center">
<i class="fas fa-robot text-6xl text-indigo-600"></i>
</div>
</div>
</div>
</div>
</section>
<!-- AI Chat Interface -->
<section class="py-12 bg-white">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12 text-gray-800">Your Personal Streaming Assistant</h2>
<div class="max-w-4xl mx-auto bg-gray-50 rounded-xl shadow-lg overflow-hidden">
<!-- Chat header -->
<div class="bg-indigo-600 text-white p-4 flex items-center">
<div class="w-10 h-10 rounded-full bg-indigo-400 flex items-center justify-center mr-3">
<i class="fas fa-robot"></i>
</div>
<div>
<h3 class="font-semibold">StreamAI Assistant</h3>
<p class="text-xs text-indigo-200">Powered by Cloudflare Workers AI</p>
</div>
<div class="ml-auto flex space-x-2">
<button class="w-8 h-8 rounded-full bg-indigo-500 hover:bg-indigo-400 flex items-center justify-center">
<i class="fas fa-ellipsis-h text-sm"></i>
</button>
</div>
</div>
<!-- Chat messages -->
<div class="h-96 overflow-y-auto p-4 space-y-4" id="chat-messages">
<div class="chat-bubble ai-bubble p-4 w-3/4">
<p>Hi there! 👋 I'm your StreamAI assistant powered by Cloudflare Workers AI. I can recommend movies, TV shows, and other streaming content based on your preferences. What are you in the mood for today?</p>
</div>
</div>
<!-- User input -->
<div class="border-t border-gray-200 p-4 bg-white">
<div class="flex items-center">
<input type="text" id="user-input" placeholder="Type your message..." class="flex-1 border border-gray-300 rounded-full py-3 px-4 focus:outline-none focus:ring-2 focus:ring-indigo-500">
<button id="send-btn" class="ml-3 w-12 h-12 rounded-full bg-indigo-600 text-white hover:bg-indigo-700 flex items-center justify-center transition">
<i class="fas fa-paper-plane"></i>
</button>
</div>
<div class="mt-2 flex space-x-2">
<button class="text-xs bg-gray-100 hover:bg-gray-200 px-3 py-1 rounded-full transition" onclick="quickPrompt('Recommend a comedy movie')">
Comedy
</button>
<button class="text-xs bg-gray-100 hover:bg-gray-200 px-3 py-1 rounded-full transition" onclick="quickPrompt('What should I watch if I feel nostalgic?')">
Nostalgic
</button>
<button class="text-xs bg-gray-100 hover:bg-gray-200 px-3 py-1 rounded-full transition" onclick="quickPrompt('Suggest a thriller series')">
Thriller
</button>
</div>
</div>
</div>
</div>
</section>
<!-- Recommended Streams Section -->
<section class="py-12 bg-gray-50">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-6 text-gray-800">Recommended For You</h2>
<!-- RSS Feed Integration -->
<div class="max-w-4xl mx-auto mb-8 bg-white p-4 rounded-lg shadow">
<div class="flex items-center mb-2">
<i class="fas fa-rss-square text-orange-500 mr-2"></i>
<h3 class="font-semibold">Personalized RSS Feed</h3>
</div>
<div class="flex items-center space-x-2 overflow-x-auto pb-2">
<button class="rss-filter-btn px-3 py-1 bg-indigo-100 text-indigo-700 rounded-full text-sm whitespace-nowrap" data-filter="all">
All Content
</button>
<button class="rss-filter-btn px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm whitespace-nowrap" data-filter="news">
News Updates
</button>
<button class="rss-filter-btn px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm whitespace-nowrap" data-filter="trending">
Trending Now
</button>
<button class="rss-filter-btn px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm whitespace-nowrap" data-filter="personalized">
For You
</button>
</div>
<div id="rss-feed" class="mt-4 space-y-3">
<!-- RSS items will be loaded here -->
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4" id="recommendations-container">
<!-- Recommendations will be dynamically inserted here -->
</div>
</div>
</section>
<!-- How It Works Section -->
<section class="py-12 bg-white">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12 text-gray-800">How StreamAI Works</h2>
<div class="grid md:grid-cols-3 gap-8">
<div class="text-center p-6 rounded-xl bg-gray-50 hover:shadow-lg transition">
<div class="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-comment-alt text-indigo-600 text-xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">1. Chat with AI</h3>
<p class="text-gray-600">Tell our AI assistant what you're in the mood for or ask for recommendations based on your preferences.</p>
</div>
<div class="text-center p-6 rounded-xl bg-gray-50 hover:shadow-lg transition">
<div class="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-brain text-indigo-600 text-xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">2. AI Processing</h3>
<p class="text-gray-600">Our Cloudflare Workers AI analyzes your request using advanced natural language processing.</p>
</div>
<div class="text-center p-6 rounded-xl bg-gray-50 hover:shadow-lg transition">
<div class="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-film text-indigo-600 text-xl"></i>
</div>
<h3 class="text-xl font-semibold mb-2">3. Get Recommendations</h3>
<p class="text-gray-600">Receive personalized streaming suggestions with direct links to watch on your favorite platforms.</p>
</div>
</div>
</div>
</section>
<!-- Video Production Section -->
<section class="py-12 bg-gray-50">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12 text-gray-800">Create Your Own Content</h2>
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-lg overflow-hidden">
<div class="p-8">
<div class="flex items-center mb-6">
<div class="w-14 h-14 rounded-full bg-gradient-to-r from-red-500 to-orange-500 flex items-center justify-center text-white mr-4">
<i class="fas fa-video text-2xl"></i>
</div>
<div>
<h3 class="text-2xl font-bold">Video Production Tools</h3>
<p class="text-gray-600">Record, edit, and share your own streaming content</p>
</div>
</div>
<div class="grid md:grid-cols-2 gap-8">
<div>
<h4 class="font-semibold text-lg mb-3">Record Live Clips</h4>
<p class="text-gray-600 mb-4">Easily capture 5-second clips of your screen and audio to create highlight reels or content snippets.</p>
<ul class="space-y-2 text-sm text-gray-600">
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Automatically segmented into manageable clips</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Screen and audio recording with one click</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Preview clips before adding to your production</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Share with Bluetooth-connected groups</span>
</li>
</ul>
</div>
<div>
<h4 class="font-semibold text-lg mb-3">Edit & Combine</h4>
<p class="text-gray-600 mb-4">Combine your clips with smooth transitions to create professional-looking videos.</p>
<ul class="space-y-2 text-sm text-gray-600">
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Multiple transition effects available</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Add titles and descriptions to your videos</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Export in multiple formats for sharing</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Benchmark your content against group submissions</span>
</li>
</ul>
</div>
</div>
<div class="mt-8 pt-6 border-t border-gray-200">
<h4 class="font-semibold text-lg mb-4">Try It Now</h4>
<p class="text-gray-600 mb-4">Click the video production button in the bottom right corner to start creating your own content.</p>
<div class="flex items-center text-sm text-indigo-600">
<i class="fas fa-info-circle mr-2"></i>
<span>You'll need to grant screen recording permissions when prompted</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-12">
<div class="container mx-auto px-4">
<div class="grid md:grid-cols-4 gap-8">
<div>
<h3 class="text-xl font-bold mb-4 flex items-center">
<i class="fas fa-stream mr-2"></i> StreamAI
</h3>
<p class="text-gray-400">Your personal streaming assistant powered by Cloudflare Workers AI technology.</p>
</div>
<div>
<h4 class="font-semibold mb-4">Quick Links</h4>
<ul class="space-y-2">
<li><a href="#" class="text-gray-400 hover:text-white transition">Home</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Features</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Pricing</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">FAQ</a></li>
</ul>
</div>
<div>
<h4 class="font-semibold mb-4">Streaming Platforms</h4>
<ul class="space-y-2">
<li><a href="#" class="text-gray-400 hover:text-white transition">Netflix</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Amazon Prime</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Disney+</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">HBO Max</a></li>
<li><a href="https://smplus.vhx.tv" target="_blank" class="text-gray-400 hover:text-white transition">SMPlus VHX</a></li>
</ul>
</div>
<div>
<h4 class="font-semibold mb-4">Connect With Us</h4>
<div class="flex space-x-4">
<a href="#" class="w-10 h-10 rounded-full bg-gray-700 hover:bg-indigo-600 flex items-center justify-center transition">
<i class="fab fa-twitter"></i>
</a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-700 hover:bg-indigo-600 flex items-center justify-center transition">
<i class="fab fa-facebook-f"></i>
</a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-700 hover:bg-indigo-600 flex items-center justify-center transition">
<i class="fab fa-instagram"></i>
</a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-700 hover:bg-indigo-600 flex items-center justify-center transition">
<i class="fab fa-discord"></i>
</a>
</div>
</div>
</div>
<div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400">
<p>&copy; 2023 StreamAI. All rights reserved.</p>
</div>
</div>
</footer>
<script>
// Configuration for Cloudflare Workers AI
const AI_CONFIG = {
accountId: 'oFD0IMs0aV8eKMMMdTEF2zRQmtzvKMH43LX5ZWUJ',
gatewayId: 'streamai_gateway',
apiToken: 'masked_for_security', // In a real app, this would be handled server-side
model: '@cf/meta/llama-2-7b-chat-int8'
};
// Sample streaming data with SMPlus VHX added to the top
const streamingData = [
{
title: "SMPlus Exclusive Series",
type: "TV Series",
genre: "Drama, Action",
platform: "SMPlus VHX",
rating: "4.9",
year: "2023",
description: "An exclusive action-packed drama series only available on SMPlus VHX.",
broadcastTime: "2023-12-15T20:00:00"
},
{
title: "The Grand Adventure",
type: "Movie",
genre: "Adventure, Comedy",
platform: "Netflix",
rating: "4.8",
year: "2022",
description: "A hilarious journey across continents with unexpected twists.",
broadcastTime: "2023-12-10T19:30:00"
},
{
title: "Dark Secrets",
type: "TV Series",
genre: "Drama, Thriller",
platform: "HBO Max",
rating: "4.7",
year: "2021",
description: "A small town's dark past resurfaces with shocking revelations.",
broadcastTime: "2023-12-12T21:00:00"
},
{
title: "Space Explorers",
type: "Documentary",
genre: "Science, Space",
platform: "Disney+",
rating: "4.9",
year: "2023",
description: "The latest discoveries from the frontiers of space exploration.",
broadcastTime: "2023-12-14T18:00:00"
},
{
title: "Romantic Getaway",
type: "Movie",
genre: "Romance, Comedy",
platform: "Amazon Prime",
rating: "4.5",
year: "2021",
description: "Two strangers find love during an unexpected vacation.",
broadcastTime: "2023-12-16T20:30:00"
},
{
title: "Tech Today",
type: "News Show",
genre: "Technology, News",
platform: "SMPlus VHX",
rating: "4.6",
year: "2023",
description: "Daily tech news and gadget reviews from around the world.",
broadcastTime: "2023-12-17T09:00:00"
},
{
title: "Cooking Masters",
type: "Reality Show",
genre: "Food, Competition",
platform: "Netflix",
rating: "4.7",
year: "2023",
description: "Top chefs compete in intense culinary challenges.",
broadcastTime: "2023-12-18T20:00:00"
},
{
title: "History Unearthed",
type: "Documentary",
genre: "History, Education",
platform: "HBO Max",
rating: "4.8",
year: "2023",
description: "Fascinating historical discoveries and their modern implications.",
broadcastTime: "2023-12-19T21:00:00"
}
];
// Sample RSS feed data
const rssFeedData = {
all: [
{
title: "New Episode: SMPlus Exclusive Series",
source: "SMPlus VHX",
time: "2 hours ago",
excerpt: "The latest episode of our exclusive series is now streaming with intense action scenes.",
category: "personalized"
},
{
title: "Trending: The Grand Adventure hits #1",
source: "Netflix",
time: "5 hours ago",
excerpt: "The comedy adventure movie is now the most-watched title on Netflix this week.",
category: "trending"
},
{
title: "Breaking: New streaming partnership announced",
source: "Streaming News",
time: "1 day ago",
excerpt: "Major platforms announce new content sharing agreement starting next month.",
category: "news"
},
{
title: "Recommended for you: Space Explorers",
source: "Disney+",
time: "1 day ago",
excerpt: "Based on your interest in science documentaries, we recommend this new series.",
category: "personalized"
},
{
title: "Upcoming: Romantic Getaway special event",
source: "Amazon Prime",
time: "2 days ago",
excerpt: "Join the cast for a live Q&A before the movie premiere this weekend.",
category: "trending"
}
],
news: [
{
title: "Breaking: New streaming partnership announced",
source: "Streaming News",
time: "1 day ago",
excerpt: "Major platforms announce new content sharing agreement starting next month.",
category: "news"
},
{
title: "Streaming industry report Q4 2023",
source: "Tech Insights",
time: "3 days ago",
excerpt: "Latest statistics show continued growth in streaming subscriptions worldwide.",
category: "news"
}
],
trending: [
{
title: "Trending: The Grand Adventure hits #1",
source: "Netflix",
time: "5 hours ago",
excerpt: "The comedy adventure movie is now the most-watched title on Netflix this week.",
category: "trending"
},
{
title: "Upcoming: Romantic Getaway special event",
source: "Amazon Prime",
time: "2 days ago",
excerpt: "Join the cast for a live Q&A before the movie premiere this weekend.",
category: "trending"
}
],
personalized: [
{
title: "New Episode: SMPlus Exclusive Series",
source: "SMPlus VHX",
time: "2 hours ago",
excerpt: "The latest episode of our exclusive series is now streaming with intense action scenes.",
category: "personalized"
},
{
title: "Recommended for you: Space Explorers",
source: "Disney+",
time: "1 day ago",
excerpt: "Based on your interest in science documentaries, we recommend this new series.",
category: "personalized"
}
]
};
// Video production variables
let isRecording = false;
let recordingInterval;
let recordedClips = [];
let mediaRecorder;
let audioContext;
let audioStream;
let videoStream;
let currentClipTime = 0;
let currentClipInterval;
// Bluetooth sharing variables
let isBluetoothConnected = false;
let bluetoothDevice;
let bluetoothServer;
let bluetoothService;
let bluetoothCharacteristic;
let sharedClips = [];
let groupMembers = [];
let username = "User" + Math.floor(Math.random() * 1000);
let currentCategory = "general";
// Initialize chat
document.addEventListener('DOMContentLoaded', function() {
const sendBtn = document.getElementById('send-btn');
const userInput = document.getElementById('user-input');
const chatMessages = document.getElementById('chat-messages');
const productionButton = document.getElementById('production-button');
const productionPanel = document.getElementById('production-panel');
const startRecordingBtn = document.getElementById('start-recording');
const stopRecordingBtn = document.getElementById('stop-recording');
const generateVideoBtn = document.getElementById('generate-video');
const clearClipsBtn = document.getElementById('clear-clips');
const rssFilterBtns = document.querySelectorAll('.rss-filter-btn');
const recordTab = document.getElementById('record-tab');
const editTab = document.getElementById('edit-tab');
const shareTab = document.getElementById('share-tab');
const rankTab = document.getElementById('rank-tab');
const recordSection = document.getElementById('record-section');
const editSection = document.getElementById('edit-section');
const shareSection = document.getElementById('share-section');
const rankSection = document.getElementById('rank-section');
const bluetoothConnectBtn = document.getElementById('bluetooth-connect');
const shareClipsBtn = document.getElementById('share-clips');
const usernameInput = document.getElementById('username');
const contentCategorySelect = document.getElementById('content-category');
const rankingAlgorithmSelect = document.getElementById('ranking-algorithm');
// Set default username
usernameInput.value = username;
// Load sample recommendations
loadRecommendations();
// Load RSS feed
loadRSSFeed('all');
// Send message on button click
sendBtn.addEventListener('click', sendMessage);
// Send message on Enter key
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// Toggle production panel
productionButton.addEventListener('click', function() {
productionPanel.classList.toggle('open');
});
// Start recording
startRecordingBtn.addEventListener('click', startRecording);
// Stop recording
stopRecordingBtn.addEventListener('click', stopRecording);
// Generate video
generateVideoBtn.addEventListener('click', generateShortVideo);
// Clear clips
clearClipsBtn.addEventListener('click', clearClips);
// Filter RSS feed
rssFilterBtns.forEach(btn => {
btn.addEventListener('click', function() {
// Update active button
rssFilterBtns.forEach(b => {
b.classList.remove('bg-indigo-100', 'text-indigo-700');
b.classList.add('bg-gray-100', 'text-gray-700');
});
this.classList.remove('bg-gray-100', 'text-gray-700');
this.classList.add('bg-indigo-100', 'text-indigo-700');
// Load filtered feed
loadRSSFeed(this.dataset.filter);
});
});
// Switch between record and edit tabs
recordTab.addEventListener('click', function() {
recordTab.classList.remove('inactive');
recordTab.classList.add('active');
editTab.classList.remove('active');
editTab.classList.add('inactive');
shareTab.classList.remove('active');
shareTab.classList.add('inactive');
rankTab.classList.remove('active');
rankTab.classList.add('inactive');
recordSection.classList.remove('hidden');
editSection.classList.add('hidden');
shareSection.classList.add('hidden');
rankSection.classList.add('hidden');
});
editTab.addEventListener('click', function() {
if (recordedClips.length === 0) {
showNotification("No Clips", "Record some clips first to edit them");
return;
}
editTab.classList.remove('inactive');
editTab.classList.add('active');
recordTab.classList.remove('active');
recordTab.classList.add('inactive');
shareTab.classList.remove('active');
shareTab.classList.add('inactive');
rankTab.classList.remove('active');
rankTab.classList.add('inactive');
recordSection.classList.add('hidden');
editSection.classList.remove('hidden');
shareSection.classList.add('hidden');
rankSection.classList.add('hidden');
});
shareTab.addEventListener('click', function() {
shareTab.classList.remove('inactive');
shareTab.classList.add('active');
recordTab.classList.remove('active');
recordTab.classList.add('inactive');
editTab.classList.remove('active');
editTab.classList.add('inactive');
rankTab.classList.remove('active');
rankTab.classList.add('inactive');
recordSection.classList.add('hidden');
editSection.classList.add('hidden');
shareSection.classList.remove('hidden');
rankSection.classList.add('hidden');
});
rankTab.addEventListener('click', function() {
if (sharedClips.length === 0) {
showNotification("No Shared Clips", "Share some clips first to see rankings");
return;
}
rankTab.classList.remove('inactive');
rankTab.classList.add('active');
recordTab.classList.remove('active');
recordTab.classList.add('inactive');
editTab.classList.remove('active');
editTab.classList.add('inactive');
shareTab.classList.remove('active');
shareTab.classList.add('inactive');
recordSection.classList.add('hidden');
editSection.classList.add('hidden');
shareSection.classList.add('hidden');
rankSection.classList.remove('hidden');
// Update rankings when tab is opened
updateRankings();
});
// Connect to Bluetooth
bluetoothConnectBtn.addEventListener('click', connectBluetooth);
// Share clips
shareClipsBtn.addEventListener('click', shareClipsWithGroup);
// Update username when changed
usernameInput.addEventListener('change', function() {
username = this.value || "User" + Math.floor(Math.random() * 1000);
});
// Update category when changed
contentCategorySelect.addEventListener('change', function() {
currentCategory = this.value;
});
// Update rankings when algorithm changes
rankingAlgorithmSelect.addEventListener('change', updateRankings);
});
// Show notification
function showNotification(title, message) {
const notification = document.getElementById('notification');
const titleElement = document.getElementById('notification-title');
const messageElement = document.getElementById('notification-message');
titleElement.textContent = title;
messageElement.textContent = message;
notification.classList.remove('hidden');
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => notification.classList.add('hidden'), 300);
}, 3000);
}
// Quick prompt buttons
function quickPrompt(prompt) {
document.getElementById('user-input').value = prompt;
sendMessage();
}
// Send message to AI
async function sendMessage() {
const userInput = document.getElementById('user-input');
const chatMessages = document.getElementById('chat-messages');
if (userInput.value.trim() === '') return;
// Add user message to chat
const userMessage = document.createElement('div');
userMessage.className = 'chat-bubble user-bubble p-4 w-3/4 ml-auto mb-4 fade-in';
userMessage.innerHTML = `<p>${userInput.value}</p>`;
chatMessages.appendChild(userMessage);
// Show typing indicator
const typingIndicator = document.createElement('div');
typingIndicator.className = 'chat-bubble ai-bubble p-4 w-1/2 mb-4';
typingIndicator.innerHTML = '<div class="typing-indicator"><span></span><span></span><span></span></div>';
chatMessages.appendChild(typingIndicator);
// Scroll to bottom
chatMessages.scrollTop = chatMessages.scrollHeight;
// Save user message
const userMessageText = userInput.value;
userInput.value = '';
try {
// Call Cloudflare Workers AI
const aiResponse = await queryCloudflareAI(userMessageText);
// Remove typing indicator
chatMessages.removeChild(typingIndicator);
// Add AI response to chat
const aiMessage = document.createElement('div');
aiMessage.className = 'chat-bubble ai-bubble p-4 w-3/4 fade-in';
aiMessage.innerHTML = `<p>${aiResponse}</p>`;
chatMessages.appendChild(aiMessage);
// Update recommendations based on AI response
updateRecommendationsFromAI(aiResponse);
} catch (error) {
// Remove typing indicator
chatMessages.removeChild(typingIndicator);
// Show error message
const errorMessage = document.createElement('div');
errorMessage.className = 'chat-bubble ai-bubble p-4 w-3/4 fade-in';
errorMessage.innerHTML = `<p class="text-red-500">Sorry, I'm having trouble connecting to the AI service. Please try again later.</p>`;
chatMessages.appendChild(errorMessage);
}
// Scroll to bottom
chatMessages.scrollTop = chatMessages.scrollHeight;
}
// Query Cloudflare Workers AI
async function queryCloudflareAI(prompt) {
// In a production environment, this would be handled by a backend service
// to keep the API token secure. For this demo, we'll simulate the response.
console.log(`[DEBUG] Would call Cloudflare AI with prompt: "${prompt}"`);
// Simulate API call delay
await new Promise(resolve => setTimeout(resolve, 1500));
// Simulate different responses based on prompt
const lowerPrompt = prompt.toLowerCase();
if (lowerPrompt.includes('comedy') || lowerPrompt.includes('funny')) {
return "I'd recommend these comedy options that should give you a good laugh:\n\n1. 'The Grand Adventure' (Netflix) - A hilarious journey with unexpected twists\n2. 'Office Shenanigans' (Hulu) - Workplace comedy at its finest\n\nComedy can really lift your mood! Would you like more suggestions?";
}
else if (lowerPrompt.includes('thriller') || lowerPrompt.includes('suspense')) {
return "For thrilling content that will keep you on the edge of your seat, consider:\n\n1. 'Dark Secrets' (HBO Max) - A town's dark past resurfaces\n2. 'Midnight Caller' (Amazon Prime) - A psychological thriller about a mysterious phone call\n\nThese should provide plenty of suspense!";
}
else if (lowerPrompt.includes('romance') || lowerPrompt.includes('love')) {
return "Romantic stories can be so heartwarming! Here are my top picks:\n\n1. 'Romantic Getaway' (Amazon Prime) - Two strangers find love on vacation\n2. 'Love in Paris' (Netflix) - A classic romantic tale set in the City of Love\n\nLet me know if you'd like something more specific!";
}
else if (lowerPrompt.includes('recommend') || lowerPrompt.includes('suggest')) {
return "Based on your request, I'd recommend these excellent streaming options:\n\n1. 'SMPlus Exclusive Series' (SMPlus VHX) - Action-packed drama series\n2. 'Space Explorers' (Disney+) - Fascinating documentary about space\n\nI've updated the recommendations section with more options for you!";
}
else {
return "I'm here to help you find the perfect streaming content! Could you tell me more about what you're looking for? For example, you could say 'recommend a sci-fi movie' or 'what should I watch if I feel like laughing?'";
}
}
// Update recommendations based on AI response
function updateRecommendationsFromAI(aiResponse) {
let filter = 'all';
if (aiResponse.includes('comedy')) {
filter = 'comedy';
} else if (aiResponse.includes('thriller') || aiResponse.includes('suspense')) {
filter = 'thriller';
} else if (aiResponse.includes('romance') || aiResponse.includes('love')) {
filter = 'romance';
}
loadRecommendations(filter);
}
// Save show and set broadcast reminder
function saveShow(title, broadcastTime) {
// In a real app, this would save to a database
console.log(`Saved show: ${title}`);
// Show notification
showNotification("Reminder Set!", `We'll notify you when "${title}" is about to broadcast.`);
// In a real app, you would schedule a notification for the broadcast time
if (broadcastTime) {
const broadcastDate = new Date(broadcastTime);
const now = new Date();
// Only schedule if broadcast is in the future
if (broadcastDate > now) {
const timeUntilBroadcast = broadcastDate - now;
// Schedule notification 30 minutes before broadcast
setTimeout(() => {
showNotification("Starting Soon!", `"${title}" will begin broadcasting in 30 minutes!`);
}, timeUntilBroadcast - (30 * 60 * 1000));
}
}
}
// Load recommendations
function loadRecommendations(filter = 'all') {
const container = document.getElementById('recommendations-container');
container.innerHTML = '';
let filteredData = streamingData;
if (filter === 'comedy') {
filteredData = streamingData.filter(item => item.genre.toLowerCase().includes('comedy'));
} else if (filter === 'thriller') {
filteredData = streamingData.filter(item => item.genre.toLowerCase().includes('thriller'));
} else if (filter === 'romance') {
filteredData = streamingData.filter(item => item.genre.toLowerCase().includes('romance'));
}
filteredData.forEach(item => {
const card = document.createElement('div');
card.className = 'stream-card bg-white rounded-lg overflow-hidden shadow-md hover:shadow-xl transition duration-300 fade-in p-4';
card.innerHTML = `
<div class="mb-3">
<div class="flex justify-between items-start">
<h3 class="font-bold text-base">${item.title}</h3>
<span class="bg-yellow-100 text-yellow-800 text-xs px-2 py-1 rounded-full flex items-center">
<i class="fas fa-star text-yellow-500 mr-1 text-xs"></i> ${item.rating}
</span>
</div>
<p class="text-gray-600 text-xs mb-1">${item.type}${item.genre}${item.year}</p>
<div class="text-xs text-indigo-600 mb-2">${item.platform}</div>
</div>
<p class="text-gray-700 text-sm mb-4">${item.description}</p>
<div class="flex justify-between items-center">
<button class="text-indigo-600 hover:text-indigo-800 text-xs font-medium" onclick="saveShow('${item.title}', '${item.broadcastTime}')">
<i class="far fa-bookmark mr-1"></i> Save
</button>
<a href="${item.platform === 'SMPlus VHX' ? 'https://smplus.vhx.tv' : '#'}" target="_blank" class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded-full text-xs font-medium transition">
<i class="fas fa-play mr-1"></i> Watch
</a>
</div>
`;
container.appendChild(card);
});
}
// Load RSS feed
function loadRSSFeed(filter) {
const container = document.getElementById('rss-feed');
container.innerHTML = '';
const feedItems = rssFeedData[filter] || rssFeedData.all;
feedItems.forEach(item => {
const feedItem = document.createElement('div');
feedItem.className = 'rss-item bg-gray-50 p-3 rounded-lg';
feedItem.innerHTML = `
<h4 class="font-medium text-sm mb-1">${item.title}</h4>
<div class="flex items-center text-xs text-gray-500 mb-2">
<span>${item.source}</span>
<span class="mx-2">•</span>
<span>${item.time}</span>
</div>
<p class="text-xs text-gray-700">${item.excerpt}</p>
`;
container.appendChild(feedItem);
});
}
// Start recording video and audio
async function startRecording() {
try {
// Get user media
videoStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
});
audioStream = await navigator.mediaDevices.getUserMedia({
audio: true
});
// Create audio context
audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(audioStream);
const destination = audioContext.createMediaStreamDestination();
source.connect(destination);
// Combine video and audio streams
const combinedStream = new MediaStream([
...videoStream.getVideoTracks(),
...destination.stream.getAudioTracks()
]);
// Create media recorder
mediaRecorder = new MediaRecorder(combinedStream, {
mimeType: 'video/webm'
});
// Update preview with live recording
const preview = document.getElementById('clip-preview');
preview.innerHTML = '<video autoplay muted></video>';
const previewVideo = preview.querySelector('video');
previewVideo.srcObject = combinedStream;
// Set recording state
isRecording = true;
document.getElementById('recording-indicator').classList.remove('hidden');
document.getElementById('start-recording').classList.add('hidden');
document.getElementById('stop-recording').classList.remove('hidden');
// Start progress bar animation
currentClipTime = 0;
const progressFill = document.getElementById('progress-fill');
progressFill.style.width = '0%';
currentClipInterval = setInterval(() => {
currentClipTime += 100;
const progressPercent = (currentClipTime / 5000) * 100;
progressFill.style.width = `${progressPercent}%`;
}, 100);
// Start recording in 5-second clips
let clipCount = 0;
recordingInterval = setInterval(() => {
if (clipCount > 0) {
// Stop current recording
mediaRecorder.stop();
}
// Start new recording
mediaRecorder.start();
clipCount++;
// Reset progress bar
currentClipTime = 0;
progressFill.style.width = '0%';
// Store clip data when available
mediaRecorder.ondataavailable = (e) => {
const clip = {
blob: e.data,
timestamp: new Date().toLocaleTimeString(),
url: URL.createObjectURL(e.data),
username: username,
category: currentCategory,
engagementScore: Math.random() * 5, // Simulated metrics
qualityScore: 3 + Math.random() * 2,
consistencyScore: 3 + Math.random() * 2
};
recordedClips.push(clip);
updateClipsList();
};
}, 5000);
showNotification("Recording Started", "Recording 5-second clips of your screen and audio");
} catch (error) {
console.error("Error starting recording:", error);
showNotification("Recording Error", "Could not start recording. Please check permissions.");
stopRecording();
}
}
// Stop recording
function stopRecording() {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
clearInterval(recordingInterval);
clearInterval(currentClipInterval);
isRecording = false;
// Stop all tracks
if (videoStream) {
videoStream.getTracks().forEach(track => track.stop());
}
if (audioStream) {
audioStream.getTracks().forEach(track => track.stop());
}
// Close audio context
if (audioContext && audioContext.state !== 'closed') {
audioContext.close();
}
// Reset preview
const preview = document.getElementById('clip-preview');
preview.innerHTML = `
<div class="clip-preview-placeholder">
<i class="fas fa-video"></i>
<p>Preview will appear here</p>
</div>
`;
// Reset progress bar
document.getElementById('progress-fill').style.width = '0%';
// Update UI
document.getElementById('recording-indicator').classList.add('hidden');
document.getElementById('start-recording').classList.remove('hidden');
document.getElementById('stop-recording').classList.add('hidden');
showNotification("Recording Stopped", `Captured ${recordedClips.length} clips ready for production`);
}
// Update clips list
function updateClipsList() {
const container = document.getElementById('clips-container');
container.innerHTML = '';
if (recordedClips.length === 0) {
container.innerHTML = '<p class="text-gray-500 text-sm">Clips will appear here...</p>';
return;
}
recordedClips.forEach((clip, index) => {
const clipItem = document.createElement('div');
clipItem.className = 'clip-item';
clipItem.innerHTML = `
<i class="fas fa-video text-gray-500 mr-2"></i>
<span class="text-sm flex-1">Clip ${index + 1}</span>
<span class="text-xs text-gray-500">${clip.timestamp}</span>
`;
// Add click handler to preview clip
clipItem.addEventListener('click', () => {
const preview = document.getElementById('clip-preview');
preview.innerHTML = '<video controls></video>';
const previewVideo = preview.querySelector('video');
previewVideo.src = clip.url;
});
container.appendChild(clipItem);
});
}
// Clear all clips
function clearClips() {
if (recordedClips.length === 0) return;
// In a real app, we would properly revoke the object URLs
recordedClips.forEach(clip => {
if (clip.url) {
URL.revokeObjectURL(clip.url);
}
});
recordedClips = [];
updateClipsList();
// Reset preview
const preview = document.getElementById('clip-preview');
preview.innerHTML = `
<div class="clip-preview-placeholder">
<i class="fas fa-video"></i>
<p>Preview will appear here</p>
</div>
`;
showNotification("Clips Cleared", "All recorded clips have been removed");
}
// Generate short video from clips
function generateShortVideo() {
if (recordedClips.length === 0) {
showNotification("No Clips", "Please record some clips first");
return;
}
// In a real app, this would use a video editing library to combine clips
// and sync with audio. For this demo, we'll simulate the process.
showNotification("Video Generation", "Processing your clips into a short video...");
setTimeout(() => {
// Simulate processing time
const videoUrl = URL.createObjectURL(new Blob(["Simulated video content"], { type: 'video/mp4' }));
// Create download link
const a = document.createElement('a');
a.href = videoUrl;
a.download = 'streamai-short.mp4';
a.click();
showNotification("Video Ready", "Your short video has been generated and downloaded");
}, 3000);
}
// Connect to Bluetooth devices
async function connectBluetooth() {
try {
// Request Bluetooth device
bluetoothDevice = await navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['generic_access']
});
// Connect to the GATT Server
bluetoothServer = await bluetoothDevice.gatt.connect();
// Get the service
bluetoothService = await bluetoothServer.getPrimaryService('generic_access');
// Get the characteristic
bluetoothCharacteristic = await bluetoothService.getCharacteristic('device_name');
// Update connection status
isBluetoothConnected = true;
const statusElement = document.getElementById('connection-status');
statusElement.innerHTML = `
<i class="fas fa-circle bluetooth-connected mr-1"></i>
<span>Connected to ${bluetoothDevice.name || 'device'}</span>
`;
// Simulate discovering group members
groupMembers = [
{ name: "User" + Math.floor(Math.random() * 1000), device: "Device 1" },
{ name: "User" + Math.floor(Math.random() * 1000), device: "Device 2" },
{ name: "User" + Math.floor(Math.random() * 1000), device: "Device 3" }
];
showNotification("Bluetooth Connected", `Connected to ${bluetoothDevice.name}. Found ${groupMembers.length} group members.`);
} catch (error) {
console.error("Bluetooth connection error:", error);
isBluetoothConnected = false;
document.getElementById('connection-status').innerHTML = `
<i class="fas fa-circle bluetooth-disconnected mr-1"></i>
<span>Not connected</span>
`;
showNotification("Connection Failed", "Could not connect to Bluetooth device");
}
}
// Share clips with Bluetooth group
async function shareClipsWithGroup() {
if (!isBluetoothConnected) {
</html>