Update app.py
Browse files
app.py
CHANGED
|
@@ -27,139 +27,77 @@ app_mode = st.sidebar.radio(
|
|
| 27 |
# VIEW 1: YOUTUBE DOWNLOADER (Swarm Mode)
|
| 28 |
# ==========================================
|
| 29 |
if app_mode == "YouTube Downloader":
|
| 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 |
-
// Try each mirror one by one
|
| 103 |
-
for (const mirror of MIRRORS) {{
|
| 104 |
-
try {{
|
| 105 |
-
log.innerText = "Trying: " + mirror.replace("https://", "");
|
| 106 |
-
|
| 107 |
-
const response = await fetch(mirror, {{
|
| 108 |
-
method: "POST",
|
| 109 |
-
headers: {{
|
| 110 |
-
"Accept": "application/json",
|
| 111 |
-
"Content-Type": "application/json"
|
| 112 |
-
}},
|
| 113 |
-
body: JSON.stringify(payload)
|
| 114 |
-
}});
|
| 115 |
-
|
| 116 |
-
const result = await response.json();
|
| 117 |
-
|
| 118 |
-
if (result.url) {{
|
| 119 |
-
showSuccess(result.url, mirror);
|
| 120 |
-
success = true;
|
| 121 |
-
break; // Stop loop if we found a working one
|
| 122 |
-
}}
|
| 123 |
-
}} catch (err) {{
|
| 124 |
-
console.log("Failed: " + mirror);
|
| 125 |
-
}}
|
| 126 |
-
}}
|
| 127 |
-
|
| 128 |
-
if (!success) {{
|
| 129 |
-
showFallback();
|
| 130 |
-
}}
|
| 131 |
-
|
| 132 |
-
btn.disabled = false;
|
| 133 |
-
btn.innerText = "🚀 Process Media";
|
| 134 |
-
}}
|
| 135 |
-
|
| 136 |
-
function showSuccess(url, source) {{
|
| 137 |
-
const status = document.getElementById('status');
|
| 138 |
-
status.className = "result success";
|
| 139 |
-
status.innerHTML = `
|
| 140 |
-
<strong>✅ Success!</strong><br><br>
|
| 141 |
-
<a href="${{url}}" class="download-link" target="_blank">⬇️ Click to Download</a>
|
| 142 |
-
<div style="margin-top:10px; font-size:11px; color:#888;">Fetched from: ${{source}}</div>
|
| 143 |
-
`;
|
| 144 |
-
status.style.display = "block";
|
| 145 |
-
}}
|
| 146 |
-
|
| 147 |
-
function showFallback() {{
|
| 148 |
-
const status = document.getElementById('status');
|
| 149 |
-
status.className = "result error";
|
| 150 |
-
// Fallback link to a reliable external tool if all APIs fail
|
| 151 |
-
const fallbackUrl = "https://cobalt.tools";
|
| 152 |
-
status.innerHTML = `
|
| 153 |
-
<strong>⚠️ API Busy</strong><br>
|
| 154 |
-
All internal servers are currently overloaded.<br><br>
|
| 155 |
-
<a href="${{fallbackUrl}}" class="download-link" style="background:#e67e22;" target="_blank">Open Backup Downloader</a>
|
| 156 |
-
`;
|
| 157 |
-
status.style.display = "block";
|
| 158 |
-
}}
|
| 159 |
-
</script>
|
| 160 |
-
</body>
|
| 161 |
-
</html>
|
| 162 |
-
"""
|
| 163 |
|
| 164 |
components.html(html_code, height=350)
|
| 165 |
|
|
|
|
| 27 |
# VIEW 1: YOUTUBE DOWNLOADER (Swarm Mode)
|
| 28 |
# ==========================================
|
| 29 |
if app_mode == "YouTube Downloader":
|
| 30 |
+
# main.py
|
| 31 |
+
# Hugging Face Space: YouTube → MP3 API + UI
|
| 32 |
+
# Works on CPU, no API key, no login
|
| 33 |
+
|
| 34 |
+
import os
|
| 35 |
+
import uuid
|
| 36 |
+
from fastapi import FastAPI
|
| 37 |
+
from fastapi.responses import FileResponse
|
| 38 |
+
import yt_dlp
|
| 39 |
+
import gradio as gr
|
| 40 |
+
|
| 41 |
+
OUTPUT_DIR = "downloads"
|
| 42 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
| 43 |
+
|
| 44 |
+
app = FastAPI()
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def download_mp3(youtube_url: str):
|
| 48 |
+
uid = str(uuid.uuid4())
|
| 49 |
+
out_file = os.path.join(OUTPUT_DIR, f"{uid}.mp3")
|
| 50 |
+
|
| 51 |
+
ydl_opts = {
|
| 52 |
+
'format': 'bestaudio/best',
|
| 53 |
+
'outtmpl': out_file.replace('.mp3', '.%(ext)s'),
|
| 54 |
+
'postprocessors': [{
|
| 55 |
+
'key': 'FFmpegExtractAudio',
|
| 56 |
+
'preferredcodec': 'mp3',
|
| 57 |
+
'preferredquality': '192',
|
| 58 |
+
}],
|
| 59 |
+
'quiet': True,
|
| 60 |
+
'noplaylist': True,
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
| 64 |
+
ydl.download([youtube_url])
|
| 65 |
+
|
| 66 |
+
return out_file
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
# ---------- API ENDPOINT ----------
|
| 70 |
+
@app.get("/mp3")
|
| 71 |
+
def mp3_api(url: str):
|
| 72 |
+
mp3_path = download_mp3(url)
|
| 73 |
+
return FileResponse(mp3_path, filename="audio.mp3", media_type="audio/mpeg")
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
# ---------- UI ----------
|
| 77 |
+
def ui_download(url):
|
| 78 |
+
mp3_path = download_mp3(url)
|
| 79 |
+
return mp3_path
|
| 80 |
+
|
| 81 |
+
ui = gr.Interface(
|
| 82 |
+
fn=ui_download,
|
| 83 |
+
inputs=gr.Textbox(label="YouTube URL"),
|
| 84 |
+
outputs=gr.File(label="Download MP3"),
|
| 85 |
+
title="YouTube → MP3 Converter",
|
| 86 |
+
description="Paste YouTube link and get MP3 audio"
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
if __name__ == "__main__":
|
| 91 |
+
ui.launch(server_name="0.0.0.0", server_port=7860)
|
| 92 |
+
|
| 93 |
+
# -----------------------------
|
| 94 |
+
# requirements.txt (create this file manually):
|
| 95 |
+
# fastapi
|
| 96 |
+
# uvicorn
|
| 97 |
+
# yt-dlp
|
| 98 |
+
# gradio
|
| 99 |
+
# ffmpeg-python
|
| 100 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
components.html(html_code, height=350)
|
| 103 |
|