thumbnail-grab / app.py
namelessai's picture
Create app.py
8f5a1d1 verified
# First, make sure you have the required libraries installed:
# pip install gradio requests
import gradio as gr
import requests
import re
from PIL import Image
from io import BytesIO
def extract_video_id(url):
"""
Extracts the YouTube video ID from a variety of URL formats.
"""
# This regex covers standard, shortened, and embed URLs
regex = r"(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})"
match = re.search(regex, url)
if match:
return match.group(1)
return None
def get_youtube_thumbnail(url):
"""
Fetches the highest quality thumbnail for a given YouTube URL.
"""
if not url or not url.strip():
# Raise a Gradio error if the input is empty
raise gr.Error("Please enter a YouTube URL.")
video_id = extract_video_id(url)
if video_id:
# URLs for different thumbnail qualities
thumbnail_urls = [
f"https://img.youtube.com/vi/{video_id}/maxresdefault.jpg", # Max resolution
f"https://img.youtube.com/vi/{video_id}/sddefault.jpg", # Standard definition
f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg", # High quality
f"https://img.youtube.com/vi/{video_id}/0.jpg" # Default
]
for thumb_url in thumbnail_urls:
try:
response = requests.get(thumb_url, timeout=5)
# Raise an exception for bad status codes (4xx or 5xx)
response.raise_for_status()
# Open the image to check if it's a valid image and not the "unavailable" placeholder
img = Image.open(BytesIO(response.content))
# YouTube returns a 120x90 placeholder if a specific resolution is not found.
# We check the width to ensure we get a real thumbnail.
if img.width > 121:
return img # Return the first valid, high-quality image found
except requests.exceptions.RequestException as e:
# This handles network errors, timeouts, etc.
print(f"Could not fetch {thumb_url}. Error: {e}")
continue # Try the next URL
except Exception as e:
# This handles errors with opening the image
print(f"Error processing image from {thumb_url}. Error: {e}")
continue
# If all URLs fail, raise an error
raise gr.Error("Could not retrieve thumbnail. The video may be private, deleted, or the URL is incorrect.")
else:
# If the regex fails to find an ID, the URL is invalid
raise gr.Error("Invalid YouTube URL. Please check the link and try again.")
# --- Gradio App Interface ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown(
"""
# 🎬 YouTube Thumbnail Downloader
Paste any YouTube video link below to instantly grab its highest-quality thumbnail.
You can then right-click the image to save it.
"""
)
with gr.Row():
url_input = gr.Textbox(
label="YouTube Video URL",
placeholder="e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ",
scale=4,
)
submit_btn = gr.Button("Get Thumbnail", variant="primary", scale=1)
image_output = gr.Image(label="Thumbnail Preview", type="pil", interactive=False)
# --- Event Listeners ---
submit_btn.click(
fn=get_youtube_thumbnail,
inputs=url_input,
outputs=image_output,
api_name="get_thumbnail"
)
# Add examples for users to try
gr.Examples(
examples=[
"https://www.youtube.com/watch?v=3JZ_D3ELwOQ",
"https://www.youtube.com/watch?v=LXb3EKWsInQ",
"https://youtu.be/i_LwzRVP7bg"
],
inputs=url_input,
outputs=image_output,
fn=get_youtube_thumbnail
)
# Launch the application
if __name__ == "__main__":
demo.launch()