|
|
import os |
|
|
import yt_dlp |
|
|
import requests |
|
|
from bs4 import BeautifulSoup |
|
|
import re |
|
|
import subprocess |
|
|
import shutil |
|
|
|
|
|
def get_ffmpeg_path(): |
|
|
"""Get FFmpeg path with fallback options""" |
|
|
ffmpeg_path = shutil.which("ffmpeg") |
|
|
if ffmpeg_path: |
|
|
return ffmpeg_path |
|
|
possible_paths = [ |
|
|
"ffmpeg", |
|
|
r"C:\Users\abhiv\OneDrive\Desktop\agentic ai\SoundFeet\ffmpeg-7.1-essentials_build\bin\ffmpeg.exe", |
|
|
"./ffmpeg/ffmpeg.exe", |
|
|
"./ffmpeg-7.1-essentials_build/bin/ffmpeg.exe" |
|
|
] |
|
|
for path in possible_paths: |
|
|
try: |
|
|
if path == "ffmpeg" or not path.endswith('.exe'): |
|
|
result = subprocess.run([path, '-version'], capture_output=True, timeout=5) |
|
|
if result.returncode == 0: |
|
|
return path |
|
|
elif os.path.exists(path): |
|
|
return path |
|
|
except: |
|
|
continue |
|
|
return "ffmpeg" |
|
|
|
|
|
FFMPEG_PATH = get_ffmpeg_path() |
|
|
|
|
|
def create_audio_folder(): |
|
|
"""Create audio folder if it doesn't exist""" |
|
|
if not os.path.exists("./audio"): |
|
|
os.makedirs("./audio") |
|
|
return "./audio" |
|
|
|
|
|
|
|
|
def check_ffmpeg(): |
|
|
"""Check if FFmpeg is available at the specified path""" |
|
|
if not os.path.exists(FFMPEG_PATH): |
|
|
print(f"β FFmpeg not found at: {FFMPEG_PATH}") |
|
|
print("Please check the path and make sure FFmpeg is installed.") |
|
|
return False |
|
|
print(f"β
FFmpeg found at: {FFMPEG_PATH}") |
|
|
return True |
|
|
|
|
|
|
|
|
def search_and_download_audio(audio_name): |
|
|
"""Search and download audio using yt-dlp's built-in search""" |
|
|
audio_folder = create_audio_folder() |
|
|
sanitized_name = sanitize_filename(audio_name) |
|
|
|
|
|
|
|
|
ydl_opts = { |
|
|
'format': 'bestaudio/best', |
|
|
'outtmpl': f'{audio_folder}/{sanitized_name}.%(ext)s', |
|
|
'postprocessors': [{ |
|
|
'key': 'FFmpegExtractAudio', |
|
|
'preferredcodec': 'mp3', |
|
|
'preferredquality': '192', |
|
|
}], |
|
|
'ffmpeg_location': os.path.dirname(FFMPEG_PATH), |
|
|
'default_search': 'ytsearch', |
|
|
'noplaylist': True, |
|
|
} |
|
|
|
|
|
try: |
|
|
print(f"π Searching for '{audio_name}' on YouTube...") |
|
|
|
|
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
|
|
|
|
|
search_query = f"{audio_name} audio" |
|
|
ydl.download([search_query]) |
|
|
|
|
|
|
|
|
mp3_file = os.path.join(audio_folder, f"{sanitized_name}.mp3") |
|
|
if os.path.exists(mp3_file): |
|
|
file_size = os.path.getsize(mp3_file) / (1024 * 1024) |
|
|
print(f"β
Audio '{sanitized_name}' downloaded successfully! ({file_size:.2f} MB)") |
|
|
return ydl_opts['outtmpl'] |
|
|
else: |
|
|
print("β Downloaded file not found.") |
|
|
return False |
|
|
|
|
|
except yt_dlp.utils.DownloadError as e: |
|
|
print(f"β Download error: {e}") |
|
|
return False |
|
|
except Exception as e: |
|
|
print(f"β Unexpected error: {e}") |
|
|
return False |
|
|
|
|
|
|
|
|
def search_youtube_improved(audio_name): |
|
|
"""Alternative search method with better headers""" |
|
|
search_query = f"{audio_name} audio" |
|
|
url = f"https://www.youtube.com/results?search_query={search_query.replace(' ', '+')}" |
|
|
|
|
|
try: |
|
|
headers = { |
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', |
|
|
'Accept-Language': 'en-US,en;q=0.5', |
|
|
'Accept-Encoding': 'gzip, deflate', |
|
|
'Connection': 'keep-alive', |
|
|
} |
|
|
|
|
|
response = requests.get(url, headers=headers, timeout=10) |
|
|
response.raise_for_status() |
|
|
|
|
|
|
|
|
video_ids = re.findall(r'watch\?v=([a-zA-Z0-9_-]{11})', response.text) |
|
|
|
|
|
|
|
|
video_links = [] |
|
|
for video_id in video_ids: |
|
|
url = f"https://www.youtube.com/watch?v={video_id}" |
|
|
if url not in video_links: |
|
|
video_links.append(url) |
|
|
|
|
|
return video_links[:5] |
|
|
|
|
|
except Exception as e: |
|
|
print(f"β Error searching YouTube: {e}") |
|
|
return [] |
|
|
|
|
|
|
|
|
def sanitize_filename(name): |
|
|
"""Remove invalid characters from filename""" |
|
|
invalid_chars = '<>:"/\\|?*' |
|
|
for char in invalid_chars: |
|
|
name = name.replace(char, '') |
|
|
return name.strip() |
|
|
|
|
|
|
|
|
def main_sound(audio_name): |
|
|
print("π΅ Audio Downloader") |
|
|
print("=" * 40) |
|
|
|
|
|
|
|
|
if not check_ffmpeg(): |
|
|
return None |
|
|
if not audio_name: |
|
|
print("β Please enter a valid audio name.") |
|
|
return None |
|
|
|
|
|
|
|
|
print("\nπ Trying direct download method...") |
|
|
file_path = search_and_download_audio(audio_name) |
|
|
if file_path: |
|
|
print(f"π Success! Audio saved as '{sanitize_filename(audio_name)}.mp3'") |
|
|
return file_path |
|
|
else: |
|
|
print("\nπ Direct method failed, trying alternative search...") |
|
|
|
|
|
|
|
|
video_urls = search_youtube_improved(audio_name) |
|
|
|
|
|
if not video_urls: |
|
|
print("β No audio found. Please try a different name.") |
|
|
print( |
|
|
"π‘ Try more specific terms like: 'city street sounds', 'footsteps on pavement', 'urban ambient noise'") |
|
|
return None |
|
|
|
|
|
print(f"π₯ Found {len(video_urls)} results. Downloading the first one...") |
|
|
|
|
|
|
|
|
file_path = download_audio_direct(audio_name, video_urls[0]) |
|
|
if file_path: |
|
|
print(f"π Audio saved in 'audio' folder!") |
|
|
return file_path |
|
|
else: |
|
|
print("β All download methods failed.") |
|
|
return None |
|
|
|
|
|
|
|
|
def download_audio_direct(audio_name, url): |
|
|
"""Direct download method for specific URLs""" |
|
|
audio_folder = create_audio_folder() |
|
|
sanitized_name = sanitize_filename(audio_name) |
|
|
|
|
|
ydl_opts = { |
|
|
'format': 'bestaudio/best', |
|
|
'outtmpl': f'{audio_folder}/{sanitized_name}.%(ext)s', |
|
|
'postprocessors': [{ |
|
|
'key': 'FFmpegExtractAudio', |
|
|
'preferredcodec': 'mp3', |
|
|
'preferredquality': '192', |
|
|
}], |
|
|
'ffmpeg_location': os.path.dirname(FFMPEG_PATH), |
|
|
} |
|
|
|
|
|
try: |
|
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
|
|
ydl.download([url]) |
|
|
return ydl_opts['outtmpl'] |
|
|
except Exception as e: |
|
|
print(f"β Error: {e}") |
|
|
return False |
|
|
|
|
|
|