File size: 6,849 Bytes
80aa632
 
 
 
 
 
3af83fc
80aa632
 
 
3af83fc
 
 
80aa632
 
 
1ba4b6a
de997dc
80aa632
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cdac1d6
 
 
80aa632
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import os
import yt_dlp
import requests
from bs4 import BeautifulSoup
import re
import subprocess
import shutil
# Set the path to your FFmpeg executable - prioritize system ffmpeg for Docker
def get_ffmpeg_path():
    """Get FFmpeg path with fallback options"""
    ffmpeg_path = shutil.which("ffmpeg")
    if ffmpeg_path:
        return ffmpeg_path
    possible_paths = [
        "ffmpeg",  # System ffmpeg (Docker/Linux)
        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)

    # Configure yt-dlp with FFmpeg path
    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',  # Use YouTube search
        'noplaylist': True,  # Download only single video, not playlist
    }

    try:
        print(f"πŸ” Searching for '{audio_name}' on YouTube...")

        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            # Search and download the first result
            search_query = f"{audio_name} audio"
            ydl.download([search_query])

        # Check if file was created
        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)  # Size in MB
            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()

        # Extract video IDs using regex from the page source
        video_ids = re.findall(r'watch\?v=([a-zA-Z0-9_-]{11})', response.text)

        # Remove duplicates and create full URLs
        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]  # Return top 5 results

    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)

    # Check FFmpeg availability first
    if not check_ffmpeg():
        return None
    if not audio_name:
        print("❌ Please enter a valid audio name.")
        return None

    # Try the direct download method first (more reliable)
    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...")

        # Try alternative search method
        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...")

        # Download using the traditional method
        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