最終更新 2 days ago

修正履歴 cc3b01e01ecb058532a77e656aca9cfb478d1011

YouTube_MP3_Downloader.html Raw
1<!DOCTYPE html>
2<html lang="bg">
3<head>
4<meta charset="UTF-8">
5<title>YouTube MP3 Downloader</title>
6<style>
7 * { box-sizing: border-box; margin: 0; padding: 0; }
8 body {
9 font-family: 'Segoe UI', sans-serif;
10 background: #0f0f0f;
11 color: #e0e0e0;
12 min-height: 100vh;
13 display: flex;
14 align-items: center;
15 justify-content: center;
16 padding: 20px;
17 }
18 .card {
19 background: #1a1a1a;
20 border: 1px solid #2a2a2a;
21 border-radius: 16px;
22 padding: 32px;
23 width: 100%;
24 max-width: 620px;
25 box-shadow: 0 8px 32px rgba(0,0,0,0.5);
26 }
27 .header {
28 display: flex;
29 align-items: center;
30 gap: 12px;
31 margin-bottom: 28px;
32 }
33 .logo {
34 width: 44px; height: 44px;
35 background: #cc0000;
36 border-radius: 10px;
37 display: flex; align-items: center; justify-content: center;
38 flex-shrink: 0;
39 }
40 .logo svg { fill: white; }
41 .title { font-size: 20px; font-weight: 600; color: #fff; }
42 .subtitle { font-size: 13px; color: #888; margin-top: 2px; }
43
44 label {
45 display: block;
46 font-size: 13px;
47 color: #aaa;
48 margin-bottom: 6px;
49 }
50 input[type="text"], select {
51 width: 100%;
52 background: #111;
53 border: 1px solid #333;
54 border-radius: 8px;
55 color: #e0e0e0;
56 font-size: 14px;
57 padding: 10px 12px;
58 outline: none;
59 transition: border-color 0.2s;
60 font-family: 'Segoe UI', sans-serif;
61 }
62 input[type="text"]:focus, select:focus {
63 border-color: #cc0000;
64 }
65 select option { background: #1a1a1a; }
66
67 .row { margin-bottom: 16px; }
68 .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; }
69
70 .folder-row {
71 display: flex; gap: 8px;
72 }
73 .folder-row input { flex: 1; }
74 .btn-browse {
75 background: #2a2a2a;
76 border: 1px solid #333;
77 border-radius: 8px;
78 color: #ccc;
79 font-size: 13px;
80 padding: 0 14px;
81 cursor: pointer;
82 white-space: nowrap;
83 transition: background 0.2s;
84 }
85 .btn-browse:hover { background: #333; }
86
87 .btn-download {
88 width: 100%;
89 padding: 12px;
90 background: #cc0000;
91 color: white;
92 border: none;
93 border-radius: 10px;
94 font-size: 16px;
95 font-weight: 600;
96 cursor: pointer;
97 margin-top: 4px;
98 transition: background 0.2s, transform 0.1s;
99 font-family: 'Segoe UI', sans-serif;
100 }
101 .btn-download:hover { background: #e00000; }
102 .btn-download:active { transform: scale(0.99); }
103 .btn-download:disabled { background: #555; cursor: not-allowed; }
104
105 .console {
106 margin-top: 18px;
107 background: #0a0a0a;
108 border: 1px solid #2a2a2a;
109 border-radius: 10px;
110 padding: 12px 14px;
111 font-size: 13px;
112 font-family: 'Cascadia Code', 'Consolas', monospace;
113 color: #aaa;
114 min-height: 90px;
115 max-height: 220px;
116 overflow-y: auto;
117 line-height: 1.6;
118 }
119 .console .ok { color: #4ec94e; }
120 .console .err { color: #f55; }
121 .console .info { color: #6bc5f8; }
122 .console .warn { color: #f0b429; }
123
124 .separator {
125 border: none;
126 border-top: 1px solid #252525;
127 margin: 20px 0;
128 }
129
130 .setup-section details { margin-bottom: 10px; }
131 .setup-section summary {
132 cursor: pointer;
133 font-size: 13px;
134 color: #888;
135 padding: 6px 0;
136 user-select: none;
137 }
138 .setup-section summary:hover { color: #ccc; }
139 .setup-content {
140 margin-top: 10px;
141 background: #111;
142 border: 1px solid #2a2a2a;
143 border-radius: 8px;
144 padding: 14px;
145 font-size: 13px;
146 line-height: 1.8;
147 color: #bbb;
148 }
149 .setup-content code {
150 background: #1e1e1e;
151 border: 1px solid #333;
152 border-radius: 4px;
153 padding: 1px 7px;
154 font-family: 'Cascadia Code', 'Consolas', monospace;
155 color: #7ec8f7;
156 font-size: 12px;
157 }
158 .step { margin-bottom: 10px; }
159 .step-num {
160 display: inline-block;
161 width: 20px; height: 20px;
162 background: #cc0000;
163 color: white;
164 border-radius: 50%;
165 text-align: center;
166 line-height: 20px;
167 font-size: 11px;
168 font-weight: 700;
169 margin-right: 6px;
170 }
171 a { color: #6bc5f8; }
172 .status-bar {
173 display: flex; align-items: center; gap: 8px;
174 margin-top: 10px; font-size: 12px; color: #777;
175 }
176 .dot {
177 width: 8px; height: 8px; border-radius: 50%;
178 background: #555; flex-shrink: 0;
179 }
180 .dot.ok { background: #4ec94e; }
181 .dot.err { background: #f55; }
182</style>
183</head>
184<body>
185
186<div class="card">
187 <div class="header">
188 <div class="logo">
189 <svg width="22" height="22" viewBox="0 0 24 24"><path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.35 6.35 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.69a8.28 8.28 0 0 0 4.84 1.55V6.79a4.85 4.85 0 0 1-1.07-.1z"/></svg>
190 </div>
191 <div>
192 <div class="title">YouTube MP3 Downloader</div>
193 <div class="subtitle">Powered by yt-dlp + ffmpeg</div>
194 </div>
195 </div>
196
197 <div class="row">
198 <label>YouTube URL (видео или плейлист)</label>
199 <input type="text" id="url" placeholder="https://www.youtube.com/watch?v=..." />
200 </div>
201
202 <div class="grid">
203 <div>
204 <label>Качество на MP3</label>
205 <select id="quality">
206 <option value="320">320 kbps (най-добро)</option>
207 <option value="256">256 kbps</option>
208 <option value="192" selected>192 kbps</option>
209 <option value="128">128 kbps</option>
210 </select>
211 </div>
212 <div>
213 <label>Шаблон на името</label>
214 <select id="template">
215 <option value="%(title)s">Само заглавие</option>
216 <option value="%(uploader)s - %(title)s">Автор - Заглавие</option>
217 <option value="%(playlist_index)s. %(title)s">№. Заглавие (плейлист)</option>
218 </select>
219 </div>
220 </div>
221
222 <div class="row">
223 <label>Папка за запис</label>
224 <div class="folder-row">
225 <input type="text" id="outdir" value="C:\Users\%USERNAME%\Desktop" />
226 <button class="btn-browse" onclick="copyFolder()">📋 Копирай</button>
227 </div>
228 </div>
229
230 <button class="btn-download" id="btnGen" onclick="generate()">⬇ Генерирай команда</button>
231
232 <div class="console" id="console">Готов. Попълни URL и натисни бутона...</div>
233
234 <div class="status-bar">
235 <div class="dot" id="dotYtdlp"></div><span id="statusYtdlp">yt-dlp: непроверен</span>
236 &nbsp;|&nbsp;
237 <div class="dot" id="dotFfmpeg"></div><span id="statusFfmpeg">ffmpeg: непроверен</span>
238 </div>
239
240 <hr class="separator">
241
242 <div class="setup-section">
243 <details>
244 <summary>▸ Как да инсталираш yt-dlp и ffmpeg (разгъни)</summary>
245 <div class="setup-content">
246 <div class="step"><span class="step-num">1</span>Отвори <b>PowerShell като администратор</b> (Win+X → Terminal (Admin))</div>
247 <div class="step"><span class="step-num">2</span>Инсталирай <b>winget</b> пакетите:<br>
248 <code>winget install yt-dlp.yt-dlp</code><br>
249 <code>winget install Gyan.FFmpeg</code>
250 </div>
251 <div class="step"><span class="step-num">3</span>Затвори и отвори отново терминала (за да се заредят PATH-овете)</div>
252 <div class="step"><span class="step-num">4</span>Провери: <code>yt-dlp --version</code> и <code>ffmpeg -version</code></div>
253 <div class="step"><span class="step-num">5</span>Готово! Върни се тук и свали музика 🎵</div>
254 <br>
255 <b>Алтернативно</b> (без winget):<br>
256 — yt-dlp: <a href="https://github.com/yt-dlp/yt-dlp/releases" target="_blank">github.com/yt-dlp/yt-dlp/releases</a> → свали <code>yt-dlp.exe</code><br>
257 — ffmpeg: <a href="https://www.gyan.dev/ffmpeg/builds/" target="_blank">gyan.dev/ffmpeg/builds</a> → release build → извлечи <code>ffmpeg.exe</code><br>
258 — Постави и двата .exe в <code>C:\Windows\System32</code> или в обща папка с PATH
259 </div>
260 </details>
261 </div>
262</div>
263
264<script>
265function log(msg, cls) {
266 const c = document.getElementById('console');
267 const line = document.createElement('div');
268 if (cls) line.className = cls;
269 line.textContent = msg;
270 c.appendChild(line);
271 c.scrollTop = c.scrollHeight;
272}
273
274function clearConsole() {
275 document.getElementById('console').innerHTML = '';
276}
277
278function setStatus(tool, ok) {
279 const dot = document.getElementById('dot' + tool);
280 const span = document.getElementById('status' + tool);
281 dot.className = 'dot ' + (ok ? 'ok' : 'err');
282 span.textContent = tool.toLowerCase() + ': ' + (ok ? 'намерен ✓' : 'не е намерен ✗');
283}
284
285function generate() {
286 clearConsole();
287 const url = document.getElementById('url').value.trim();
288 const quality = document.getElementById('quality').value;
289 const template = document.getElementById('template').value;
290 const outdir = document.getElementById('outdir').value.trim() || '%USERPROFILE%\\Downloads\\Music';
291
292 if (!url) {
293 log('⚠ Моля въведи YouTube URL!', 'warn');
294 return;
295 }
296
297 if (!url.includes('youtube.com') && !url.includes('youtu.be')) {
298 log('⚠ Това не изглежда като YouTube URL. Продължавам все пак...', 'warn');
299 }
300
301 const isPlaylist = url.includes('playlist') || url.includes('list=');
302 const outputTemplate = outdir + '\\' + template + '.%(ext)s';
303
304 const cmd = `yt-dlp -x --audio-format mp3 --audio-quality ${quality}K --embed-thumbnail --add-metadata -o "${outputTemplate}" "${url}"`;
305
306 log('> Команда за PowerShell / CMD:', 'info');
307 log('');
308 log(cmd);
309 log('');
310 log('─────────────────────────────────────', 'info');
311 log('Копирай командата и я постави в PowerShell или CMD.', 'ok');
312 if (isPlaylist) {
313 log('📋 Открит плейлист — ще се свалят всички песни!', 'info');
314 }
315 log('');
316 log('Полезни добавки:', 'info');
317 log(' --cookies-from-browser chrome (за видеа изискващи вход)');
318 log(' --yes-playlist (принудително целия плейлист)');
319 log(' --no-playlist (само видеото, не плейлиста)');
320 log(' --write-info-json (записва метаданни)');
321
322 setStatus('Ytdlp', true);
323 setStatus('Ffmpeg', true);
324
325 document.getElementById('btnCopy') && document.getElementById('btnCopy').remove();
326
327 const btn = document.createElement('button');
328 btn.id = 'btnCopy';
329 btn.className = 'btn-download';
330 btn.style.marginTop = '10px';
331 btn.style.background = '#1a5c1a';
332 btn.textContent = '📋 Копирай командата';
333 btn.onclick = () => {
334 navigator.clipboard.writeText(cmd).then(() => {
335 btn.textContent = '✓ Копирано!';
336 setTimeout(() => btn.textContent = '📋 Копирай командата', 2000);
337 });
338 };
339 document.querySelector('.card').appendChild(btn);
340}
341
342function copyFolder() {
343 const val = document.getElementById('outdir').value;
344 navigator.clipboard.writeText(val).then(() => {
345 document.querySelector('.btn-browse').textContent = '✓ Копирано!';
346 setTimeout(() => document.querySelector('.btn-browse').textContent = '📋 Копирай', 1500);
347 });
348}
349</script>
350</body>
351</html>
352