MySafeCode commited on
Commit
ba95a67
·
verified ·
1 Parent(s): 5193b85

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +304 -39
app.py CHANGED
@@ -2,53 +2,318 @@ import gradio as gr
2
  from yt_dlp import YoutubeDL
3
  import os
4
  from pydub import AudioSegment
 
 
5
 
6
- DOWNLOADS_FOLDER = "downloads"
 
7
  os.makedirs(DOWNLOADS_FOLDER, exist_ok=True)
8
 
9
- def download_soundcloud(url, file_format, duration_sec):
10
- # Download best audio first (usually m4a)
11
- ydl_opts = {
12
- 'format': 'bestaudio/best',
13
- 'outtmpl': os.path.join(DOWNLOADS_FOLDER, '%(title)s.%(ext)s')
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- with YoutubeDL(ydl_opts) as ydl:
17
- info = ydl.extract_info(url, download=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- original_file = os.path.join(DOWNLOADS_FOLDER, f"{info['title']}.{info['ext']}")
 
 
 
 
20
 
21
- # Load audio and trim to duration
22
- audio = AudioSegment.from_file(original_file)
23
- duration_ms = min(len(audio), int(duration_sec * 1000))
24
- trimmed_audio = audio[:duration_ms]
25
 
26
- # Determine output file path
27
- if file_format.lower() == "mp3":
28
- output_file = os.path.splitext(original_file)[0] + ".mp3"
29
- trimmed_audio.export(output_file, format="mp3")
30
- elif file_format.lower() == "opus":
31
- output_file = os.path.splitext(original_file)[0] + ".opus"
32
- trimmed_audio.export(output_file, format="opus")
33
- else: # keep original format
34
- output_file = os.path.splitext(original_file)[0] + f".{info['ext']}"
35
- trimmed_audio.export(output_file, format=info['ext'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- return output_file
38
-
39
- # Gradio interface
40
- with gr.Blocks() as iface:
41
- url_input = gr.Textbox(label="SoundCloud URL", value="https://soundcloud.com/antonio-antetomaso/mutiny-on-the-bounty-closing-titles-cover")
42
- format_choice = gr.Dropdown(choices=["mp3", "m4a", "opus"], value="mp3", label="Select format")
43
- duration_slider = gr.Slider(minimum=5, maximum=300, value=30, step=5, label="Duration (seconds)")
44
- download_button = gr.Button("Download")
45
- download_file = gr.File(label="Download your track")
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- download_button.click(
48
- fn=download_soundcloud,
49
- inputs=[url_input, format_choice, duration_slider],
50
- outputs=download_file
 
 
 
 
 
 
 
51
  )
52
 
53
- iface.launch(show_error=True)
54
-
 
 
 
 
 
 
 
 
2
  from yt_dlp import YoutubeDL
3
  import os
4
  from pydub import AudioSegment
5
+ import tempfile
6
+ import json
7
 
8
+ # Use temp directory for better security
9
+ DOWNLOADS_FOLDER = tempfile.mkdtemp(prefix="audio_downloader_")
10
  os.makedirs(DOWNLOADS_FOLDER, exist_ok=True)
11
 
12
+ def download_youtube_audio(url, file_format, duration_sec):
13
+ """Download and process audio from YouTube"""
14
+ try:
15
+ # Download best audio available
16
+ ydl_opts = {
17
+ 'format': 'bestaudio/best',
18
+ 'outtmpl': os.path.join(DOWNLOADS_FOLDER, '%(title)s.%(ext)s'),
19
+ 'quiet': False,
20
+ 'no_warnings': False,
21
+ 'extract_flat': False,
22
+ 'noplaylist': True,
23
+ }
24
+
25
+ with YoutubeDL(ydl_opts) as ydl:
26
+ info = ydl.extract_info(url, download=True)
27
+
28
+ original_file = os.path.join(DOWNLOADS_FOLDER, f"{info['title']}.{info['ext']}")
29
+
30
+ # Clean filename
31
+ safe_title = "".join(c for c in info['title'] if c.isalnum() or c in (' ', '-', '_')).rstrip()
32
+ safe_title = safe_title[:100]
33
+ original_file_safe = os.path.join(DOWNLOADS_FOLDER, f"{safe_title}.{info['ext']}")
34
+
35
+ if original_file != original_file_safe:
36
+ if os.path.exists(original_file_safe):
37
+ os.remove(original_file_safe)
38
+ os.rename(original_file, original_file_safe)
39
+ original_file = original_file_safe
40
+
41
+ # Load audio
42
+ audio = AudioSegment.from_file(original_file)
43
+
44
+ # Handle duration
45
+ if duration_sec > 0:
46
+ duration_ms = min(len(audio), int(duration_sec * 1000))
47
+ trimmed_audio = audio[:duration_ms]
48
+ else:
49
+ trimmed_audio = audio
50
+
51
+ # Determine output file
52
+ base_name = os.path.splitext(original_file)[0]
53
+
54
+ if file_format.lower() == "mp3":
55
+ output_file = base_name + ".mp3"
56
+ trimmed_audio.export(output_file, format="mp3", bitrate="192k")
57
+
58
+ elif file_format.lower() == "opus":
59
+ output_file = base_name + ".opus"
60
+ trimmed_audio.export(output_file, format="opus", bitrate="128k")
61
+
62
+ elif file_format.lower() == "wav":
63
+ output_file = base_name + ".wav"
64
+ trimmed_audio.export(output_file, format="wav")
65
+
66
+ elif file_format.lower() == "m4a":
67
+ output_file = base_name + ".m4a"
68
+ trimmed_audio.export(output_file, format="ipod", codec="aac")
69
+
70
+ else:
71
+ output_file = original_file
72
+
73
+ # Clean up original if converted
74
+ if output_file != original_file and os.path.exists(original_file):
75
+ os.remove(original_file)
76
+
77
+ # For Gradio 6+, return a dictionary for gr.File component
78
+ return {
79
+ "path": output_file,
80
+ "name": os.path.basename(output_file)
81
+ }, f"✅ Downloaded: {os.path.basename(output_file)}"
82
 
83
+ except Exception as e:
84
+ return None, f"❌ Error: {str(e)}"
85
+
86
+ def download_soundcloud_audio(url, file_format, duration_sec):
87
+ """Download and process audio from SoundCloud"""
88
+ try:
89
+ ydl_opts = {
90
+ 'format': 'bestaudio/best',
91
+ 'outtmpl': os.path.join(DOWNLOADS_FOLDER, '%(title)s.%(ext)s'),
92
+ 'quiet': False,
93
+ 'no_warnings': False,
94
+ 'extract_flat': False,
95
+ }
96
+
97
+ with YoutubeDL(ydl_opts) as ydl:
98
+ info = ydl.extract_info(url, download=True)
99
+
100
+ original_file = os.path.join(DOWNLOADS_FOLDER, f"{info['title']}.{info['ext']}")
101
+
102
+ # Clean filename
103
+ safe_title = "".join(c for c in info['title'] if c.isalnum() or c in (' ', '-', '_')).rstrip()
104
+ safe_title = safe_title[:100]
105
+ original_file_safe = os.path.join(DOWNLOADS_FOLDER, f"{safe_title}.{info['ext']}")
106
+
107
+ if original_file != original_file_safe:
108
+ if os.path.exists(original_file_safe):
109
+ os.remove(original_file_safe)
110
+ os.rename(original_file, original_file_safe)
111
+ original_file = original_file_safe
112
+
113
+ # Load and process audio
114
+ audio = AudioSegment.from_file(original_file)
115
+
116
+ if duration_sec > 0:
117
+ duration_ms = min(len(audio), int(duration_sec * 1000))
118
+ trimmed_audio = audio[:duration_ms]
119
+ else:
120
+ trimmed_audio = audio
121
+
122
+ # Convert to desired format
123
+ base_name = os.path.splitext(original_file)[0]
124
+
125
+ if file_format.lower() == "mp3":
126
+ output_file = base_name + ".mp3"
127
+ trimmed_audio.export(output_file, format="mp3", bitrate="192k")
128
+
129
+ elif file_format.lower() == "opus":
130
+ output_file = base_name + ".opus"
131
+ trimmed_audio.export(output_file, format="opus", bitrate="128k")
132
+
133
+ elif file_format.lower() == "wav":
134
+ output_file = base_name + ".wav"
135
+ trimmed_audio.export(output_file, format="wav")
136
+
137
+ elif file_format.lower() == "m4a":
138
+ output_file = base_name + ".m4a"
139
+ trimmed_audio.export(output_file, format="ipod", codec="aac")
140
+
141
+ else:
142
+ output_file = original_file
143
+
144
+ # Clean up
145
+ if output_file != original_file and os.path.exists(original_file):
146
+ os.remove(original_file)
147
+
148
+ # For Gradio 6+, return a dictionary for gr.File component
149
+ return {
150
+ "path": output_file,
151
+ "name": os.path.basename(output_file)
152
+ }, f"✅ Downloaded: {os.path.basename(output_file)}"
153
 
154
+ except Exception as e:
155
+ return None, f"❌ Error: {str(e)}"
156
+
157
+ # Create Gradio interface
158
+ with gr.Blocks(title="Audio Downloader") as iface: # Removed theme from here
159
 
160
+ gr.Markdown("# 🎵 Audio Downloader")
161
+ gr.Markdown("Download audio from YouTube or SoundCloud")
 
 
162
 
163
+ with gr.Tabs():
164
+ # YouTube Tab
165
+ with gr.Tab("YouTube"):
166
+ with gr.Row():
167
+ with gr.Column():
168
+ youtube_url = gr.Textbox(
169
+ label="YouTube URL",
170
+ placeholder="https://www.youtube.com/watch?v=...",
171
+ lines=1
172
+ )
173
+
174
+ with gr.Row():
175
+ youtube_format = gr.Dropdown(
176
+ choices=["mp3", "m4a", "opus", "wav"],
177
+ value="mp3",
178
+ label="Output Format"
179
+ )
180
+
181
+ youtube_duration = gr.Slider(
182
+ minimum=0,
183
+ maximum=1800,
184
+ value=60,
185
+ step=5,
186
+ label="Duration (seconds)",
187
+ info="0 = full video"
188
+ )
189
+
190
+ youtube_btn = gr.Button(
191
+ "Download from YouTube",
192
+ variant="primary",
193
+ size="lg"
194
+ )
195
+
196
+ youtube_status = gr.Textbox(
197
+ label="Status",
198
+ interactive=False
199
+ )
200
+
201
+ youtube_output = gr.File(
202
+ label="Downloaded File",
203
+ interactive=False,
204
+ file_count="single" # Explicitly specify file count
205
+ )
206
+
207
+ # YouTube examples
208
+ with gr.Accordion("YouTube Examples", open=False):
209
+ gr.Examples(
210
+ examples=[
211
+ ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
212
+ ["https://www.youtube.com/watch?v=JGwWNGJdvx8"],
213
+ ["https://www.youtube.com/watch?v=9bZkp7q19f0"],
214
+ ["https://youtu.be/kJQP7kiw5Fk"]
215
+ ],
216
+ inputs=youtube_url,
217
+ label="Try these URLs:"
218
+ )
219
+
220
+ # SoundCloud Tab
221
+ with gr.Tab("SoundCloud"):
222
+ with gr.Row():
223
+ with gr.Column():
224
+ soundcloud_url = gr.Textbox(
225
+ label="SoundCloud URL",
226
+ placeholder="https://soundcloud.com/...",
227
+ lines=1
228
+ )
229
+
230
+ with gr.Row():
231
+ soundcloud_format = gr.Dropdown(
232
+ choices=["mp3", "m4a", "opus", "wav"],
233
+ value="mp3",
234
+ label="Output Format"
235
+ )
236
+
237
+ soundcloud_duration = gr.Slider(
238
+ minimum=0,
239
+ maximum=600,
240
+ value=60,
241
+ step=5,
242
+ label="Duration (seconds)",
243
+ info="0 = full track"
244
+ )
245
+
246
+ soundcloud_btn = gr.Button(
247
+ "Download from SoundCloud",
248
+ variant="primary",
249
+ size="lg"
250
+ )
251
+
252
+ soundcloud_status = gr.Textbox(
253
+ label="Status",
254
+ interactive=False
255
+ )
256
+
257
+ soundcloud_output = gr.File(
258
+ label="Downloaded File",
259
+ interactive=False,
260
+ file_count="single" # Explicitly specify file count
261
+ )
262
+
263
+ # SoundCloud examples
264
+ with gr.Accordion("SoundCloud Examples", open=False):
265
+ gr.Examples(
266
+ examples=[
267
+ ["https://soundcloud.com/antonio-antetomaso/mutiny-on-the-bounty-closing-titles-cover"],
268
+ ["https://soundcloud.com/officialnikkig/kill-bill-sza-kill-bill-remix"],
269
+ ["https://soundcloud.com/lofi-girl"],
270
+ ["https://soundcloud.com/monstercat/pegboard-nerds-disconnected"]
271
+ ],
272
+ inputs=soundcloud_url,
273
+ label="Try these URLs:"
274
+ )
275
 
276
+ # Instructions
277
+ with gr.Accordion("📖 Instructions & Info", open=False):
278
+ gr.Markdown("""
279
+ ### How to Use:
280
+ 1. **Select the platform tab** (YouTube or SoundCloud)
281
+ 2. **Paste a URL** from the selected platform
282
+ 3. **Choose output format** (MP3, M4A, Opus, or WAV)
283
+ 4. **Set duration** (0 for full track, or specify seconds)
284
+ 5. **Click Download** button
285
+
286
+ ### Supported Formats:
287
+ - **MP3**: Most compatible, good quality
288
+ - **M4A**: Apple format, smaller file size
289
+ - **Opus**: Best quality at low bitrates
290
+ - **WAV**: Lossless, large file size
291
+
292
+ ### Notes:
293
+ - Files are saved in a temporary folder
294
+ - Some content may have download restrictions
295
+ - Long videos may take time to process
296
+ """)
297
 
298
+ # Connect button events
299
+ youtube_btn.click(
300
+ fn=download_youtube_audio,
301
+ inputs=[youtube_url, youtube_format, youtube_duration],
302
+ outputs=[youtube_output, youtube_status]
303
+ )
304
+
305
+ soundcloud_btn.click(
306
+ fn=download_soundcloud_audio,
307
+ inputs=[soundcloud_url, soundcloud_format, soundcloud_duration],
308
+ outputs=[soundcloud_output, soundcloud_status]
309
  )
310
 
311
+ # Launch the app
312
+ if __name__ == "__main__":
313
+ iface.launch(
314
+ server_name="127.0.0.1",
315
+ server_port=7860,
316
+ show_error=True,
317
+ share=False,
318
+ theme=gr.themes.Soft() # Moved theme to launch() method
319
+ )