developer28's picture
Update app.py
ca78672 verified
raw
history blame
10.8 kB
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()