| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>mp3_mp4 - Video Downloader</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> |
| |
| @keyframes fadeIn { |
| from { opacity: 0; } |
| to { opacity: 1; } |
| } |
| |
| @keyframes slideUp { |
| from { transform: translateY(20px); opacity: 0; } |
| to { transform: translateY(0); opacity: 1; } |
| } |
| |
| .fade-in { |
| animation: fadeIn 0.5s ease-out forwards; |
| } |
| |
| .slide-up { |
| animation: slideUp 0.4s ease-out forwards; |
| } |
| |
| |
| ::-webkit-scrollbar { |
| width: 6px; |
| } |
| |
| ::-webkit-scrollbar-track { |
| background: rgba(0, 0, 0, 0.1); |
| } |
| |
| ::-webkit-scrollbar-thumb { |
| background: #4f46e5; |
| border-radius: 3px; |
| } |
| |
| |
| .dark-toggle { |
| transition: all 0.3s ease; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-200 min-h-screen transition-colors duration-300"> |
| |
| <div class="max-w-md mx-auto min-h-screen flex flex-col overflow-hidden relative" id="app"> |
| |
| <div id="welcome-screen" class="flex flex-col items-center justify-center flex-1 p-6 fade-in"> |
| <div class="text-center slide-up"> |
| <div class="w-24 h-24 bg-indigo-500 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg"> |
| <i class="fas fa-music text-white text-4xl"></i> |
| </div> |
| <h1 class="text-4xl font-bold text-indigo-600 dark:text-indigo-400 mb-2">mp3_mp4</h1> |
| <p class="text-lg text-gray-600 dark:text-gray-300 mb-8">Paste your link and download easily</p> |
| <button onclick="showMainScreen()" class="bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-8 rounded-full shadow-md transition-all transform hover:scale-105"> |
| Start |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="main-screen" class="flex-1 flex flex-col p-6 hidden"> |
| |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold text-indigo-600 dark:text-indigo-400">Download Media</h2> |
| <div class="flex items-center space-x-4"> |
| <button onclick="toggleDarkMode()" class="dark-toggle p-2 rounded-full bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600"> |
| <i class="fas fa-moon dark:hidden"></i> |
| <i class="fas fa-sun hidden dark:block"></i> |
| </button> |
| <button onclick="showHistoryScreen()" class="p-2 rounded-full bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600"> |
| <i class="fas fa-history"></i> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="flex-1 flex flex-col"> |
| <div class="mb-6"> |
| <label for="video-url" class="block text-sm font-medium mb-2">Video URL</label> |
| <div class="relative"> |
| <input type="text" id="video-url" placeholder="Paste YouTube, TikTok, Instagram, etc. link here" |
| class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition-all"> |
| <button onclick="pasteFromClipboard()" class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded-md text-sm transition-colors"> |
| <i class="fas fa-paste mr-1"></i> Paste |
| </button> |
| </div> |
| </div> |
|
|
| <div class="mb-6"> |
| <label class="block text-sm font-medium mb-2">Download Format</label> |
| <div class="grid grid-cols-2 gap-4"> |
| <button id="mp3-btn" onclick="selectFormat('mp3')" class="format-btn bg-indigo-100 dark:bg-indigo-900 border-2 border-indigo-300 dark:border-indigo-700 py-3 px-4 rounded-lg flex items-center justify-center transition-all hover:bg-indigo-200 dark:hover:bg-indigo-800"> |
| <i class="fas fa-music mr-2"></i> MP3 (Audio) |
| </button> |
| <button id="mp4-btn" onclick="selectFormat('mp4')" class="format-btn bg-gray-100 dark:bg-gray-800 border-2 border-gray-300 dark:border-gray-700 py-3 px-4 rounded-lg flex items-center justify-center transition-all hover:bg-gray-200 dark:hover:bg-gray-700"> |
| <i class="fas fa-video mr-2"></i> MP4 (Video) |
| </button> |
| </div> |
| </div> |
|
|
| <div class="mt-auto"> |
| <button id="download-btn" onclick="startDownload()" disabled class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-4 rounded-lg shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"> |
| <i class="fas fa-download mr-2"></i> Download |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="progress-screen" class="flex-1 flex flex-col items-center justify-center p-6 hidden"> |
| <div class="text-center max-w-xs"> |
| <div class="relative w-24 h-24 mb-6"> |
| <div class="absolute inset-0 rounded-full border-4 border-indigo-200 dark:border-indigo-800"></div> |
| <div id="progress-circle" class="absolute inset-0 rounded-full border-4 border-indigo-500 border-t-indigo-500 border-r-indigo-500 animate-spin" style="clip: rect(0, 24px, 24px, 12px);"></div> |
| <div class="absolute inset-0 flex items-center justify-center"> |
| <i id="progress-icon" class="fas fa-download text-indigo-500 text-2xl"></i> |
| </div> |
| </div> |
| |
| <h3 id="progress-title" class="text-xl font-semibold mb-2">Preparing Download</h3> |
| <p id="progress-message" class="text-gray-600 dark:text-gray-300 mb-6">Validating your link...</p> |
| |
| <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 mb-6"> |
| <div id="progress-bar" class="bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| |
| <button onclick="cancelDownload()" class="text-indigo-600 dark:text-indigo-400 font-medium hover:underline"> |
| Cancel |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="history-screen" class="flex-1 flex flex-col p-6 hidden"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold text-indigo-600 dark:text-indigo-400">Download History</h2> |
| <button onclick="showMainScreen()" class="p-2 rounded-full bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600"> |
| <i class="fas fa-arrow-left"></i> |
| </button> |
| </div> |
| |
| <div class="flex-1 overflow-y-auto"> |
| <div id="history-list" class="space-y-3"> |
| |
| <div class="text-center py-10 text-gray-500" id="empty-history"> |
| <i class="fas fa-history text-4xl mb-3 opacity-30"></i> |
| <p>Your download history is empty</p> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="settings-menu" class="absolute inset-0 bg-white dark:bg-gray-800 shadow-lg z-10 hidden flex-col p-6"> |
| <div class="flex justify-between items-center mb-8"> |
| <h2 class="text-2xl font-bold text-indigo-600 dark:text-indigo-400">Settings</h2> |
| <button onclick="hideSettingsMenu()" class="p-2 rounded-full bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| |
| <div class="space-y-6"> |
| <div> |
| <h3 class="font-medium mb-3">Appearance</h3> |
| <div class="flex items-center justify-between"> |
| <span>Dark Mode</span> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" id="dark-mode-toggle" class="sr-only peer"> |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 dark:peer-focus:ring-indigo-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-indigo-600"></div> |
| </label> |
| </div> |
| </div> |
| |
| <div> |
| <h3 class="font-medium mb-3">Download Options</h3> |
| <div class="space-y-4"> |
| <div class="flex items-center justify-between"> |
| <span>Default Format</span> |
| <select class="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 text-gray-800 dark:text-gray-200 rounded-md px-3 py-1 text-sm"> |
| <option>MP3</option> |
| <option>MP4</option> |
| </select> |
| </div> |
| <div class="flex items-center justify-between"> |
| <span>Video Quality</span> |
| <select class="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 text-gray-800 dark:text-gray-200 rounded-md px-3 py-1 text-sm"> |
| <option>720p (Recommended)</option> |
| <option>480p</option> |
| <option>360p</option> |
| </select> |
| </div> |
| </div> |
| </div> |
| |
| <div> |
| <h3 class="font-medium mb-3">About</h3> |
| <p class="text-sm text-gray-600 dark:text-gray-300">App mp3_mp4 - Designed to simplify your downloads</p> |
| <p class="text-sm text-gray-500 mt-2">Version 1.0.0</p> |
| </div> |
| </div> |
| |
| <div class="mt-auto pt-6"> |
| <button class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-4 rounded-lg shadow-md transition-all"> |
| Save Settings |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| let currentFormat = null; |
| let downloadInProgress = false; |
| let downloadHistory = JSON.parse(localStorage.getItem('downloadHistory')) || []; |
| |
| |
| const welcomeScreen = document.getElementById('welcome-screen'); |
| const mainScreen = document.getElementById('main-screen'); |
| const progressScreen = document.getElementById('progress-screen'); |
| const historyScreen = document.getElementById('history-screen'); |
| const settingsMenu = document.getElementById('settings-menu'); |
| const downloadBtn = document.getElementById('download-btn'); |
| const videoUrlInput = document.getElementById('video-url'); |
| const progressBar = document.getElementById('progress-bar'); |
| const progressTitle = document.getElementById('progress-title'); |
| const progressMessage = document.getElementById('progress-message'); |
| const progressCircle = document.getElementById('progress-circle'); |
| const progressIcon = document.getElementById('progress-icon'); |
| const historyList = document.getElementById('history-list'); |
| const emptyHistory = document.getElementById('empty-history'); |
| const darkModeToggle = document.getElementById('dark-mode-toggle'); |
| |
| |
| function initApp() { |
| |
| if (localStorage.getItem('darkMode') === 'true' || |
| (!localStorage.getItem('darkMode') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { |
| document.documentElement.classList.add('dark'); |
| darkModeToggle.checked = true; |
| } |
| |
| |
| renderHistory(); |
| } |
| |
| |
| function showMainScreen() { |
| welcomeScreen.classList.add('hidden'); |
| mainScreen.classList.remove('hidden'); |
| progressScreen.classList.add('hidden'); |
| historyScreen.classList.add('hidden'); |
| settingsMenu.classList.add('hidden'); |
| } |
| |
| function showProgressScreen() { |
| mainScreen.classList.add('hidden'); |
| progressScreen.classList.remove('hidden'); |
| } |
| |
| function showHistoryScreen() { |
| mainScreen.classList.add('hidden'); |
| historyScreen.classList.remove('hidden'); |
| } |
| |
| function showSettingsMenu() { |
| settingsMenu.classList.remove('hidden'); |
| } |
| |
| function hideSettingsMenu() { |
| settingsMenu.classList.add('hidden'); |
| } |
| |
| |
| function selectFormat(format) { |
| currentFormat = format; |
| |
| |
| document.querySelectorAll('.format-btn').forEach(btn => { |
| btn.classList.remove('border-indigo-300', 'dark:border-indigo-700', 'bg-indigo-100', 'dark:bg-indigo-900'); |
| btn.classList.add('border-gray-300', 'dark:border-gray-700', 'bg-gray-100', 'dark:bg-gray-800'); |
| }); |
| |
| const selectedBtn = document.getElementById(`${format}-btn`); |
| selectedBtn.classList.remove('border-gray-300', 'dark:border-gray-700', 'bg-gray-100', 'dark:bg-gray-800'); |
| selectedBtn.classList.add('border-indigo-300', 'dark:border-indigo-700', 'bg-indigo-100', 'dark:bg-indigo-900'); |
| |
| |
| updateDownloadButtonState(); |
| } |
| |
| |
| function updateDownloadButtonState() { |
| const url = videoUrlInput.value.trim(); |
| downloadBtn.disabled = !(url && currentFormat); |
| } |
| |
| |
| function pasteFromClipboard() { |
| navigator.clipboard.readText().then(text => { |
| videoUrlInput.value = text; |
| updateDownloadButtonState(); |
| }).catch(err => { |
| console.error('Failed to read clipboard:', err); |
| |
| videoUrlInput.value = ''; |
| videoUrlInput.placeholder = "Paste not supported, type manually"; |
| }); |
| } |
| |
| |
| function startDownload() { |
| const url = videoUrlInput.value.trim(); |
| if (!url || !currentFormat) return; |
| |
| showProgressScreen(); |
| downloadInProgress = true; |
| |
| |
| simulateDownloadProcess(url, currentFormat); |
| } |
| |
| |
| function cancelDownload() { |
| downloadInProgress = false; |
| progressTitle.textContent = 'Download Cancelled'; |
| progressMessage.textContent = 'The download was cancelled by the user'; |
| progressIcon.className = 'fas fa-times-circle text-red-500 text-2xl'; |
| progressBar.style.width = '0%'; |
| |
| setTimeout(() => { |
| showMainScreen(); |
| }, 2000); |
| } |
| |
| |
| function simulateDownloadProcess(url, format) { |
| |
| progressTitle.textContent = 'Validating Link'; |
| progressMessage.textContent = 'Checking if the URL is valid...'; |
| progressBar.style.width = '10%'; |
| |
| setTimeout(() => { |
| if (!isValidUrl(url)) { |
| downloadInProgress = false; |
| progressTitle.textContent = 'Invalid Link'; |
| progressMessage.textContent = 'Please check the URL and try again'; |
| progressIcon.className = 'fas fa-exclamation-circle text-red-500 text-2xl'; |
| progressBar.style.width = '0%'; |
| |
| setTimeout(() => { |
| showMainScreen(); |
| }, 2000); |
| return; |
| } |
| |
| |
| progressTitle.textContent = 'Downloading'; |
| progressMessage.textContent = `Preparing ${format.toUpperCase()} file...`; |
| progressBar.style.width = '30%'; |
| |
| setTimeout(() => { |
| progressBar.style.width = '60%'; |
| progressMessage.textContent = 'Processing media...'; |
| |
| setTimeout(() => { |
| |
| downloadInProgress = false; |
| progressBar.style.width = '100%'; |
| progressTitle.textContent = 'Download Complete'; |
| progressMessage.textContent = `Your ${format.toUpperCase()} file is ready`; |
| progressIcon.className = 'fas fa-check-circle text-green-500 text-2xl'; |
| |
| |
| addToHistory(url, format); |
| |
| setTimeout(() => { |
| showMainScreen(); |
| progressBar.style.width = '0%'; |
| }, 2000); |
| }, 1500); |
| }, 1500); |
| }, 1500); |
| } |
| |
| |
| function isValidUrl(url) { |
| try { |
| new URL(url); |
| return true; |
| } catch (e) { |
| return false; |
| } |
| } |
| |
| |
| function addToHistory(url, format) { |
| const entry = { |
| id: Date.now(), |
| url, |
| format, |
| title: `Downloaded ${format.toUpperCase()} from ${extractDomain(url)}`, |
| date: new Date().toLocaleString(), |
| filename: `media_${Date.now()}.${format}` |
| }; |
| |
| downloadHistory.unshift(entry); |
| localStorage.setItem('downloadHistory', JSON.stringify(downloadHistory)); |
| renderHistory(); |
| } |
| |
| function renderHistory() { |
| if (downloadHistory.length === 0) { |
| emptyHistory.classList.remove('hidden'); |
| return; |
| } |
| |
| emptyHistory.classList.add('hidden'); |
| historyList.innerHTML = ''; |
| |
| downloadHistory.forEach(entry => { |
| const historyItem = document.createElement('div'); |
| historyItem.className = 'bg-white dark:bg-gray-800 p-4 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700'; |
| historyItem.innerHTML = ` |
| <div class="flex justify-between items-start mb-2"> |
| <h3 class="font-medium truncate">${entry.title}</h3> |
| <span class="text-xs text-gray-500 ml-2 whitespace-nowrap">${entry.date}</span> |
| </div> |
| <div class="flex items-center justify-between text-sm"> |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200"> |
| ${entry.format.toUpperCase()} |
| </span> |
| <div class="space-x-2"> |
| <button onclick="playMedia('${entry.filename}')" class="text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300"> |
| <i class="fas fa-play"></i> Play |
| </button> |
| <button onclick="showInFolder('${entry.filename}')" class="text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-300"> |
| <i class="fas fa-folder-open"></i> Folder |
| </button> |
| </div> |
| </div> |
| `; |
| historyList.appendChild(historyItem); |
| }); |
| } |
| |
| |
| function playMedia(filename) { |
| alert(`In a real app, this would play: ${filename}`); |
| } |
| |
| function showInFolder(filename) { |
| alert(`In a real app, this would open folder containing: ${filename}`); |
| } |
| |
| |
| function extractDomain(url) { |
| try { |
| const domain = new URL(url).hostname.replace('www.', ''); |
| return domain.split('.')[0]; |
| } catch (e) { |
| return 'unknown'; |
| } |
| } |
| |
| |
| function toggleDarkMode() { |
| const isDark = document.documentElement.classList.toggle('dark'); |
| localStorage.setItem('darkMode', isDark); |
| darkModeToggle.checked = isDark; |
| } |
| |
| |
| videoUrlInput.addEventListener('input', updateDownloadButtonState); |
| darkModeToggle.addEventListener('change', toggleDarkMode); |
| |
| |
| document.addEventListener('DOMContentLoaded', initApp); |
| </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=AllBajo/mp3-mp4" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |