Spaces:
Sleeping
Sleeping
File size: 13,303 Bytes
c0a4ca6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Professional media downloader with yt-dlp. Download from 1000+ platforms with advanced format selection and progress tracking.">
<title>Universal Media Downloader</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<!-- PWA Meta Tags -->
<meta name="theme-color" content="#06B6D4">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Media Downloader">
<!-- Service Worker -->
<link rel="manifest" href="/manifest.json">
</head>
<body>
<div class="app-container">
<!-- Header -->
<header class="app-header">
<div class="header-content">
<h1 class="app-title">Downloader</h1>
<div class="header-controls">
<button id="settings-btn" class="icon-btn" aria-label="Settings">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,8A4,4 0 0,0 8,12A4,4 0 0,0 12,16A4,4 0 0,0 16,12A4,4 0 0,0 12,8M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z"/>
</svg>
</button>
<button id="update-btn" class="icon-btn" aria-label="Check for updates" title="Update yt-dlp">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,6H13V11.59L17.59,16.59L16.17,18L11,12.83V6M12,4A1,1 0 0,1 13,5A1,1 0 0,1 12,6A1,1 0 0,1 11,5A1,1 0 0,1 12,4M7,12A1,1 0 0,1 8,11A1,1 0 0,1 7,10A1,1 0 0,1 6,11A1,1 0 0,1 7,12M17,12A1,1 0 0,1 16,11A1,1 0 0,1 17,10A1,1 0 0,1 18,11A1,1 0 0,1 17,12Z"/>
</svg>
</button>
</div>
</div>
</header>
<!-- Main Content -->
<main class="app-main">
<!-- URL Input Section -->
<section class="input-section">
<form id="download-form" class="url-form" aria-describedby="form-help">
<div class="input-group">
<label for="url-input" class="input-label">Media URL</label>
<div class="url-input-container">
<input
type="url"
id="url-input"
name="url"
placeholder="https://www.youtube.com/watch?v=..."
required
aria-describedby="form-help"
autocomplete="url"
inputmode="url"
class="url-input"
>
<button type="submit" id="analyze-btn" class="analyze-btn" aria-label="Analyze URL and show available formats">
<span class="btn-text">Analyze</span>
<span class="btn-loading" aria-hidden="true">
<svg class="spinner" viewBox="0 0 24 24">
<circle class="path" cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round"/>
</svg>
</span>
</button>
</div>
</div>
<p id="form-help" class="help-text">Enter a video, audio, or playlist URL from supported platforms</p>
</form>
</section>
<!-- Status and Progress -->
<section class="status-section" aria-labelledby="status-title">
<h2 id="status-title" class="section-title">Status</h2>
<div id="status-container" class="status-container" aria-live="assertive" role="status">
<div class="status-item">
<span class="status-icon">ℹ️</span>
<span class="status-text">Ready to analyze URLs. Enter a link to begin.</span>
</div>
</div>
<div id="progress-section" class="progress-section" style="display: none;">
<div class="progress-header">
<span id="progress-title" class="progress-title">Downloading...</span>
<span id="progress-speed" class="progress-speed"></span>
</div>
<div class="progress-bar-container">
<progress id="progress-bar" value="0" max="100" class="progress-bar"></progress>
<span id="progress-percentage" class="progress-percentage">0%</span>
</div>
</div>
</section>
<!-- Media Info Section -->
<section id="media-info-section" class="media-info-section" style="display: none;">
<h2 class="section-title">Media Information</h2>
<div id="media-info" class="media-info">
<div class="media-thumbnail">
<img id="media-thumb" alt="" style="display: none;">
<div id="thumb-placeholder" class="thumb-placeholder">
<svg class="placeholder-icon" viewBox="0 0 24 24">
<path d="M8.5,13.5L11,16.51L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z"/>
</svg>
</div>
</div>
<div class="media-details">
<h3 id="media-title" class="media-title"></h3>
<div class="media-meta">
<span id="media-uploader" class="media-uploader"></span>
<span id="media-platform" class="platform-badge"></span>
<span id="media-duration" class="duration"></span>
</div>
<div class="media-stats">
<span id="media-views" class="stat-item"></span>
<span id="media-likes" class="stat-item"></span>
</div>
</div>
</div>
</section>
<!-- Download Options -->
<section id="formats-section" class="formats-section" style="display: none;">
<div class="section-header">
<h2 class="section-title">Available Formats</h2>
<div class="format-filters">
<button class="filter-btn active" data-filter="all" aria-label="Show all formats">All</button>
<button class="filter-btn" data-filter="video" aria-label="Show video formats only">Video</button>
<button class="filter-btn" data-filter="audio" aria-label="Show audio formats only">Audio</button>
</div>
</div>
<div id="format-list" class="format-list" role="list" aria-label="Available download formats">
<!-- Format options will be populated here -->
</div>
</section>
<!-- Download Queue -->
<section class="queue-section">
<div class="section-header">
<h2 class="section-title">Download Queue</h2>
<button id="clear-queue-btn" class="secondary-btn" aria-label="Clear all queued downloads">Clear All</button>
</div>
<div id="queue-list" class="queue-list" role="list" aria-label="Active downloads">
<!-- Active downloads will appear here -->
</div>
</section>
<!-- Error Section -->
<section id="error-section" class="error-section" style="display: none;">
<h2 class="section-title">Error</h2>
<div id="error-messages" class="error-container" role="alert" aria-live="assertive">
<!-- Error messages -->
</div>
</section>
<!-- Success Section -->
<section id="success-section" class="success-section" style="display: none;">
<h2 class="section-title">Success</h2>
<div id="success-messages" class="success-container" role="status" aria-live="polite">
<!-- Success messages -->
</div>
</section>
</main>
<!-- Bottom Navigation (Mobile) -->
<nav class="bottom-nav" role="navigation" aria-label="Main navigation">
<button class="nav-item active" data-tab="download" aria-label="Download section">
<svg class="nav-icon" viewBox="0 0 24 24">
<path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"/>
</svg>
<span class="nav-label">Download</span>
</button>
<button class="nav-item" data-tab="history" aria-label="Download history">
<svg class="nav-icon" viewBox="0 0 24 24">
<path d="M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3"/>
</svg>
<span class="nav-label">History</span>
</button>
<button class="nav-item" data-tab="settings" aria-label="Settings">
<svg class="nav-icon" viewBox="0 0 24 24">
<path d="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.68 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z"/>
</svg>
<span class="nav-label">Settings</span>
</button>
</nav>
</div>
<!-- Settings Modal -->
<div id="settings-modal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h3>Settings</h3>
<button class="modal-close" aria-label="Close settings">×</button>
</div>
<div class="modal-body">
<div class="setting-group">
<label class="setting-label">Auto-update yt-dlp</label>
<label class="toggle">
<input type="checkbox" id="auto-update" checked>
<span class="toggle-slider"></span>
</label>
</div>
<div class="setting-group">
<label class="setting-label">Privacy mode</label>
<label class="toggle">
<input type="checkbox" id="privacy-mode">
<span class="toggle-slider"></span>
</label>
</div>
<div class="setting-group">
<label class="setting-label">Default download quality</label>
<select id="default-quality" class="setting-select">
<option value="best">Best available</option>
<option value="1080p">1080p</option>
<option value="720p">720p</option>
<option value="480p">480p</option>
<option value="360p">360p</option>
</select>
</div>
</div>
<div class="modal-footer">
<button class="primary-btn" id="save-settings">Save Settings</button>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html> |