File size: 10,770 Bytes
e1c4426
 
 
 
 
 
 
ca78672
 
e1c4426
 
 
 
 
 
 
 
 
 
 
 
e132b35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e1c4426
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e132b35
ca78672
 
e1c4426
 
 
75f9b66
e1c4426
 
 
 
 
 
 
 
ba2b618
e1c4426
ca78672
e1c4426
ba2b618
e1c4426
 
ca78672
 
e1c4426
75f9b66
 
e1c4426
75f9b66
348e3c3
75f9b66
e1c4426
 
 
 
 
 
 
e132b35
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import gradio as gr
import yt_dlp
import os
import tempfile
import shutil
from pathlib import Path
import re
import uuid
session_data = {}

class YouTubeDownloader:
    def __init__(self):
        self.download_dir = tempfile.mkdtemp()

    def is_valid_youtube_url(self, url):
        youtube_regex = re.compile(
            r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/'
            r'(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})'
        )
        return youtube_regex.match(url) is not None

    def format_video_info(self, video_info):
        """Format video information into a readable report"""
        if not video_info:
            return "❌ No video information available."
        
        # Format duration
        duration = video_info.get('duration', 0)
        duration_str = f"{duration//3600}:{(duration%3600)//60:02d}:{duration%60:02d}" if duration else "Unknown"
        
        # Format upload date
        upload_date = video_info.get('upload_date', '')
        if upload_date and len(upload_date) == 8:
            formatted_date = f"{upload_date[:4]}-{upload_date[4:6]}-{upload_date[6:8]}"
        else:
            formatted_date = upload_date or "Unknown"
        
        # Format numbers
        def format_number(num):
            if num >= 1_000_000:
                return f"{num/1_000_000:.1f}M"
            elif num >= 1_000:
                return f"{num/1_000:.1f}K"
            else:
                return str(num)
        
        # Build the report
        report = f"""
πŸ“Ή VIDEO ANALYSIS REPORT
{'='*50}

πŸ“ BASIC INFORMATION:
β€’ Title: {video_info.get('title', 'Unknown')}
β€’ Channel: {video_info.get('channel', 'Unknown')}
β€’ Uploader: {video_info.get('uploader', 'Unknown')}
β€’ Upload Date: {formatted_date}
β€’ Duration: {duration_str}

πŸ“Š STATISTICS:
β€’ Views: {format_number(video_info.get('view_count', 0))}
β€’ Likes: {format_number(video_info.get('like_count', 0))}
β€’ Comments: {format_number(video_info.get('comment_count', 0))}
β€’ Channel Followers: {format_number(video_info.get('channel_followers', 0))}

🏷️ CATEGORIES & TAGS:
β€’ Categories: {', '.join(video_info.get('categories', [])) or 'None'}
β€’ Tags: {', '.join(video_info.get('tags', [])[:10]) or 'None'}
{('β€’ More tags...' if len(video_info.get('tags', [])) > 10 else '')}

πŸ“– DESCRIPTION:
{video_info.get('description', 'No description available')[:500]}
{'...' if len(video_info.get('description', '')) > 500 else ''}

πŸ”— VIDEO URL:
{video_info.get('webpage_url', 'Unknown')}
        """
        
        return report.strip()

    def get_video_info(self, url, progress=gr.Progress(), cookiefile=None):
        if not url or not url.strip():
            return None, "❌ Please enter a YouTube URL"

        if not self.is_valid_youtube_url(url):
            return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"

        try:
            progress(0.2, desc="Fetching video information...")
            ydl_opts = {
                'noplaylist': True,
                'extract_flat': False,
            }
            if cookiefile:
                ydl_opts['cookiefile'] = cookiefile

            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                try:
                    info = ydl.extract_info(url, download=False)
                    video_info = {
                        'title': info.get('title', 'Unknown'),
                        'description': info.get('description', 'No description available'),
                        'duration': info.get('duration', 0),
                        'view_count': info.get('view_count', 0),
                        'like_count': info.get('like_count', 0),
                        'comment_count': info.get('comment_count', 0),
                        'upload_date': info.get('upload_date', ''),
                        'uploader': info.get('uploader', 'Unknown'),
                        'channel': info.get('channel', 'Unknown'),
                        'channel_followers': info.get('channel_follower_count', 0),
                        'tags': info.get('tags', []),
                        'categories': info.get('categories', []),
                        'thumbnail': info.get('thumbnail', ''),
                        'webpage_url': info.get('webpage_url', url)
                    }
                    progress(1.0, desc="Information retrieved!")
                    return video_info, "βœ… Video information retrieved successfully"
                except yt_dlp.DownloadError as e:
                    error_msg = str(e)
                    if "Video unavailable" in error_msg:
                        return None, "❌ Video is unavailable or private"
                    elif "age-restricted" in error_msg.lower():
                        return None, "❌ Video is age-restricted"
                    else:
                        return None, f"❌ Failed to get video info: {error_msg}"
        except Exception as e:
            return None, f"❌ An unexpected error occurred: {str(e)}"

    def download_video(self, url, progress=gr.Progress(), cookiefile=None):
        if not url or not url.strip():
            return None, "❌ Please enter a YouTube URL"

        if not self.is_valid_youtube_url(url):
            return None, "❌ Invalid YouTube URL. Please enter a valid YouTube video URL"

        try:
            progress(0.1, desc="Initializing download...")
            ydl_opts = {
                'format': 'best[ext=mp4]/best',
                'outtmpl': os.path.join(self.download_dir, '%(title)s.%(ext)s'),
                'noplaylist': True,
            }
            if cookiefile:
                ydl_opts['cookiefile'] = cookiefile

            progress(0.3, desc="Fetching video information...")
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                try:
                    info = ydl.extract_info(url, download=False)
                    video_title = info.get('title', 'Unknown')
                    duration = info.get('duration', 0)
                    progress(0.5, desc=f"Downloading: {video_title[:50]}...")
                    ydl.download([url])
                    progress(0.9, desc="Finalizing download...")
                    downloaded_files = list(Path(self.download_dir).glob('*'))
                    if downloaded_files:
                        downloaded_file = downloaded_files[0]
                        file_size = downloaded_file.stat().st_size / (1024 * 1024)
                        progress(1.0, desc="Download completed!")
                        success_message = f"βœ… Successfully downloaded: {video_title}\n"
                        success_message += f"πŸ“ File size: {file_size:.1f} MB\n"
                        success_message += f"⏱️ Duration: {duration//60}:{duration%60:02d}" if duration else ""
                        return str(downloaded_file), success_message
                    else:
                        return None, "❌ Download completed but file not found"
                except yt_dlp.DownloadError as e:
                    error_msg = str(e)
                    if "Video unavailable" in error_msg:
                        return None, "❌ Video is unavailable or private"
                    elif "age-restricted" in error_msg.lower():
                        return None, "❌ Video is age-restricted and cannot be downloaded"
                    elif "copyright" in error_msg.lower():
                        return None, "❌ Video cannot be downloaded due to copyright restrictions"
                    else:
                        return None, f"❌ Download failed: {error_msg}"
        except Exception as e:
            return None, f"❌ An unexpected error occurred: {str(e)}"

    def cleanup(self):
        try:
            shutil.rmtree(self.download_dir, ignore_errors=True)
        except:
            pass

downloader = YouTubeDownloader()

def create_interface():
    with gr.Blocks(title="YouTube Video Downloader & Analyzer") as demo:
        url_input = gr.Textbox(label="YouTube URL", placeholder="https://www.youtube.com/watch?v=...")
        cookies_input = gr.File(label="Upload cookies.txt (optional)", type="filepath", file_types=[".txt"])
        download_btn = gr.Button("Download Video")
        status_output = gr.Textbox(label="Download Status")
        file_output = gr.File(label="Downloaded Video", visible=False)
        analysis_btn = gr.Button("Show Analysis Results", visible=False)
        analysis_output = gr.Textbox(label="Video Analysis Results", visible=False, lines=20)
        video_info_state = gr.Textbox(value=False)
        

        def handle_download(url, cookies_path):
            if not url or not url.strip():
                return "Please enter a YouTube URL", gr.File(visible=False), gr.Button(visible=False), None

            cookiefile = cookies_path.strip() if cookies_path and os.path.exists(cookies_path.strip()) else None
            video_info, info_message = downloader.get_video_info(url, cookiefile=cookiefile)
            file_path, download_message = downloader.download_video(url, cookiefile=cookiefile)
            print(f"[DEBUG] Download message: {download_message}")

            if file_path and video_info:
                success_message = f"{download_message}\n\nVideo downloaded successfully! Click 'Show Analysis Results' to see detailed information."
                return success_message, gr.File(value=file_path, visible=True), gr.Button(visible=True), gr.State(video_info)
            elif file_path:
                return f"{download_message}\n\nVideo downloaded but analysis data unavailable.", gr.File(value=file_path, visible=True), gr.Button(visible=False), gr.State("")
            else:
                return f"❌ Download failed:\n{download_message}", gr.File(visible=False), gr.Button(visible=False), gr.State(None)

        def show_analysis(video_info):
            print("[DEBUG] Received session_id:", session_id)
            video_info = session_data.get(session_id)
            if video_info:
                return downloader.format_video_info(video_info), gr.Textbox(visible=True)
            return "❌ No analysis data available.", gr.Textbox(visible=True)

        download_btn.click(handle_download, inputs=[url_input, cookies_input], outputs=[status_output, file_output, analysis_btn, video_info_state])
        analysis_btn.click(show_analysis, inputs=[video_info_state], outputs=[analysis_output])
        url_input.submit(handle_download, inputs=[url_input, cookies_input], outputs=[status_output, file_output, analysis_btn, video_info_state])

    return demo

if __name__ == "__main__":
    demo = create_interface()
    import atexit
    atexit.register(downloader.cleanup)
    demo.launch()