Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -29,11 +29,13 @@ format_option = st.selectbox(
|
|
29 |
)
|
30 |
|
31 |
def get_format_options(selection):
|
|
|
|
|
|
|
|
|
|
|
32 |
if selection == "Best Quality (Video + Audio)":
|
33 |
-
return
|
34 |
-
'format': 'best', # Changed from bestvideo+bestaudio to best
|
35 |
-
'merge_output_format': 'mp4'
|
36 |
-
}
|
37 |
elif selection == "Audio Only (Best Quality)":
|
38 |
return {
|
39 |
'format': 'bestaudio/best',
|
@@ -43,22 +45,27 @@ def get_format_options(selection):
|
|
43 |
}]
|
44 |
}
|
45 |
elif selection == "720p":
|
46 |
-
|
47 |
-
|
48 |
-
'merge_output_format': 'mp4'
|
49 |
-
}
|
50 |
elif selection == "480p":
|
51 |
-
|
52 |
-
|
53 |
-
'merge_output_format': 'mp4'
|
54 |
-
}
|
55 |
elif selection == "360p":
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
def download_video(url, format_selection):
|
|
|
|
|
|
|
|
|
62 |
try:
|
63 |
format_opts = get_format_options(format_selection)
|
64 |
|
@@ -66,20 +73,20 @@ def download_video(url, format_selection):
|
|
66 |
'outtmpl': str(output_dir / '%(title)s.%(ext)s'),
|
67 |
'quiet': True,
|
68 |
'no_warnings': True,
|
69 |
-
# Enhanced options to bypass restrictions
|
70 |
'nocheckcertificate': True,
|
71 |
-
'ignoreerrors':
|
72 |
'no_color': True,
|
73 |
'noprogress': True,
|
74 |
'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',
|
75 |
'referer': 'https://www.youtube.com/',
|
76 |
-
'http-chunk-size': '10485760',
|
|
|
77 |
}
|
78 |
|
79 |
# Update options with format-specific settings
|
80 |
ydl_opts.update(format_opts)
|
81 |
|
82 |
-
# Progress
|
83 |
progress_bar = st.progress(0)
|
84 |
status_text = st.empty()
|
85 |
|
@@ -97,15 +104,36 @@ def download_video(url, format_selection):
|
|
97 |
|
98 |
ydl_opts['progress_hooks'] = [progress_hook]
|
99 |
|
|
|
100 |
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
except Exception as e:
|
108 |
-
st.error(f"An error occurred: {str(e)}")
|
109 |
return None
|
110 |
|
111 |
# Download button
|
@@ -116,18 +144,25 @@ if st.button("Download"):
|
|
116 |
downloaded_file_path = download_video(video_url, format_option)
|
117 |
|
118 |
if downloaded_file_path and os.path.exists(downloaded_file_path):
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
else:
|
128 |
-
st.error("❌ Download failed. Please try again.")
|
129 |
except Exception as e:
|
130 |
-
st.error(f"❌ An error occurred: {str(e)}")
|
131 |
else:
|
132 |
st.warning("⚠️ Please enter a valid YouTube URL.")
|
133 |
|
@@ -141,5 +176,20 @@ with st.expander("ℹ️ Help"):
|
|
141 |
4. Wait for the download to complete
|
142 |
5. Click the download button that appears
|
143 |
|
144 |
-
**
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
)
|
30 |
|
31 |
def get_format_options(selection):
|
32 |
+
base_options = {
|
33 |
+
'format': 'best',
|
34 |
+
'merge_output_format': 'mp4',
|
35 |
+
}
|
36 |
+
|
37 |
if selection == "Best Quality (Video + Audio)":
|
38 |
+
return base_options
|
|
|
|
|
|
|
39 |
elif selection == "Audio Only (Best Quality)":
|
40 |
return {
|
41 |
'format': 'bestaudio/best',
|
|
|
45 |
}]
|
46 |
}
|
47 |
elif selection == "720p":
|
48 |
+
base_options['format'] = 'best[height<=720]'
|
49 |
+
return base_options
|
|
|
|
|
50 |
elif selection == "480p":
|
51 |
+
base_options['format'] = 'best[height<=480]'
|
52 |
+
return base_options
|
|
|
|
|
53 |
elif selection == "360p":
|
54 |
+
base_options['format'] = 'best[height<=360]'
|
55 |
+
return base_options
|
56 |
+
|
57 |
+
return base_options
|
58 |
+
|
59 |
+
def validate_url(url):
|
60 |
+
if not url:
|
61 |
+
return False
|
62 |
+
return 'youtube.com' in url or 'youtu.be' in url
|
63 |
|
64 |
def download_video(url, format_selection):
|
65 |
+
if not validate_url(url):
|
66 |
+
st.error("Please enter a valid YouTube URL")
|
67 |
+
return None
|
68 |
+
|
69 |
try:
|
70 |
format_opts = get_format_options(format_selection)
|
71 |
|
|
|
73 |
'outtmpl': str(output_dir / '%(title)s.%(ext)s'),
|
74 |
'quiet': True,
|
75 |
'no_warnings': True,
|
|
|
76 |
'nocheckcertificate': True,
|
77 |
+
'ignoreerrors': False, # Changed to False to catch errors
|
78 |
'no_color': True,
|
79 |
'noprogress': True,
|
80 |
'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',
|
81 |
'referer': 'https://www.youtube.com/',
|
82 |
+
'http-chunk-size': '10485760',
|
83 |
+
'extract_flat': True, # Only extract video metadata first
|
84 |
}
|
85 |
|
86 |
# Update options with format-specific settings
|
87 |
ydl_opts.update(format_opts)
|
88 |
|
89 |
+
# Progress elements
|
90 |
progress_bar = st.progress(0)
|
91 |
status_text = st.empty()
|
92 |
|
|
|
104 |
|
105 |
ydl_opts['progress_hooks'] = [progress_hook]
|
106 |
|
107 |
+
# First, try to extract info without downloading
|
108 |
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
109 |
+
try:
|
110 |
+
info = ydl.extract_info(url, download=False)
|
111 |
+
if info is None:
|
112 |
+
st.error("Could not fetch video information. The video might be private or age-restricted.")
|
113 |
+
return None
|
114 |
+
|
115 |
+
# If info extraction successful, proceed with download
|
116 |
+
ydl_opts['extract_flat'] = False # Now enable full extraction
|
117 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl_download:
|
118 |
+
filename = ydl_download.prepare_filename(info)
|
119 |
+
ydl_download.download([url])
|
120 |
+
|
121 |
+
# Check if file exists and has size > 0
|
122 |
+
if os.path.exists(filename) and os.path.getsize(filename) > 0:
|
123 |
+
return filename
|
124 |
+
else:
|
125 |
+
st.error("Download completed but file appears to be empty or missing.")
|
126 |
+
return None
|
127 |
+
|
128 |
+
except yt_dlp.utils.DownloadError as e:
|
129 |
+
st.error(f"Download Error: {str(e)}")
|
130 |
+
return None
|
131 |
+
except Exception as e:
|
132 |
+
st.error(f"An unexpected error occurred: {str(e)}")
|
133 |
+
return None
|
134 |
|
135 |
except Exception as e:
|
136 |
+
st.error(f"An error occurred during setup: {str(e)}")
|
137 |
return None
|
138 |
|
139 |
# Download button
|
|
|
144 |
downloaded_file_path = download_video(video_url, format_option)
|
145 |
|
146 |
if downloaded_file_path and os.path.exists(downloaded_file_path):
|
147 |
+
try:
|
148 |
+
with open(downloaded_file_path, 'rb') as file:
|
149 |
+
file_data = file.read()
|
150 |
+
if len(file_data) > 0:
|
151 |
+
st.download_button(
|
152 |
+
label="Click here to download",
|
153 |
+
data=file_data,
|
154 |
+
file_name=os.path.basename(downloaded_file_path),
|
155 |
+
mime="application/octet-stream"
|
156 |
+
)
|
157 |
+
st.success("✅ Download ready!")
|
158 |
+
else:
|
159 |
+
st.error("❌ Downloaded file is empty.")
|
160 |
+
except IOError as e:
|
161 |
+
st.error(f"❌ Error reading file: {str(e)}")
|
162 |
else:
|
163 |
+
st.error("❌ Download failed. Please try again with a different video or format.")
|
164 |
except Exception as e:
|
165 |
+
st.error(f"❌ An unexpected error occurred: {str(e)}")
|
166 |
else:
|
167 |
st.warning("⚠️ Please enter a valid YouTube URL.")
|
168 |
|
|
|
176 |
4. Wait for the download to complete
|
177 |
5. Click the download button that appears
|
178 |
|
179 |
+
**Troubleshooting:**
|
180 |
+
- If download fails, try a different format
|
181 |
+
- Some videos might be restricted or private
|
182 |
+
- Make sure the URL is from YouTube
|
183 |
+
""")
|
184 |
+
|
185 |
+
# Clean up old files
|
186 |
+
def cleanup_old_files():
|
187 |
+
try:
|
188 |
+
for file in output_dir.glob('*'):
|
189 |
+
if file.is_file():
|
190 |
+
file.unlink()
|
191 |
+
except Exception as e:
|
192 |
+
st.warning(f"Could not clean up old files: {str(e)}")
|
193 |
+
|
194 |
+
# Run cleanup when the app starts
|
195 |
+
cleanup_old_files()
|