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

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -406
app.py DELETED
@@ -1,406 +0,0 @@
1
- import gradio as gr
2
- import yt_dlp
3
- import os
4
- import tempfile
5
- import shutil
6
- from pathlib import Path
7
- import re
8
-
9
- class YouTubeDownloader:
10
- def __init__(self):
11
- self.download_dir = tempfile.mkdtemp()
12
-
13
- def is_valid_youtube_url(self, url):
14
- """Validate if the URL is a valid YouTube 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
- """Get detailed video information without downloading"""
23
- if not url or not url.strip():
24
- return None, "❌ Please enter a YouTube URL"
25
-
26
- if not self.is_valid_youtube_url(url):
27
- return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"
28
-
29
- try:
30
- progress(0.2, desc="Fetching video information...")
31
-
32
- # Configure yt-dlp options for info extraction
33
- ydl_opts = {
34
- 'noplaylist': True,
35
- 'extract_flat': False,
36
- }
37
- if cookiefile:
38
- ydl_opts['cookiefile'] = cookiefile
39
-
40
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
41
- try:
42
- info = ydl.extract_info(url, download=False)
43
-
44
- # Extract detailed information
45
- video_info = {
46
- 'title': info.get('title', 'Unknown'),
47
- 'description': info.get('description', 'No description available'),
48
- 'duration': info.get('duration', 0),
49
- 'view_count': info.get('view_count', 0),
50
- 'like_count': info.get('like_count', 0),
51
- 'comment_count': info.get('comment_count', 0),
52
- 'upload_date': info.get('upload_date', ''),
53
- 'uploader': info.get('uploader', 'Unknown'),
54
- 'channel': info.get('channel', 'Unknown'),
55
- 'channel_followers': info.get('channel_follower_count', 0),
56
- 'tags': info.get('tags', []),
57
- 'categories': info.get('categories', []),
58
- 'thumbnail': info.get('thumbnail', ''),
59
- 'webpage_url': info.get('webpage_url', url)
60
- }
61
-
62
- progress(1.0, desc="Information retrieved!")
63
-
64
- return video_info, "βœ… Video information retrieved successfully"
65
-
66
- except yt_dlp.DownloadError as e:
67
- error_msg = str(e)
68
- if "Video unavailable" in error_msg:
69
- return None, "❌ Video is unavailable or private"
70
- elif "age-restricted" in error_msg.lower():
71
- return None, "❌ Video is age-restricted"
72
- else:
73
- return None, f"❌ Failed to get video info: {error_msg}"
74
-
75
- except Exception as e:
76
- return None, f"❌ An unexpected error occurred: {str(e)}"
77
-
78
- def download_video(self, url, progress=gr.Progress(),cookiefile=None):
79
- """Download YouTube video using yt-dlp"""
80
- if not url or not url.strip():
81
- return None, "❌ Please enter a YouTube URL"
82
-
83
- if not self.is_valid_youtube_url(url):
84
- return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"
85
-
86
- try:
87
- progress(0.1, desc="Initializing download...")
88
-
89
- # Configure yt-dlp options
90
- ydl_opts = {
91
- 'format': 'best[ext=mp4]/best', # Prefer mp4 format
92
- 'outtmpl': os.path.join(self.download_dir, '%(title)s.%(ext)s'),
93
- 'noplaylist': True, # Download only single video, not playlist
94
- }
95
- if cookiefile:
96
- ydl_opts['cookiefile'] = cookiefile
97
-
98
- progress(0.3, desc="Fetching video information...")
99
-
100
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
101
- # Get video info first
102
- try:
103
- info = ydl.extract_info(url, download=False)
104
- video_title = info.get('title', 'Unknown')
105
- duration = info.get('duration', 0)
106
-
107
- progress(0.5, desc=f"Downloading: {video_title[:50]}...")
108
-
109
- # Download the video
110
- ydl.download([url])
111
-
112
- progress(0.9, desc="Finalizing download...")
113
-
114
- # Find the downloaded file
115
- downloaded_files = list(Path(self.download_dir).glob('*'))
116
- if downloaded_files:
117
- downloaded_file = downloaded_files[0]
118
- file_size = downloaded_file.stat().st_size / (1024 * 1024) # Size in MB
119
-
120
- progress(1.0, desc="Download completed!")
121
-
122
- success_message = f"βœ… Successfully downloaded: {video_title}\n"
123
- success_message += f"πŸ“ File size: {file_size:.1f} MB\n"
124
- success_message += f"⏱️ Duration: {duration//60}:{duration%60:02d}" if duration else ""
125
-
126
- return str(downloaded_file), success_message
127
- else:
128
- return None, "❌ Download completed but file not found"
129
-
130
- except yt_dlp.DownloadError as e:
131
- error_msg = str(e)
132
- if "Video unavailable" in error_msg:
133
- return None, "❌ Video is unavailable or private"
134
- elif "age-restricted" in error_msg.lower():
135
- return None, "❌ Video is age-restricted and cannot be downloaded"
136
- elif "copyright" in error_msg.lower():
137
- return None, "❌ Video cannot be downloaded due to copyright restrictions"
138
- else:
139
- return None, f"❌ Download failed: {error_msg}"
140
-
141
- except Exception as e:
142
- return None, f"❌ An unexpected error occurred: {str(e)}"
143
-
144
- def format_video_info(self, video_info):
145
- """Format video information for display"""
146
- if not video_info:
147
- return "No video information available"
148
-
149
- # Format duration
150
- duration = video_info.get('duration', 0)
151
- if duration:
152
- minutes = duration // 60
153
- seconds = duration % 60
154
- duration_str = f"{minutes}:{seconds:02d}"
155
- else:
156
- duration_str = "Unknown"
157
-
158
- # Format upload date
159
- upload_date = video_info.get('upload_date', '')
160
- if upload_date and len(upload_date) == 8:
161
- formatted_date = f"{upload_date[6:8]}/{upload_date[4:6]}/{upload_date[:4]}"
162
- else:
163
- formatted_date = "Unknown"
164
-
165
- # Format numbers with commas
166
- def format_number(num):
167
- if isinstance(num, (int, float)) and num > 0:
168
- return f"{int(num):,}"
169
- return "0"
170
-
171
- # Get video details
172
- title = video_info.get('title', 'Unknown')
173
- channel = video_info.get('channel', 'Unknown')
174
- uploader = video_info.get('uploader', 'Unknown')
175
- views = format_number(video_info.get('view_count', 0))
176
- likes = format_number(video_info.get('like_count', 0))
177
- comments = format_number(video_info.get('comment_count', 0))
178
- subscribers = format_number(video_info.get('channel_followers', 0))
179
- description = video_info.get('description', 'No description available')
180
- tags = video_info.get('tags', [])
181
-
182
- # Create detailed analysis
183
- info_text = f"""VIDEO ANALYSIS RESULTS
184
- ========================
185
-
186
- BASIC INFORMATION:
187
- - Title: {title}
188
- - Channel: {channel}
189
- - Uploader: {uploader}
190
- - Duration: {duration_str}
191
- - Upload Date: {formatted_date}
192
-
193
- ENGAGEMENT STATISTICS:
194
- - Total Views: {views}
195
- - Total Likes: {likes}
196
- - Total Comments: {comments}
197
- - Channel Subscribers: {subscribers}
198
-
199
- CONTENT TAGS:
200
- {', '.join(tags[:15]) if tags else 'No tags available'}
201
-
202
- VIDEO DESCRIPTION:
203
- {description[:1000]}{'...(truncated)' if len(description) > 1000 else ''}
204
-
205
- ANALYSIS SUMMARY:
206
- - Video has {views} views with {likes} likes
207
- - Engagement rate based on likes to views ratio
208
- - Video duration is {duration_str}
209
- - Posted on {formatted_date}
210
- - Contains {len(tags)} tags for discoverability"""
211
-
212
- return info_text
213
-
214
- def cleanup(self):
215
- """Clean up temporary files"""
216
- try:
217
- shutil.rmtree(self.download_dir, ignore_errors=True)
218
- except:
219
- pass
220
-
221
- # Initialize downloader
222
- downloader = YouTubeDownloader()
223
-
224
- # Create Gradio interface
225
- def create_interface():
226
- with gr.Blocks(
227
- title="YouTube Video Downloader & Analyzer",
228
- theme="soft",
229
- css="""
230
- .container {
231
- max-width: 900px;
232
- margin: 0 auto;
233
- }
234
- .header {
235
- text-align: center;
236
- margin-bottom: 2rem;
237
- }
238
- .instructions {
239
- background-color: #f8f9fa;
240
- padding: 1rem;
241
- border-radius: 8px;
242
- margin-bottom: 1rem;
243
- }
244
- """
245
- ) as demo:
246
-
247
- gr.HTML("""
248
- <div class="header">
249
- <h1>YouTube Video Downloader & Analyzer</h1>
250
- <p>Download YouTube videos and get detailed analysis results</p>
251
- </div>
252
- """)
253
-
254
- gr.HTML("""
255
- <div class="instructions">
256
- <h3>How to use:</h3>
257
- <ul>
258
- <li>1. Enter a YouTube video URL</li>
259
- <li>2. Click "Download Video" to download the video file</li>
260
- <li>3. After download, click "Show Analysis Results" to see detailed video information</li>
261
- <li>4. View comprehensive statistics including views, likes, comments, description, and more</li>
262
- </ul>
263
- <p><strong>Note:</strong> This tool respects YouTube's terms of service. Only download videos you have permission to download.</p>
264
- </div>
265
- """)
266
-
267
- # State to store video info
268
- video_info_state = gr.State(value=None)
269
-
270
- url_input = gr.Textbox(
271
- label="YouTube URL",
272
- placeholder="https://www.youtube.com/watch?v=...",
273
- lines=1,
274
- max_lines=1
275
- )
276
-
277
- cookies_input = gr.File(
278
- label="Upload cookies.txt (optional for age-restricted/protected videos)",
279
- type="filepath",
280
- file_types=[".txt"],
281
- visible=True
282
- )
283
-
284
- download_btn = gr.Button(
285
- "Download Video",
286
- variant="primary",
287
- size="lg"
288
- )
289
-
290
- status_output = gr.Textbox(
291
- label="Download Status",
292
- lines=3,
293
- max_lines=5,
294
- interactive=False
295
- )
296
-
297
- file_output = gr.File(
298
- label="Downloaded Video",
299
- visible=False
300
- )
301
-
302
- analysis_btn = gr.Button(
303
- "Show Analysis Results",
304
- variant="secondary",
305
- size="lg",
306
- visible=False
307
- )
308
-
309
- analysis_output = gr.Textbox(
310
- label="Video Analysis Results",
311
- lines=20,
312
- max_lines=25,
313
- interactive=False,
314
- visible=False
315
- )
316
-
317
- # Event handlers
318
- def handle_download(url,cookies_path):
319
- if not url or not url.strip():
320
- return "Please enter a YouTube URL", gr.File(visible=False), gr.Button(visible=False), None
321
-
322
- # Set cookies path if provided
323
- cookiefile = cookies_path if cookies_path and os.path.exists(cookies_path) else None
324
-
325
- # First get video info and store it
326
- video_info, info_message = downloader.get_video_info(url,cookiefile=cookiefile)
327
-
328
- # Then download the video
329
- file_path, download_message = downloader.download_video(url,cookiefile=cookiefile)
330
-
331
- if file_path and video_info:
332
- success_message = f"{download_message}\n\nVideo downloaded successfully! Click 'Show Analysis Results' to see detailed information."
333
- return (
334
- success_message,
335
- gr.File(value=file_path, visible=True),
336
- gr.Button(visible=True),
337
- video_info
338
- )
339
- elif file_path:
340
- return (
341
- f"{download_message}\n\nVideo downloaded but analysis data unavailable.",
342
- gr.File(value=file_path, visible=True),
343
- gr.Button(visible=False),
344
- None
345
- )
346
- else:
347
- return (
348
- f"❌ Error: {download_message}",
349
- gr.File(visible=False),
350
- gr.Button(visible=False),
351
- None
352
- )
353
-
354
- def show_analysis(video_info):
355
- if video_info:
356
- formatted_info = downloader.format_video_info(video_info)
357
- return formatted_info, gr.Textbox(visible=True)
358
- else:
359
- return "No analysis data available.", gr.Textbox(visible=True)
360
-
361
- # Button click events
362
- download_btn.click(
363
- fn=handle_download,
364
- inputs=[url_input,cookies_input],
365
- outputs=[status_output, file_output, analysis_btn, video_info_state],
366
- show_progress="full"
367
- )
368
-
369
- analysis_btn.click(
370
- fn=show_analysis,
371
- inputs=[video_info_state],
372
- outputs=[analysis_output, analysis_output]
373
- )
374
-
375
- # Allow Enter key to trigger download
376
- url_input.submit(
377
- fn=handle_download,
378
- inputs=[url_input,cookies_input],
379
- outputs=[status_output, file_output, analysis_btn, video_info_state],
380
- show_progress="full"
381
- )
382
-
383
- gr.HTML("""
384
- <div style="margin-top: 2rem; text-align: center; color: #666;">
385
- <p><strong>Legal Notice:</strong> Please ensure you have the right to download the content.
386
- Respect copyright laws and YouTube's terms of service.</p>
387
- </div>
388
- """)
389
-
390
- return demo
391
-
392
- # Create and launch the app
393
- if __name__ == "__main__":
394
- demo = create_interface()
395
-
396
- # Clean up on exit
397
- import atexit
398
- atexit.register(downloader.cleanup)
399
-
400
- # Launch the app
401
- demo.launch()
402
- #server_name="0.0.0.0",
403
- #server_port=5000,
404
- #share=False,
405
- #show_error=True
406
-