Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| import pafy | |
| import random | |
| from typing import Tuple | |
| from pathlib import Path | |
| import tempfile | |
| def extract_random_frames(youtube_url: str, num_frames: int = 5) -> Tuple[list, str]: | |
| """Extract random frames from a YouTube video""" | |
| try: | |
| # Create YouTube video object | |
| video = pafy.new(youtube_url) | |
| best = video.getbest(preftype="mp4") | |
| # Create temporary file | |
| temp_dir = tempfile.mkdtemp() | |
| temp_path = Path(temp_dir) / "temp_video.mp4" | |
| # Download the video | |
| best.download(filepath=str(temp_path)) | |
| # Open video file | |
| cap = cv2.VideoCapture(str(temp_path)) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if total_frames == 0: | |
| raise ValueError("No frames found in video") | |
| # Select random frames | |
| frame_indices = sorted(random.sample(range(total_frames), min(num_frames, total_frames))) | |
| frames = [] | |
| for idx in frame_indices: | |
| cap.set(cv2.CAP_PROP_POS_FRAMES, idx) | |
| ret, frame = cap.read() | |
| if ret: | |
| frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| frames.append(frame) | |
| cap.release() | |
| # Clean up | |
| temp_path.unlink() | |
| Path(temp_dir).rmdir() | |
| if not frames: | |
| raise ValueError("Failed to extract any frames") | |
| return frames, f"Extracted {len(frames)} random frames from '{video.title}'" | |
| except Exception as e: | |
| return [], f"Error: {str(e)}" | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# 🎥 YouTube Frame Randomizer") | |
| gr.Markdown("Extract random frames from any YouTube video") | |
| with gr.Row(): | |
| with gr.Column(): | |
| youtube_url = gr.Textbox( | |
| label="YouTube URL", | |
| placeholder="Paste YouTube video URL here...", | |
| info="Example: https://www.youtube.com/watch?v=dQw4w9WgXcQ" | |
| ) | |
| num_frames = gr.Slider( | |
| minimum=1, | |
| maximum=20, | |
| value=5, | |
| step=1, | |
| label="Number of Frames to Extract" | |
| ) | |
| extract_btn = gr.Button("Extract Frames", variant="primary") | |
| with gr.Column(): | |
| gallery = gr.Gallery( | |
| label="Extracted Frames", | |
| columns=3, | |
| height="auto", | |
| object_fit="contain" | |
| ) | |
| info_output = gr.Textbox(label="Video Info", interactive=False) | |
| # Built with anycoder attribution | |
| gr.Markdown( | |
| "[Built with anycoder](https://huggingface.co/spaces/akhaliq/anycoder)", | |
| elem_classes=["footer"] | |
| ) | |
| extract_btn.click( | |
| fn=extract_random_frames, | |
| inputs=[youtube_url, num_frames], | |
| outputs=[gallery, info_output], | |
| api_visibility="public" | |
| ) | |
| # Launch with modern theme and settings | |
| demo.launch( | |
| theme=gr.themes.Soft( | |
| primary_hue="blue", | |
| secondary_hue="indigo", | |
| font=gr.themes.GoogleFont("Inter") | |
| ), | |
| css=""" | |
| .footer { | |
| text-align: center; | |
| margin-top: 20px; | |
| color: #666; | |
| } | |
| .footer a { | |
| color: #666; | |
| text-decoration: none; | |
| } | |
| .footer a:hover { | |
| text-decoration: underline; | |
| } | |
| """ | |
| ) |