diff --git a/projects/packages/videopress/changelog/update-videopress-set-video-by-pasting-guid b/projects/packages/videopress/changelog/update-videopress-set-video-by-pasting-guid new file mode 100644 index 000000000000..963066d96f2a --- /dev/null +++ b/projects/packages/videopress/changelog/update-videopress-set-video-by-pasting-guid @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +VideoPress: set block video by providing a GUID value diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/replace-control/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/replace-control/index.tsx index 258ed312d653..ea0dfd998df9 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/replace-control/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/replace-control/index.tsx @@ -2,12 +2,16 @@ * WordPress dependencies */ import { MediaReplaceFlow } from '@wordpress/block-editor'; -import { AdminAjaxQueryAttachmentsResponseItemProps } from '../../../../../types'; /** * Internal dependencies */ import { VIDEOPRESS_VIDEO_ALLOWED_MEDIA_TYPES } from '../../constants'; -import { VideoBlockAttributes } from '../../types'; +/** + * Types + */ +import type { AdminAjaxQueryAttachmentsResponseItemProps } from '../../../../../types'; +import type { VideoBlockAttributes } from '../../types'; + import './style.scss'; type ReplaceControlProps = { diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js index cdbd90e31908..113644e7e9a8 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js @@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n'; */ import useResumableUploader from '../../../../../hooks/use-resumable-uploader'; import { uploadFromLibrary } from '../../../../../hooks/use-uploader'; -import { pickGUIDFromUrl } from '../../../../../lib/url'; +import { buildVideoPressURL } from '../../../../../lib/url'; import { VIDEOPRESS_VIDEO_ALLOWED_MEDIA_TYPES } from '../../constants'; import { PlaceholderWrapper } from '../../edit'; import { description, title } from '../../index'; @@ -104,20 +104,20 @@ const VideoPressUploader = ( { /** * Handler to add a video via an URL. * - * @param {string} videoUrl - URL of the video to attach + * @param {string} videoSource - URL of the video to attach * @param {string} id - Attachment ID if available */ - function onSelectURL( videoUrl, id = undefined ) { - const videoGuid = pickGUIDFromUrl( videoUrl ); - if ( ! videoGuid ) { + function onSelectURL( videoSource, id ) { + // If the video source is a VideoPress URL, we can use it directly. + const videoUrlData = buildVideoPressURL( videoSource ); + if ( ! videoUrlData ) { setUploadErrorDataState( { data: { message: __( 'Invalid VideoPress URL', 'jetpack-videopress-pkg' ) }, } ); return; } - // Update guid based on the URL. - setAttributes( { guid: videoGuid, src: videoUrl, id } ); + setAttributes( { guid: videoUrlData.guid, src: videoUrlData.url, id } ); handleDoneUpload(); } diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx index 0197c47bd287..104c85672df8 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx @@ -19,7 +19,7 @@ import debugFactory from 'debug'; * Internal dependencies */ import getMediaToken from '../../../lib/get-media-token'; -import { getVideoPressUrl, pickGUIDFromUrl } from '../../../lib/url'; +import { buildVideoPressURL, getVideoPressUrl } from '../../../lib/url'; import { useSyncMedia } from '../../hooks/use-video-data-update'; import ColorPanel from './components/color-panel'; import DetailsPanel from './components/details-panel'; @@ -481,15 +481,15 @@ export default function VideoPressEdit( { description: media.description, } ); } } - onSelectURL={ url => { - const videoGuid = pickGUIDFromUrl( url ); - if ( ! videoGuid ) { + onSelectURL={ videoSource => { + const videoUrlData = buildVideoPressURL( videoSource ); + if ( ! videoUrlData ) { debug( 'Invalid URL. No video GUID provided' ); return; } // Update guid based on the URL. - setAttributes( { guid: videoGuid, src: url } ); + setAttributes( { guid: videoUrlData.guid, src: videoUrlData.url } ); } } /> diff --git a/projects/packages/videopress/src/client/lib/get-media-token/index.ts b/projects/packages/videopress/src/client/lib/get-media-token/index.ts index 9ed5c2a34031..a1d11546230f 100644 --- a/projects/packages/videopress/src/client/lib/get-media-token/index.ts +++ b/projects/packages/videopress/src/client/lib/get-media-token/index.ts @@ -15,8 +15,8 @@ import { * Return media token data hiting the admin-ajax endpoint. * * @param {MediaTokenScopeProps} scope - The scope of the token to request. - * @param {GetMediaTokenArgsProps} args - function arguments - * @returns {MediaTokenProps} Media token data. + * @param {GetMediaTokenArgsProps} args - function arguments. + * @returns {MediaTokenProps} Media token data. */ const getMediaToken = function ( scope: MediaTokenScopeProps, diff --git a/projects/packages/videopress/src/client/lib/url/index.ts b/projects/packages/videopress/src/client/lib/url/index.ts index 7b6e6dea64cc..f184fa0b676a 100644 --- a/projects/packages/videopress/src/client/lib/url/index.ts +++ b/projects/packages/videopress/src/client/lib/url/index.ts @@ -1,5 +1,20 @@ import { addQueryArgs } from '@wordpress/url'; -import { VideoBlockAttributes } from '../../block-editor/blocks/video/types'; +import { VideoBlockAttributes, VideoGUID } from '../../block-editor/blocks/video/types'; + +type VideoPressUrlOptions = Pick< + VideoBlockAttributes, + | 'autoplay' + | 'controls' + | 'loop' + | 'muted' + | 'playsinline' + | 'poster' + | 'preload' + | 'seekbarColor' + | 'seekbarPlayedColor' + | 'seekbarLoadingColor' + | 'useAverageColor' +>; export const getVideoPressUrl = ( guid: string, @@ -15,20 +30,7 @@ export const getVideoPressUrl = ( seekbarPlayedColor, seekbarLoadingColor, useAverageColor, - }: Pick< - VideoBlockAttributes, - | 'autoplay' - | 'controls' - | 'loop' - | 'muted' - | 'playsinline' - | 'poster' - | 'preload' - | 'seekbarColor' - | 'seekbarPlayedColor' - | 'seekbarLoadingColor' - | 'useAverageColor' - > + }: VideoPressUrlOptions ) => { if ( ! guid ) { return null; @@ -64,7 +66,7 @@ export const getVideoPressUrl = ( return addQueryArgs( `https://videopress.com/v/${ guid }`, options ); }; -export const pickGUIDFromUrl = ( url: string ) => { +export const pickGUIDFromUrl: ( url: string ) => null | string = url => { if ( ! url ) { return null; } @@ -79,3 +81,47 @@ export const pickGUIDFromUrl = ( url: string ) => { return urlParts.groups.guid; }; + +/** + * Check if a string is a valid VideoPress GUID. + * + * @param {string} value - The string to check. + * @returns {boolean | VideoGUID} Video GUID if the string is valid, false otherwise. + */ +export function isVideoPressGuid( value: string ): boolean | VideoGUID { + const guid = value.match( /^[a-zA-Z\d]{8}$/ ); + if ( ! guid ) { + return false; + } + + return guid[ 0 ]; +} + +/** + * Build a VideoPress URL from a VideoPress GUID or a VideoPress URL. + * The function returns an { url, guid } object, or false. + * + * @param {string | VideoGUID} value - The VideoPress GUID or URL. + * @param {VideoPressUrlOptions} attributes - The VideoPress URL options. + * @returns {false | string} VideoPress URL if the string is valid, false otherwise. + */ +export function buildVideoPressURL( + value: string | VideoGUID, + attributes?: VideoPressUrlOptions +): false | { url: string; guid: VideoGUID } { + const isGuidValue = isVideoPressGuid( value ); + if ( isGuidValue ) { + if ( ! attributes ) { + return { url: `https://videopress.com/v/${ value }`, guid: value }; + } + + return { url: getVideoPressUrl( value, attributes ), guid: value }; + } + + const isGuidFromUrl = pickGUIDFromUrl( value ); + if ( isGuidFromUrl ) { + return { url: value, guid: isGuidFromUrl }; + } + + return false; +}