src/video_toys/lib/youtube.ts (68 lines of code) (raw):

/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /* tslint:disable */ // Function to extract YouTube video ID export const getYouTubeVideoId = (url: string): string | null => { try { const parsedUrl = new URL(url); // Handle standard watch URLs (youtube.com/watch?v=...) if ( parsedUrl.hostname === 'www.youtube.com' || parsedUrl.hostname === 'youtube.com' ) { const videoId = parsedUrl.searchParams.get('v'); if (videoId && videoId.length === 11) { return videoId; } } // Handle short URLs (youtu.be/...) if (parsedUrl.hostname === 'youtu.be') { const videoId = parsedUrl.pathname.substring(1); // Remove leading '/' if (videoId && videoId.length === 11) { return videoId; } } // Handle embed URLs (youtube.com/embed/...) if (parsedUrl.pathname.startsWith('/embed/')) { const videoId = parsedUrl.pathname.substring(7); // Length of '/embed/' if (videoId && videoId.length === 11) { return videoId; } } } catch (e) { // Ignore URL parsing errors, means it's likely not a valid URL format console.warn('URL parsing failed:', e); } // Fallback using simplified Regex for other potential edge cases not caught by URL parsing const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; const match = url.match(regExp); if (match && match[2].length === 11) { return match[2]; } return null; }; // Helper function to validate a YouTube video URL export async function validateYoutubeUrl( url: string, ): Promise<{isValid: boolean; error?: string}> { if (getYouTubeVideoId(url)) { return {isValid: true}; } return {isValid: false, error: 'Invalid YouTube URL'}; } // Helper function to extract YouTube video ID and create embed URL export function getYoutubeEmbedUrl(url: string): string { const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; const match = url.match(regExp); const videoId = match && match[2].length === 11 ? match[2] : null; if (videoId) { return `https://www.youtube.com/embed/${videoId}`; } // This fallback is unlikely to be hit if validation is working console.warn( 'Could not extract video ID for embedding, using original URL:', url, ); return url; } export async function getYouTubeVideoTitle(url: string) { const oEmbedUrl = `https://www.youtube.com/oembed?url=${encodeURIComponent(url)}&format=json`; const response = await fetch(oEmbedUrl); if (!response.ok) { throw new Error('Not valid Url'); } // Parse the JSON response const data = await response.json(); // Display the title if (data && data.title) { return data.title; } else { throw new Error('Error: No title found in the response.'); } }