| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>MP4 to MP3 Converter</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> |
| .dropzone { |
| border: 2px dashed #3b82f6; |
| transition: all 0.3s ease; |
| } |
| .dropzone.active { |
| border-color: #10b981; |
| background-color: #f0f9ff; |
| } |
| .waveform { |
| height: 60px; |
| background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%); |
| 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>'); |
| mask-size: 100% 100%; |
| animation: wave 2s linear infinite; |
| } |
| @keyframes wave { |
| 0% { mask-position: 0% 0%; } |
| 100% { mask-position: 100% 0%; } |
| } |
| .progress-bar { |
| transition: width 0.3s ease; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 min-h-screen"> |
| <div class="container mx-auto px-4 py-12 max-w-4xl"> |
| <div class="text-center mb-12"> |
| <h1 class="text-4xl font-bold text-indigo-700 mb-2">MP4 to MP3 Converter</h1> |
| <p class="text-gray-600">Convert your video files to high-quality audio in seconds</p> |
| <div class="waveform w-full mt-6 rounded-lg"></div> |
| </div> |
|
|
| <div class="bg-white rounded-xl shadow-xl overflow-hidden"> |
| <div class="p-6"> |
| <div class="flex flex-col md:flex-row gap-6"> |
| <div class="flex-1"> |
| <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer"> |
| <div class="flex flex-col items-center justify-center h-full"> |
| <i class="fas fa-file-video text-5xl text-indigo-500 mb-4"></i> |
| <h3 class="text-xl font-semibold text-gray-700 mb-2">Drop MP4 file here</h3> |
| <p class="text-gray-500 mb-4">or click to browse files</p> |
| <input type="file" id="fileInput" accept="video/mp4" class="hidden"> |
| <button id="browseBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg transition"> |
| Select File |
| </button> |
| </div> |
| </div> |
| </div> |
| <div class="flex-1 flex flex-col justify-center"> |
| <div class="bg-gray-50 p-6 rounded-lg"> |
| <h3 class="text-lg font-medium text-gray-800 mb-4">Conversion Settings</h3> |
| |
| <div class="space-y-4"> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Audio Quality</label> |
| <select id="qualitySelect" class="w-full p-2 border border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500"> |
| <option value="high">High (320 kbps)</option> |
| <option value="medium" selected>Medium (192 kbps)</option> |
| <option value="low">Low (128 kbps)</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Output Format</label> |
| <div class="flex items-center space-x-4"> |
| <div class="flex items-center"> |
| <input type="radio" id="formatMp3" name="format" value="mp3" checked class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"> |
| <label for="formatMp3" class="ml-2 block text-sm text-gray-700">MP3</label> |
| </div> |
| <div class="flex items-center"> |
| <input type="radio" id="formatWav" name="format" value="wav" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"> |
| <label for="formatWav" class="ml-2 block text-sm text-gray-700">WAV</label> |
| </div> |
| </div> |
| </div> |
| |
| <div class="pt-2"> |
| <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"> |
| Convert to MP3 |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div id="fileInfo" class="hidden mt-6 bg-blue-50 border-l-4 border-blue-500 p-4 rounded"> |
| <div class="flex items-start"> |
| <div class="flex-shrink-0 pt-1"> |
| <i class="fas fa-info-circle text-blue-500"></i> |
| </div> |
| <div class="ml-3"> |
| <h3 class="text-sm font-medium text-blue-800">File Selected</h3> |
| <div class="mt-1 text-sm text-blue-700"> |
| <p id="fileName" class="font-medium"></p> |
| <p id="fileSize" class="text-xs mt-1"></p> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div id="progressContainer" class="hidden mt-6"> |
| <div class="flex justify-between mb-1"> |
| <span class="text-sm font-medium text-gray-700">Conversion Progress</span> |
| <span id="progressPercent" class="text-sm font-medium text-gray-700">0%</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| |
| <div id="resultContainer" class="hidden mt-6 bg-green-50 border-l-4 border-green-500 p-4 rounded"> |
| <div class="flex items-start"> |
| <div class="flex-shrink-0 pt-1"> |
| <i class="fas fa-check-circle text-green-500"></i> |
| </div> |
| <div class="ml-3"> |
| <h3 class="text-sm font-medium text-green-800">Conversion Complete!</h3> |
| <div class="mt-2 flex items-center"> |
| <audio id="audioPreview" controls class="mr-4"></audio> |
| <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"> |
| <i class="fas fa-download mr-2"></i> Download MP3 |
| </a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-gray-50 px-6 py-4 border-t border-gray-200"> |
| <div class="flex items-center justify-between"> |
| <p class="text-sm text-gray-500"> |
| <i class="fas fa-lock mr-1"></i> Your files are processed locally and never uploaded |
| </p> |
| <button id="resetBtn" class="text-sm text-indigo-600 hover:text-indigo-800 hidden"> |
| <i class="fas fa-redo mr-1"></i> Start Over |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| <div class="mt-12 text-center text-gray-500 text-sm"> |
| <p>Convert unlimited MP4 files to MP3 for free. No registration required.</p> |
| <p class="mt-1">Works entirely in your browser - no server processing.</p> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| const dropzone = document.getElementById('dropzone'); |
| const fileInput = document.getElementById('fileInput'); |
| const browseBtn = document.getElementById('browseBtn'); |
| const convertBtn = document.getElementById('convertBtn'); |
| const fileInfo = document.getElementById('fileInfo'); |
| const fileName = document.getElementById('fileName'); |
| const fileSize = document.getElementById('fileSize'); |
| const progressContainer = document.getElementById('progressContainer'); |
| const progressBar = document.getElementById('progressBar'); |
| const progressPercent = document.getElementById('progressPercent'); |
| const resultContainer = document.getElementById('resultContainer'); |
| const audioPreview = document.getElementById('audioPreview'); |
| const downloadBtn = document.getElementById('downloadBtn'); |
| const resetBtn = document.getElementById('resetBtn'); |
| const qualitySelect = document.getElementById('qualitySelect'); |
| |
| let currentFile = null; |
| let audioBlob = null; |
| |
| |
| ['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('active'); |
| } |
| |
| function unhighlight() { |
| dropzone.classList.remove('active'); |
| } |
| |
| dropzone.addEventListener('drop', handleDrop, false); |
| |
| function handleDrop(e) { |
| const dt = e.dataTransfer; |
| const files = dt.files; |
| handleFiles(files); |
| } |
| |
| |
| browseBtn.addEventListener('click', () => { |
| fileInput.click(); |
| }); |
| |
| fileInput.addEventListener('change', () => { |
| if (fileInput.files.length) { |
| handleFiles(fileInput.files); |
| } |
| }); |
| |
| function handleFiles(files) { |
| const file = files[0]; |
| |
| |
| if (!file.type.includes('mp4') && !file.name.toLowerCase().endsWith('.mp4')) { |
| showError('Please select an MP4 video file.'); |
| return; |
| } |
| |
| currentFile = file; |
| |
| |
| fileName.textContent = file.name; |
| fileSize.textContent = formatFileSize(file.size); |
| fileInfo.classList.remove('hidden'); |
| |
| |
| convertBtn.disabled = false; |
| convertBtn.classList.remove('opacity-50', 'cursor-not-allowed'); |
| |
| |
| resultContainer.classList.add('hidden'); |
| resetBtn.classList.add('hidden'); |
| } |
| |
| function formatFileSize(bytes) { |
| if (bytes === 0) return '0 Bytes'; |
| const k = 1024; |
| const sizes = ['Bytes', 'KB', 'MB', 'GB']; |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; |
| } |
| |
| |
| convertBtn.addEventListener('click', startConversion); |
| |
| function startConversion() { |
| if (!currentFile) return; |
| |
| |
| progressContainer.classList.remove('hidden'); |
| progressBar.style.width = '0%'; |
| progressPercent.textContent = '0%'; |
| |
| |
| convertBtn.disabled = true; |
| convertBtn.classList.add('opacity-50', 'cursor-not-allowed'); |
| |
| |
| let progress = 0; |
| const interval = setInterval(() => { |
| progress += Math.random() * 10; |
| if (progress >= 100) { |
| progress = 100; |
| clearInterval(interval); |
| completeConversion(); |
| } |
| |
| progressBar.style.width = `${progress}%`; |
| progressPercent.textContent = `${Math.round(progress)}%`; |
| }, 300); |
| } |
| |
| function completeConversion() { |
| |
| |
| setTimeout(() => { |
| |
| const audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3'; |
| |
| fetch(audioUrl) |
| .then(response => response.blob()) |
| .then(blob => { |
| audioBlob = blob; |
| |
| |
| const audioUrl = URL.createObjectURL(blob); |
| audioPreview.src = audioUrl; |
| |
| |
| const downloadUrl = URL.createObjectURL(blob); |
| const originalName = currentFile.name.replace(/\.[^/.]+$/, ""); |
| downloadBtn.href = downloadUrl; |
| downloadBtn.download = `${originalName}.mp3`; |
| |
| |
| resultContainer.classList.remove('hidden'); |
| resetBtn.classList.remove('hidden'); |
| |
| |
| progressContainer.classList.add('hidden'); |
| }); |
| }, 500); |
| } |
| |
| |
| resetBtn.addEventListener('click', resetConverter); |
| |
| function resetConverter() { |
| |
| currentFile = null; |
| audioBlob = null; |
| |
| fileInfo.classList.add('hidden'); |
| progressContainer.classList.add('hidden'); |
| resultContainer.classList.add('hidden'); |
| resetBtn.classList.add('hidden'); |
| |
| convertBtn.disabled = true; |
| convertBtn.classList.add('opacity-50', 'cursor-not-allowed'); |
| |
| fileInput.value = ''; |
| audioPreview.src = ''; |
| } |
| |
| |
| function showError(message) { |
| const errorDiv = document.createElement('div'); |
| 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'; |
| errorDiv.innerHTML = ` |
| <div class="flex items-center"> |
| <i class="fas fa-exclamation-circle mr-2"></i> |
| <span>${message}</span> |
| </div> |
| `; |
| document.body.appendChild(errorDiv); |
| |
| setTimeout(() => { |
| errorDiv.classList.add('opacity-0', 'transition-opacity', 'duration-500'); |
| setTimeout(() => errorDiv.remove(), 500); |
| }, 3000); |
| } |
| }); |
| </script> |
| </body> |
| </html> |