mp3-mp4 / index.html
AllBajo's picture
undefined - Initial Deployment
dd60a28 verified
<!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>
/* Custom animations */
@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;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
}
::-webkit-scrollbar-thumb {
background: #4f46e5;
border-radius: 3px;
}
/* Dark mode toggle transition */
.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">
<!-- App Container -->
<div class="max-w-md mx-auto min-h-screen flex flex-col overflow-hidden relative" id="app">
<!-- Welcome Screen -->
<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>
<!-- Main Screen -->
<div id="main-screen" class="flex-1 flex flex-col p-6 hidden">
<!-- Header -->
<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>
<!-- Input Form -->
<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>
<!-- Download Progress Screen -->
<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>
<!-- History Screen -->
<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">
<!-- History items will be added here dynamically -->
<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>
<!-- Settings Menu -->
<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>
// App state
let currentFormat = null;
let downloadInProgress = false;
let downloadHistory = JSON.parse(localStorage.getItem('downloadHistory')) || [];
// DOM elements
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');
// Initialize app
function initApp() {
// Check for dark mode preference
if (localStorage.getItem('darkMode') === 'true' ||
(!localStorage.getItem('darkMode') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
darkModeToggle.checked = true;
}
// Load history
renderHistory();
}
// Screen navigation
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');
}
// Format selection
function selectFormat(format) {
currentFormat = format;
// Update button styles
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');
// Enable download button if URL is present
updateDownloadButtonState();
}
// Update download button state
function updateDownloadButtonState() {
const url = videoUrlInput.value.trim();
downloadBtn.disabled = !(url && currentFormat);
}
// Paste from clipboard
function pasteFromClipboard() {
navigator.clipboard.readText().then(text => {
videoUrlInput.value = text;
updateDownloadButtonState();
}).catch(err => {
console.error('Failed to read clipboard:', err);
// Fallback for browsers that don't support clipboard API
videoUrlInput.value = '';
videoUrlInput.placeholder = "Paste not supported, type manually";
});
}
// Start download process
function startDownload() {
const url = videoUrlInput.value.trim();
if (!url || !currentFormat) return;
showProgressScreen();
downloadInProgress = true;
// Simulate download process (in a real app, this would call your API)
simulateDownloadProcess(url, currentFormat);
}
// Cancel download
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);
}
// Simulate download process (replace with actual API call)
function simulateDownloadProcess(url, format) {
// Validation phase
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;
}
// Download phase
progressTitle.textContent = 'Downloading';
progressMessage.textContent = `Preparing ${format.toUpperCase()} file...`;
progressBar.style.width = '30%';
setTimeout(() => {
progressBar.style.width = '60%';
progressMessage.textContent = 'Processing media...';
setTimeout(() => {
// Completion phase
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';
// Add to history
addToHistory(url, format);
setTimeout(() => {
showMainScreen();
progressBar.style.width = '0%';
}, 2000);
}, 1500);
}, 1500);
}, 1500);
}
// Validate URL (simplified for demo)
function isValidUrl(url) {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
}
// History management
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);
});
}
// Simulate media actions
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}`);
}
// Extract domain from URL
function extractDomain(url) {
try {
const domain = new URL(url).hostname.replace('www.', '');
return domain.split('.')[0];
} catch (e) {
return 'unknown';
}
}
// Dark mode toggle
function toggleDarkMode() {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('darkMode', isDark);
darkModeToggle.checked = isDark;
}
// Event listeners
videoUrlInput.addEventListener('input', updateDownloadButtonState);
darkModeToggle.addEventListener('change', toggleDarkMode);
// Initialize
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>