installed plugin Infinite Uploads version 2.0.8

This commit is contained in:
2025-05-02 12:03:21 +00:00
committed by Gitium
parent 7ca941b591
commit 8fefb19ab4
1179 changed files with 99739 additions and 0 deletions

View File

@ -0,0 +1,44 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "infinite-uploads/video",
"version": "0.1.0",
"title": "Infinite Uploads Video",
"category": "media",
"icon": "format-video",
"description": "Upload & Embed a video via Infinite Uploads Video Cloud.",
"attributes": {
"video_id": {
"type": "string"
},
"autoplay": {
"type": "boolean",
"default": false
},
"loop": {
"type": "boolean",
"default": false
},
"muted": {
"type": "boolean",
"default": false
},
"preload": {
"type": "boolean",
"default": true
}
},
"supports": {
"html": false,
"anchor": true,
"align": true,
"spacing": {
"margin": true,
"padding": true
}
},
"textdomain": "infinite-uploads",
"editorScript": "file:../../../build/block.js",
"editorStyle": "file:../../../build/block.css",
"style": "file:../../../build/style-block.css"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
import {__, _x} from '@wordpress/i18n';
import {Button, Modal} from '@wordpress/components';
import {useState, useEffect} from '@wordpress/element';
import Library from '../../../admin/components/Library';
import {InfiniteUploadsIcon} from '../Images';
import './styles.scss';
export default function LibraryModal({selectVideo, ...props}) {
const [isOpen, setOpen] = useState(false);
const openModal = () => setOpen(true);
const closeModal = () => setOpen(false);
return (
<>
<Button variant="primary" onClick={openModal}>
{__('Select from Library', 'infinite-uploads')}
</Button>
{isOpen && (
<Modal
{...props}
isDismissible={true}
onRequestClose={closeModal}
icon={InfiniteUploadsIcon(false)}
style={{width: '98%'}}
title={__('Cloud Video Library', 'infinite-uploads')}
className="iup-block-library-model"
>
<p>
{__(
'Select a video from your library to insert into the editor.',
'infinite-uploads'
)}
</p>
<Library selectVideo={selectVideo}/>
</Modal>
)}
</>
);
}

View File

@ -0,0 +1,33 @@
//scope bootstrap styles to library modal only
.iup-block-library-model {
@import '~bootstrap/scss/bootstrap';
.components-modal__header-heading {
margin-bottom: 0;
margin-left: 0.5em;
}
.bg-black {
background-color: #000 !important;
}
.text-secondary {
color: #6c757d !important;
font-size: 16px;
}
.rounded-top {
border-top-left-radius: 0.375rem !important;
border-top-right-radius: 0.375rem !important;
}
.btn .dashicons {
font-size: 1.5rem;
line-height: 1;
margin-right: 0.5rem;
}
.rounded-pill {
border-radius: 50rem !important;
}
}

View File

@ -0,0 +1,63 @@
/**
* WordPress dependencies
*/
import {__, _x} from '@wordpress/i18n';
import {ToggleControl, SelectControl} from '@wordpress/components';
import {useMemo, useCallback, Platform} from '@wordpress/element';
const VideoSettings = ({setAttributes, attributes}) => {
const {autoplay, loop, muted, preload} = attributes;
const autoPlayHelpText = __(
'Autoplay may cause usability issues for some users.'
);
const getAutoplayHelp = Platform.select({
web: useCallback((checked) => {
return checked ? autoPlayHelpText : null;
}, []),
native: autoPlayHelpText,
});
const toggleFactory = useMemo(() => {
const toggleAttribute = (attribute) => {
return (newValue) => {
setAttributes({[attribute]: newValue});
};
};
return {
autoplay: toggleAttribute('autoplay'),
loop: toggleAttribute('loop'),
muted: toggleAttribute('muted'),
preload: toggleAttribute('preload'),
};
}, []);
return (
<>
<ToggleControl
label={__('Autoplay')}
onChange={toggleFactory.autoplay}
checked={autoplay}
help={getAutoplayHelp}
/>
<ToggleControl
label={__('Loop')}
onChange={toggleFactory.loop}
checked={loop}
/>
<ToggleControl
label={__('Muted')}
onChange={toggleFactory.muted}
checked={muted}
/>
<ToggleControl
label={__('Preload')}
onChange={toggleFactory.preload}
checked={preload}
/>
</>
);
};
export default VideoSettings;

View File

@ -0,0 +1,94 @@
/*
* Because of the way Uppy is designed, we can't use onBeforeUpload to set the video_id as it does not support async.
* So this custom plugin is used to set the video_id before the upload starts.
*
* @see https://uppy.io/docs/writing-plugins/#Example-of-a-custom-plugin
*/
import {UIPlugin} from '@uppy/core';
class UppyCreateVid extends UIPlugin {
constructor(uppy, opts) {
super(uppy, {...{}, ...opts});
this.id = this.opts.id || 'CreateVid';
this.type = 'modifier';
}
createVideo(title) {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.append('title', title);
formData.append('nonce', IUP_VIDEO.nonce);
const options = {
method: 'POST',
headers: {
Accept: 'application/json',
},
body: formData,
};
fetch(
`${ajaxurl}?action=infinite-uploads-video-create`,
options
)
.then((response) => response.json())
.then((data) => {
console.log(data);
if (data.success) {
resolve(data.data);
} else {
reject(data.data);
}
})
.catch((error) => {
console.log('Error:', error);
return reject(error);
});
});
}
prepareUpload = (fileIDs) => {
const promises = fileIDs.map((fileID) => {
const file = this.uppy.getFile(fileID);
//get the title from the file name and remove the extension
const title = file.name.replace(/\.[^/.]+$/, '');
return this.createVideo(title)
.then((upload) => {
console.log(`Video ${upload.VideoId} created`);
this.opts.uploadAuth.current = {...this.opts.uploadAuth.current, [fileID]: upload};
})
.catch((err) => {
this.uppy.log(
`Video could not be created ${file.id}:`,
'warning'
);
this.uppy.log(err, 'warning');
});
});
const emitPreprocessCompleteForAll = () => {
fileIDs.forEach((fileID) => {
const file = this.uppy.getFile(fileID);
this.uppy.emit('preprocess-complete', file);
});
};
// Why emit `preprocess-complete` for all files at once, instead of
// above when each is processed?
// Because it leads to StatusBar showing a weird “upload 6 files” button,
// while waiting for all the files to complete pre-processing.
return Promise.all(promises).then(emitPreprocessCompleteForAll);
};
install() {
this.uppy.addPreProcessor(this.prepareUpload);
}
uninstall() {
this.uppy.removePreProcessor(this.prepareUpload);
}
}
export default UppyCreateVid;

View File

@ -0,0 +1,340 @@
/**
* WordPress components that create the necessary UI elements for the block
*
* @see https://developer.wordpress.org/block-editor/packages/packages-components/
*
* See https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/video/
*/
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-block-editor/#useBlockProps
*/
import {useSelect} from '@wordpress/data';
import {
PanelBody, Placeholder, Spinner,
ToolbarButton,
} from '@wordpress/components';
import {useBlockProps, InspectorControls, BlockControls} from '@wordpress/block-editor';
import {replace} from '@wordpress/icons';
import {InfiniteUploadsIcon} from './components/Images';
import {__, sprintf} from '@wordpress/i18n';
import {useRef, useEffect, useState} from '@wordpress/element';
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
import {DragDrop, StatusBar, useUppy} from '@uppy/react';
import UppyCreateVid from './edit-uppy-plugin';
import VideoCommonSettings from './edit-common-settings';
import LibraryModal from './components/LibraryModal';
import '../../assets/css/admin.css';
//pulled from wp_localize_script later
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#edit
*
* @param {Object} props Properties passed to the function.
* @param {Object} props.attributes Available block attributes.
* @param {Function} props.setAttributes Function that updates individual attributes.
*
* @return {WPElement} Element to render.
*/
export default function Edit({clientId, attributes, setAttributes}) {
const blockProps = useBlockProps();
const isSelected = useSelect((select) =>
select('core/block-editor').isBlockSelected(clientId, true)
);
/* Possible video statuses
Created = 0
Uploaded = 1
Processing = 2
Transcoding = 3
Finished = 4
Error = 5
UploadFailed = 6
*/
const [video, setVideo] = useState(null);
const [isUploading, setUploading] = useState(false);
const [showOverlay, setShowOverlay] = useState(true);
const uploadAuth = useRef(null);
//reenable the click overlay whenever the block is unselected so we can click back on it
useEffect(() => {
if (!isSelected) {
setShowOverlay(true);
}
}, [isSelected]);
useEffect(() => {
if (attributes.video_id) {
getVideo();
}
}, []);
//poll the video status every 5 seconds while status is 2-3
useEffect(() => {
if (video && (video.status === 2 || video.status === 3)) {
const interval = setInterval(() => {
getVideo();
}, 5000);
return () => clearInterval(interval);
}
}, [video]);
const uppy = useUppy(() => {
return new Uppy({
debug: true,
restrictions: {
maxNumberOfFiles: 1,
allowedFileTypes: ['video/*'],
},
autoProceed: true,
allowMultipleUploadBatches: false,
onBeforeUpload: (files) => {
//TODO trigger error if video_id is null
},
})
.use(Tus, {
endpoint: 'https://video.bunnycdn.com/tusupload',
retryDelays: [0, 1000, 3000, 5000, 10000],
onBeforeRequest: (req, file) => {
//console.log('Video Auth:', uploadAuth.current[file.id]);
if (uploadAuth.current[file.id]) {
setAttributes({
video_id: uploadAuth.current[file.id].VideoId,
});
attributes.video_id = uploadAuth.current[file.id].VideoId; //I don't know why this is needed
} else {
throw new Error('Error fetching auth.');
return false;
}
req.setHeader(
'AuthorizationSignature',
uploadAuth.current[file.id].AuthorizationSignature
);
req.setHeader(
'AuthorizationExpire',
uploadAuth.current[file.id].AuthorizationExpire
);
req.setHeader('VideoId', uploadAuth.current[file.id].VideoId);
req.setHeader('LibraryId', IUP_VIDEO.libraryId);
},
})
.use(UppyCreateVid, {uploadAuth}); //our custom plugin
});
let uploadSuccess = useRef(false);
uppy.on('upload', (data) => {
// data object consists of `id` with upload ID and `fileIDs` array
// with file IDs in current upload
// data: { id, fileIDs }
setUploading(true);
uploadSuccess.current = false;
});
uppy.on('cancel-all', () => {
setUploading(false);
});
uppy.on('error', (error) => {
console.error(error.stack);
setUploading(false);
});
uppy.on('upload-error', (file, error, response) => {
console.log('error with file:', file.id);
console.log('error message:', error);
setUploading(false);
});
uppy.on('upload-success', (file, response) => {
if (!uploadSuccess.current) {
uploadSuccess.current = true;
getVideo();
}
setUploading(false);
});
function getVideo() {
if (!attributes.video_id) {
return false;
}
const options = {
method: 'GET',
headers: {
Accept: 'application/json',
AccessKey: IUP_VIDEO.apiKey,
},
};
fetch(
`https://video.bunnycdn.com/library/${IUP_VIDEO.libraryId}/videos/${attributes.video_id}`,
options
)
.then((response) => response.json())
.then((data) => {
console.log('Video:', data);
setVideo(data);
})
.catch((error) => {
console.error(error);
});
}
const selectVideo = (video) => {
setAttributes({video_id: video.guid});
setVideo(video);
setUploading(false);
};
if (
!isUploading &&
attributes.video_id &&
video &&
[1, 2, 3, 4].includes(video.status)
) {
if (video.status === 4) {
return (
<>
<div {...blockProps}>
<figure className="iup-video-embed-wrapper">
<iframe
src={`https://iframe.mediadelivery.net/embed/${IUP_VIDEO.libraryId}/${attributes.video_id}?autoplay=${attributes.autoplay}&preload=${attributes.preload}&loop=${attributes.loop}&muted=${attributes.muted}`}
loading="lazy"
className="iup-video-embed"
sandbox="allow-scripts allow-same-origin allow-presentation"
allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"
allowFullScreen={true}
></iframe>
</figure>
{showOverlay && (
<button
className="iup-video-overlay"
onClick={() => setShowOverlay(false)}
/>
)}
</div>
<BlockControls group="other">
<ToolbarButton
onClick={() => setAttributes({video_id: null})}
icon={replace}
label={__('Replace Video', 'infinite-uploads')}
/>
</BlockControls>
<InspectorControls>
<PanelBody title={__('Settings')}>
<VideoCommonSettings
setAttributes={setAttributes}
attributes={attributes}
/>
</PanelBody>
</InspectorControls>
</>
);
} else {
let label = '';
let style = {};
if (video.status === 3) {
label = sprintf(
__('Video %d%% encoded...', 'infinite-uploads'),
video.encodeProgress
);
style = {
backgroundImage: `url("${IUP_VIDEO.cdnUrl}/${attributes.video_id}/${video.thumbnailFileName}")`,
};
} else if (video.status <= 1) {
label = __('Awaiting Upload...', 'infinite-uploads');
} else if (video.status > 4) {
label = __('Video Error. Upload again.', 'infinite-uploads');
} else {
label = sprintf(
__('Video %d%% processed...', 'infinite-uploads'),
video.encodeProgress
);
}
return (
<>
<div {...blockProps}>
<div className="ratio-16-9-outer">
<div className="ratio-16-9-inner" style={style}>
<div className="ratio-16-9-content">
<Spinner
style={{
height: '0.9em',
width: '0.9em',
}}
/>{' '}
{label}
</div>
</div>
</div>
</div>
<InspectorControls>
<PanelBody title={__('Settings')}>
<VideoCommonSettings
setAttributes={setAttributes}
attributes={attributes}
/>
</PanelBody>
</InspectorControls>
</>
);
}
} else {
return (
<div {...blockProps}>
<Placeholder
icon={InfiniteUploadsIcon}
instructions={__(
'Upload a new video direct to the cloud or select a video from your cloud library.',
'infinite-uploads'
)}
label={__('Infinite Uploads Video', 'infinite-uploads')}
>
<div className="placeholder-wrapper">
<div className="uppy-wrapper">
{!isUploading ? (
<DragDrop
width="100%"
height="100%"
// assuming `props.uppy` contains an Uppy instance:
uppy={uppy}
locale={{
strings: {
// Text to show on the droppable area.
// `%{browse}` is replaced with a link that opens the system file selection dialog.
dropHereOr: __(
'Drop video file here or %{browse}.',
'infinite-uploads'
),
// Used as the label for the link that opens the system file selection dialog.
browse: __(
'browse files',
'infinite-uploads'
),
},
}}
/>
) : (
''
)}
<StatusBar
// assuming `props.uppy` contains an Uppy instance:
uppy={uppy}
hideUploadButton={false}
hideAfterFinish={true}
showProgressDetails
/>
</div>
{!isUploading && (
<LibraryModal selectVideo={selectVideo}/>
)}
</div>
</Placeholder>
</div>
);
}
}

View File

@ -0,0 +1,102 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-infinite-uploads-video {
box-sizing: border-box;
position: relative;
text-align: left;
color: #1e1e1e;
-moz-font-smoothing: subpixel-antialiased;
-webkit-font-smoothing: subpixel-antialiased;
border-radius: 2px;
background-color: #fff;
box-shadow: inset 0 0 0 1px #1e1e1e;
outline: 1px solid transparent;
@import '../../../node_modules/@uppy/core/dist/style';
@import '../../../node_modules/@uppy/drag-drop/dist/style';
@import '../../../node_modules/@uppy/status-bar/dist/style';
.placeholder-wrapper {
width: 100%;
}
.uppy-wrapper {
margin-bottom: 1em;
}
.uppy-StatusBar-progress {
height: 1em;
background-color: var(--wp-admin-theme-color);
}
.uppy-StatusBar::before {
height: 1em;
}
.uppy-StatusBar-content {
margin-top: 1em;
}
.uppy-StatusBar-actions {
margin-top: 1em;
}
.uppy-DragDrop-inner {
padding: 40px 20px;
}
.uppy-DragDrop-arrow {
width: 40px;
height: 40px;
}
.ratio-16-9-outer {
position: relative;
width: 100%;
overflow: hidden;
&:before {
content: '';
display: block;
padding-top: calc(9 / 16) * 100%;
}
> .ratio-16-9-inner {
background-size: cover;
background-position: 50% 50%;
background-repeat: no-repeat;
background-color: #000000;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ratio-16-9-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5em;
background-color: rgba(0, 0, 0, 0.5);
}
}
.iup-video-overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border: 0;
background: none;
}
}

View File

@ -0,0 +1,50 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block
*/
import {registerBlockType} from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor. All other files
* get applied to the editor only.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
import './editor.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
import {InfiniteUploadsIcon} from './components/Images';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block
*/
registerBlockType(metadata.name, {
/**
* Used to construct a preview for the block to be shown in the block inserter.
*/
example: {
attributes: {
video_id: '',
},
},
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
icon: InfiniteUploadsIcon(false),
});

View File

@ -0,0 +1,40 @@
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-block-editor/#useBlockProps
*/
import {useBlockProps} from '@wordpress/block-editor';
/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#save
*
* @param {Object} props Properties passed to the function.
* @param {Object} props.attributes Available block attributes.
* @return {WPElement} Element to render.
*/
export default function save({attributes}) {
const blockProps = useBlockProps.save();
if (attributes.video_id) {
return (
<figure {...blockProps}>
<div className="iup-video-embed-wrapper">
<iframe
src={`https://iframe.mediadelivery.net/embed/${IUP_VIDEO.libraryId}/${attributes.video_id}?autoplay=${attributes.autoplay}&preload=${attributes.preload}&loop=${attributes.loop}&muted=${attributes.muted}`}
loading="lazy"
className="iup-video-embed"
sandbox="allow-scripts allow-same-origin allow-presentation"
allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"
allowFullScreen={true}
></iframe>
</div>
</figure>
);
} else {
return <div {...blockProps}></div>;
}
}

View File

@ -0,0 +1,21 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-infinite-uploads-video {
.iup-video-embed-wrapper {
position: relative;
padding-top: 56.25%;
min-width: var(--wp--style--global--content-size);
}
.iup-video-embed {
border: none;
position: absolute;
top: 0;
height: 100%;
width: 100%;
}
}