Gertie01's picture
Update app.py
f9e6e7c verified
python
import gradio as gr
import cv2
import random
import os
import tempfile
import numpy as np
import yt_dlp
def get_random_frame(youtube_url):
"""
Downloads a video from YouTube and returns a random frame.
"""
if not youtube_url:
raise gr.Error("Please provide a valid YouTube URL.")
# Create a temporary directory for the download
temp_dir = tempfile.mkdtemp()
try:
# Configure yt-dlp options
ydl_opts = {
'format': 'best[ext=mp4]/best', # Prefer MP4 for better OpenCV compatibility
'outtmpl': os.path.join(temp_dir, '%(id)s.%(ext)s'),
'quiet': True,
'no_warnings': True,
}
# Download video info first to check validity
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
try:
info = ydl.extract_info(youtube_url, download=False)
if 'duration' not in info:
raise gr.Error("Could not retrieve video duration. The video might be private or a live stream.")
except Exception as e:
raise gr.Error(f"Invalid YouTube URL or Video unavailable: {str(e)}")
# Download the video
ydl.params['quiet'] = False # Show progress
info = ydl.extract_info(youtube_url, download=True)
video_path = ydl.prepare_filename(info)
# Open the video file using OpenCV
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise gr.Error("Could not open the video file after downloading.")
# Get total number of frames
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
if total_frames == 0:
raise gr.Error("Video has no frames.")
# Select a random frame index
random_frame_idx = random.randint(0, total_frames - 1)
# Set the frame position
cap.set(cv2.CAP_PROP_POS_FRAMES, random_frame_idx)
# Read the frame
ret, frame = cap.read()
cap.release()
if not ret:
raise gr.Error("Failed to read the selected frame.")
# Convert BGR (OpenCV default) to RGB (Gradio/Image default)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
return frame_rgb
except gr.Error:
raise
except Exception as e:
raise gr.Error(f"An unexpected error occurred: {str(e)}")
finally:
# Clean up temporary files
import shutil
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir, ignore_errors=True)
# Gradio 6 Application
with gr.Blocks() as demo:
# Header with required link
gr.HTML("""
<div style="text-align: center; margin-bottom: 20px;">
<h1>YouTube Frame Randomizer</h1>
<p>Enter a YouTube URL to extract a random frame from the video.</p>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #007bff; text-decoration: none; font-weight: bold;">Built with anycoder</a>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
url_input = gr.Textbox(
label="YouTube URL",
placeholder="https://www.youtube.com/watch?v=...",
lines=1
)
randomize_btn = gr.Button("Get Random Frame", variant="primary", size="lg")
gr.Markdown("""
### How it works:
1. Paste a YouTube link.
2. Click the button.
3. The app downloads the video (this may take a moment).
4. A random timestamp is selected and the frame is displayed.
""")
with gr.Column(scale=2):
output_image = gr.Image(
label="Random Frame",
type="numpy",
interactive=False
)
# Event listener
randomize_btn.click(
fn=get_random_frame,
inputs=url_input,
outputs=output_image,
api_visibility="public"
)
# Launch the app with Gradio 6 syntax
# Note: theme, css, and footer_links are now parameters of demo.launch()
demo.launch(
theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="cyan",
),
footer_links=[
{"label": "Gradio", "url": "https://gradio.app"},
{"label": "Hugging Face", "url": "https://huggingface.co"},
{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}
]
)