(url: string)
| 62 | * host-agnostic — any direct media file URL is embeddable. |
| 63 | */ |
| 64 | export function getEmbedInfo(url: string): EmbedInfo | null { |
| 65 | const parsed = parseUrl(url) |
| 66 | const host = parsed?.hostname.toLowerCase() ?? null |
| 67 | if (parsed && hostMatches(host, 'youtube.com', 'youtu.be')) { |
| 68 | const segments = parsed.pathname.split('/') |
| 69 | let id: string | null | undefined |
| 70 | if (hostMatches(host, 'youtu.be')) id = segments[1] |
| 71 | else if (segments[1] === 'embed') id = segments[2] |
| 72 | else id = parsed.searchParams.get('v') |
| 73 | if (id && /^[a-zA-Z0-9_-]{11}$/.test(id)) { |
| 74 | return { url: `https://www.youtube.com/embed/${id}`, type: 'iframe' } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | if (hostMatches(host, 'vimeo.com')) { |
| 79 | const vimeoMatch = url.match(/vimeo\.com\/(\d+)/) |
| 80 | if (vimeoMatch) { |
| 81 | return { url: `https://player.vimeo.com/video/${vimeoMatch[1]}`, type: 'iframe' } |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | if (hostMatches(host, 'dailymotion.com')) { |
| 86 | const dailymotionMatch = url.match(/dailymotion\.com\/video\/([a-zA-Z0-9]+)/) |
| 87 | if (dailymotionMatch) { |
| 88 | return { |
| 89 | url: `https://www.dailymotion.com/embed/video/${dailymotionMatch[1]}`, |
| 90 | type: 'iframe', |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | if (hostMatches(host, 'twitch.tv')) { |
| 96 | const twitchVideoMatch = url.match(/twitch\.tv\/videos\/(\d+)/) |
| 97 | if (twitchVideoMatch) { |
| 98 | return { |
| 99 | url: `https://player.twitch.tv/?video=${twitchVideoMatch[1]}&parent=${getTwitchParent()}`, |
| 100 | type: 'iframe', |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | const twitchClipMatch = |
| 105 | url.match(/clips\.twitch\.tv\/([a-zA-Z0-9_-]+)/) || |
| 106 | url.match(/twitch\.tv\/[^/]+\/clip\/([a-zA-Z0-9_-]+)/) |
| 107 | if (twitchClipMatch) { |
| 108 | return { |
| 109 | url: `https://clips.twitch.tv/embed?clip=${twitchClipMatch[1]}&parent=${getTwitchParent()}`, |
| 110 | type: 'iframe', |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | const twitchChannelMatch = url.match(/twitch\.tv\/([a-zA-Z0-9_]+)(?:\/|$)/) |
| 115 | if (twitchChannelMatch && !url.includes('/videos/') && !url.includes('/clip/')) { |
| 116 | return { |
| 117 | url: `https://player.twitch.tv/?channel=${twitchChannelMatch[1]}&parent=${getTwitchParent()}`, |
| 118 | type: 'iframe', |
| 119 | } |
| 120 | } |
| 121 | } |
no test coverage detected