lexicalspace commited on
Commit
4ed0744
·
verified ·
1 Parent(s): a7b775c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -133
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
- st.title("🎥 YouTube Media Extractor")
31
- st.caption("🚀 Swarm Mode: Tries 5 different servers to bypass blocks.")
32
-
33
- # Input Fields
34
- url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/watch?v=...")
35
-
36
- col1, col2 = st.columns(2)
37
- with col1:
38
- is_audio = st.toggle("Audio Only (MP3)", value=False)
39
-
40
- mode_str = "audio" if is_audio else "auto"
41
-
42
- if url:
43
- st.info("👇 Click the button below to process.")
44
-
45
- # --- JAVASCRIPT SWARM LOGIC ---
46
- html_code = f"""
47
- <!DOCTYPE html>
48
- <html>
49
- <head>
50
- <style>
51
- body {{ font-family: sans-serif; color: white; background: transparent; }}
52
- .btn {{
53
- background: #FF4B4B; color: white; border: none; padding: 12px 24px;
54
- border-radius: 8px; font-size: 16px; cursor: pointer; width: 100%;
55
- transition: 0.3s; font-weight: bold; margin-bottom: 10px;
56
- }}
57
- .btn:hover {{ background: #FF2B2B; }}
58
- .btn:disabled {{ background: #555; cursor: not-allowed; }}
59
- .result {{ margin-top: 15px; padding: 15px; border-radius: 8px; display: none; }}
60
- .success {{ background: #1E3A2F; border: 1px solid #2ecc71; color: #2ecc71; }}
61
- .error {{ background: #3A1E1E; border: 1px solid #e74c3c; color: #e74c3c; }}
62
- a.download-link {{
63
- color: white; text-decoration: none; display: block; padding: 12px;
64
- background: #2ecc71; border-radius: 5px; text-align: center; font-weight: bold;
65
- }}
66
- .log {{ font-size: 12px; color: #aaa; margin-top: 5px; font-family: monospace; }}
67
- </style>
68
- </head>
69
- <body>
70
- <button id="procBtn" class="btn" onclick="startSwarm()">🚀 Process Media</button>
71
- <div id="status" class="result"></div>
72
- <div id="log" class="log"></div>
73
-
74
- <script>
75
- // LIST OF PUBLIC MIRRORS (The Swarm)
76
- const MIRRORS = [
77
- "https://api.cobalt.750.moe/json",
78
- "https://cobalt.api.timelessnesses.me/api/json",
79
- "https://cobalt-api.hyper.lol/json",
80
- "https://co.wuk.sh/api/json",
81
- "https://api.cobalt.tools/json"
82
- ];
83
-
84
- async function startSwarm() {{
85
- const btn = document.getElementById('procBtn');
86
- const status = document.getElementById('status');
87
- const log = document.getElementById('log');
88
-
89
- btn.disabled = true;
90
- btn.innerText = "⏳ Trying Servers...";
91
- status.style.display = "none";
92
- log.innerText = "";
93
-
94
- const payload = {{
95
- url: "{url}",
96
- downloadMode: "{mode_str}",
97
- videoQuality: "1080"
98
- }};
99
-
100
- let success = false;
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