beppe1234 commited on
Commit
10eb234
·
verified ·
1 Parent(s): d27dbd6

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +226 -59
index.html CHANGED
@@ -89,6 +89,19 @@
89
  background-size: cover;
90
  background-position: center;
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  </style>
93
  </head>
94
  <body class="bg-gray-900 text-gray-100 min-h-screen">
@@ -98,7 +111,7 @@
98
  AI Video Highlight Generator
99
  </h1>
100
  <p class="text-lg text-gray-400 max-w-2xl mx-auto">
101
- Upload a video or paste a YouTube URL to automatically extract the most interesting moments with AI-generated subtitles.
102
  </p>
103
  </header>
104
 
@@ -177,7 +190,7 @@
177
  </div>
178
 
179
  <button id="processBtn" class="bg-gradient-to-r from-purple-600 to-emerald-600 hover:from-purple-500 hover:to-emerald-500 px-6 py-3 rounded-full font-medium transition-all transform hover:scale-105">
180
- <i class="fas fa-magic mr-2"></i> Generate Highlights
181
  </button>
182
  </div>
183
  </div>
@@ -199,12 +212,22 @@
199
  <!-- Results Section -->
200
  <div id="resultsSection" class="hidden p-6">
201
  <div class="flex justify-between items-center mb-6">
202
- <h3 class="text-xl font-semibold">Your Highlights</h3>
203
- <button id="downloadBtn" class="bg-gradient-to-r from-purple-600 to-emerald-600 hover:from-purple-500 hover:to-emerald-500 px-6 py-3 rounded-full font-medium transition-all flex items-center gap-2">
204
- <i class="fas fa-download"></i> Download All
205
  </button>
206
  </div>
207
 
 
 
 
 
 
 
 
 
 
 
208
  <div id="highlightResults" class="grid grid-cols-1 gap-6">
209
  <!-- Highlight results will be added here by JavaScript -->
210
  </div>
@@ -237,7 +260,7 @@
237
  const pauseBtn = document.getElementById('pauseBtn');
238
  const playVideoBtn = document.getElementById('playVideoBtn');
239
  const processBtn = document.getElementById('processBtn');
240
- const downloadBtn = document.getElementById('downloadBtn');
241
  const currentTimeEl = document.getElementById('currentTime');
242
  const durationEl = document.getElementById('duration');
243
  const waveformContainer = document.getElementById('waveformContainer');
@@ -254,6 +277,9 @@
254
  const progressText = document.getElementById('progressText');
255
  const resultsSection = document.getElementById('resultsSection');
256
  const playerOverlay = document.getElementById('playerOverlay');
 
 
 
257
 
258
  // State variables
259
  let videoFile = null;
@@ -270,6 +296,7 @@
270
  let youtubeCurrentTime = 0;
271
  let youtubeThumbnail = '';
272
  let youtubeTitle = '';
 
273
 
274
  // Event Listeners
275
  fileInput.addEventListener('change', handleFileSelect);
@@ -278,7 +305,7 @@
278
  pauseBtn.addEventListener('click', pauseVideo);
279
  playVideoBtn.addEventListener('click', playVideo);
280
  processBtn.addEventListener('click', processVideo);
281
- downloadBtn.addEventListener('click', downloadHighlights);
282
  videoPlayer.addEventListener('timeupdate', updateVideoTime);
283
  videoPlayer.addEventListener('ended', () => {
284
  playBtn.innerHTML = '<i class="fas fa-redo"></i>';
@@ -325,8 +352,8 @@
325
  }
326
 
327
  // Extract video ID from URL
328
- const videoId = extractYouTubeId(url);
329
- if (!videoId) {
330
  alert('Please enter a valid YouTube URL');
331
  return;
332
  }
@@ -343,7 +370,7 @@
343
  showUploadProgress('Loading YouTube video...');
344
 
345
  // Load YouTube player
346
- loadYouTubeVideo(videoId);
347
  }
348
 
349
  function extractYouTubeId(url) {
@@ -482,6 +509,7 @@
482
  }
483
 
484
  function updateWaveformProgress(currentTime) {
 
485
  const progressPercent = (currentTime / videoDuration) * 100;
486
  waveformProgress.style.width = `${progressPercent}%`;
487
  waveformMarker.style.left = `${progressPercent}%`;
@@ -661,6 +689,11 @@
661
 
662
  function processVideo() {
663
  if (isProcessing) return;
 
 
 
 
 
664
  isProcessing = true;
665
 
666
  // Show processing state
@@ -683,7 +716,7 @@
683
  resultsSection.classList.remove('hidden');
684
 
685
  // Reset button
686
- processBtn.innerHTML = '<i class="fas fa-magic mr-2"></i> Generate Highlights';
687
  processBtn.disabled = false;
688
  isProcessing = false;
689
  }, 3000);
@@ -693,20 +726,29 @@
693
  // In a real app, this would come from your AI analysis
694
  highlights = [];
695
 
696
- // Generate 3-5 random highlights
697
- const highlightCount = Math.floor(Math.random() * 3) + 3;
 
698
 
 
699
  for (let i = 0; i < highlightCount; i++) {
700
- const duration = Math.random() * 10 + 5; // 5-15 seconds
701
- const maxStart = videoDuration - duration;
702
- const start = Math.random() * maxStart;
 
 
 
703
 
704
  highlights.push({
705
- start,
706
- end: start + duration,
707
  confidence: Math.random() * 0.5 + 0.5, // 0.5-1.0
708
- title: `Highlight ${i+1}`,
709
- description: `This is an automatically generated highlight clip from the video. The AI detected this as an interesting moment.`
 
 
 
 
710
  });
711
  }
712
 
@@ -721,11 +763,11 @@
721
  // Generate subtitles for each highlight
722
  highlights.forEach((highlight, i) => {
723
  const textOptions = [
724
- "This is an important moment in the video.",
725
- "The speaker is making a key point here.",
726
- "Watch this interesting interaction.",
727
- "The main subject is demonstrating something valuable.",
728
- "This clip contains the most engaging content."
729
  ];
730
 
731
  subtitles.push({
@@ -742,11 +784,32 @@
742
  clip.className = 'highlight-clip';
743
  clip.style.left = `${(highlight.start / videoDuration) * 100}%`;
744
  clip.style.width = `${((highlight.end - highlight.start) / videoDuration) * 100}%`;
745
- clip.title = `Highlight: ${formatTime(highlight.start)} - ${formatTime(highlight.end)}`;
 
746
  waveform.appendChild(clip);
 
 
 
 
 
 
747
  });
748
  }
749
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
750
  function displayHighlightClips() {
751
  highlightClips.innerHTML = '';
752
  highlightResults.innerHTML = '';
@@ -756,14 +819,15 @@
756
  highlights.forEach((highlight, index) => {
757
  // Create clip card for waveform section
758
  const clipCard = document.createElement('div');
759
- clipCard.className = 'bg-gray-700 rounded-lg p-4 flex items-start gap-4';
 
760
  clipCard.innerHTML = `
761
  <div class="bg-purple-600/20 w-12 h-12 rounded-full flex items-center justify-center flex-shrink-0">
762
  <span class="text-xl font-bold">${index+1}</span>
763
  </div>
764
  <div>
765
  <h4 class="font-semibold mb-1">${highlight.title}</h4>
766
- <p class="text-sm text-gray-400 mb-2">${formatTime(highlight.start)} - ${formatTime(highlight.end)}</p>
767
  <p class="text-sm">${highlight.description}</p>
768
  </div>
769
  `;
@@ -771,46 +835,63 @@
771
 
772
  // Create result card for results section
773
  const resultCard = document.createElement('div');
774
- resultCard.className = 'bg-gray-800 rounded-xl overflow-hidden border border-gray-700';
 
775
  resultCard.innerHTML = `
776
  <div class="relative">
777
  <div class="w-full bg-black aspect-video flex items-center justify-center relative">
778
  ${videoType === 'youtube' ?
779
- `<img src="${youtubeThumbnail}" alt="${titleBase}" class="w-full h-full object-cover">
780
- <div class="absolute inset-0 flex items-center justify-center">
781
- <div class="bg-black/50 rounded-full w-16 h-16 flex items-center justify-center">
782
  <i class="fas fa-play text-white text-2xl"></i>
783
  </div>
784
  </div>` :
785
  `<video class="w-full h-full" muted>
786
  <source src="${videoBlobUrl}" type="video/mp4">
787
- </video>`}
 
 
 
 
 
788
  </div>
789
  <div class="absolute bottom-4 left-0 right-0 px-4">
790
  <div class="bg-black/70 text-white rounded px-3 py-2 text-center max-w-md mx-auto">
791
- ${subtitles[index]?.text || 'Important moment'}
792
  </div>
793
  </div>
794
  </div>
795
  <div class="p-4">
796
  <div class="flex justify-between items-start mb-2">
797
- <h4 class="font-semibold text-lg">${titleBase}: ${highlight.title}</h4>
798
- <button class="download-clip-btn bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded text-sm flex items-center gap-1" data-index="${index}">
799
- <i class="fas fa-download text-xs"></i> Download
 
 
 
800
  </button>
801
  </div>
802
- <p class="text-sm text-gray-400 mb-2">${formatTime(highlight.start)} - ${formatTime(highlight.end)}</p>
803
  <p class="text-sm">${highlight.description}</p>
804
  </div>
805
  `;
806
  highlightResults.appendChild(resultCard);
 
 
 
 
 
 
 
807
  });
808
 
809
  // Add event listeners to download buttons
810
  document.querySelectorAll('.download-clip-btn').forEach(btn => {
811
- btn.addEventListener('click', function() {
812
- const index = this.getAttribute('data-index');
813
- downloadHighlight(index);
 
814
  });
815
  });
816
  }
@@ -821,28 +902,114 @@
821
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
822
  }
823
 
824
- function downloadHighlight(index) {
825
- if (index < 0 || index >= highlights.length) return;
 
826
 
827
- const highlight = highlights[index];
 
 
 
828
 
829
- // Show different messages based on video source
830
- if (videoType === 'youtube') {
831
- const youtubeUrl = `https://www.youtube.com/watch?v=${youtubePlayer.getVideoData().video_id}&t=${Math.floor(highlight.start)}`;
832
- alert(`YouTube Highlight: ${highlight.title}\nClip URL: ${youtubeUrl}\nIn a real app, this would download the YouTube clip.`);
833
- } else {
834
- alert(`Downloading highlight: ${highlight.title}\nThis would download the clip from ${formatTime(highlight.start)} to ${formatTime(highlight.end)}`);
835
- }
 
 
 
 
 
 
 
 
 
836
  }
837
 
838
- function downloadHighlights() {
839
- if (videoType === 'youtube') {
840
- const videoId = youtubePlayer.getVideoData().video_id;
841
- const url = `https://www.youtube.com/watch?v=${videoId}`;
842
- alert(`Downloading all highlights from YouTube video\nIn a real app, this would package all clips from ${url}`);
843
- } else {
844
- alert('Downloading all highlights as a ZIP file\nIn a real app, this would package all clips together for download');
845
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  }
847
  });
848
  </script>
 
89
  background-size: cover;
90
  background-position: center;
91
  }
92
+ .export-progress {
93
+ transition: width 0.3s ease;
94
+ }
95
+ .clip-preview {
96
+ position: relative;
97
+ }
98
+ .clip-preview:hover .clip-overlay {
99
+ opacity: 1;
100
+ }
101
+ .clip-overlay {
102
+ opacity: 0;
103
+ transition: opacity 0.3s ease;
104
+ }
105
  </style>
106
  </head>
107
  <body class="bg-gray-900 text-gray-100 min-h-screen">
 
111
  AI Video Highlight Generator
112
  </h1>
113
  <p class="text-lg text-gray-400 max-w-2xl mx-auto">
114
+ Upload a video or paste a YouTube URL to automatically extract 1-minute highlight clips with AI analysis.
115
  </p>
116
  </header>
117
 
 
190
  </div>
191
 
192
  <button id="processBtn" class="bg-gradient-to-r from-purple-600 to-emerald-600 hover:from-purple-500 hover:to-emerald-500 px-6 py-3 rounded-full font-medium transition-all transform hover:scale-105">
193
+ <i class="fas fa-magic mr-2"></i> Generate 1-Min Highlights
194
  </button>
195
  </div>
196
  </div>
 
212
  <!-- Results Section -->
213
  <div id="resultsSection" class="hidden p-6">
214
  <div class="flex justify-between items-center mb-6">
215
+ <h3 class="text-xl font-semibold">Your 1-Minute Highlights</h3>
216
+ <button id="downloadAllBtn" class="bg-gradient-to-r from-purple-600 to-emerald-600 hover:from-purple-500 hover:to-emerald-500 px-6 py-3 rounded-full font-medium transition-all flex items-center gap-2">
217
+ <i class="fas fa-download"></i> Download All (ZIP)
218
  </button>
219
  </div>
220
 
221
+ <div id="exportStatus" class="hidden mb-4 bg-gray-700 rounded-lg p-4">
222
+ <div class="flex justify-between items-center mb-2">
223
+ <span class="font-medium">Preparing clips for download...</span>
224
+ <span id="exportPercent" class="font-bold">0%</span>
225
+ </div>
226
+ <div class="w-full bg-gray-600 rounded-full h-2.5">
227
+ <div id="exportProgress" class="bg-emerald-500 h-2.5 rounded-full export-progress" style="width: 0%"></div>
228
+ </div>
229
+ </div>
230
+
231
  <div id="highlightResults" class="grid grid-cols-1 gap-6">
232
  <!-- Highlight results will be added here by JavaScript -->
233
  </div>
 
260
  const pauseBtn = document.getElementById('pauseBtn');
261
  const playVideoBtn = document.getElementById('playVideoBtn');
262
  const processBtn = document.getElementById('processBtn');
263
+ const downloadAllBtn = document.getElementById('downloadAllBtn');
264
  const currentTimeEl = document.getElementById('currentTime');
265
  const durationEl = document.getElementById('duration');
266
  const waveformContainer = document.getElementById('waveformContainer');
 
277
  const progressText = document.getElementById('progressText');
278
  const resultsSection = document.getElementById('resultsSection');
279
  const playerOverlay = document.getElementById('playerOverlay');
280
+ const exportStatus = document.getElementById('exportStatus');
281
+ const exportProgress = document.getElementById('exportProgress');
282
+ const exportPercent = document.getElementById('exportPercent');
283
 
284
  // State variables
285
  let videoFile = null;
 
296
  let youtubeCurrentTime = 0;
297
  let youtubeThumbnail = '';
298
  let youtubeTitle = '';
299
+ let youtubeVideoId = '';
300
 
301
  // Event Listeners
302
  fileInput.addEventListener('change', handleFileSelect);
 
305
  pauseBtn.addEventListener('click', pauseVideo);
306
  playVideoBtn.addEventListener('click', playVideo);
307
  processBtn.addEventListener('click', processVideo);
308
+ downloadAllBtn.addEventListener('click', handleDownloadAll);
309
  videoPlayer.addEventListener('timeupdate', updateVideoTime);
310
  videoPlayer.addEventListener('ended', () => {
311
  playBtn.innerHTML = '<i class="fas fa-redo"></i>';
 
352
  }
353
 
354
  // Extract video ID from URL
355
+ youtubeVideoId = extractYouTubeId(url);
356
+ if (!youtubeVideoId) {
357
  alert('Please enter a valid YouTube URL');
358
  return;
359
  }
 
370
  showUploadProgress('Loading YouTube video...');
371
 
372
  // Load YouTube player
373
+ loadYouTubeVideo(youtubeVideoId);
374
  }
375
 
376
  function extractYouTubeId(url) {
 
509
  }
510
 
511
  function updateWaveformProgress(currentTime) {
512
+ if (!videoDuration) return;
513
  const progressPercent = (currentTime / videoDuration) * 100;
514
  waveformProgress.style.width = `${progressPercent}%`;
515
  waveformMarker.style.left = `${progressPercent}%`;
 
689
 
690
  function processVideo() {
691
  if (isProcessing) return;
692
+ if (videoDuration < 60) {
693
+ alert('Video must be at least 1 minute long to generate highlights');
694
+ return;
695
+ }
696
+
697
  isProcessing = true;
698
 
699
  // Show processing state
 
716
  resultsSection.classList.remove('hidden');
717
 
718
  // Reset button
719
+ processBtn.innerHTML = '<i class="fas fa-magic mr-2"></i> Generate 1-Min Highlights';
720
  processBtn.disabled = false;
721
  isProcessing = false;
722
  }, 3000);
 
726
  // In a real app, this would come from your AI analysis
727
  highlights = [];
728
 
729
+ // Determine how many 1-minute highlights we can have
730
+ const maxHighlights = Math.floor(videoDuration / 60);
731
+ const highlightCount = Math.min(maxHighlights, 3); // Max 3 highlights for demo
732
 
733
+ // Generate highlights at approximately 25%, 50%, 75% of video
734
  for (let i = 0; i < highlightCount; i++) {
735
+ // Get a position in the video (25%, 50%, 75%)
736
+ const positionPercent = 0.25 + (0.25 * i);
737
+ let start = positionPercent * videoDuration;
738
+
739
+ // Make sure highlight doesn't go past end of video
740
+ start = Math.min(start, videoDuration - 60);
741
 
742
  highlights.push({
743
+ start: start,
744
+ end: start + 60, // Exactly 1 minute
745
  confidence: Math.random() * 0.5 + 0.5, // 0.5-1.0
746
+ title: `Best Moment ${i+1}`,
747
+ description: `Watch this exciting 1-minute highlight reel from the video. Automatically generated by AI analysis.`,
748
+ id: `highlight_${Date.now()}_${i}`,
749
+ previewImage: videoType === 'youtube' ?
750
+ `https://img.youtube.com/vi/${youtubeVideoId}/mqdefault.jpg` :
751
+ (videoBlobUrl ? videoBlobUrl : '')
752
  });
753
  }
754
 
 
763
  // Generate subtitles for each highlight
764
  highlights.forEach((highlight, i) => {
765
  const textOptions = [
766
+ "This is the most exciting part of the video!",
767
+ "The best 1-minute segment from this content.",
768
+ "AI selected this as the most engaging moment.",
769
+ "Highlight reel of the most important content.",
770
+ "This 60-second clip contains the key takeaways."
771
  ];
772
 
773
  subtitles.push({
 
784
  clip.className = 'highlight-clip';
785
  clip.style.left = `${(highlight.start / videoDuration) * 100}%`;
786
  clip.style.width = `${((highlight.end - highlight.start) / videoDuration) * 100}%`;
787
+ clip.title = `1-min Highlight: ${formatTime(highlight.start)} - ${formatTime(highlight.end)}`;
788
+ clip.dataset.clipId = highlight.id;
789
  waveform.appendChild(clip);
790
+
791
+ // Make highlight clip clickable
792
+ clip.addEventListener('click', (e) => {
793
+ e.stopPropagation();
794
+ seekToHighlight(highlight.start);
795
+ });
796
  });
797
  }
798
 
799
+ function seekToHighlight(time) {
800
+ if (videoType === 'youtube' && youtubePlayer) {
801
+ youtubePlayer.seekTo(time, true);
802
+ if (!isYouTubePlaying) {
803
+ youtubePlayer.playVideo();
804
+ }
805
+ } else if (videoType === 'file') {
806
+ videoPlayer.currentTime = time;
807
+ if (videoPlayer.paused) {
808
+ videoPlayer.play();
809
+ }
810
+ }
811
+ }
812
+
813
  function displayHighlightClips() {
814
  highlightClips.innerHTML = '';
815
  highlightResults.innerHTML = '';
 
819
  highlights.forEach((highlight, index) => {
820
  // Create clip card for waveform section
821
  const clipCard = document.createElement('div');
822
+ clipCard.className = 'bg-gray-700 rounded-lg p-4 flex items-start gap-4 hover:bg-gray-600 transition-colors cursor-pointer';
823
+ clipCard.addEventListener('click', () => seekToHighlight(highlight.start));
824
  clipCard.innerHTML = `
825
  <div class="bg-purple-600/20 w-12 h-12 rounded-full flex items-center justify-center flex-shrink-0">
826
  <span class="text-xl font-bold">${index+1}</span>
827
  </div>
828
  <div>
829
  <h4 class="font-semibold mb-1">${highlight.title}</h4>
830
+ <p class="text-sm text-gray-400 mb-2">${formatTime(highlight.start)} - ${formatTime(highlight.end)} (1 min)</p>
831
  <p class="text-sm">${highlight.description}</p>
832
  </div>
833
  `;
 
835
 
836
  // Create result card for results section
837
  const resultCard = document.createElement('div');
838
+ resultCard.className = 'bg-gray-800 rounded-xl overflow-hidden border border-gray-700 clip-preview';
839
+ resultCard.setAttribute('data-clip-id', highlight.id);
840
  resultCard.innerHTML = `
841
  <div class="relative">
842
  <div class="w-full bg-black aspect-video flex items-center justify-center relative">
843
  ${videoType === 'youtube' ?
844
+ `<img src="${highlight.previewImage}" alt="${titleBase}" class="w-full h-full object-cover">
845
+ <div class="clip-overlay absolute inset-0 flex items-center justify-center bg-black/50">
846
+ <div class="bg-white/20 rounded-full w-16 h-16 flex items-center justify-center backdrop-blur-sm">
847
  <i class="fas fa-play text-white text-2xl"></i>
848
  </div>
849
  </div>` :
850
  `<video class="w-full h-full" muted>
851
  <source src="${videoBlobUrl}" type="video/mp4">
852
+ </video>
853
+ <div class="clip-overlay absolute inset-0 flex items-center justify-center bg-black/50">
854
+ <div class="bg-white/20 rounded-full w-16 h-16 flex items-center justify-center backdrop-blur-sm">
855
+ <i class="fas fa-play text-white text-2xl"></i>
856
+ </div>
857
+ </div>`}
858
  </div>
859
  <div class="absolute bottom-4 left-0 right-0 px-4">
860
  <div class="bg-black/70 text-white rounded px-3 py-2 text-center max-w-md mx-auto">
861
+ ${subtitles[index]?.text || '1-minute highlight'}
862
  </div>
863
  </div>
864
  </div>
865
  <div class="p-4">
866
  <div class="flex justify-between items-start mb-2">
867
+ <div>
868
+ <h4 class="font-semibold text-lg">${titleBase}</h4>
869
+ <p class="text-sm text-gray-400">${highlight.title}</p>
870
+ </div>
871
+ <button class="download-clip-btn bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded font-medium flex items-center gap-2" data-clip-id="${highlight.id}">
872
+ <i class="fas fa-download"></i> Download
873
  </button>
874
  </div>
875
+ <p class="text-sm text-gray-400 mb-2">${formatTime(highlight.start)} - ${formatTime(highlight.end)} (1 min)</p>
876
  <p class="text-sm">${highlight.description}</p>
877
  </div>
878
  `;
879
  highlightResults.appendChild(resultCard);
880
+
881
+ // Add click handler to preview the clip
882
+ const videoPreview = resultCard.querySelector('video, img');
883
+ videoPreview.parentElement.addEventListener('click', (e) => {
884
+ e.preventDefault();
885
+ seekToHighlight(highlight.start);
886
+ });
887
  });
888
 
889
  // Add event listeners to download buttons
890
  document.querySelectorAll('.download-clip-btn').forEach(btn => {
891
+ btn.addEventListener('click', function(e) {
892
+ e.stopPropagation();
893
+ const clipId = this.getAttribute('data-clip-id');
894
+ downloadHighlight(clipId);
895
  });
896
  });
897
  }
 
902
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
903
  }
904
 
905
+ function downloadHighlight(clipId) {
906
+ const highlight = highlights.find(h => h.id === clipId);
907
+ if (!highlight) return;
908
 
909
+ // Show exporting status
910
+ exportStatus.classList.remove('hidden');
911
+ exportProgress.style.width = '0%';
912
+ exportPercent.textContent = '0%';
913
 
914
+ // Simulate export progress
915
+ let progress = 0;
916
+ const interval = setInterval(() => {
917
+ progress += Math.random() * 10;
918
+ if (progress >= 100) {
919
+ progress = 100;
920
+ clearInterval(interval);
921
+
922
+ // After a small delay, show completion
923
+ setTimeout(() => {
924
+ completeExport(highlight);
925
+ }, 500);
926
+ }
927
+ exportProgress.style.width = `${progress}%`;
928
+ exportPercent.textContent = `${Math.floor(progress)}%`;
929
+ }, 100);
930
  }
931
 
932
+ function completeExport(highlight) {
933
+ exportProgress.style.width = '100%';
934
+ exportPercent.textContent = '100%';
935
+
936
+ setTimeout(() => {
937
+ // Create a dummy download link (in a real app, this would be your exported clip)
938
+ const dummyDownloadUrl = videoType === 'youtube' ?
939
+ `https://www.youtube.com/watch?v=${youtubeVideoId}&t=${Math.floor(highlight.start)}` :
940
+ videoBlobUrl;
941
+
942
+ const a = document.createElement('a');
943
+ a.href = dummyDownloadUrl;
944
+ a.download = `highlight_${formatTime(highlight.start)}_${formatTime(highlight.end)}.mp4`;
945
+ a.style.display = 'none';
946
+ document.body.appendChild(a);
947
+ a.click();
948
+ document.body.removeChild(a);
949
+
950
+ exportStatus.classList.add('hidden');
951
+
952
+ if (videoType === 'youtube') {
953
+ alert(`In a real application, this would download the 1-minute YouTube clip from ${formatTime(highlight.start)} to ${formatTime(highlight.end)}. For now, it links to the YouTube video at the start time.`);
954
+ } else {
955
+ alert(`In a real application, this would download just the 1-minute clip from ${formatTime(highlight.start)} to ${formatTime(highlight.end)}. For demo purposes, it downloads the full video.`);
956
+ }
957
+ }, 500);
958
+ }
959
+
960
+ function handleDownloadAll() {
961
+ if (highlights.length === 0) return;
962
+
963
+ // Show exporting status
964
+ exportStatus.classList.remove('hidden');
965
+ exportProgress.style.width = '0%';
966
+ exportPercent.textContent = '0%';
967
+
968
+ // Simulate export progress for all clips
969
+ let progress = 0;
970
+ const interval = setInterval(() => {
971
+ progress += Math.random() * 5;
972
+ if (progress >= 100) {
973
+ progress = 100;
974
+ clearInterval(interval);
975
+
976
+ setTimeout(() => {
977
+ completeAllExport();
978
+ }, 500);
979
+ }
980
+ exportProgress.style.width = `${progress}%`;
981
+ exportPercent.textContent = `${Math.floor(progress)}%`;
982
+ }, 100);
983
+ }
984
+
985
+ function completeAllExport() {
986
+ exportProgress.style.width = '100%';
987
+ exportPercent.textContent = '100%';
988
+
989
+ setTimeout(() => {
990
+ // Create a dummy ZIP download (in a real app, this would package all clips)
991
+ let downloadUrl;
992
+ let downloadText;
993
+
994
+ if (videoType === 'youtube') {
995
+ downloadUrl = `https://www.youtube.com/watch?v=${youtubeVideoId}`;
996
+ downloadText = `In a real application, this would download all 1-minute YouTube highlights as a ZIP file. For now, it links to the full YouTube video.`;
997
+ } else {
998
+ downloadUrl = videoBlobUrl;
999
+ downloadText = `In a real application, this would download all 1-minute highlights as a ZIP file. For demo purposes, it downloads the full video.`;
1000
+ }
1001
+
1002
+ const a = document.createElement('a');
1003
+ a.href = downloadUrl;
1004
+ a.download = `highlights_${videoType === 'youtube' ? youtubeTitle : 'your_video'}.zip`;
1005
+ a.style.display = 'none';
1006
+ document.body.appendChild(a);
1007
+ a.click();
1008
+ document.body.removeChild(a);
1009
+
1010
+ exportStatus.classList.add('hidden');
1011
+ alert(downloadText);
1012
+ }, 500);
1013
  }
1014
  });
1015
  </script>