diff --git a/clock/src/controller/asset/Asset.js b/clock/src/controller/asset/Asset.js index 1300e1d9..0a4441ed 100644 --- a/clock/src/controller/asset/Asset.js +++ b/clock/src/controller/asset/Asset.js @@ -14,6 +14,7 @@ import Ruv from "./Ruv"; import controllerActions from "../../actions/controller"; import "./Asset.css"; +import VideoPlayer from "./VideoPlayer"; class Asset extends Component { static propTypes = { @@ -60,7 +61,11 @@ class Asset extends Component { if (sync && auth.isEmpty) { return; } - const typeNeedsManualRemove = asset.type !== assetTypes.URL; + const typesWithoutManualRemove = [assetTypes.URL, assetTypes.VIDEO]; + const typeNeedsManualRemove = !typesWithoutManualRemove.includes( + asset.type, + ); + if (time && !thumbnail && typeNeedsManualRemove) { this.timeout = setTimeout(removeAssetAfterTimeout, time * 1000); } @@ -184,57 +189,71 @@ class Asset extends Component { ); } - render() { + renderSub() { const { asset, thumbnail } = this.props; - if (!asset) { + const { subIn, subOut } = asset; + if (!subIn || !subOut) { + console.log("No subin or subout", asset); return null; } + return ( + + {[subIn, subOut].map((subAsset) => + this.getPlayerAsset({ + asset: subAsset, + widthMultiplier: 0.7, + includeBackground: false, + }), + )} + + ); + } - if (asset.type === assetTypes.IMAGE) { - return ( - {asset.key} - ); - } - if (asset.type === assetTypes.URL) { - return this.renderUrl(); - } - if (asset.type === assetTypes.RUV) { - return this.renderRuv(); - } - if ( - asset.type === assetTypes.PLAYER || - asset.type === assetTypes.NO_IMAGE_PLAYER - ) { - return this.getPlayerAsset({ asset, widthMultiplier: 1 }); + render() { + const { asset, thumbnail, removeAssetAfterTimeout } = this.props; + if (!asset) { + return null; } - if (asset.type === assetTypes.SUB) { - const { subIn, subOut } = asset; - if (!subIn || !subOut) { - console.log("No subin or subout", asset); + + switch (asset.type) { + case assetTypes.IMAGE: + return ( + {asset.key} + ); + case assetTypes.VIDEO: + return ( + + ); + + case assetTypes.URL: + return this.renderUrl(); + + case assetTypes.RUV: + return this.renderRuv(); + + case assetTypes.PLAYER: + case assetTypes.NO_IMAGE_PLAYER: + return this.getPlayerAsset({ asset, widthMultiplier: 1 }); + + case assetTypes.SUB: + return this.renderSub(); + + case assetTypes.FREE_TEXT: + return this.renderFreeText(); + + default: + console.error("No type for item ", asset); return null; - } - return ( - - {[subIn, subOut].map((subAsset) => - this.getPlayerAsset({ - asset: subAsset, - widthMultiplier: 0.7, - includeBackground: false, - }), - )} - - ); } - if (asset.type === assetTypes.FREE_TEXT) { - return this.renderFreeText(); - } - console.error("No type for item ", asset); - return null; } } diff --git a/clock/src/controller/asset/AssetTypes.js b/clock/src/controller/asset/AssetTypes.js index a855400d..0c93288c 100644 --- a/clock/src/controller/asset/AssetTypes.js +++ b/clock/src/controller/asset/AssetTypes.js @@ -4,6 +4,7 @@ export default { PLAYER: "PLAYER", NO_IMAGE_PLAYER: "NO_IMAGE_PLAYER", IMAGE: "IMAGE", + VIDEO: "VIDEO", SUB: "SUB", FREE_TEXT: "FREE_TEXT", }; diff --git a/clock/src/controller/asset/VideoPlayer.js b/clock/src/controller/asset/VideoPlayer.js new file mode 100644 index 00000000..eaadae84 --- /dev/null +++ b/clock/src/controller/asset/VideoPlayer.js @@ -0,0 +1,42 @@ +import React, { useRef, useEffect } from "react"; +import PropTypes from "prop-types"; + +import { assetPropType } from "../../propTypes"; + +const VideoPlayer = ({ + asset: { url, key }, + thumbnail, + playbackSpeed = 1, + onEnded, +}) => { + const videoRef = useRef(null); + + if (playbackSpeed !== 1) { + useEffect(() => { + if (videoRef.current && !thumbnail) { + videoRef.current.playbackRate = playbackSpeed; // Set the playback rate + } + }, [playbackSpeed, url || key]); // Update playback speed when it changes + } + return ( +
+
+ ); +}; +VideoPlayer.propTypes = { + asset: assetPropType.isRequired, + playbackSpeed: PropTypes.number.isRequired, + onEnded: PropTypes.func.isRequired, + thumbnail: PropTypes.bool, +}; + +export default VideoPlayer; diff --git a/clock/src/controller/media/ImageList.js b/clock/src/controller/media/ImageList.js index 7267a5db..9de89d10 100644 --- a/clock/src/controller/media/ImageList.js +++ b/clock/src/controller/media/ImageList.js @@ -10,6 +10,10 @@ import TrashIcon from "@rsuite/icons/Trash"; import "./ImageList.css"; +const AssetTypeSuffixMap = { + mp4: assetTypes.VIDEO, +}; + const ImageList = ({ prefix, renderAsset, @@ -81,12 +85,15 @@ const ImageList = ({
{ + const parts = name.split("."); + const suffix = parts[parts.length - 1]; + const type = AssetTypeSuffixMap[suffix] || assetTypes.IMAGE; const asset = { // To be able to add the same image multiple times to the queue, // we need to make the key unique key: imageUrl + Date.now(), url: imageUrl, - type: assetTypes.IMAGE, + type, }; if (displayNow) { renderAsset({ asset });