Iammcqwory commited on
Commit
3f32c95
·
verified ·
1 Parent(s): b67b878

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -178
app.py CHANGED
@@ -1,198 +1,138 @@
1
  import streamlit as st
2
- from pytube import YouTube
3
  import tempfile
4
  import os
5
- from typing import Optional
6
- import re
7
 
8
- def setup_page_config():
9
- st.set_page_config(
10
- page_title="YouTube Downloader",
11
- page_icon="🎥",
12
- layout="wide"
13
- )
14
 
15
- def create_sidebar():
16
- st.sidebar.title("YouTube Downloader App")
17
- st.sidebar.markdown("""
18
- **Step-by-Step Guide:**
19
- 1. Enter a YouTube URL
20
- 2. Choose quality (Video/Audio)
21
- 3. Click download
22
- 4. Save to your device
23
-
24
- **Supported Formats:**
25
- - Video: MP4 (Multiple resolutions)
26
- - Audio: MP3 (Multiple bitrates)
27
- """)
28
 
29
- def validate_youtube_url(url: str) -> bool:
30
- youtube_regex = r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})'
31
- return bool(re.match(youtube_regex, url))
32
 
33
- def fetch_video_streams(url: str) -> Optional[YouTube]:
34
- try:
35
- yt = YouTube(url)
36
- video_streams = yt.streams.filter(progressive=True, file_extension='mp4')
37
- if not video_streams:
38
- st.error("No video streams found for this URL")
39
- return None
40
-
41
- resolutions = list({stream.resolution for stream in video_streams})
42
- resolutions.sort(reverse=True, key=lambda x: int(x[:-1]) if x else 0)
43
-
44
- st.session_state['video_streams'] = video_streams
45
- st.session_state['video_resolutions'] = resolutions
46
- st.session_state['video_title'] = yt.title
47
- return yt
48
- except Exception as e:
49
- st.error(f"Error fetching video: {str(e)}")
50
- return None
51
 
52
- def fetch_audio_streams(url: str) -> Optional[YouTube]:
53
- try:
54
- yt = YouTube(url)
55
- audio_streams = yt.streams.filter(only_audio=True, file_extension='webm')
56
- if not audio_streams:
57
- st.error("No audio streams found for this URL")
58
- return None
59
-
60
- bitrates = list({stream.abr for stream in audio_streams if stream.abr})
61
- bitrates.sort(reverse=True, key=lambda x: int(x.split('kbps')[0]))
62
-
63
- st.session_state['audio_streams'] = audio_streams
64
- st.session_state['audio_bitrates'] = bitrates
65
- st.session_state['audio_title'] = yt.title
66
- return yt
67
- except Exception as e:
68
- st.error(f"Error fetching audio: {str(e)}")
69
- return None
70
-
71
- def handle_video_download(stream, title: str):
72
- try:
73
- with tempfile.TemporaryDirectory() as temp_dir:
74
- filename = f"{title}.mp4"
75
- filename = re.sub(r'[<>:"/\\|?*]', '_', filename) # Remove invalid characters
76
- temp_path = os.path.join(temp_dir, filename)
77
-
78
- with st.spinner("Preparing video for download..."):
79
- stream.download(temp_dir, filename)
80
-
81
- with open(temp_path, 'rb') as f:
82
- st.download_button(
83
- label="💾 Save Video",
84
- data=f.read(),
85
- file_name=filename,
86
- mime="video/mp4",
87
- key="video_download"
88
- )
89
- except Exception as e:
90
- st.error(f"Download failed: {str(e)}")
91
-
92
- def handle_audio_download(stream, title: str):
93
- try:
94
- with tempfile.TemporaryDirectory() as temp_dir:
95
- filename = f"{title}.mp3"
96
- filename = re.sub(r'[<>:"/\\|?*]', '_', filename) # Remove invalid characters
97
- temp_path = os.path.join(temp_dir, filename)
98
-
99
- with st.spinner("Preparing audio for download..."):
100
- stream.download(temp_dir, filename)
101
-
102
- with open(temp_path, 'rb') as f:
103
- st.download_button(
104
- label="🎵 Save Audio",
105
- data=f.read(),
106
- file_name=filename,
107
- mime="audio/mpeg",
108
- key="audio_download"
109
- )
110
- except Exception as e:
111
- st.error(f"Download failed: {str(e)}")
112
 
113
- def main():
114
- setup_page_config()
115
- create_sidebar()
116
 
117
- st.title("YouTube Downloader App")
118
- st.warning("⚠️ Please ensure you have the right to download content. Respect copyright laws.")
119
-
120
- tab1, tab2 = st.tabs(["📺 Video Downloader", "🎵 Audio Downloader"])
121
-
122
- # Video Downloader Tab
123
- with tab1:
124
- st.markdown("### Download YouTube Videos")
125
- with st.form("video_form", clear_on_submit=False):
126
  url = st.text_input("Enter YouTube URL:", key="video_url")
127
- fetch_btn = st.form_submit_button("🔍 Fetch Video Details")
128
 
129
- if fetch_btn:
130
- if not url:
131
- st.error("Please enter a URL")
132
- elif not validate_youtube_url(url):
133
- st.error("Invalid YouTube URL")
134
- else:
135
- yt = fetch_video_streams(url)
136
- if yt:
137
- st.success("Video details fetched successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- if 'video_streams' in st.session_state:
140
- st.subheader(f"🎥 {st.session_state.get('video_title', 'Untitled')}")
141
- selected_resolution = st.selectbox(
142
- "Select Resolution:",
143
- st.session_state.get('video_resolutions', []),
144
- key="video_resolution"
145
- )
146
-
147
- selected_stream = next(
148
- (s for s in st.session_state['video_streams']
149
- if s.resolution == selected_resolution),
150
- None
151
- )
152
 
153
- if selected_stream:
154
- st.info(f"File size: {selected_stream.filesize / 1024 / 1024:.1f} MB")
155
- if st.button("⬇️ Prepare Video Download"):
156
- handle_video_download(selected_stream, st.session_state['video_title'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- # Audio Downloader Tab
159
- with tab2:
160
- st.markdown("### Download YouTube Audio")
161
- with st.form("audio_form", clear_on_submit=False):
162
  url = st.text_input("Enter YouTube URL:", key="audio_url")
163
- fetch_btn = st.form_submit_button("🔍 Fetch Audio Details")
164
 
165
- if fetch_btn:
166
- if not url:
167
- st.error("Please enter a URL")
168
- elif not validate_youtube_url(url):
169
- st.error("Invalid YouTube URL")
170
- else:
171
- yt = fetch_audio_streams(url)
172
- if yt:
173
- st.success("Audio details fetched successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
- if 'audio_streams' in st.session_state:
176
- st.subheader(f"🎵 {st.session_state.get('audio_title', 'Untitled')}")
177
- selected_bitrate = st.selectbox(
178
- "Select Audio Quality:",
179
- st.session_state.get('audio_bitrates', []),
180
- key="audio_bitrate"
181
- )
182
-
183
- selected_stream = next(
184
- (s for s in st.session_state['audio_streams']
185
- if s.abr == selected_bitrate),
186
- None
187
- )
188
 
189
- if selected_stream:
190
- st.info(f"File size: {selected_stream.filesize / 1024 / 1024:.1f} MB")
191
- if st.button("⬇️ Prepare Audio Download"):
192
- handle_audio_download(selected_stream, st.session_state['audio_title'])
193
-
194
- st.markdown("---")
195
- st.caption("Made with ❤️ by Marcos")
 
 
 
 
 
 
 
196
 
197
- if __name__ == "__main__":
198
- main()
 
 
1
  import streamlit as st
2
+ from pytubefix import YouTube # Use pytubefix
3
  import tempfile
4
  import os
5
+ from urllib.error import HTTPError # For error handling
 
6
 
7
+ st.set_page_config(layout="wide")
 
 
 
 
 
8
 
9
+ # App Layout
10
+ st.sidebar.title("YouTube Downloader")
11
+ st.sidebar.markdown("Made with 💛 for educational use only.")
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # Disclaimer
14
+ st.warning("Warning: Respect copyright laws and YouTube's terms of service.")
 
15
 
16
+ # Create tabs
17
+ tab1, tab2 = st.tabs(["Video Downloader", "Audio Downloader"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
+ # Utility function to handle YouTube object with User-Agent
20
+ def get_youtube(url):
21
+ custom_user_agent = {
22
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
23
+ }
24
+ return YouTube(url, headers=custom_user_agent)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ # Video Downloader Tab
27
+ with tab1:
28
+ st.write("Download YouTube videos in MP4 format.")
29
 
30
+ # State management for video streams
31
+ if not st.session_state.get('video_streams', None):
32
+ with st.form("video_form"):
 
 
 
 
 
 
33
  url = st.text_input("Enter YouTube URL:", key="video_url")
34
+ fetch_btn = st.form_submit_button("Fetch Video Qualities")
35
 
36
+ if fetch_btn and url:
37
+ with st.spinner("Fetching video qualities..."):
38
+ try:
39
+ yt = get_youtube(url)
40
+ video_streams = yt.streams.filter(progressive=True, file_extension='mp4')
41
+ resolutions = sorted(list({stream.resolution for stream in video_streams}), reverse=True)
42
+ st.session_state['video_streams'] = video_streams
43
+ st.session_state['video_resolutions'] = resolutions
44
+ st.session_state['video_title'] = yt.title
45
+ st.experimental_rerun()
46
+ except HTTPError as e:
47
+ st.error(f"HTTP Error {e.code}: {e.reason}")
48
+ except Exception as e:
49
+ st.error(f"Error: {str(e)}")
50
+ else:
51
+ st.subheader(f"Title: {st.session_state.get('video_title', 'Untitled')}")
52
+ selected_resolution = st.selectbox(
53
+ "Select Resolution:",
54
+ st.session_state.get('video_resolutions', []),
55
+ key="video_resolution"
56
+ )
57
 
58
+ selected_stream = next(
59
+ (s for s in st.session_state['video_streams'] if s.resolution == selected_resolution),
60
+ None
61
+ )
62
+
63
+ if selected_stream:
64
+ download_btn = st.button("Download Video")
 
 
 
 
 
 
65
 
66
+ if download_btn:
67
+ with tempfile.TemporaryDirectory() as temp_dir:
68
+ filename = f"{st.session_state['video_title']}.mp4".replace(" ", "_")
69
+ temp_path = os.path.join(temp_dir, filename)
70
+ selected_stream.download(temp_dir, filename)
71
+ with open(temp_path, 'rb') as f:
72
+ st.download_button(
73
+ label="Click here to download",
74
+ data=f.read(),
75
+ file_name=filename,
76
+ mime="video/mp4"
77
+ )
78
+ else:
79
+ st.warning("Selected resolution unavailable. Try another.")
80
+
81
+ # Audio Downloader Tab
82
+ with tab2:
83
+ st.write("Download YouTube audio in MP3 format.")
84
 
85
+ # State management for audio streams
86
+ if not st.session_state.get('audio_streams', None):
87
+ with st.form("audio_form"):
 
88
  url = st.text_input("Enter YouTube URL:", key="audio_url")
89
+ fetch_btn = st.form_submit_button("Fetch Audio Qualities")
90
 
91
+ if fetch_btn and url:
92
+ with st.spinner("Fetching audio qualities..."):
93
+ try:
94
+ yt = get_youtube(url)
95
+ audio_streams = yt.streams.filter(only_audio=True)
96
+ bitrates = sorted(list({f"{stream.abr}kbps" for stream in audio_streams if stream.abr}), reverse=True)
97
+ st.session_state['audio_streams'] = audio_streams
98
+ st.session_state['audio_bitrates'] = bitrates
99
+ st.session_state['audio_title'] = yt.title
100
+ st.experimental_rerun()
101
+ except HTTPError as e:
102
+ st.error(f"HTTP Error {e.code}: {e.reason}")
103
+ except Exception as e:
104
+ st.error(f"Error: {str(e)}")
105
+ else:
106
+ st.subheader(f"Title: {st.session_state.get('audio_title', 'Untitled')}")
107
+ selected_bitrate = st.selectbox(
108
+ "Select Bitrate:",
109
+ st.session_state.get('audio_bitrates', []),
110
+ key="audio_bitrate"
111
+ )
112
 
113
+ selected_stream = next(
114
+ (s for s in st.session_state['audio_streams'] if f"{s.abr}kbps" == selected_bitrate),
115
+ None
116
+ )
117
+
118
+ if selected_stream:
119
+ download_btn = st.button("Download Audio")
 
 
 
 
 
 
120
 
121
+ if download_btn:
122
+ with tempfile.TemporaryDirectory() as temp_dir:
123
+ filename = f"{st.session_state['audio_title']}.mp3".replace(" ", "_")
124
+ temp_path = os.path.join(temp_dir, filename)
125
+ selected_stream.download(temp_dir, filename)
126
+ with open(temp_path, 'rb') as f:
127
+ st.download_button(
128
+ label="Click here to download",
129
+ data=f.read(),
130
+ file_name=filename,
131
+ mime="audio/mpeg"
132
+ )
133
+ else:
134
+ st.warning("Selected bitrate unavailable. Try another.")
135
 
136
+ # Footer
137
+ st.markdown("---")
138
+ st.warning("⚠️ Use this app responsibly. Downloads may be restricted by terms of service ⚠️")