/** * @typedef {Object} Suggestion * @property {string} title * @property {string} id * @property {number=} duration * @property {boolean=} isShort * @property {string=} url * @property {string=} thumbnail * @property {string=} uploaderName * @property {string=} type */ /** @type {{ id: 'yt', label: string, search: (q: string, opts: { limit: number, page?: number, sort?: 'relevance'|'date'|'views' }) => Promise }} */ const handler = { id: 'yt', label: 'YouTube', async search(q, opts) { const { limit = 10, sort = 'relevance' } = opts || {}; try { const API_KEY = process.env.YOUTUBE_API_KEY; if (!API_KEY) { throw new Error('YOUTUBE_API_KEY not configured'); } let order = 'relevance'; if (sort === 'date') order = 'date'; else if (sort === 'views') order = 'viewCount'; const response = await fetch( `https://www.googleapis.com/youtube/v3/search?` + new URLSearchParams({ part: 'snippet', q: q, type: 'video', maxResults: Math.min(limit, 50).toString(), key: API_KEY, order }) ); if (!response.ok) { throw new Error(`YouTube API error: ${response.status}`); } const data = await response.json(); return (data.items || []).map(item => ({ title: item.snippet.title, id: item.id.videoId, url: `https://www.youtube.com/watch?v=${item.id.videoId}`, thumbnail: item.snippet.thumbnails?.medium?.url || item.snippet.thumbnails?.default?.url, uploaderName: item.snippet.channelTitle, type: 'video' })); } catch (error) { console.error('YouTube search error:', error); return []; } } }; export default handler;