Spaces:
Running
Running
| 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"} | |
| ] | |
| ) |