Professorjoe's picture
Modify to receive pasted url in another window. When one is being used, disable the other input windo - Initial Deployment
7447431 verified
Raw
History Blame Contribute Delete
19.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Transcript Generator</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">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#4F46E5',
secondary: '#818CF8',
accent: '#F97316',
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
}
.dropzone {
border: 2px dashed #c3cfe2;
border-radius: 10px;
transition: all 0.3s ease;
}
.dropzone.dragover {
border-color: #4F46E5;
background-color: rgba(79, 70, 229, 0.05);
}
.progress-bar {
transition: width 0.5s ease;
}
.transcript-container {
max-height: 300px;
overflow-y: auto;
scrollbar-width: thin;
}
.transcript-container::-webkit-scrollbar {
width: 8px;
}
.transcript-container::-webkit-scrollbar-thumb {
background-color: #c3cfe2;
border-radius: 4px;
}
.transcript-container::-webkit-scrollbar-thumb:hover {
background-color: #a5b4fc;
}
.pulse-animation {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body class="py-8 px-4">
<div class="max-w-4xl mx-auto">
<!-- Header -->
<header class="text-center mb-12">
<h1 class="text-3xl md:text-4xl font-bold text-gray-800 mb-2">Video Transcript Generator</h1>
<p class="text-gray-600">Upload a video and get instant transcriptions with multiple export options</p>
</header>
<div class="bg-white rounded-xl shadow-lg p-6 md:p-8">
<!-- Input Method Tabs -->
<div class="flex border-b border-gray-200 mb-6">
<button id="fileTab" class="px-4 py-2 font-medium text-primary border-b-2 border-primary transition-colors">
<i class="fas fa-upload mr-2"></i>File Upload
</button>
<button id="urlTab" class="px-4 py-2 font-medium text-gray-500 border-b-2 border-transparent hover:text-gray-700 transition-colors">
<i class="fas fa-link mr-2"></i>Video URL
</button>
</div>
<!-- File Upload Section -->
<div id="fileSection">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Upload Video</h2>
<div class="dropzone p-8 text-center cursor-pointer" id="dropzone">
<input type="file" id="fileInput" class="hidden" accept="video/*">
<div class="flex flex-col items-center justify-center">
<i class="fas fa-cloud-upload-alt text-4xl text-primary mb-4"></i>
<p class="text-gray-600 mb-2">Drag & drop your video file here</p>
<p class="text-sm text-gray-500 mb-4">or</p>
<label for="fileInput" class="bg-primary text-white px-6 py-2 rounded-lg cursor-pointer hover:bg-secondary transition-colors">
Browse Files
</label>
<p class="text-xs text-gray-500 mt-4">Supported formats: MP4, MOV, AVI, WebM</p>
</div>
</div>
</div>
<!-- URL Input Section -->
<div id="urlSection" class="hidden">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Enter Video URL</h2>
<div class="space-y-4">
<input type="url" id="urlInput" placeholder="https://example.com/video.mp4"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary">
<button id="processUrlBtn" class="bg-primary text-white px-6 py-2 rounded-lg hover:bg-secondary transition-colors">
Process URL
</button>
</div>
</div>
<!-- Progress Bar -->
<div id="progressSection" class="mb-8 hidden">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Processing Video</h2>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="progress-bar bg-primary h-2.5 rounded-full" style="width: 0%"></div>
</div>
<p class="text-sm text-gray-600 mt-2 text-center" id="progressText">0%</p>
</div>
<!-- Results Section -->
<div id="resultsSection" class="hidden">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Transcript Results</h2>
<!-- Action Buttons -->
<div class="flex flex-wrap gap-3 mb-6">
<button id="copyBtn" class="flex items-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-800 px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-copy"></i> Copy
</button>
<button id="saveBtn" class="flex items-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-800 px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-save"></i> Save as TXT
</button>
<button id="emailBtn" class="flex items-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-800 px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-envelope"></i> Email
</button>
</div>
<!-- Transcript Display -->
<div class="transcript-container bg-gray-50 p-4 rounded-lg border border-gray-200 mb-6">
<p id="transcriptText" class="text-gray-700 leading-relaxed"></p>
</div>
<!-- Email Modal -->
<div id="emailModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-xl p-6 w-full max-w-md">
<h3 class="text-xl font-semibold text-gray-800 mb-4">Email Transcript</h3>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Email Address</label>
<input type="email" id="emailInput" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary">
</div>
<div class="flex justify-end gap-3">
<button id="cancelEmail" class="px-4 py-2 text-gray-600 hover:text-gray-800">Cancel</button>
<button id="sendEmail" class="bg-primary text-white px-4 py-2 rounded-lg hover:bg-secondary transition-colors">Send</button>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="text-center mt-12 text-gray-600 text-sm">
<p>© 2023 Video Transcript Generator. All rights reserved.</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const fileSection = document.getElementById('fileSection');
const urlSection = document.getElementById('urlSection');
const fileTab = document.getElementById('fileTab');
const urlTab = document.getElementById('urlTab');
const urlInput = document.getElementById('urlInput');
const processUrlBtn = document.getElementById('processUrlBtn');
const progressSection = document.getElementById('progressSection');
const progressBar = document.querySelector('.progress-bar');
const progressText = document.getElementById('progressText');
const resultsSection = document.getElementById('resultsSection');
const transcriptText = document.getElementById('transcriptText');
const copyBtn = document.getElementById('copyBtn');
const saveBtn = document.getElementById('saveBtn');
const emailBtn = document.getElementById('emailBtn');
const emailModal = document.getElementById('emailModal');
const cancelEmail = document.getElementById('cancelEmail');
const sendEmail = document.getElementById('sendEmail');
const emailInput = document.getElementById('emailInput');
let currentTranscript = "";
let currentMethod = 'file';
// Tab switching functionality
fileTab.addEventListener('click', function() {
if (currentMethod !== 'file') {
currentMethod = 'file';
fileTab.classList.add('text-primary', 'border-primary');
fileTab.classList.remove('text-gray-500', 'border-transparent');
urlTab.classList.add('text-gray-500', 'border-transparent');
urlTab.classList.remove('text-primary', 'border-primary');
fileSection.classList.remove('hidden');
urlSection.classList.add('hidden');
}
});
urlTab.addEventListener('click', function() {
if (currentMethod !== 'url') {
currentMethod = 'url';
urlTab.classList.add('text-primary', 'border-primary');
urlTab.classList.remove('text-gray-500', 'border-transparent');
fileTab.classList.add('text-gray-500', 'border-transparent');
fileTab.classList.remove('text-primary', 'border-primary');
urlSection.classList.remove('hidden');
fileSection.classList.add('hidden');
}
});
// URL processing
processUrlBtn.addEventListener('click', function() {
const url = urlInput.value.trim();
if (url) {
if (isValidUrl(url)) {
processVideoUrl(url);
} else {
alert('Please enter a valid URL');
}
} else {
alert('Please enter a video URL');
}
});
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (_) {
return false;
}
}
// Drag and drop functionality
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropzone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropzone.classList.add('dragover');
}
function unhighlight() {
dropzone.classList.remove('dragover');
}
dropzone.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
fileInput.addEventListener('change', function() {
handleFiles(this.files);
});
function handleFiles(files) {
if (files.length > 0) {
const file = files[0];
if (file.type.startsWith('video/')) {
processVideoFile(file);
} else {
alert('Please upload a valid video file.');
}
}
}
function processVideoFile(file) {
// Show processing UI
progressSection.classList.remove('hidden');
resultsSection.classList.add('hidden');
// Simulate processing progress
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 10;
if (progress >= 100) {
progress = 100;
clearInterval(interval);
showResults(file.name);
}
progressBar.style.width = `${progress}%`;
progressText.textContent = `${Math.round(progress)}%`;
}, 300);
}
function processVideoUrl(url) {
// Show processing UI
progressSection.classList.remove('hidden');
resultsSection.classList.add('hidden');
// Extract filename from URL for display
const filename = url.split('/').pop() || 'video_from_url';
// Simulate processing progress
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 10;
if (progress >= 100) {
progress = 100;
clearInterval(interval);
showResults(filename);
}
progressBar.style.width = `${progress}%`;
progressText.textContent = `${Math.round(progress)}%`;
}, 300);
}
function showResults(filename) {
// Hide progress and show results
progressSection.classList.add('hidden');
resultsSection.classList.remove('hidden');
// Generate example transcript
currentTranscript = `Transcript for: ${filename}\n\n`;
currentTranscript += "[00:00:01] Hello and welcome to this video presentation.\n";
currentTranscript += "[00:00:05] Today we're going to discuss the importance of transcript generation.\n";
currentTranscript += "[00:00:12] Transcripts make video content accessible to everyone.\n";
currentTranscript += "[00:00:18] They help with SEO and allow users to quickly find information.\n";
currentTranscript += "[00:00:25] This is just a sample transcript generated by our tool.\n";
currentTranscript += "[00:00:32] In a real application, this would be the actual content from your video.\n";
currentTranscript += "[00:00:40] Thank you for using our Video Transcript Generator!";
transcriptText.textContent = currentTranscript;
}
// Copy functionality
copyBtn.addEventListener('click', function() {
navigator.clipboard.writeText(currentTranscript).then(() => {
const originalHtml = copyBtn.innerHTML;
copyBtn.innerHTML = '<i class="fas fa-check"></i> Copied!';
setTimeout(() => {
copyBtn.innerHTML = originalHtml;
}, 2000);
});
});
// Save functionality
saveBtn.addEventListener('click', function() {
const blob = new Blob([currentTranscript], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'transcript.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
// Email functionality
emailBtn.addEventListener('click', function() {
emailModal.classList.remove('hidden');
});
cancelEmail.addEventListener('click', function() {
emailModal.classList.add('hidden');
emailInput.value = '';
});
sendEmail.addEventListener('click', function() {
const email = emailInput.value;
if (validateEmail(email)) {
// Simulate sending email
emailModal.classList.add('hidden');
alert(`Transcript sent to ${email}`);
emailInput.value = '';
} else {
alert('Please enter a valid email address.');
}
});
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Professorjoe/prof-joebell-projects-space" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>