Download index.html from Docfile/ytb: direct link, hf CLI and curl.
- Browser
- Download file 7.09 kB
-
https://huggingface.co/spaces/Docfile/ytb/resolve/main/index.html
- Command line
-
hf download hf://spaces/Docfile/ytb/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Docfile/ytb/resolve/main/index.html
7.09 kB
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>YouTube to MP3</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| max-width: 600px; | |
| margin: 50px auto; | |
| padding: 20px; | |
| background: #f5f5f5; | |
| } | |
| .container { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 10px; | |
| box-shadow: 0 2px 10px rgba(0,0,0,0.1); | |
| } | |
| h1 { | |
| color: #333; | |
| margin-bottom: 30px; | |
| } | |
| input[type="url"] { | |
| width: 100%; | |
| padding: 12px; | |
| border: 1px solid #ddd; | |
| border-radius: 5px; | |
| margin-bottom: 15px; | |
| box-sizing: border-box; | |
| } | |
| button { | |
| background: #ff0000; | |
| color: white; | |
| padding: 12px 30px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| width: 100%; | |
| } | |
| button:hover { | |
| background: #cc0000; | |
| } | |
| button:disabled { | |
| background: #ccc; | |
| cursor: not-allowed; | |
| } | |
| #status { | |
| margin-top: 20px; | |
| padding: 15px; | |
| border-radius: 5px; | |
| display: none; | |
| } | |
| .analyzing { background: #fff3cd; } | |
| .downloading { background: #d1ecf1; } | |
| .completed { background: #d4edda; } | |
| .error { background: #f8d7da; } | |
| #progress { | |
| margin-top: 10px; | |
| font-weight: bold; | |
| } | |
| .task-list { | |
| margin-top: 30px; | |
| } | |
| .task-item { | |
| background: #f9f9f9; | |
| padding: 15px; | |
| border-radius: 5px; | |
| margin-bottom: 10px; | |
| cursor: pointer; | |
| } | |
| .task-item:hover { | |
| background: #eee; | |
| } | |
| .task-url { | |
| font-size: 14px; | |
| color: #666; | |
| margin-bottom: 5px; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .task-status { | |
| font-weight: bold; | |
| margin-bottom: 5px; | |
| } | |
| .task-completed { color: #28a745; } | |
| .task-downloading { color: #17a2b8; } | |
| .task-error { color: #dc3545; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>🎵 YouTube to MP3</h1> | |
| <p>Entrez une URL YouTube (vidéo ou playlist)</p> | |
| <input type="url" id="urlInput" placeholder="https://www.youtube.com/watch?v=..." /> | |
| <button onclick="startDownload()">Télécharger</button> | |
| <div id="status"></div> | |
| <div id="progress"></div> | |
| <div class="task-list"> | |
| <h3>Tâches récentes</h3> | |
| <div id="tasksList"></div> | |
| </div> | |
| </div> | |
| <script> | |
| let currentTaskId = null; | |
| let tasks = JSON.parse(localStorage.getItem('tasks') || '[]'); | |
| function saveTasks() { | |
| localStorage.setItem('tasks', JSON.stringify(tasks)); | |
| } | |
| function renderTasks() { | |
| const list = document.getElementById('tasksList'); | |
| list.innerHTML = ''; | |
| tasks.slice().reverse().forEach(task => { | |
| const div = document.createElement('div'); | |
| div.className = 'task-item'; | |
| div.onclick = () => checkStatus(task.id); | |
| let statusClass = ''; | |
| let statusText = ''; | |
| if (task.status === 'completed') { | |
| statusClass = 'task-completed'; | |
| statusText = '✓ Terminé'; | |
| } else if (task.status === 'downloading' || task.status === 'analyzing') { | |
| statusClass = 'task-downloading'; | |
| statusText = `⏳ ${task.progress}/${task.total}`; | |
| } else if (task.status === 'error') { | |
| statusClass = 'task-error'; | |
| statusText = '✗ Erreur'; | |
| } | |
| div.innerHTML = ` | |
| <div class="task-status ${statusClass}">${statusText}</div> | |
| <div class="task-url">${task.url}</div> | |
| `; | |
| list.appendChild(div); | |
| }); | |
| } | |
| async function startDownload() { | |
| const url = document.getElementById('urlInput').value; | |
| if (!url) { | |
| alert('Veuillez entrer une URL'); | |
| return; | |
| } | |
| const response = await fetch('/download', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ url }) | |
| }); | |
| const data = await response.json(); | |
| if (data.error) { | |
| alert(data.error); | |
| return; | |
| } | |
| currentTaskId = data.task_id; | |
| tasks.push({ id: currentTaskId, url: url, status: 'analyzing', progress: 0, total: 0 }); | |
| saveTasks(); | |
| renderTasks(); | |
| checkStatus(currentTaskId); | |
| } | |
| async function checkStatus(taskId) { | |
| currentTaskId = taskId; | |
| const response = await fetch(`/status/${taskId}`); | |
| const data = await response.json(); | |
| const statusDiv = document.getElementById('status'); | |
| const progressDiv = document.getElementById('progress'); | |
| statusDiv.style.display = 'block'; | |
| statusDiv.className = data.status; | |
| if (data.status === 'analyzing') { | |
| statusDiv.textContent = '📊 Analyse de la playlist...'; | |
| } else if (data.status === 'downloading') { | |
| statusDiv.textContent = '📥 Téléchargement en cours...'; | |
| progressDiv.textContent = `${data.progress}/${data.total} vidéos`; | |
| } else if (data.status === 'completed') { | |
| statusDiv.textContent = '✅ Téléchargement terminé!'; | |
| progressDiv.innerHTML = `<a href="/download/${taskId}" style="color: #007bff;">📦 Télécharger le ZIP</a>`; | |
| } else if (data.status === 'error') { | |
| statusDiv.textContent = '❌ Erreur: ' + data.error; | |
| progressDiv.textContent = ''; | |
| } | |
| const taskIndex = tasks.findIndex(t => t.id === taskId); | |
| if (taskIndex !== -1) { | |
| tasks[taskIndex] = { ...tasks[taskIndex], status: data.status, progress: data.progress, total: data.total }; | |
| saveTasks(); | |
| renderTasks(); | |
| } | |
| if (data.status === 'downloading' || data.status === 'analyzing') { | |
| setTimeout(() => checkStatus(taskId), 2000); | |
| } | |
| } | |
| renderTasks(); | |
| </script> | |
| </body> | |
| </html> |