File size: 4,527 Bytes
6856097
 
 
718a117
6856097
718a117
 
6856097
718a117
 
 
 
 
 
 
 
 
 
6856097
718a117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6856097
718a117
 
 
 
6856097
 
 
718a117
 
 
 
6856097
718a117
 
6856097
718a117
 
6856097
718a117
6856097
718a117
 
 
 
 
6856097
718a117
 
 
 
6856097
718a117
 
 
 
 
 
6856097
718a117
6856097
 
718a117
 
 
 
 
 
 
 
 
6856097
718a117
 
6856097
718a117
 
6856097
718a117
6856097
718a117
 
 
 
 
 
 
 
 
 
 
 
 
6856097
718a117
 
 
 
 
 
6856097
 
 
718a117
 
6856097
 
 
718a117
6856097
718a117
 
 
 
 
6856097
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
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"}
    ]
)