tsbetterworkpmo commited on
Commit
c3f3eea
·
verified ·
1 Parent(s): c3e97ba

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +580 -19
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Videomerger
3
- emoji:
4
- colorFrom: gray
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: videomerger
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,580 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>VideoMerge Pro - Combine Videos in 4K</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #6366f1;
12
+ border-radius: 0.5rem;
13
+ transition: all 0.3s ease;
14
+ }
15
+ .dropzone.active {
16
+ border-color: #10b981;
17
+ background-color: rgba(16, 185, 129, 0.05);
18
+ }
19
+ .video-preview {
20
+ aspect-ratio: 16/9;
21
+ background-color: #1e293b;
22
+ }
23
+ .progress-bar {
24
+ height: 6px;
25
+ transition: width 0.3s ease;
26
+ }
27
+ .timeline-track {
28
+ height: 60px;
29
+ background-color: #1e293b;
30
+ overflow-x: auto;
31
+ }
32
+ .video-clip {
33
+ min-width: 120px;
34
+ height: 50px;
35
+ background-color: #6366f1;
36
+ border-radius: 4px;
37
+ position: relative;
38
+ }
39
+ .clip-handle {
40
+ width: 6px;
41
+ height: 100%;
42
+ background-color: rgba(255, 255, 255, 0.5);
43
+ position: absolute;
44
+ top: 0;
45
+ cursor: ew-resize;
46
+ }
47
+ .clip-handle.left {
48
+ left: 0;
49
+ border-top-left-radius: 4px;
50
+ border-bottom-left-radius: 4px;
51
+ }
52
+ .clip-handle.right {
53
+ right: 0;
54
+ border-top-right-radius: 4px;
55
+ border-bottom-right-radius: 4px;
56
+ }
57
+ .settings-panel {
58
+ transition: all 0.3s ease;
59
+ max-height: 0;
60
+ overflow: hidden;
61
+ }
62
+ .settings-panel.open {
63
+ max-height: 500px;
64
+ }
65
+ </style>
66
+ </head>
67
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
68
+ <div class="container mx-auto px-4 py-8">
69
+ <!-- Header -->
70
+ <header class="mb-8">
71
+ <div class="flex items-center justify-between">
72
+ <div class="flex items-center space-x-2">
73
+ <i class="fas fa-film text-indigo-500 text-2xl"></i>
74
+ <h1 class="text-2xl font-bold">VideoMerge <span class="text-indigo-500">Pro</span></h1>
75
+ </div>
76
+ <div>
77
+ <button class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
78
+ <i class="fas fa-user"></i>
79
+ <span>Sign In</span>
80
+ </button>
81
+ </div>
82
+ </div>
83
+ <p class="text-gray-400 mt-2">Combine multiple videos seamlessly and export in stunning 4K quality</p>
84
+ </header>
85
+
86
+ <!-- Main Content -->
87
+ <main>
88
+ <!-- Upload Section -->
89
+ <section class="mb-8">
90
+ <div class="dropzone p-8 text-center cursor-pointer" id="dropzone">
91
+ <div class="flex flex-col items-center justify-center space-y-4">
92
+ <i class="fas fa-cloud-upload-alt text-indigo-500 text-5xl"></i>
93
+ <h2 class="text-xl font-semibold">Drag & Drop Video Files</h2>
94
+ <p class="text-gray-400">or click to browse files (MP4, MOV, AVI supported)</p>
95
+ <input type="file" id="fileInput" class="hidden" accept="video/*" multiple>
96
+ <button id="browseBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg">
97
+ Select Videos
98
+ </button>
99
+ </div>
100
+ </div>
101
+ </section>
102
+
103
+ <!-- Video Timeline -->
104
+ <section class="mb-8 bg-gray-800 rounded-lg p-4">
105
+ <div class="flex justify-between items-center mb-4">
106
+ <h3 class="text-lg font-semibold">Video Timeline</h3>
107
+ <div class="flex space-x-2">
108
+ <button id="clearAllBtn" class="bg-gray-700 hover:bg-gray-600 text-white px-3 py-1 rounded">
109
+ <i class="fas fa-trash mr-1"></i> Clear All
110
+ </button>
111
+ <button id="addTransitionBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded">
112
+ <i class="fas fa-random mr-1"></i> Add Transition
113
+ </button>
114
+ </div>
115
+ </div>
116
+
117
+ <div class="timeline-track rounded p-2 mb-4" id="timeline">
118
+ <div class="flex space-x-2" id="videoClipsContainer">
119
+ <!-- Video clips will be added here dynamically -->
120
+ <div class="text-gray-400 flex items-center justify-center w-full" id="emptyTimelineMessage">
121
+ <p>Add videos to start creating your timeline</p>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="flex justify-between items-center">
127
+ <div class="text-sm text-gray-400">
128
+ <span id="totalDuration">Total Duration: 0:00</span>
129
+ </div>
130
+ <div>
131
+ <button id="playAllBtn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg mr-2">
132
+ <i class="fas fa-play mr-1"></i> Play All
133
+ </button>
134
+ <button id="previewBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
135
+ <i class="fas fa-eye mr-1"></i> Preview
136
+ </button>
137
+ </div>
138
+ </div>
139
+ </section>
140
+
141
+ <!-- Preview Section -->
142
+ <section class="mb-8 bg-gray-800 rounded-lg p-4 hidden" id="previewSection">
143
+ <div class="flex justify-between items-center mb-4">
144
+ <h3 class="text-lg font-semibold">Preview</h3>
145
+ <button id="closePreviewBtn" class="text-gray-400 hover:text-white">
146
+ <i class="fas fa-times"></i>
147
+ </button>
148
+ </div>
149
+ <div class="video-preview rounded-lg overflow-hidden relative" id="previewVideo">
150
+ <video controls class="w-full h-full" id="mergedPreview"></video>
151
+ <div class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-50 hidden" id="previewOverlay">
152
+ <i class="fas fa-play text-white text-4xl"></i>
153
+ </div>
154
+ </div>
155
+ </section>
156
+
157
+ <!-- Export Settings -->
158
+ <section class="mb-8 bg-gray-800 rounded-lg overflow-hidden">
159
+ <div class="p-4 cursor-pointer flex justify-between items-center" id="settingsToggle">
160
+ <h3 class="text-lg font-semibold">
161
+ <i class="fas fa-cog text-indigo-500 mr-2"></i> Export Settings
162
+ </h3>
163
+ <i class="fas fa-chevron-down text-gray-400 transition-transform" id="settingsChevron"></i>
164
+ </div>
165
+
166
+ <div class="settings-panel bg-gray-700" id="settingsPanel">
167
+ <div class="p-4 grid grid-cols-1 md:grid-cols-2 gap-6">
168
+ <!-- Resolution -->
169
+ <div>
170
+ <label class="block text-sm font-medium mb-2">Resolution</label>
171
+ <div class="flex space-x-2">
172
+ <button class="resolution-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-resolution="720p">720p</button>
173
+ <button class="resolution-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-resolution="1080p">1080p</button>
174
+ <button class="resolution-btn px-3 py-1 rounded bg-indigo-600 border-indigo-600 text-white" data-resolution="4k">4K (3840x2160)</button>
175
+ </div>
176
+ </div>
177
+
178
+ <!-- Frame Rate -->
179
+ <div>
180
+ <label class="block text-sm font-medium mb-2">Frame Rate</label>
181
+ <div class="flex space-x-2">
182
+ <button class="fps-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-fps="24">24fps</button>
183
+ <button class="fps-btn px-3 py-1 rounded bg-indigo-600 border-indigo-600 text-white" data-fps="30">30fps</button>
184
+ <button class="fps-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-fps="60">60fps</button>
185
+ </div>
186
+ </div>
187
+
188
+ <!-- Format -->
189
+ <div>
190
+ <label class="block text-sm font-medium mb-2">Format</label>
191
+ <div class="flex space-x-2">
192
+ <button class="format-btn px-3 py-1 rounded bg-indigo-600 border-indigo-600 text-white" data-format="mp4">MP4</button>
193
+ <button class="format-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-format="mov">MOV</button>
194
+ <button class="format-btn px-3 py-1 rounded border border-gray-600 hover:bg-gray-600" data-format="avi">AVI</button>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- Quality -->
199
+ <div>
200
+ <label class="block text-sm font-medium mb-2">Quality</label>
201
+ <div class="flex items-center space-x-2">
202
+ <input type="range" min="1" max="100" value="90" class="w-full" id="qualitySlider">
203
+ <span class="text-sm w-12 text-center" id="qualityValue">90%</span>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </section>
209
+
210
+ <!-- Export Button -->
211
+ <section class="text-center">
212
+ <button id="exportBtn" class="bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 text-white px-8 py-3 rounded-lg text-lg font-semibold shadow-lg">
213
+ <i class="fas fa-file-export mr-2"></i> Export Merged Video (4K 30fps)
214
+ </button>
215
+ </section>
216
+ </main>
217
+
218
+ <!-- Processing Modal -->
219
+ <div class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden" id="processingModal">
220
+ <div class="bg-gray-800 rounded-lg p-6 max-w-md w-full">
221
+ <div class="flex justify-between items-center mb-4">
222
+ <h3 class="text-lg font-semibold">Processing Your Video</h3>
223
+ <div class="text-sm text-gray-400" id="processingStep">Step 1/3: Preparing files</div>
224
+ </div>
225
+
226
+ <div class="w-full bg-gray-700 rounded-full h-2.5 mb-4">
227
+ <div class="progress-bar bg-indigo-600 rounded-full h-2.5" id="progressBar" style="width: 0%"></div>
228
+ </div>
229
+
230
+ <div class="text-center py-4">
231
+ <i class="fas fa-cog fa-spin text-indigo-500 text-4xl mb-3"></i>
232
+ <p class="text-gray-300" id="processingMessage">Combining your videos and optimizing for 4K quality...</p>
233
+ </div>
234
+
235
+ <div class="text-right">
236
+ <button id="cancelProcessingBtn" class="text-gray-400 hover:text-white">
237
+ Cancel Processing
238
+ </button>
239
+ </div>
240
+ </div>
241
+ </div>
242
+
243
+ <!-- Success Modal -->
244
+ <div class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden" id="successModal">
245
+ <div class="bg-gray-800 rounded-lg p-6 max-w-md w-full text-center">
246
+ <div class="text-green-500 text-5xl mb-4">
247
+ <i class="fas fa-check-circle"></i>
248
+ </div>
249
+ <h3 class="text-xl font-semibold mb-2">Export Complete!</h3>
250
+ <p class="text-gray-300 mb-6">Your 4K 30fps video is ready to download.</p>
251
+ <div class="flex justify-center space-x-4">
252
+ <button id="downloadBtn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-lg">
253
+ <i class="fas fa-download mr-2"></i> Download
254
+ </button>
255
+ <button id="newProjectBtn" class="bg-gray-700 hover:bg-gray-600 text-white px-6 py-2 rounded-lg">
256
+ <i class="fas fa-plus mr-2"></i> New Project
257
+ </button>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ </div>
262
+
263
+ <script>
264
+ document.addEventListener('DOMContentLoaded', function() {
265
+ // DOM Elements
266
+ const dropzone = document.getElementById('dropzone');
267
+ const fileInput = document.getElementById('fileInput');
268
+ const browseBtn = document.getElementById('browseBtn');
269
+ const videoClipsContainer = document.getElementById('videoClipsContainer');
270
+ const emptyTimelineMessage = document.getElementById('emptyTimelineMessage');
271
+ const totalDuration = document.getElementById('totalDuration');
272
+ const clearAllBtn = document.getElementById('clearAllBtn');
273
+ const playAllBtn = document.getElementById('playAllBtn');
274
+ const previewBtn = document.getElementById('previewBtn');
275
+ const previewSection = document.getElementById('previewSection');
276
+ const closePreviewBtn = document.getElementById('closePreviewBtn');
277
+ const mergedPreview = document.getElementById('mergedPreview');
278
+ const previewOverlay = document.getElementById('previewOverlay');
279
+ const exportBtn = document.getElementById('exportBtn');
280
+ const processingModal = document.getElementById('processingModal');
281
+ const successModal = document.getElementById('successModal');
282
+ const progressBar = document.getElementById('progressBar');
283
+ const processingStep = document.getElementById('processingStep');
284
+ const processingMessage = document.getElementById('processingMessage');
285
+ const downloadBtn = document.getElementById('downloadBtn');
286
+ const newProjectBtn = document.getElementById('newProjectBtn');
287
+ const cancelProcessingBtn = document.getElementById('cancelProcessingBtn');
288
+ const settingsToggle = document.getElementById('settingsToggle');
289
+ const settingsPanel = document.getElementById('settingsPanel');
290
+ const settingsChevron = document.getElementById('settingsChevron');
291
+ const qualitySlider = document.getElementById('qualitySlider');
292
+ const qualityValue = document.getElementById('qualityValue');
293
+
294
+ // State
295
+ let videoFiles = [];
296
+ let totalDurationSeconds = 0;
297
+
298
+ // Initialize settings panel
299
+ settingsToggle.addEventListener('click', () => {
300
+ settingsPanel.classList.toggle('open');
301
+ settingsChevron.classList.toggle('rotate-180');
302
+ });
303
+
304
+ // Quality slider
305
+ qualitySlider.addEventListener('input', () => {
306
+ qualityValue.textContent = `${qualitySlider.value}%`;
307
+ });
308
+
309
+ // Dropzone functionality
310
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
311
+ dropzone.addEventListener(eventName, preventDefaults, false);
312
+ });
313
+
314
+ function preventDefaults(e) {
315
+ e.preventDefault();
316
+ e.stopPropagation();
317
+ }
318
+
319
+ ['dragenter', 'dragover'].forEach(eventName => {
320
+ dropzone.addEventListener(eventName, highlight, false);
321
+ });
322
+
323
+ ['dragleave', 'drop'].forEach(eventName => {
324
+ dropzone.addEventListener(eventName, unhighlight, false);
325
+ });
326
+
327
+ function highlight() {
328
+ dropzone.classList.add('active');
329
+ }
330
+
331
+ function unhighlight() {
332
+ dropzone.classList.remove('active');
333
+ }
334
+
335
+ dropzone.addEventListener('drop', handleDrop, false);
336
+
337
+ function handleDrop(e) {
338
+ const dt = e.dataTransfer;
339
+ const files = dt.files;
340
+ handleFiles(files);
341
+ }
342
+
343
+ browseBtn.addEventListener('click', () => {
344
+ fileInput.click();
345
+ });
346
+
347
+ fileInput.addEventListener('change', () => {
348
+ handleFiles(fileInput.files);
349
+ });
350
+
351
+ function handleFiles(files) {
352
+ for (let i = 0; i < files.length; i++) {
353
+ const file = files[i];
354
+ if (file.type.startsWith('video/')) {
355
+ videoFiles.push(file);
356
+ addVideoToTimeline(file);
357
+ }
358
+ }
359
+
360
+ if (videoFiles.length > 0) {
361
+ emptyTimelineMessage.classList.add('hidden');
362
+ updateTotalDuration();
363
+ }
364
+ }
365
+
366
+ function addVideoToTimeline(file) {
367
+ const videoClip = document.createElement('div');
368
+ videoClip.className = 'video-clip flex-shrink-0 relative group';
369
+ videoClip.draggable = true;
370
+ videoClip.dataset.filename = file.name;
371
+
372
+ // Create video element to get duration
373
+ const video = document.createElement('video');
374
+ video.src = URL.createObjectURL(file);
375
+ video.onloadedmetadata = function() {
376
+ const duration = video.duration;
377
+ totalDurationSeconds += duration;
378
+ updateTotalDuration();
379
+
380
+ // Set clip width based on duration (120px = 10 seconds)
381
+ const width = Math.max(120, (duration / 10) * 120);
382
+ videoClip.style.width = `${width}px`;
383
+
384
+ // Add clip info
385
+ const clipInfo = document.createElement('div');
386
+ clipInfo.className = 'absolute inset-0 flex items-center justify-center text-white text-xs font-medium truncate px-2';
387
+ clipInfo.textContent = `${file.name} (${formatDuration(duration)})`;
388
+ videoClip.appendChild(clipInfo);
389
+
390
+ // Add resize handles
391
+ const leftHandle = document.createElement('div');
392
+ leftHandle.className = 'clip-handle left opacity-0 group-hover:opacity-100';
393
+ videoClip.appendChild(leftHandle);
394
+
395
+ const rightHandle = document.createElement('div');
396
+ rightHandle.className = 'clip-handle right opacity-0 group-hover:opacity-100';
397
+ videoClip.appendChild(rightHandle);
398
+
399
+ // Add drag and drop functionality
400
+ videoClip.addEventListener('dragstart', handleDragStart);
401
+ videoClip.addEventListener('dragover', handleDragOver);
402
+ videoClip.addEventListener('drop', handleDropClip);
403
+ };
404
+
405
+ videoClipsContainer.appendChild(videoClip);
406
+ }
407
+
408
+ function updateTotalDuration() {
409
+ const minutes = Math.floor(totalDurationSeconds / 60);
410
+ const seconds = Math.floor(totalDurationSeconds % 60);
411
+ totalDuration.textContent = `Total Duration: ${minutes}:${seconds.toString().padStart(2, '0')}`;
412
+ }
413
+
414
+ function formatDuration(seconds) {
415
+ const mins = Math.floor(seconds / 60);
416
+ const secs = Math.floor(seconds % 60);
417
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
418
+ }
419
+
420
+ // Timeline functionality
421
+ function handleDragStart(e) {
422
+ e.dataTransfer.setData('text/plain', e.target.dataset.filename);
423
+ e.target.classList.add('opacity-50');
424
+ }
425
+
426
+ function handleDragOver(e) {
427
+ e.preventDefault();
428
+ const afterElement = getDragAfterElement(videoClipsContainer, e.clientX);
429
+ const draggable = document.querySelector('.dragging');
430
+ if (afterElement == null) {
431
+ videoClipsContainer.appendChild(draggable);
432
+ } else {
433
+ videoClipsContainer.insertBefore(draggable, afterElement);
434
+ }
435
+ }
436
+
437
+ function handleDropClip(e) {
438
+ e.preventDefault();
439
+ e.target.classList.remove('opacity-50');
440
+ }
441
+
442
+ function getDragAfterElement(container, x) {
443
+ const draggableElements = [...container.querySelectorAll('.video-clip:not(.dragging)')];
444
+
445
+ return draggableElements.reduce((closest, child) => {
446
+ const box = child.getBoundingClientRect();
447
+ const offset = x - box.left - box.width / 2;
448
+ if (offset < 0 && offset > closest.offset) {
449
+ return { offset: offset, element: child };
450
+ } else {
451
+ return closest;
452
+ }
453
+ }, { offset: Number.NEGATIVE_INFINITY }).element;
454
+ }
455
+
456
+ // Clear all button
457
+ clearAllBtn.addEventListener('click', () => {
458
+ videoFiles = [];
459
+ totalDurationSeconds = 0;
460
+ videoClipsContainer.innerHTML = '';
461
+ emptyTimelineMessage.classList.remove('hidden');
462
+ updateTotalDuration();
463
+ });
464
+
465
+ // Preview functionality
466
+ previewBtn.addEventListener('click', () => {
467
+ if (videoFiles.length === 0) return;
468
+
469
+ previewSection.classList.remove('hidden');
470
+ // In a real app, we would actually merge the videos here
471
+ // For this demo, we'll just show the first video
472
+ mergedPreview.src = URL.createObjectURL(videoFiles[0]);
473
+ mergedPreview.load();
474
+ });
475
+
476
+ closePreviewBtn.addEventListener('click', () => {
477
+ previewSection.classList.add('hidden');
478
+ mergedPreview.pause();
479
+ });
480
+
481
+ previewOverlay.addEventListener('click', () => {
482
+ mergedPreview.play();
483
+ previewOverlay.classList.add('hidden');
484
+ });
485
+
486
+ mergedPreview.addEventListener('pause', () => {
487
+ previewOverlay.classList.remove('hidden');
488
+ });
489
+
490
+ // Export functionality
491
+ exportBtn.addEventListener('click', () => {
492
+ if (videoFiles.length === 0) return;
493
+
494
+ processingModal.classList.remove('hidden');
495
+ let progress = 0;
496
+ const interval = setInterval(() => {
497
+ progress += 5;
498
+ progressBar.style.width = `${progress}%`;
499
+
500
+ if (progress <= 30) {
501
+ processingStep.textContent = 'Step 1/3: Preparing files';
502
+ processingMessage.textContent = 'Analyzing video files and preparing for merge...';
503
+ } else if (progress <= 70) {
504
+ processingStep.textContent = 'Step 2/3: Merging videos';
505
+ processingMessage.textContent = 'Combining your videos and applying transitions...';
506
+ } else {
507
+ processingStep.textContent = 'Step 3/3: Rendering 4K output';
508
+ processingMessage.textContent = 'Optimizing for 4K quality at 30fps...';
509
+ }
510
+
511
+ if (progress >= 100) {
512
+ clearInterval(interval);
513
+ setTimeout(() => {
514
+ processingModal.classList.add('hidden');
515
+ successModal.classList.remove('hidden');
516
+ }, 500);
517
+ }
518
+ }, 200);
519
+
520
+ cancelProcessingBtn.addEventListener('click', () => {
521
+ clearInterval(interval);
522
+ processingModal.classList.add('hidden');
523
+ }, { once: true });
524
+ });
525
+
526
+ // Success modal buttons
527
+ downloadBtn.addEventListener('click', () => {
528
+ // In a real app, this would download the merged video
529
+ alert('Download would start here in a real application');
530
+ });
531
+
532
+ newProjectBtn.addEventListener('click', () => {
533
+ successModal.classList.add('hidden');
534
+ clearAllBtn.click();
535
+ });
536
+
537
+ // Resolution, FPS, and Format buttons
538
+ document.querySelectorAll('.resolution-btn').forEach(btn => {
539
+ btn.addEventListener('click', () => {
540
+ document.querySelectorAll('.resolution-btn').forEach(b => {
541
+ b.classList.remove('bg-indigo-600', 'border-indigo-600', 'text-white');
542
+ b.classList.add('border-gray-600', 'hover:bg-gray-600');
543
+ });
544
+ btn.classList.add('bg-indigo-600', 'border-indigo-600', 'text-white');
545
+ btn.classList.remove('border-gray-600', 'hover:bg-gray-600');
546
+
547
+ // Update export button text
548
+ if (btn.dataset.resolution === '4k') {
549
+ exportBtn.innerHTML = `<i class="fas fa-file-export mr-2"></i> Export Merged Video (4K 30fps)`;
550
+ } else {
551
+ exportBtn.innerHTML = `<i class="fas fa-file-export mr-2"></i> Export Merged Video (${btn.dataset.resolution.toUpperCase()} 30fps)`;
552
+ }
553
+ });
554
+ });
555
+
556
+ document.querySelectorAll('.fps-btn').forEach(btn => {
557
+ btn.addEventListener('click', () => {
558
+ document.querySelectorAll('.fps-btn').forEach(b => {
559
+ b.classList.remove('bg-indigo-600', 'border-indigo-600', 'text-white');
560
+ b.classList.add('border-gray-600', 'hover:bg-gray-600');
561
+ });
562
+ btn.classList.add('bg-indigo-600', 'border-indigo-600', 'text-white');
563
+ btn.classList.remove('border-gray-600', 'hover:bg-gray-600');
564
+ });
565
+ });
566
+
567
+ document.querySelectorAll('.format-btn').forEach(btn => {
568
+ btn.addEventListener('click', () => {
569
+ document.querySelectorAll('.format-btn').forEach(b => {
570
+ b.classList.remove('bg-indigo-600', 'border-indigo-600', 'text-white');
571
+ b.classList.add('border-gray-600', 'hover:bg-gray-600');
572
+ });
573
+ btn.classList.add('bg-indigo-600', 'border-indigo-600', 'text-white');
574
+ btn.classList.remove('border-gray-600', 'hover:bg-gray-600');
575
+ });
576
+ });
577
+ });
578
+ </script>
579
+ <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=tsbetterworkpmo/videomerger" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
580
+ </html>
prompts.txt ADDED
File without changes