From 3b4fe9bba6cb91300cb6a8d2bcd2c341d5a8700f Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 12 Feb 2024 14:55:15 +0000 Subject: [PATCH 01/22] feat: Enable usage of v5's editor component --- .../jetpack/extensions/blocks/videopress/editor.native.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/editor.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/editor.native.js index 42f02c8156b08..f21f77d6d84c8 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/editor.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/editor.native.js @@ -1,4 +1,5 @@ import { addFilter } from '@wordpress/hooks'; +import withVideoPressEdit from './edit'; import withVideoPressSave from './save'; const addVideoPressSupport = ( settings, name ) => { @@ -7,7 +8,7 @@ const addVideoPressSupport = ( settings, name ) => { return settings; } - const { save } = settings; + const { edit, save } = settings; const attributesDefinition = { autoplay: { @@ -96,6 +97,7 @@ const addVideoPressSupport = ( settings, name ) => { return { ...settings, attributes: attributesDefinition, + edit: withVideoPressEdit( edit ), save: withVideoPressSave( save ), }; }; From 07a7b966a637cbe5a46d893a9530f14ec77191a3 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 12 Feb 2024 14:57:02 +0000 Subject: [PATCH 02/22] docs: Add changelog entry --- .../jetpack/changelog/rnmobile-support-for-videopress-v5 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 projects/plugins/jetpack/changelog/rnmobile-support-for-videopress-v5 diff --git a/projects/plugins/jetpack/changelog/rnmobile-support-for-videopress-v5 b/projects/plugins/jetpack/changelog/rnmobile-support-for-videopress-v5 new file mode 100644 index 0000000000000..75fd24faf09cf --- /dev/null +++ b/projects/plugins/jetpack/changelog/rnmobile-support-for-videopress-v5 @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +RNMobile: Enable support for editing v5 of the VideoPress block in the Jetpack app. From ea3a0a90b2c5071b0ff0210179fcd020bb5fa759 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Tue, 13 Feb 2024 14:45:41 +0000 Subject: [PATCH 03/22] feat: Dupe Video block for basis of v5 support With this commit, the main Video block files have been duplicated. They will be iterated on in subsequent commits and serve the basis of the changes we'll make to support VideoPress v5. --- .../videopress/edit-common-settings.native.js | 85 +++++ .../blocks/videopress/edit.native.js | 338 ++++++++++++++++++ .../blocks/videopress/icon-retry.native.js | 11 + .../blocks/videopress/style.native.scss | 71 ++++ 4 files changed, 505 insertions(+) create mode 100644 projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js create mode 100644 projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js create mode 100644 projects/plugins/jetpack/extensions/blocks/videopress/icon-retry.native.js create mode 100644 projects/plugins/jetpack/extensions/blocks/videopress/style.native.scss diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js new file mode 100644 index 0000000000000..6ac38f82145e5 --- /dev/null +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js @@ -0,0 +1,85 @@ +/** + * WordPress dependencies + */ +import { ToggleControl, SelectControl } from '@wordpress/components'; +import { useMemo, useCallback } from '@wordpress/element'; +import { __, _x } from '@wordpress/i18n'; + +const options = [ + { value: 'auto', label: __( 'Auto', 'jetpack' ) }, + { value: 'metadata', label: __( 'Metadata', 'jetpack' ) }, + { value: 'none', label: _x( 'None', 'Preload value', 'jetpack' ) }, +]; + +const VideoSettings = ( { setAttributes, attributes } ) => { + const { autoplay, controls, loop, muted, playsInline, preload } = attributes; + + const toggleFactory = useMemo( () => { + const toggleAttribute = attribute => { + return newValue => { + setAttributes( { [ attribute ]: newValue } ); + }; + }; + + return { + autoplay: toggleAttribute( 'autoplay' ), + loop: toggleAttribute( 'loop' ), + muted: toggleAttribute( 'muted' ), + controls: toggleAttribute( 'controls' ), + playsInline: toggleAttribute( 'playsInline' ), + }; + }, [ setAttributes ] ); + + const onChangePreload = useCallback( + value => { + setAttributes( { preload: value } ); + }, + [ setAttributes ] + ); + + return ( + <> + + + + + + + + ); +}; + +export default VideoSettings; diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js new file mode 100644 index 0000000000000..e781484cf7861 --- /dev/null +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -0,0 +1,338 @@ +/** + * External dependencies + */ +/** + * WordPress dependencies + */ +import { + BlockCaption, + MediaPlaceholder, + MediaUpload, + MediaUploadProgress, + MEDIA_TYPE_VIDEO, + BlockControls, + VIDEO_ASPECT_RATIO, + VideoPlayer, + InspectorControls, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { Icon, ToolbarButton, ToolbarGroup, PanelBody } from '@wordpress/components'; +import { withPreferredColorScheme, compose } from '@wordpress/compose'; +import { withDispatch, withSelect } from '@wordpress/data'; +import { Component } from '@wordpress/element'; +import { doAction, hasAction } from '@wordpress/hooks'; +import { __, sprintf } from '@wordpress/i18n'; +import { video as SvgIcon, replace } from '@wordpress/icons'; +import { store as noticesStore } from '@wordpress/notices'; +import { + mediaUploadSync, + requestImageFailedRetryDialog, + requestImageUploadCancelDialog, +} from '@wordpress/react-native-bridge'; +import { isURL, getProtocol } from '@wordpress/url'; +import { View, TouchableWithoutFeedback, Text } from 'react-native'; +/** + * Internal dependencies + */ +import { createUpgradedEmbedBlock } from '../embed/util'; +import VideoCommonSettings from './edit-common-settings'; +import SvgIconRetry from './icon-retry'; +import style from './style.scss'; + +const ICON_TYPE = { + PLACEHOLDER: 'placeholder', + RETRY: 'retry', + UPLOAD: 'upload', +}; + +class VideoEdit extends Component { + constructor( props ) { + super( props ); + + this.state = { + isCaptionSelected: false, + videoContainerHeight: 0, + }; + + this.mediaUploadStateReset = this.mediaUploadStateReset.bind( this ); + this.onSelectMediaUploadOption = this.onSelectMediaUploadOption.bind( this ); + this.onSelectURL = this.onSelectURL.bind( this ); + this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this ); + this.finishMediaUploadWithFailure = this.finishMediaUploadWithFailure.bind( this ); + this.updateMediaProgress = this.updateMediaProgress.bind( this ); + this.onVideoPressed = this.onVideoPressed.bind( this ); + this.onVideoContanerLayout = this.onVideoContanerLayout.bind( this ); + this.onFocusCaption = this.onFocusCaption.bind( this ); + } + + componentDidMount() { + const { attributes } = this.props; + if ( attributes.id && getProtocol( attributes.src ) === 'file:' ) { + mediaUploadSync(); + } + } + + componentWillUnmount() { + // This action will only exist if the user pressed the trash button on the block holder. + if ( hasAction( 'blocks.onRemoveBlockCheckUpload' ) && this.state.isUploadInProgress ) { + doAction( 'blocks.onRemoveBlockCheckUpload', this.props.attributes.id ); + } + } + + static getDerivedStateFromProps( props, state ) { + // Avoid a UI flicker in the toolbar by insuring that isCaptionSelected + // is updated immediately any time the isSelected prop becomes false. + return { + isCaptionSelected: props.isSelected && state.isCaptionSelected, + }; + } + + onVideoPressed() { + const { attributes } = this.props; + + if ( this.state.isUploadInProgress ) { + requestImageUploadCancelDialog( attributes.id ); + } else if ( attributes.id && getProtocol( attributes.src ) === 'file:' ) { + requestImageFailedRetryDialog( attributes.id ); + } + + this.setState( { + isCaptionSelected: false, + } ); + } + + onFocusCaption() { + if ( ! this.state.isCaptionSelected ) { + this.setState( { isCaptionSelected: true } ); + } + } + + updateMediaProgress( payload ) { + const { setAttributes } = this.props; + if ( payload.mediaUrl ) { + setAttributes( { url: payload.mediaUrl } ); + } + if ( ! this.state.isUploadInProgress ) { + this.setState( { isUploadInProgress: true } ); + } + } + + finishMediaUploadWithSuccess( payload ) { + const { setAttributes } = this.props; + setAttributes( { src: payload.mediaUrl, id: payload.mediaServerId } ); + this.setState( { isUploadInProgress: false } ); + } + + finishMediaUploadWithFailure( payload ) { + const { setAttributes } = this.props; + setAttributes( { id: payload.mediaId } ); + this.setState( { isUploadInProgress: false } ); + } + + mediaUploadStateReset() { + const { setAttributes } = this.props; + setAttributes( { id: null, src: null } ); + this.setState( { isUploadInProgress: false } ); + } + + onSelectMediaUploadOption( { id, url } ) { + const { setAttributes } = this.props; + setAttributes( { id, src: url } ); + } + + onSelectURL( url ) { + const { createErrorNotice, onReplace, setAttributes } = this.props; + + if ( isURL( url ) && /^https?:/.test( getProtocol( url ) ) ) { + // Check if there's an embed block that handles this URL. + const embedBlock = createUpgradedEmbedBlock( { + attributes: { url }, + } ); + if ( undefined !== embedBlock ) { + onReplace( embedBlock ); + return; + } + + setAttributes( { src: url, id: undefined, poster: undefined } ); + } else { + createErrorNotice( __( 'Invalid URL.', 'jetpack' ) ); + } + } + + onVideoContanerLayout( event ) { + const { width } = event.nativeEvent.layout; + const height = width / VIDEO_ASPECT_RATIO; + if ( height !== this.state.videoContainerHeight ) { + this.setState( { videoContainerHeight: height } ); + } + } + + getIcon( iconType ) { + let iconStyle; + switch ( iconType ) { + case ICON_TYPE.RETRY: + return ; + case ICON_TYPE.PLACEHOLDER: + iconStyle = this.props.getStylesFromColorScheme( style.icon, style.iconDark ); + break; + case ICON_TYPE.UPLOAD: + iconStyle = this.props.getStylesFromColorScheme( + style.iconUploading, + style.iconUploadingDark + ); + break; + } + + return ; + } + + render() { + const { setAttributes, attributes, isSelected, wasBlockJustInserted } = this.props; + const { id, src, guid } = attributes; + const { videoContainerHeight } = this.state; + + const toolbarEditButton = ( + { + return ( + + { getMediaOptions() } + + + ); + } } + > + ); + + // NOTE: `guid` is not part of the block's attribute definition. This case + // handled here is a temporary fix until a we find a better approach. + const isSourcePresent = src || ( guid && id ); + if ( ! isSourcePresent ) { + return ( + + + + ); + } + + return ( + + + { ! this.state.isCaptionSelected && { toolbarEditButton } } + { isSelected && ( + + + + + + ) } + { + const showVideo = isURL( src ) && ! isUploadInProgress && ! isUploadFailed; + const icon = this.getIcon( isUploadFailed ? ICON_TYPE.RETRY : ICON_TYPE.UPLOAD ); + const styleIconContainer = isUploadFailed ? style.modalIconRetry : style.modalIcon; + + const iconContainer = { icon }; + + const videoStyle = { + height: videoContainerHeight, + ...style.video, + }; + + const containerStyle = + showVideo && isSelected ? style.containerFocused : style.container; + + return ( + + { showVideo && ( + + + + ) } + { ! showVideo && ( + + { videoContainerHeight > 0 && iconContainer } + { isUploadFailed && ( + { retryMessage } + ) } + + ) } + + ); + } } + /> + + ! caption /* translators: accessibility text. Empty video caption. */ + ? __( 'Video caption. Empty', 'jetpack' ) + : sprintf( + /* translators: accessibility text. %s: video caption. */ + __( 'Video caption. %s', 'jetpack' ), + caption + ) + } + clientId={ this.props.clientId } + isSelected={ this.state.isCaptionSelected } + onFocus={ this.onFocusCaption } + onBlur={ this.props.onBlur } // Always assign onBlur as props. + insertBlocksAfter={ this.props.insertBlocksAfter } + /> + + + ); + } +} + +export default compose( [ + withSelect( ( select, { clientId } ) => ( { + wasBlockJustInserted: select( blockEditorStore ).wasBlockJustInserted( + clientId, + 'inserter_menu' + ), + } ) ), + withDispatch( dispatch => { + const { createErrorNotice } = dispatch( noticesStore ); + + return { createErrorNotice }; + } ), + withPreferredColorScheme, +] )( VideoEdit ); diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/icon-retry.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/icon-retry.native.js new file mode 100644 index 0000000000000..d9b3d82e796cb --- /dev/null +++ b/projects/plugins/jetpack/extensions/blocks/videopress/icon-retry.native.js @@ -0,0 +1,11 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/components'; + +export default ( + + + + +); diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/style.native.scss b/projects/plugins/jetpack/extensions/blocks/videopress/style.native.scss new file mode 100644 index 0000000000000..654a0085bdbeb --- /dev/null +++ b/projects/plugins/jetpack/extensions/blocks/videopress/style.native.scss @@ -0,0 +1,71 @@ +.video { + width: 100%; +} + +.videoContainer { + flex: 1; + background-color: #000; +} + +.placeholderContainer { + flex: 1; + justify-content: center; + align-items: center; + background-color: $gray-light; +} + +.placeholderContainerDark { + background-color: $gray-90; +} + +.uploadFailedText { + color: $gray-dark; + font-size: 14; + margin-top: 5; + text-align: center; +} + +.modalIcon { + width: 40px; + height: 40px; + justify-content: center; + align-items: center; +} + +.modalIconRetry { + width: 80px; + height: 80px; + justify-content: center; + align-items: center; +} + +.container { + flex: 1; +} + +.containerFocused { + flex: 1; + border-color: $blue-medium; + border-width: 2px; + border-style: solid; +} + +.icon { + fill: $gray-dark; + width: 100%; + height: 100%; +} + +.iconDark { + fill: $white; +} + +.iconUploading { + fill: $gray-lighten-20; + width: 100%; + height: 100%; +} + +.iconUploadingDark { + fill: $gray-70; +} From f5e9233eac12ade6058e5c3890f12c4f2bf0bf9d Mon Sep 17 00:00:00 2001 From: Siobhan Date: Tue, 13 Feb 2024 15:27:24 +0000 Subject: [PATCH 04/22] feat: Fetch VideoPress metadata in edit component The Video block's is refactored to fetch VideoPress metadata, therefore enabling support for v5. --- .../blocks/videopress/edit.native.js | 147 ++++++++++++------ 1 file changed, 101 insertions(+), 46 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index e781484cf7861..b639d17d12a0c 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -1,9 +1,7 @@ -/** - * External dependencies - */ /** * WordPress dependencies */ +import apiFetch from '@wordpress/api-fetch'; import { BlockCaption, MediaPlaceholder, @@ -17,7 +15,7 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { Icon, ToolbarButton, ToolbarGroup, PanelBody } from '@wordpress/components'; -import { withPreferredColorScheme, compose } from '@wordpress/compose'; +import { withPreferredColorScheme, compose, createHigherOrderComponent } from '@wordpress/compose'; import { withDispatch, withSelect } from '@wordpress/data'; import { Component } from '@wordpress/element'; import { doAction, hasAction } from '@wordpress/hooks'; @@ -30,14 +28,17 @@ import { requestImageUploadCancelDialog, } from '@wordpress/react-native-bridge'; import { isURL, getProtocol } from '@wordpress/url'; -import { View, TouchableWithoutFeedback, Text } from 'react-native'; +/** + * External dependencies + */ +import { ActivityIndicator, View, TouchableWithoutFeedback, Text } from 'react-native'; /** * Internal dependencies */ -import { createUpgradedEmbedBlock } from '../embed/util'; import VideoCommonSettings from './edit-common-settings'; import SvgIconRetry from './icon-retry'; import style from './style.scss'; +import { pickGUIDFromUrl } from './utils'; const ICON_TYPE = { PLACEHOLDER: 'placeholder', @@ -45,13 +46,17 @@ const ICON_TYPE = { UPLOAD: 'upload', }; -class VideoEdit extends Component { +class VideoPressEdit extends Component { constructor( props ) { super( props ); this.state = { isCaptionSelected: false, videoContainerHeight: 0, + isUploadInProgress: false, + isUploadFailed: false, + isLoadingMetadata: false, + metadata: {}, }; this.mediaUploadStateReset = this.mediaUploadStateReset.bind( this ); @@ -65,11 +70,20 @@ class VideoEdit extends Component { this.onFocusCaption = this.onFocusCaption.bind( this ); } - componentDidMount() { + async componentDidMount() { const { attributes } = this.props; + const { guid } = attributes; if ( attributes.id && getProtocol( attributes.src ) === 'file:' ) { mediaUploadSync(); } + + // Try to infer the VideoPress ID from the source upon component mount. + // If the ID already exists, fetch the metadata to get the video URL. + if ( ! guid ) { + await this.setGuid(); + } else { + await this.fetchMetadata( guid ); + } } componentWillUnmount() { @@ -80,13 +94,40 @@ class VideoEdit extends Component { } static getDerivedStateFromProps( props, state ) { - // Avoid a UI flicker in the toolbar by insuring that isCaptionSelected - // is updated immediately any time the isSelected prop becomes false. return { + // Avoid a UI flicker in the toolbar by insuring that isCaptionSelected + // is updated immediately any time the isSelected prop becomes false. isCaptionSelected: props.isSelected && state.isCaptionSelected, + // Reset metadata when "guid" attribute is not defined. + metadata: props.attributes?.guid ? state.metadata : {}, }; } + async setGuid( value ) { + const { setAttributes, attributes } = this.props; + const { src } = attributes; + // If no value is passed, we try to extract the VideoPress ID from the source. + const guid = value ?? pickGUIDFromUrl( src ) ?? undefined; + setAttributes( { guid } ); + if ( guid ) { + await this.fetchMetadata( guid ); + } + } + + async fetchMetadata( guid ) { + this.setState( { isLoadingMetadata: true } ); + try { + const metadata = await apiFetch( { + path: `/rest/v1.1/videos/${ guid }`, + } ); + this.setState( { metadata, isLoadingMetadata: false } ); + } catch ( error ) { + // eslint-disable-next-line no-console + console.error( `Couldn't fetch metadata of VideoPress video with ID = ${ guid }`, error ); + this.setState( { isLoadingMetadata: false } ); + } + } + onVideoPressed() { const { attributes } = this.props; @@ -119,8 +160,11 @@ class VideoEdit extends Component { finishMediaUploadWithSuccess( payload ) { const { setAttributes } = this.props; - setAttributes( { src: payload.mediaUrl, id: payload.mediaServerId } ); + const { mediaUrl, mediaServerId, metadata = {} } = payload; + const { videopressGUID } = metadata; + setAttributes( { src: mediaUrl, id: mediaServerId } ); this.setState( { isUploadInProgress: false } ); + this.setGuid( videopressGUID ); } finishMediaUploadWithFailure( payload ) { @@ -131,29 +175,23 @@ class VideoEdit extends Component { mediaUploadStateReset() { const { setAttributes } = this.props; - setAttributes( { id: null, src: null } ); + setAttributes( { id: null, src: null, guid: null } ); this.setState( { isUploadInProgress: false } ); } - onSelectMediaUploadOption( { id, url } ) { + onSelectMediaUploadOption( payload ) { const { setAttributes } = this.props; + const { id, url, metadata = {} } = payload; + const { videopressGUID } = metadata; setAttributes( { id, src: url } ); + this.setGuid( videopressGUID ); } onSelectURL( url ) { - const { createErrorNotice, onReplace, setAttributes } = this.props; + const { createErrorNotice, setAttributes } = this.props; - if ( isURL( url ) && /^https?:/.test( getProtocol( url ) ) ) { - // Check if there's an embed block that handles this URL. - const embedBlock = createUpgradedEmbedBlock( { - attributes: { url }, - } ); - if ( undefined !== embedBlock ) { - onReplace( embedBlock ); - return; - } - - setAttributes( { src: url, id: undefined, poster: undefined } ); + if ( isURL( url ) ) { + setAttributes( { id: url, src: url } ); } else { createErrorNotice( __( 'Invalid URL.', 'jetpack' ) ); } @@ -186,10 +224,19 @@ class VideoEdit extends Component { return ; } + getVideoURL() { + const { attributes } = this.props; + const { src, guid } = attributes; + const { metadata = {} } = this.state; + + return metadata.original || `https://videopress.com/v/${ guid }` || src; + } + render() { const { setAttributes, attributes, isSelected, wasBlockJustInserted } = this.props; const { id, src, guid } = attributes; - const { videoContainerHeight } = this.state; + const { isLoadingMetadata, isUploadInProgress, isUploadFailed, videoContainerHeight } = + this.state; const toolbarEditButton = ( ); - // NOTE: `guid` is not part of the block's attribute definition. This case - // handled here is a temporary fix until a we find a better approach. const isSourcePresent = src || ( guid && id ); if ( ! isSourcePresent ) { return ( @@ -251,8 +296,13 @@ class VideoEdit extends Component { onFinishMediaUploadWithFailure={ this.finishMediaUploadWithFailure } onUpdateMediaProgress={ this.updateMediaProgress } onMediaUploadStateReset={ this.mediaUploadStateReset } - renderContent={ ( { isUploadInProgress, isUploadFailed, retryMessage } ) => { - const showVideo = isURL( src ) && ! isUploadInProgress && ! isUploadFailed; + renderContent={ ( { retryMessage } ) => { + const videoURL = this.getVideoURL(); + const showVideo = + isURL( videoURL ) && + ! isUploadInProgress && + ! isUploadFailed && + ! isLoadingMetadata; const icon = this.getIcon( isUploadFailed ? ICON_TYPE.RETRY : ICON_TYPE.UPLOAD ); const styleIconContainer = isUploadFailed ? style.modalIconRetry : style.modalIcon; @@ -273,7 +323,7 @@ class VideoEdit extends Component { @@ -289,7 +339,8 @@ class VideoEdit extends Component { ), } } > - { videoContainerHeight > 0 && iconContainer } + { videoContainerHeight > 0 && + ( isLoadingMetadata ? : iconContainer ) } { isUploadFailed && ( { retryMessage } ) } @@ -322,17 +373,21 @@ class VideoEdit extends Component { } } -export default compose( [ - withSelect( ( select, { clientId } ) => ( { - wasBlockJustInserted: select( blockEditorStore ).wasBlockJustInserted( - clientId, - 'inserter_menu' - ), - } ) ), - withDispatch( dispatch => { - const { createErrorNotice } = dispatch( noticesStore ); - - return { createErrorNotice }; - } ), - withPreferredColorScheme, -] )( VideoEdit ); +export default CoreVideoEdit => + compose( [ + withSelect( ( select, { clientId } ) => ( { + wasBlockJustInserted: select( blockEditorStore ).wasBlockJustInserted( + clientId, + 'inserter_menu' + ), + } ) ), + withDispatch( dispatch => { + const { createErrorNotice } = dispatch( noticesStore ); + + return { createErrorNotice }; + } ), + withPreferredColorScheme, + createHigherOrderComponent( WrappedComponent => props => { + return ; + } ), + ] )( VideoPressEdit ); From 79b062d3a7825323b0dad5fbff6dd6db11c2b82d Mon Sep 17 00:00:00 2001 From: Siobhan Date: Tue, 13 Feb 2024 15:27:49 +0000 Subject: [PATCH 05/22] fix: Ensure plays inline toggle works as expected --- .../blocks/videopress/edit-common-settings.native.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js index 6ac38f82145e5..58f88bab8e953 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js @@ -12,7 +12,7 @@ const options = [ ]; const VideoSettings = ( { setAttributes, attributes } ) => { - const { autoplay, controls, loop, muted, playsInline, preload } = attributes; + const { autoplay, controls, loop, muted, playsinline, preload } = attributes; const toggleFactory = useMemo( () => { const toggleAttribute = attribute => { @@ -26,7 +26,7 @@ const VideoSettings = ( { setAttributes, attributes } ) => { loop: toggleAttribute( 'loop' ), muted: toggleAttribute( 'muted' ), controls: toggleAttribute( 'controls' ), - playsInline: toggleAttribute( 'playsInline' ), + playsinline: toggleAttribute( 'playsinline' ), }; }, [ setAttributes ] ); @@ -67,8 +67,8 @@ const VideoSettings = ( { setAttributes, attributes } ) => { Date: Tue, 13 Feb 2024 15:36:32 +0000 Subject: [PATCH 06/22] fix: Remove typo in settings component --- .../extensions/blocks/videopress/edit-common-settings.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js index 58f88bab8e953..0c01411f6cb29 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js @@ -44,7 +44,7 @@ const VideoSettings = ( { setAttributes, attributes } ) => { label={ __( 'Autoplay', 'jetpack' ) } onChange={ toggleFactory.autoplay } checked={ !! autoplay } - help={ __( 'Autoplay may cause usability issues for some users!', 'jetpack' ) } + help={ __( 'Autoplay may cause usability issues for some users', 'jetpack' ) } /> Date: Tue, 13 Feb 2024 20:53:45 +0000 Subject: [PATCH 07/22] refactor: Update logic for fetching video's URL --- .../jetpack/extensions/blocks/videopress/edit.native.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index b639d17d12a0c..ccd00e6cd059a 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -226,10 +226,15 @@ class VideoPressEdit extends Component { getVideoURL() { const { attributes } = this.props; - const { src, guid } = attributes; + const { guid } = attributes; const { metadata = {} } = this.state; - return metadata.original || `https://videopress.com/v/${ guid }` || src; + // Private videos will open in the player for logged in users with the WordPress.com URL. + // However, they'll still display blank in the editor. + // TODO: We need to iterate so that private videos display as expected. + return metadata.is_private + ? `https://video.wordpress.com/v/${ guid }` + : `https://videopress.com/v/${ guid }`; } render() { From a5d7df8438fb6241e14b3392ffe1d3bea7e080df Mon Sep 17 00:00:00 2001 From: Siobhan Date: Tue, 13 Feb 2024 22:54:06 +0000 Subject: [PATCH 08/22] feat: Ensure poster displays in thumbnail --- .../plugins/jetpack/extensions/blocks/videopress/edit.native.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index ccd00e6cd059a..3a53f7a2dcc42 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -303,6 +303,7 @@ class VideoPressEdit extends Component { onMediaUploadStateReset={ this.mediaUploadStateReset } renderContent={ ( { retryMessage } ) => { const videoURL = this.getVideoURL(); + const videoPoster = this.state.metadata.poster; const showVideo = isURL( videoURL ) && ! isUploadInProgress && @@ -330,6 +331,7 @@ class VideoPressEdit extends Component { style={ videoStyle } source={ { uri: videoURL } } paused={ true } + poster={ videoPoster } /> ) } From 9fecddc3cd16b78fe2089821a2d77a8f8dc3085b Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 14 Feb 2024 14:14:25 +0000 Subject: [PATCH 09/22] fix: Ensure isUploadFailed state is always correct --- .../jetpack/extensions/blocks/videopress/edit.native.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 3a53f7a2dcc42..317a3abb345da 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -163,20 +163,20 @@ class VideoPressEdit extends Component { const { mediaUrl, mediaServerId, metadata = {} } = payload; const { videopressGUID } = metadata; setAttributes( { src: mediaUrl, id: mediaServerId } ); - this.setState( { isUploadInProgress: false } ); + this.setState( { isUploadInProgress: false, isUploadFailed: false } ); this.setGuid( videopressGUID ); } finishMediaUploadWithFailure( payload ) { const { setAttributes } = this.props; setAttributes( { id: payload.mediaId } ); - this.setState( { isUploadInProgress: false } ); + this.setState( { isUploadInProgress: false, isUploadFailed: true } ); } mediaUploadStateReset() { const { setAttributes } = this.props; setAttributes( { id: null, src: null, guid: null } ); - this.setState( { isUploadInProgress: false } ); + this.setState( { isUploadInProgress: false, isUploadFailed: false } ); } onSelectMediaUploadOption( payload ) { From 92904ee90b6dd7ea3554701d9cf36dd8d44a6a4f Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 14 Feb 2024 14:14:57 +0000 Subject: [PATCH 10/22] feat: Show activity indicator if video's uploading --- .../jetpack/extensions/blocks/videopress/edit.native.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 317a3abb345da..ad13f0cbeb7cc 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -347,7 +347,11 @@ class VideoPressEdit extends Component { } } > { videoContainerHeight > 0 && - ( isLoadingMetadata ? : iconContainer ) } + ( isUploadInProgress || isLoadingMetadata ? ( + + ) : ( + iconContainer + ) ) } { isUploadFailed && ( { retryMessage } ) } From 1aa07e559e325882f78d999f30a74a2da1279a44 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 14 Feb 2024 14:15:22 +0000 Subject: [PATCH 11/22] refactor: Ensure fetchMetadata logic is correct --- .../extensions/blocks/videopress/edit.native.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index ad13f0cbeb7cc..84e266fbc0c1c 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -116,16 +116,15 @@ class VideoPressEdit extends Component { async fetchMetadata( guid ) { this.setState( { isLoadingMetadata: true } ); - try { - const metadata = await apiFetch( { - path: `/rest/v1.1/videos/${ guid }`, + await apiFetch( { path: `/rest/v1.1/videos/${ guid }` } ) + .then( metadata => { + this.setState( { metadata, isLoadingMetadata: false } ); + } ) + .catch( () => { + // eslint-disable-next-line no-console + console.error( `Couldn't fetch metadata of VideoPress video with ID = ${ guid }` ); + this.setState( { isLoadingMetadata: false } ); } ); - this.setState( { metadata, isLoadingMetadata: false } ); - } catch ( error ) { - // eslint-disable-next-line no-console - console.error( `Couldn't fetch metadata of VideoPress video with ID = ${ guid }`, error ); - this.setState( { isLoadingMetadata: false } ); - } } onVideoPressed() { From 1b98f618c42d9136a4e49a434f90fb5751a0d270 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 14 Feb 2024 14:32:37 +0000 Subject: [PATCH 12/22] refactor: Call poster directly, no redundant var --- .../jetpack/extensions/blocks/videopress/edit.native.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 84e266fbc0c1c..b79537b9f9df2 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -302,7 +302,6 @@ class VideoPressEdit extends Component { onMediaUploadStateReset={ this.mediaUploadStateReset } renderContent={ ( { retryMessage } ) => { const videoURL = this.getVideoURL(); - const videoPoster = this.state.metadata.poster; const showVideo = isURL( videoURL ) && ! isUploadInProgress && @@ -330,7 +329,7 @@ class VideoPressEdit extends Component { style={ videoStyle } source={ { uri: videoURL } } paused={ true } - poster={ videoPoster } + poster={ this.state.metadata.poster } /> ) } From b4d689c5f0100769cd40ec4f2447cd0ad6ef462d Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 16 Feb 2024 11:02:17 +0000 Subject: [PATCH 13/22] fix: Return early if GUID is falsey, avoid crash There are times where GUID may be undefined, which leads to a crash in react-native-video. Details on the crash and further reasoning for this fix can be found here: https://github.com/Automattic/jetpack/pull/35637#issuecomment-1948152835 --- .../jetpack/extensions/blocks/videopress/edit.native.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index b79537b9f9df2..091d145899258 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -228,6 +228,10 @@ class VideoPressEdit extends Component { const { guid } = attributes; const { metadata = {} } = this.state; + if ( ! guid ) { + return; + } + // Private videos will open in the player for logged in users with the WordPress.com URL. // However, they'll still display blank in the editor. // TODO: We need to iterate so that private videos display as expected. From 7804db2bd9137d5136c02cb8d2e4c43d17429eb7 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 16 Feb 2024 11:03:30 +0000 Subject: [PATCH 14/22] refactor: Tidy up consts for improved readability --- .../jetpack/extensions/blocks/videopress/edit.native.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 091d145899258..bcd8065ccb8a7 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -224,9 +224,8 @@ class VideoPressEdit extends Component { } getVideoURL() { - const { attributes } = this.props; - const { guid } = attributes; - const { metadata = {} } = this.state; + const { guid } = this.props.attributes; + const { is_private } = this.state.metadata || {}; if ( ! guid ) { return; @@ -235,7 +234,7 @@ class VideoPressEdit extends Component { // Private videos will open in the player for logged in users with the WordPress.com URL. // However, they'll still display blank in the editor. // TODO: We need to iterate so that private videos display as expected. - return metadata.is_private + return is_private ? `https://video.wordpress.com/v/${ guid }` : `https://videopress.com/v/${ guid }`; } From 85a30acab5f76b33b0e3a537b479e7edbb91335b Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 16 Feb 2024 11:06:15 +0000 Subject: [PATCH 15/22] refactor: Replace inline styles with object ref This commit follows the feedback here: https://github.com/Automattic/jetpack/pull/35637#discussion_r1491978385 --- .../jetpack/extensions/blocks/videopress/edit.native.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index bcd8065ccb8a7..112cd9389a24c 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -269,7 +269,7 @@ class VideoPressEdit extends Component { const isSourcePresent = src || ( guid && id ); if ( ! isSourcePresent ) { return ( - + - + { ! this.state.isCaptionSelected && { toolbarEditButton } } { isSelected && ( From 11a8a8a4e447006fe0c420dc1a4a6a80c0455c6e Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 16 Feb 2024 23:04:01 +0000 Subject: [PATCH 16/22] refactor: Pass token to support private sites With this commit, the video's token is passed to ensure it can be played back on private sites/videos for both platforms. --- .../blocks/videopress/edit.native.js | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 112cd9389a24c..be89e25bed518 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -27,7 +27,7 @@ import { requestImageFailedRetryDialog, requestImageUploadCancelDialog, } from '@wordpress/react-native-bridge'; -import { isURL, getProtocol } from '@wordpress/url'; +import { isURL, getProtocol, addQueryArgs } from '@wordpress/url'; /** * External dependencies */ @@ -57,6 +57,7 @@ class VideoPressEdit extends Component { isUploadFailed: false, isLoadingMetadata: false, metadata: {}, + metadataToken: null, }; this.mediaUploadStateReset = this.mediaUploadStateReset.bind( this ); @@ -83,6 +84,7 @@ class VideoPressEdit extends Component { await this.setGuid(); } else { await this.fetchMetadata( guid ); + await this.fetchMetadataToken( guid ); } } @@ -111,6 +113,7 @@ class VideoPressEdit extends Component { setAttributes( { guid } ); if ( guid ) { await this.fetchMetadata( guid ); + await this.fetchMetadataToken( guid ); } } @@ -127,6 +130,20 @@ class VideoPressEdit extends Component { } ); } + async fetchMetadataToken( guid ) { + try { + const response = await apiFetch( { + path: `/wpcom/v2/media/videopress-playback-jwt/${ guid }`, + method: 'POST', + } ); + const { metadata_token } = response; + this.setState( { metadataToken: metadata_token } ); + } catch ( error ) { + // eslint-disable-next-line no-console + console.error( `Couldn't fetch token of VideoPress video with ID = ${ guid }` ); + } + } + onVideoPressed() { const { attributes } = this.props; @@ -225,18 +242,14 @@ class VideoPressEdit extends Component { getVideoURL() { const { guid } = this.props.attributes; - const { is_private } = this.state.metadata || {}; + const { original } = this.state.metadata || {}; + const { metadataToken } = this.state; - if ( ! guid ) { + if ( ! guid || ! original ) { return; } - // Private videos will open in the player for logged in users with the WordPress.com URL. - // However, they'll still display blank in the editor. - // TODO: We need to iterate so that private videos display as expected. - return is_private - ? `https://video.wordpress.com/v/${ guid }` - : `https://videopress.com/v/${ guid }`; + return metadataToken ? addQueryArgs( original, { metadata_token: metadataToken } ) : original; } render() { @@ -332,7 +345,6 @@ class VideoPressEdit extends Component { style={ videoStyle } source={ { uri: videoURL } } paused={ true } - poster={ this.state.metadata.poster } /> ) } From ce02a7c0a060f2d31d49215a4c90cc22964211bb Mon Sep 17 00:00:00 2001 From: Siobhan Date: Tue, 20 Feb 2024 23:34:36 +0000 Subject: [PATCH 17/22] fix: Return URL for non-VideoPress videos There are instances when the VideoPress code runs despite videos not being converted to VideoPress. For instance, on Jetpack-connected sites with the VideoPress module disabled. To ensure the video block continues to function as expected, we need to return an src for those sites. --- .../extensions/blocks/videopress/edit.native.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index be89e25bed518..55ae012dc6e11 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -241,11 +241,18 @@ class VideoPressEdit extends Component { } getVideoURL() { - const { guid } = this.props.attributes; + const { guid, src } = this.props.attributes; const { original } = this.state.metadata || {}; const { metadataToken } = this.state; - if ( ! guid || ! original ) { + // If video is not converted to VideoPress, return src. + if ( ! guid ) { + return src; + } + + // Prevent crash caused by original value changing before it's defined. + // See: https://github.com/wordpress-mobile/WordPress-iOS/issues/20882 + if ( ! original ) { return; } From 1955fc1c226b02a55c2f5e5fd3fe292ddb2005d5 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 22 Feb 2024 15:38:00 +0000 Subject: [PATCH 18/22] fix: Ensure failed state is reset when users retry --- .../plugins/jetpack/extensions/blocks/videopress/edit.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 55ae012dc6e11..1171fc70d46c0 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -170,7 +170,7 @@ class VideoPressEdit extends Component { setAttributes( { url: payload.mediaUrl } ); } if ( ! this.state.isUploadInProgress ) { - this.setState( { isUploadInProgress: true } ); + this.setState( { isUploadInProgress: true, isUploadFailed: false } ); } } From 95a72774e70aae80a1961159bbb28142e59281ec Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 22 Feb 2024 15:49:50 +0000 Subject: [PATCH 19/22] refactor: Tweaks to allow reusing translations The strings used in the block's settings have been tweaked to match the web, so that translations can be reused. --- .../videopress/edit-common-settings.native.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js index 0c01411f6cb29..b4ac7dfd70a4a 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js @@ -6,9 +6,12 @@ import { useMemo, useCallback } from '@wordpress/element'; import { __, _x } from '@wordpress/i18n'; const options = [ - { value: 'auto', label: __( 'Auto', 'jetpack' ) }, - { value: 'metadata', label: __( 'Metadata', 'jetpack' ) }, - { value: 'none', label: _x( 'None', 'Preload value', 'jetpack' ) }, + { value: 'auto', label: _x( 'Auto', 'VideoPress preload setting', 'jetpack' ) }, + { + value: 'metadata', + label: _x( 'Metadata', 'VideoPress preload setting', 'jetpack' ), + }, + { value: 'none', label: _x( 'None', 'VideoPress preload setting', 'jetpack' ) }, ]; const VideoSettings = ( { setAttributes, attributes } ) => { @@ -60,13 +63,13 @@ const VideoSettings = ( { setAttributes, attributes } ) => { /> From f1ae7fb120221b3c678e11f4008149ab04abf289 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 22 Feb 2024 16:05:32 +0000 Subject: [PATCH 20/22] refactor: Align id definition with the video block Addresses feedback here: https://github.com/Automattic/jetpack/pull/35637#discussion_r1499014896 --- .../plugins/jetpack/extensions/blocks/videopress/edit.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index 1171fc70d46c0..a9c9038e27fe2 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -207,7 +207,7 @@ class VideoPressEdit extends Component { const { createErrorNotice, setAttributes } = this.props; if ( isURL( url ) ) { - setAttributes( { id: url, src: url } ); + setAttributes( { id: undefined, src: url } ); } else { createErrorNotice( __( 'Invalid URL.', 'jetpack' ) ); } From e1de8246aef251df54a83e02bd992fd95432fe55 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 23 Feb 2024 16:00:09 +0000 Subject: [PATCH 21/22] feat: Enable embed block convert after URL insert Feedback here: https://github.com/Automattic/jetpack/pull/35637#discussion_r1498997417 --- .../extensions/blocks/videopress/constants.js | 2 ++ .../blocks/videopress/edit.native.js | 13 ++++++-- .../extensions/blocks/videopress/utils.js | 33 ++++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/constants.js b/projects/plugins/jetpack/extensions/blocks/videopress/constants.js index d38ab599e0965..29d6dec5b79e3 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/constants.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/constants.js @@ -15,3 +15,5 @@ export const VIDEO_PRIVACY = { PRIVATE: 1, SITE_DEFAULT: 2, }; + +export const DEFAULT_EMBED_BLOCK = 'core/embed'; diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js index a9c9038e27fe2..63e35295f364d 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit.native.js @@ -38,7 +38,7 @@ import { ActivityIndicator, View, TouchableWithoutFeedback, Text } from 'react-n import VideoCommonSettings from './edit-common-settings'; import SvgIconRetry from './icon-retry'; import style from './style.scss'; -import { pickGUIDFromUrl } from './utils'; +import { pickGUIDFromUrl, createVideoPressEmbedBlock } from './utils'; const ICON_TYPE = { PLACEHOLDER: 'placeholder', @@ -204,9 +204,18 @@ class VideoPressEdit extends Component { } onSelectURL( url ) { - const { createErrorNotice, setAttributes } = this.props; + const { createErrorNotice, setAttributes, onReplace } = this.props; if ( isURL( url ) ) { + // Check if there's an embed block that handles this URL. + const embedBlock = createVideoPressEmbedBlock( { + attributes: { url }, + } ); + if ( undefined !== embedBlock ) { + onReplace( embedBlock ); + return; + } + setAttributes( { id: undefined, src: url } ); } else { createErrorNotice( __( 'Invalid URL.', 'jetpack' ) ); diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/utils.js b/projects/plugins/jetpack/extensions/blocks/videopress/utils.js index 63024ea83bce8..c4c275556555e 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/utils.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/utils.js @@ -2,8 +2,9 @@ * The code below is pulled from Gutenberg embed block, until we can use it directly from Gutenberg * https://github.com/WordPress/gutenberg/blob/e4b6d70f129a745a0cc7dc556d41a44bdab7b0ca/packages/block-library/src/embed/util.js#L177 */ +import { createBlock, getBlockType } from '@wordpress/blocks'; import classnames from 'classnames'; -import { ASPECT_RATIOS } from './constants'; +import { ASPECT_RATIOS, DEFAULT_EMBED_BLOCK } from './constants'; /** * Removes all previously set aspect ratio related classes and return the rest @@ -108,3 +109,33 @@ export const isVideoPressBlockBasedOnAttributes = attributes => { return true; }; + +/** + * Creates an embed block if a VideoPress URL is passed. + * + * @param {object} props - The block's props. + * @returns {object|undefined} The embed block, if appropriate. + */ +export const createVideoPressEmbedBlock = props => { + const { attributes = {} } = props; + const { url, ...restAttributes } = attributes; + + if ( ! url || ! getBlockType( DEFAULT_EMBED_BLOCK ) ) { + return; + } + + const isVideoPress = /^https?:\/\/videopress\.com\/.+/i.test( url ); + + if ( isVideoPress ) { + const matchedAttributes = { + providerNameSlug: 'videopress', + responsive: true, + }; + + return createBlock( DEFAULT_EMBED_BLOCK, { + url, + ...restAttributes, + ...matchedAttributes, + } ); + } +}; From e88d3d4c562afec065c652de3756fe032fb308bc Mon Sep 17 00:00:00 2001 From: Siobhan Date: Fri, 23 Feb 2024 16:09:16 +0000 Subject: [PATCH 22/22] refactor: Fix missing period at end of sentence --- .../extensions/blocks/videopress/edit-common-settings.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js index b4ac7dfd70a4a..420e03b7a7a54 100644 --- a/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js +++ b/projects/plugins/jetpack/extensions/blocks/videopress/edit-common-settings.native.js @@ -47,7 +47,7 @@ const VideoSettings = ( { setAttributes, attributes } ) => { label={ __( 'Autoplay', 'jetpack' ) } onChange={ toggleFactory.autoplay } checked={ !! autoplay } - help={ __( 'Autoplay may cause usability issues for some users', 'jetpack' ) } + help={ __( 'Autoplay may cause usability issues for some users.', 'jetpack' ) } />