"""Search YouTube for videos matching a query (no API key required)."""
import json
import logging
from youtube_search import YoutubeSearch
logger = logging.getLogger(__name__)
TOOL_NAME = "search_youtube_videos"
TOOL_DESCRIPTION = (
"Search YouTube for videos matching a query. Returns titles, "
"URLs, durations, channels, and thumbnails without requiring "
"an API key."
)
TOOL_PARAMETERS = {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search term to look for on YouTube.",
},
"limit": {
"type": "integer",
"description": "Maximum number of results (default 5, max 20).",
},
},
"required": ["query"],
}
[docs]
async def run(query: str, limit: int = 5, ctx=None) -> str:
"""Execute this tool and return the result.
Args:
query (str): Search query or input string.
limit (int): Maximum number of items.
ctx: Tool execution context providing access to bot internals.
Returns:
str: Result string.
"""
if not query or not query.strip():
return json.dumps({"error": "Missing required argument: query cannot be empty."})
limit = max(1, min(limit, 20))
logger.info(f"search_youtube_videos: query='{query}', limit={limit}")
try:
results = YoutubeSearch(query, max_results=limit).to_dict()
if not results:
return json.dumps({
"success": True,
"query": query,
"results": [],
"message": "No videos found for this query.",
})
videos = []
for video in results:
video_id = video.get("id", "")
videos.append({
"title": video.get("title", "Unknown"),
"id": video_id,
"url": f"https://www.youtube.com/watch?v={video_id}" if video_id else video.get("url_suffix", ""),
"duration": video.get("duration", "Unknown"),
"channel": video.get("channel", "Unknown"),
"views": video.get("views", "Unknown"),
"published": video.get("publish_time", "Unknown"),
"thumbnail": f"https://i.ytimg.com/vi/{video_id}/hqdefault.jpg" if video_id else "",
})
logger.info(f"Found {len(videos)} videos for query: '{query}'")
return json.dumps({
"success": True,
"query": query,
"count": len(videos),
"results": videos,
}, indent=2)
except Exception as e:
logger.error(f"Error searching YouTube for '{query}': {e}")
return json.dumps({"error": f"Failed to search YouTube: {str(e)}"})