webscarper / app.py
mobenta's picture
Update app.py
073280f verified
raw
history blame
7.12 kB
import yt_dlp
import logging
import gradio as gr
import re
# Configure logging for debugging purposes
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# Function to search YouTube videos using yt-dlp for better reliability
def youtube_search(query, max_results=50):
ydl_opts = {
'quiet': False, # Set to False to get more detailed output from yt-dlp
'extract_flat': 'in_playlist',
'logger': logging.getLogger(), # Use the logging module to capture yt-dlp logs
'simulate': True,
'noplaylist': True, # To avoid playlist entries
}
search_url = f"ytsearch{max_results}:{query}"
logging.debug(f"Starting YouTube search for query: {query}")
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
result = ydl.extract_info(search_url, download=False)
gallery_items = []
detailed_entries = []
if 'entries' in result:
logging.debug(f"Number of entries found: {len(result['entries'])}")
for entry in result['entries']:
video_id = entry.get('id')
thumbnail_url = entry.get('thumbnail') if entry.get('thumbnail') else "https://via.placeholder.com/150"
video_title = entry.get('title', "Unknown Title")
if video_id:
# Collect and display details
print("\n==============================")
print("Video Details:")
print("==============================")
print(f"ID: {entry.get('id', 'N/A')}")
print(f"Title: {entry.get('title', 'N/A')}")
print(f"Uploader: {entry.get('uploader', 'N/A')}")
print(f"Uploader ID: {entry.get('uploader_id', 'N/A')}")
print(f"Upload Date: {entry.get('upload_date', 'N/A')}")
print(f"Description: {entry.get('description', 'N/A')}")
print(f"Duration (seconds): {entry.get('duration', 'N/A')}")
print(f"View Count: {entry.get('view_count', 'N/A')}")
print(f"Like Count: {entry.get('like_count', 'N/A')}")
print(f"Dislike Count: {entry.get('dislike_count', 'N/A')}")
print(f"Comment Count: {entry.get('comment_count', 'N/A')}")
print(f"Average Rating: {entry.get('average_rating', 'N/A')}")
print(f"Thumbnail URL: {entry.get('thumbnail', 'N/A')}")
print(f"Webpage URL: {entry.get('webpage_url', 'N/A')}")
print(f"Channel URL: {entry.get('channel_url', 'N/A')}")
print(f"Categories: {entry.get('categories', 'N/A')}")
print(f"Tags: {entry.get('tags', 'N/A')}")
print(f"Channel ID: {entry.get('channel_id', 'N/A')}")
print(f"Age Restriction: {entry.get('age_limit', 'N/A')}")
print(f"Is Live: {entry.get('is_live', 'N/A')}")
print(f"FPS: {entry.get('fps', 'N/A')}")
print(f"Resolution: {entry.get('resolution', 'N/A')}")
print(f"Aspect Ratio: {entry.get('aspect_ratio', 'N/A')}")
print(f"Video Codec: {entry.get('vcodec', 'N/A')}")
print(f"Audio Codec: {entry.get('acodec', 'N/A')}")
print("==============================\n")
gallery_items.append((thumbnail_url, video_id, video_title))
detailed_entries.append(entry)
else:
logging.warning("No entries found in search result.")
return gallery_items, ""
except Exception as e:
error_message = f"Error during YouTube yt-dlp request: {e}"
logging.error(error_message)
return [], error_message
# Function to display the video using the video URL
def show_video(video_url):
video_id = None
patterns = [
r"youtube\.com/watch\?v=([^&?\/]+)",
r"youtube\.com/embed/([^&?\/]+)",
r"youtube\.com/v/([^&?\/]+)",
r"youtu\.be/([^&?\/]+)"
]
for pattern in patterns:
match = re.search(pattern, video_url)
if match:
video_id = match.group(1)
logging.debug(f"Extracted video ID: {video_id}")
break
if not video_id:
logging.error("Invalid YouTube URL. Please enter a valid YouTube video link.")
return "Invalid YouTube URL. Please enter a valid YouTube video link."
embed_url = f"https://www.youtube.com/embed/{video_id}"
logging.debug(f"Embed URL generated: {embed_url}")
html_code = f'''
<iframe width="560" height="315" src="{embed_url}"
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
'''
return html_code
# Create the Gradio interface
with gr.Blocks() as demo:
gr.Markdown("## YouTube Video Search, Selection, and Playback")
with gr.Row():
with gr.Column(scale=3):
search_query_input = gr.Textbox(label="Search YouTube", placeholder="Enter your search query here")
search_button = gr.Button("Search")
search_output = gr.Gallery(label="Search Results", columns=5, height="1500px")
error_output = gr.Textbox(label="Error Message", interactive=False, visible=False)
with gr.Column(scale=2):
selected_video_link = gr.Textbox(label="Selected Video Link", interactive=False)
play_video_button = gr.Button("Play Video")
video_output = gr.HTML(label="Video Player")
# Define search button behavior
def update_search_results(query):
gallery_items, error_message = youtube_search(query)
if error_message:
return [], error_message, gr.update(visible=True)
gallery_items_display = [(item[0], item[1]) for item in gallery_items]
return gallery_items_display, "", gr.update(visible=False)
# Update the selected video link field when a video is clicked in the gallery
def on_video_select(evt: gr.SelectData):
selected_video_id = evt.value["caption"]
video_url = f"https://www.youtube.com/watch?v={selected_video_id}"
logging.debug(f"Video selected: {video_url}")
return video_url
# Play the video when the Play Video button is clicked
def play_video(video_url):
logging.debug(f"Playing video with URL: {video_url}")
return show_video(video_url)
search_button.click(update_search_results, inputs=search_query_input, outputs=[search_output, error_output, error_output])
search_output.select(on_video_select, inputs=None, outputs=selected_video_link)
play_video_button.click(play_video, inputs=selected_video_link, outputs=video_output)
# Launch the Gradio interface
demo.launch()