fix(builder): VideoBlock parses more YouTube/Vimeo URL shapes (D4)
Extend detectVideoType to handle youtube.com/shorts/ID, youtube.com/live/ID, youtube.com/watch?...&v=ID (v not the first query param), and Vimeo private-hash URLs (vimeo.com/ID/HASH -> ?h=HASH player param). Existing shapes (youtu.be/ID, youtube.com/embed/ID, youtube.com/watch?v=ID, vimeo.com/ID, direct files) keep working. The emitted embed src still passes through safeUrl unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,18 +26,43 @@ interface VideoBlockProps {
|
||||
|
||||
/* ---------- URL detection ---------- */
|
||||
|
||||
/**
|
||||
* Extract a YouTube video ID from any of the URL shapes WHP users paste:
|
||||
* youtu.be/ID, youtube.com/embed/ID, youtube.com/shorts/ID,
|
||||
* youtube.com/live/ID (path-based), and youtube.com/watch?...v=ID where `v`
|
||||
* may appear anywhere in the query string (not just as the first param).
|
||||
*/
|
||||
function extractYouTubeId(url: string): string | null {
|
||||
const pathMatch = url.match(
|
||||
/(?:youtube\.com\/(?:embed|shorts|live)\/|youtu\.be\/)([a-zA-Z0-9_-]+)/
|
||||
);
|
||||
if (pathMatch) return pathMatch[1];
|
||||
|
||||
const queryMatch = url.match(/youtube\.com\/watch\?([^\s#]+)/);
|
||||
if (queryMatch) {
|
||||
const v = new URLSearchParams(queryMatch[1]).get('v');
|
||||
if (v) return v;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function detectVideoType(url: string): { type: VideoType; embedUrl: string } {
|
||||
if (!url) return { type: 'none', embedUrl: '' };
|
||||
|
||||
// YouTube
|
||||
const ytMatch = url.match(
|
||||
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]+)/
|
||||
);
|
||||
if (ytMatch) return { type: 'youtube', embedUrl: `https://www.youtube.com/embed/${ytMatch[1]}?rel=0` };
|
||||
const ytId = extractYouTubeId(url);
|
||||
if (ytId) return { type: 'youtube', embedUrl: `https://www.youtube.com/embed/${ytId}?rel=0` };
|
||||
|
||||
// Vimeo
|
||||
const vmMatch = url.match(/vimeo\.com\/(\d+)/);
|
||||
if (vmMatch) return { type: 'vimeo', embedUrl: `https://player.vimeo.com/video/${vmMatch[1]}` };
|
||||
// Vimeo: vimeo.com/ID, or vimeo.com/ID/HASH for unlisted/private videos
|
||||
// (the hash becomes the player's `h` query param).
|
||||
const vmMatch = url.match(/vimeo\.com\/(\d+)(?:\/([a-zA-Z0-9]+))?/);
|
||||
if (vmMatch) {
|
||||
const embedUrl = vmMatch[2]
|
||||
? `https://player.vimeo.com/video/${vmMatch[1]}?h=${vmMatch[2]}`
|
||||
: `https://player.vimeo.com/video/${vmMatch[1]}`;
|
||||
return { type: 'vimeo', embedUrl };
|
||||
}
|
||||
|
||||
// Direct file
|
||||
if (url.match(/\.(mp4|webm|ogg|mov)(\?|$)/i)) return { type: 'file', embedUrl: url };
|
||||
|
||||
Reference in New Issue
Block a user