diff --git a/frontend/src/components/MediaManagerPanel.jsx b/frontend/src/components/MediaManagerPanel.jsx index 7110d60..7634090 100644 --- a/frontend/src/components/MediaManagerPanel.jsx +++ b/frontend/src/components/MediaManagerPanel.jsx @@ -9,6 +9,7 @@ import { t } from '../i18n/index.js' import ImmichAssetPicker from './ImmichAssetPicker.jsx' import { fetchImmichConfig } from '../api/immichApi.js' import { blurPlaceholder } from '../utils/blurhash.js' +import { youtubeWatchUrl } from '../utils/youtube.js' const MEDIA_TYPES = [ { value: 'photo', label: t('Photo'), Icon: Image }, @@ -24,7 +25,6 @@ const FAMILY_TYPES = ['photo', 'video', 'audio', 'citation', 'document'] const TYPE_NAMES = { photo: t('Photo'), video: t('Vidéo'), audio: t('Voix'), citation: t('Citation'), document: t('Document'), geojson: t('Carte'), gpx: t('Trace GPX') } const TYPE_SHORT = { video: t('Vidéo'), audio: t('Voix'), citation: '«', document: t('Doc') } -const YOUTUBE_RE = /^https:\/\/(www\.)?(youtube\.com|youtu\.be)\// const HTTP_URL_RE = /^https?:\/\/\S+$/i const MediaManagerPanel = ({ @@ -90,7 +90,7 @@ const MediaManagerPanel = ({ } if (isYoutubeVideo) { - return YOUTUBE_RE.test(youtubeUrl.trim()) + return youtubeWatchUrl(youtubeUrl) !== null } return Boolean(file) @@ -134,7 +134,7 @@ const MediaManagerPanel = ({ source: source.trim() || null, mediaType, citationText: citationText.trim(), - youtubeUrl: isYoutubeVideo ? youtubeUrl.trim() : null, + youtubeUrl: isYoutubeVideo ? youtubeWatchUrl(youtubeUrl) : null, submittedByLabel: canManage ? null : contributorName.trim(), }) } @@ -280,7 +280,9 @@ const MediaManagerPanel = ({ setYoutubeUrl(event.target.value)} placeholder="https://www.youtube.com/watch?v=…" diff --git a/frontend/src/components/MediaViewer.jsx b/frontend/src/components/MediaViewer.jsx index f397af7..4e16a00 100644 --- a/frontend/src/components/MediaViewer.jsx +++ b/frontend/src/components/MediaViewer.jsx @@ -11,6 +11,7 @@ import { import './MediaViewer.css' import { t } from '../i18n/index.js' import { firstNameLabel } from '../utils/personName.js' +import { youtubeEmbedUrl } from '../utils/youtube.js' import { eventTitle } from '../utils/lifeTimeline.js' import { getAccountErrorMessage } from '../utils/errorMessages.js' import { growFromTransform, takeOrigin } from '../utils/openOrigin.js' @@ -343,20 +344,15 @@ const MediaViewer = ({ } if (normalizedMimeType === 'video/youtube') { - // Extract YouTube video ID and build embed URL - const watchMatch = mediaUrl.match(/[?&]v=([^&]+)/) - const shortMatch = mediaUrl.match(/youtu\.be\/([^/?]+)/) - const videoId = (watchMatch?.[1] || shortMatch?.[1] || '').split(/[?#]/)[0] - // Un identifiant YouTube fait 11 caractères : tout le reste est refusé plutôt qu'intégré - if (!/^[A-Za-z0-9_-]{11}$/.test(videoId)) { + // Toute forme de lien YouTube (barre d'adresse, partage, intégration, Short) ; le reste est refusé plutôt qu'intégré + const embedUrl = youtubeEmbedUrl(mediaUrl) + if (!embedUrl) { return (