File size: 4,476 Bytes
26b7f05 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
import gradio as gr
from yt_dlp import YoutubeDL
import tempfile
import os
import subprocess
def download_snippet(url, duration_sec):
"""Download and trim audio snippet"""
# Create temp directory
temp_dir = tempfile.mkdtemp()
try:
# First, download the full track (or best we can get)
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': os.path.join(temp_dir, 'full_audio.%(ext)s'),
'quiet': True,
'no_warnings': True,
'noplaylist': True,
}
with YoutubeDL(ydl_opts) as ydl:
# Get info for filename
info = ydl.extract_info(url, download=False)
title = info.get('title', 'soundcloud_track')
safe_title = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).rstrip()
# Download
ydl.download([url])
# Find the downloaded file
downloaded_files = [f for f in os.listdir(temp_dir) if f.startswith('full_audio')]
if not downloaded_files:
raise Exception("No file was downloaded")
input_file = os.path.join(temp_dir, downloaded_files[0])
# Check if file exists and has content
if not os.path.exists(input_file) or os.path.getsize(input_file) == 0:
raise Exception("Downloaded file is empty")
# Create output filename
output_file = os.path.join(temp_dir, f"{safe_title}_{duration_sec}s.mp3")
# Use ffmpeg to trim (this is the key fix!)
cmd = [
'ffmpeg',
'-i', input_file, # Input file
'-t', str(duration_sec), # Duration to keep
'-acodec', 'libmp3lame', # MP3 codec
'-q:a', '2', # Good quality
'-y', # Overwrite output
output_file
]
# Run ffmpeg
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"FFmpeg error: {result.stderr}")
# Check if output was created
if not os.path.exists(output_file) or os.path.getsize(output_file) == 0:
raise Exception("Trimmed file is empty")
return output_file, f"{safe_title}_{duration_sec}s.mp3"
except Exception as e:
# Clean up on error
if os.path.exists(temp_dir):
import shutil
shutil.rmtree(temp_dir, ignore_errors=True)
raise e
# Simple Gradio interface
with gr.Blocks(title="SoundCloud Snippet", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🎵 SoundCloud Snippet Downloader
Download the first N seconds of any public SoundCloud track
""")
with gr.Row():
url = gr.Textbox(
label="SoundCloud URL",
placeholder="https://soundcloud.com/artist/track-name",
value="https://soundcloud.com/emma-eline-pihlstr-m/have-yourself-a-merry-little-christmas",
lines=2
)
with gr.Row():
duration = gr.Slider(
minimum=5,
maximum=400,
value=30,
step=5,
label="Duration (seconds)"
)
with gr.Row():
download_btn = gr.Button("Download Snippet", variant="primary")
with gr.Row():
audio_player = gr.Audio(label="Preview", type="filepath")
download_file = gr.DownloadButton("Save MP3", visible=False)
# Store file path
file_path = gr.State()
def process_download(url, duration):
if not url or 'soundcloud.com' not in url.lower():
raise gr.Error("Please enter a valid SoundCloud URL")
try:
filepath, filename = download_snippet(url, duration)
return {
audio_player: filepath,
download_file: gr.DownloadButton(visible=True),
file_path: filepath
}
except Exception as e:
raise gr.Error(f"Download failed: {str(e)}")
download_btn.click(
process_download,
inputs=[url, duration],
outputs=[audio_player, download_file, file_path]
)
download_file.click(
lambda x: x if x and os.path.exists(x) else None,
inputs=[file_path],
outputs=None
)
if __name__ == "__main__":
demo.launch() |