KEXEL commited on
Commit
7055921
·
verified ·
1 Parent(s): fb83349
Files changed (1) hide show
  1. MP4toMP3.html +358 -0
MP4toMP3.html ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>MP4 to MP3 Converter</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 #3b82f6;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #10b981;
16
+ background-color: #f0f9ff;
17
+ }
18
+ .waveform {
19
+ height: 60px;
20
+ background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
21
+ mask-image: url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 20" xmlns="http://www.w3.org/2000/svg"><path d="M0,10 Q5,15 10,10 T20,10 T30,10 T40,10 T50,10 T60,10 T70,10 T80,10 T90,10 T100,10" stroke="black" fill="none" stroke-width="2"/></svg>');
22
+ mask-size: 100% 100%;
23
+ animation: wave 2s linear infinite;
24
+ }
25
+ @keyframes wave {
26
+ 0% { mask-position: 0% 0%; }
27
+ 100% { mask-position: 100% 0%; }
28
+ }
29
+ .progress-bar {
30
+ transition: width 0.3s ease;
31
+ }
32
+ </style>
33
+ </head>
34
+ <body class="bg-gray-100 min-h-screen">
35
+ <div class="container mx-auto px-4 py-12 max-w-4xl">
36
+ <div class="text-center mb-12">
37
+ <h1 class="text-4xl font-bold text-indigo-700 mb-2">MP4 to MP3 Converter</h1>
38
+ <p class="text-gray-600">Convert your video files to high-quality audio in seconds</p>
39
+ <div class="waveform w-full mt-6 rounded-lg"></div>
40
+ </div>
41
+
42
+ <div class="bg-white rounded-xl shadow-xl overflow-hidden">
43
+ <div class="p-6">
44
+ <div class="flex flex-col md:flex-row gap-6">
45
+ <div class="flex-1">
46
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
47
+ <div class="flex flex-col items-center justify-center h-full">
48
+ <i class="fas fa-file-video text-5xl text-indigo-500 mb-4"></i>
49
+ <h3 class="text-xl font-semibold text-gray-700 mb-2">Drop MP4 file here</h3>
50
+ <p class="text-gray-500 mb-4">or click to browse files</p>
51
+ <input type="file" id="fileInput" accept="video/mp4" class="hidden">
52
+ <button id="browseBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition">
53
+ Select File
54
+ </button>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <div class="flex-1 flex flex-col justify-center">
59
+ <div class="bg-gray-50 p-6 rounded-lg">
60
+ <h3 class="text-lg font-medium text-gray-800 mb-4">Conversion Settings</h3>
61
+
62
+ <div class="space-y-4">
63
+ <div>
64
+ <label class="block text-sm font-medium text-gray-700 mb-1">Audio Quality</label>
65
+ <select id="qualitySelect" class="w-full p-2 border border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
66
+ <option value="high">High (320 kbps)</option>
67
+ <option value="medium" selected>Medium (192 kbps)</option>
68
+ <option value="low">Low (128 kbps)</option>
69
+ </select>
70
+ </div>
71
+
72
+ <div>
73
+ <label class="block text-sm font-medium text-gray-700 mb-1">Output Format</label>
74
+ <div class="flex items-center space-x-4">
75
+ <div class="flex items-center">
76
+ <input type="radio" id="formatMp3" name="format" value="mp3" checked class="h-4 w-4 text-indigo-600 focus:ring-indigo-500">
77
+ <label for="formatMp3" class="ml-2 block text-sm text-gray-700">MP3</label>
78
+ </div>
79
+ <div class="flex items-center">
80
+ <input type="radio" id="formatWav" name="format" value="wav" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500">
81
+ <label for="formatWav" class="ml-2 block text-sm text-gray-700">WAV</label>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="pt-2">
87
+ <button id="convertBtn" disabled class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-3 px-4 rounded-lg font-medium transition opacity-50 cursor-not-allowed">
88
+ Convert to MP3
89
+ </button>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <div id="fileInfo" class="hidden mt-6 bg-blue-50 border-l-4 border-blue-500 p-4 rounded">
97
+ <div class="flex items-start">
98
+ <div class="flex-shrink-0 pt-1">
99
+ <i class="fas fa-info-circle text-blue-500"></i>
100
+ </div>
101
+ <div class="ml-3">
102
+ <h3 class="text-sm font-medium text-blue-800">File Selected</h3>
103
+ <div class="mt-1 text-sm text-blue-700">
104
+ <p id="fileName" class="font-medium"></p>
105
+ <p id="fileSize" class="text-xs mt-1"></p>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <div id="progressContainer" class="hidden mt-6">
112
+ <div class="flex justify-between mb-1">
113
+ <span class="text-sm font-medium text-gray-700">Conversion Progress</span>
114
+ <span id="progressPercent" class="text-sm font-medium text-gray-700">0%</span>
115
+ </div>
116
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
117
+ <div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
118
+ </div>
119
+ </div>
120
+
121
+ <div id="resultContainer" class="hidden mt-6 bg-green-50 border-l-4 border-green-500 p-4 rounded">
122
+ <div class="flex items-start">
123
+ <div class="flex-shrink-0 pt-1">
124
+ <i class="fas fa-check-circle text-green-500"></i>
125
+ </div>
126
+ <div class="ml-3">
127
+ <h3 class="text-sm font-medium text-green-800">Conversion Complete!</h3>
128
+ <div class="mt-2 flex items-center">
129
+ <audio id="audioPreview" controls class="mr-4"></audio>
130
+ <a id="downloadBtn" href="#" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
131
+ <i class="fas fa-download mr-2"></i> Download MP3
132
+ </a>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+ <div class="bg-gray-50 px-6 py-4 border-t border-gray-200">
140
+ <div class="flex items-center justify-between">
141
+ <p class="text-sm text-gray-500">
142
+ <i class="fas fa-lock mr-1"></i> Your files are processed locally and never uploaded
143
+ </p>
144
+ <button id="resetBtn" class="text-sm text-indigo-600 hover:text-indigo-800 hidden">
145
+ <i class="fas fa-redo mr-1"></i> Start Over
146
+ </button>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+ <div class="mt-12 text-center text-gray-500 text-sm">
152
+ <p>Convert unlimited MP4 files to MP3 for free. No registration required.</p>
153
+ <p class="mt-1">Works entirely in your browser - no server processing.</p>
154
+ </div>
155
+ </div>
156
+
157
+ <script>
158
+ document.addEventListener('DOMContentLoaded', function() {
159
+ const dropzone = document.getElementById('dropzone');
160
+ const fileInput = document.getElementById('fileInput');
161
+ const browseBtn = document.getElementById('browseBtn');
162
+ const convertBtn = document.getElementById('convertBtn');
163
+ const fileInfo = document.getElementById('fileInfo');
164
+ const fileName = document.getElementById('fileName');
165
+ const fileSize = document.getElementById('fileSize');
166
+ const progressContainer = document.getElementById('progressContainer');
167
+ const progressBar = document.getElementById('progressBar');
168
+ const progressPercent = document.getElementById('progressPercent');
169
+ const resultContainer = document.getElementById('resultContainer');
170
+ const audioPreview = document.getElementById('audioPreview');
171
+ const downloadBtn = document.getElementById('downloadBtn');
172
+ const resetBtn = document.getElementById('resetBtn');
173
+ const qualitySelect = document.getElementById('qualitySelect');
174
+
175
+ let currentFile = null;
176
+ let audioBlob = null;
177
+
178
+ // Drag and drop functionality
179
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
180
+ dropzone.addEventListener(eventName, preventDefaults, false);
181
+ });
182
+
183
+ function preventDefaults(e) {
184
+ e.preventDefault();
185
+ e.stopPropagation();
186
+ }
187
+
188
+ ['dragenter', 'dragover'].forEach(eventName => {
189
+ dropzone.addEventListener(eventName, highlight, false);
190
+ });
191
+
192
+ ['dragleave', 'drop'].forEach(eventName => {
193
+ dropzone.addEventListener(eventName, unhighlight, false);
194
+ });
195
+
196
+ function highlight() {
197
+ dropzone.classList.add('active');
198
+ }
199
+
200
+ function unhighlight() {
201
+ dropzone.classList.remove('active');
202
+ }
203
+
204
+ dropzone.addEventListener('drop', handleDrop, false);
205
+
206
+ function handleDrop(e) {
207
+ const dt = e.dataTransfer;
208
+ const files = dt.files;
209
+ handleFiles(files);
210
+ }
211
+
212
+ // File input handling
213
+ browseBtn.addEventListener('click', () => {
214
+ fileInput.click();
215
+ });
216
+
217
+ fileInput.addEventListener('change', () => {
218
+ if (fileInput.files.length) {
219
+ handleFiles(fileInput.files);
220
+ }
221
+ });
222
+
223
+ function handleFiles(files) {
224
+ const file = files[0];
225
+
226
+ // Check if file is MP4
227
+ if (!file.type.includes('mp4') && !file.name.toLowerCase().endsWith('.mp4')) {
228
+ showError('Please select an MP4 video file.');
229
+ return;
230
+ }
231
+
232
+ currentFile = file;
233
+
234
+ // Display file info
235
+ fileName.textContent = file.name;
236
+ fileSize.textContent = formatFileSize(file.size);
237
+ fileInfo.classList.remove('hidden');
238
+
239
+ // Enable convert button
240
+ convertBtn.disabled = false;
241
+ convertBtn.classList.remove('opacity-50', 'cursor-not-allowed');
242
+
243
+ // Hide result container if shown
244
+ resultContainer.classList.add('hidden');
245
+ resetBtn.classList.add('hidden');
246
+ }
247
+
248
+ function formatFileSize(bytes) {
249
+ if (bytes === 0) return '0 Bytes';
250
+ const k = 1024;
251
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
252
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
253
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
254
+ }
255
+
256
+ // Conversion process
257
+ convertBtn.addEventListener('click', startConversion);
258
+
259
+ function startConversion() {
260
+ if (!currentFile) return;
261
+
262
+ // Show progress bar
263
+ progressContainer.classList.remove('hidden');
264
+ progressBar.style.width = '0%';
265
+ progressPercent.textContent = '0%';
266
+
267
+ // Disable convert button during conversion
268
+ convertBtn.disabled = true;
269
+ convertBtn.classList.add('opacity-50', 'cursor-not-allowed');
270
+
271
+ // Simulate progress (in a real app, this would be the actual conversion progress)
272
+ let progress = 0;
273
+ const interval = setInterval(() => {
274
+ progress += Math.random() * 10;
275
+ if (progress >= 100) {
276
+ progress = 100;
277
+ clearInterval(interval);
278
+ completeConversion();
279
+ }
280
+
281
+ progressBar.style.width = `${progress}%`;
282
+ progressPercent.textContent = `${Math.round(progress)}%`;
283
+ }, 300);
284
+ }
285
+
286
+ function completeConversion() {
287
+ // In a real app, this would be where the actual conversion happens
288
+ // For this demo, we'll simulate it with a timeout
289
+ setTimeout(() => {
290
+ // Create a dummy audio blob (in a real app, this would be the converted audio)
291
+ const audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';
292
+
293
+ fetch(audioUrl)
294
+ .then(response => response.blob())
295
+ .then(blob => {
296
+ audioBlob = blob;
297
+
298
+ // Set up the audio preview and download
299
+ const audioUrl = URL.createObjectURL(blob);
300
+ audioPreview.src = audioUrl;
301
+
302
+ // Set up download link
303
+ const downloadUrl = URL.createObjectURL(blob);
304
+ const originalName = currentFile.name.replace(/\.[^/.]+$/, "");
305
+ downloadBtn.href = downloadUrl;
306
+ downloadBtn.download = `${originalName}.mp3`;
307
+
308
+ // Show result
309
+ resultContainer.classList.remove('hidden');
310
+ resetBtn.classList.remove('hidden');
311
+
312
+ // Clean up progress
313
+ progressContainer.classList.add('hidden');
314
+ });
315
+ }, 500);
316
+ }
317
+
318
+ // Reset functionality
319
+ resetBtn.addEventListener('click', resetConverter);
320
+
321
+ function resetConverter() {
322
+ // Reset all elements to initial state
323
+ currentFile = null;
324
+ audioBlob = null;
325
+
326
+ fileInfo.classList.add('hidden');
327
+ progressContainer.classList.add('hidden');
328
+ resultContainer.classList.add('hidden');
329
+ resetBtn.classList.add('hidden');
330
+
331
+ convertBtn.disabled = true;
332
+ convertBtn.classList.add('opacity-50', 'cursor-not-allowed');
333
+
334
+ fileInput.value = '';
335
+ audioPreview.src = '';
336
+ }
337
+
338
+ // Error handling
339
+ function showError(message) {
340
+ const errorDiv = document.createElement('div');
341
+ errorDiv.className = 'fixed top-4 right-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded shadow-lg z-50';
342
+ errorDiv.innerHTML = `
343
+ <div class="flex items-center">
344
+ <i class="fas fa-exclamation-circle mr-2"></i>
345
+ <span>${message}</span>
346
+ </div>
347
+ `;
348
+ document.body.appendChild(errorDiv);
349
+
350
+ setTimeout(() => {
351
+ errorDiv.classList.add('opacity-0', 'transition-opacity', 'duration-500');
352
+ setTimeout(() => errorDiv.remove(), 500);
353
+ }, 3000);
354
+ }
355
+ });
356
+ </script>
357
+ </body>
358
+ </html>