developer28 commited on
Commit
e1c4426
Β·
verified Β·
1 Parent(s): bb7c5f8

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -0
app.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ import yt_dlp
4
+ import os
5
+ import tempfile
6
+ import shutil
7
+ from pathlib import Path
8
+ import re
9
+
10
+ class YouTubeDownloader:
11
+ def __init__(self):
12
+ self.download_dir = tempfile.mkdtemp()
13
+
14
+ def is_valid_youtube_url(self, url):
15
+ youtube_regex = re.compile(
16
+ r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/'
17
+ r'(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})'
18
+ )
19
+ return youtube_regex.match(url) is not None
20
+
21
+ def get_video_info(self, url, progress=gr.Progress(), cookiefile=None):
22
+ if not url or not url.strip():
23
+ return None, "❌ Please enter a YouTube URL"
24
+
25
+ if not self.is_valid_youtube_url(url):
26
+ return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"
27
+
28
+ try:
29
+ progress(0.2, desc="Fetching video information...")
30
+ ydl_opts = {
31
+ 'noplaylist': True,
32
+ 'extract_flat': False,
33
+ }
34
+ if cookiefile:
35
+ ydl_opts['cookiefile'] = cookiefile
36
+
37
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
38
+ try:
39
+ info = ydl.extract_info(url, download=False)
40
+ video_info = {
41
+ 'title': info.get('title', 'Unknown'),
42
+ 'description': info.get('description', 'No description available'),
43
+ 'duration': info.get('duration', 0),
44
+ 'view_count': info.get('view_count', 0),
45
+ 'like_count': info.get('like_count', 0),
46
+ 'comment_count': info.get('comment_count', 0),
47
+ 'upload_date': info.get('upload_date', ''),
48
+ 'uploader': info.get('uploader', 'Unknown'),
49
+ 'channel': info.get('channel', 'Unknown'),
50
+ 'channel_followers': info.get('channel_follower_count', 0),
51
+ 'tags': info.get('tags', []),
52
+ 'categories': info.get('categories', []),
53
+ 'thumbnail': info.get('thumbnail', ''),
54
+ 'webpage_url': info.get('webpage_url', url)
55
+ }
56
+ progress(1.0, desc="Information retrieved!")
57
+ return video_info, "βœ… Video information retrieved successfully"
58
+ except yt_dlp.DownloadError as e:
59
+ error_msg = str(e)
60
+ if "Video unavailable" in error_msg:
61
+ return None, "❌ Video is unavailable or private"
62
+ elif "age-restricted" in error_msg.lower():
63
+ return None, "❌ Video is age-restricted"
64
+ else:
65
+ return None, f"❌ Failed to get video info: {error_msg}"
66
+ except Exception as e:
67
+ return None, f"❌ An unexpected error occurred: {str(e)}"
68
+
69
+ def download_video(self, url, progress=gr.Progress(), cookiefile=None):
70
+ if not url or not url.strip():
71
+ return None, "❌ Please enter a YouTube URL"
72
+
73
+ if not self.is_valid_youtube_url(url):
74
+ return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"
75
+
76
+ try:
77
+ progress(0.1, desc="Initializing download...")
78
+ ydl_opts = {
79
+ 'format': 'best[ext=mp4]/best',
80
+ 'outtmpl': os.path.join(self.download_dir, '%(title)s.%(ext)s'),
81
+ 'noplaylist': True,
82
+ }
83
+ if cookiefile:
84
+ ydl_opts['cookiefile'] = cookiefile
85
+
86
+ progress(0.3, desc="Fetching video information...")
87
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
88
+ try:
89
+ info = ydl.extract_info(url, download=False)
90
+ video_title = info.get('title', 'Unknown')
91
+ duration = info.get('duration', 0)
92
+ progress(0.5, desc=f"Downloading: {video_title[:50]}...")
93
+ ydl.download([url])
94
+ progress(0.9, desc="Finalizing download...")
95
+ downloaded_files = list(Path(self.download_dir).glob('*'))
96
+ if downloaded_files:
97
+ downloaded_file = downloaded_files[0]
98
+ file_size = downloaded_file.stat().st_size / (1024 * 1024)
99
+ progress(1.0, desc="Download completed!")
100
+ success_message = f"βœ… Successfully downloaded: {video_title}\n"
101
+ success_message += f"πŸ“ File size: {file_size:.1f} MB\n"
102
+ success_message += f"⏱️ Duration: {duration//60}:{duration%60:02d}" if duration else ""
103
+ return str(downloaded_file), success_message
104
+ else:
105
+ return None, "❌ Download completed but file not found"
106
+ except yt_dlp.DownloadError as e:
107
+ error_msg = str(e)
108
+ if "Video unavailable" in error_msg:
109
+ return None, "❌ Video is unavailable or private"
110
+ elif "age-restricted" in error_msg.lower():
111
+ return None, "❌ Video is age-restricted and cannot be downloaded"
112
+ elif "copyright" in error_msg.lower():
113
+ return None, "❌ Video cannot be downloaded due to copyright restrictions"
114
+ else:
115
+ return None, f"❌ Download failed: {error_msg}"
116
+ except Exception as e:
117
+ return None, f"❌ An unexpected error occurred: {str(e)}"
118
+
119
+ def cleanup(self):
120
+ try:
121
+ shutil.rmtree(self.download_dir, ignore_errors=True)
122
+ except:
123
+ pass
124
+
125
+ downloader = YouTubeDownloader()
126
+
127
+ def create_interface():
128
+ with gr.Blocks(title="YouTube Video Downloader & Analyzer") as demo:
129
+ url_input = gr.Textbox(label="YouTube URL", placeholder="https://www.youtube.com/watch?v=...")
130
+ cookies_input = gr.File(label="Upload cookies.txt (optional)", type="filepath", file_types=[".txt"])
131
+ download_btn = gr.Button("Download Video")
132
+ status_output = gr.Textbox(label="Download Status")
133
+ file_output = gr.File(label="Downloaded Video", visible=False)
134
+ analysis_btn = gr.Button("Show Analysis Results", visible=False)
135
+ analysis_output = gr.Textbox(label="Video Analysis Results", visible=False)
136
+ video_info_state = gr.State(value=None)
137
+
138
+ def handle_download(url, cookies_path):
139
+ if not url or not url.strip():
140
+ return "Please enter a YouTube URL", gr.File(visible=False), gr.Button(visible=False), None
141
+
142
+ cookiefile = cookies_path.strip() if cookies_path and os.path.exists(cookies_path.strip()) else None
143
+ video_info, info_message = downloader.get_video_info(url, cookiefile=cookiefile)
144
+ file_path, download_message = downloader.download_video(url, cookiefile=cookiefile)
145
+ print(f"[DEBUG] Download message: {download_message}")
146
+
147
+ if file_path and video_info:
148
+ success_message = f"{download_message}\n\nVideo downloaded successfully! Click 'Show Analysis Results' to see detailed information."
149
+ return success_message, gr.File(value=file_path, visible=True), gr.Button(visible=True), video_info
150
+ elif file_path:
151
+ return f"{download_message}\n\nVideo downloaded but analysis data unavailable.", gr.File(value=file_path, visible=True), gr.Button(visible=False), None
152
+ else:
153
+ return f"❌ Download failed:\n{download_message}", gr.File(visible=False), gr.Button(visible=False), None
154
+
155
+ def show_analysis(video_info):
156
+ if video_info:
157
+ return downloader.format_video_info(video_info), gr.Textbox(visible=True)
158
+ return "No analysis data available.", gr.Textbox(visible=True)
159
+
160
+ download_btn.click(handle_download, inputs=[url_input, cookies_input], outputs=[status_output, file_output, analysis_btn, video_info_state])
161
+ analysis_btn.click(show_analysis, inputs=[video_info_state], outputs=[analysis_output, analysis_output])
162
+ url_input.submit(handle_download, inputs=[url_input, cookies_input], outputs=[status_output, file_output, analysis_btn, video_info_state])
163
+
164
+ return demo
165
+
166
+ if __name__ == "__main__":
167
+ demo = create_interface()
168
+ import atexit
169
+ atexit.register(downloader.cleanup)
170
+ demo.launch()