From dfb5354d2d13062ce1a6f74c7e9f914e3a0f9dee Mon Sep 17 00:00:00 2001 From: Muffin Date: Mon, 5 Aug 2024 21:22:46 -0500 Subject: [PATCH] Lily/Video: playback rate (#1642) --- extensions/Lily/Video.js | 51 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/extensions/Lily/Video.js b/extensions/Lily/Video.js index c68eea793..8050f2134 100644 --- a/extensions/Lily/Video.js +++ b/extensions/Lily/Video.js @@ -307,6 +307,23 @@ }, }, }, + { + opcode: "setPlaybackRate", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate( + "set playback rate of video [NAME] to [RATE]" + ), + arguments: { + NAME: { + type: Scratch.ArgumentType.STRING, + defaultValue: "my video", + }, + RATE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "2", + }, + }, + }, ], menus: { targets: { @@ -349,6 +366,10 @@ text: Scratch.translate("height"), value: "height", }, + { + text: Scratch.translate("playback rate"), + value: "playback rate", + }, ], }, }, @@ -475,6 +496,8 @@ return videoSkin.size[0]; case "height": return videoSkin.size[1]; + case "playback rate": + return videoSkin.videoElement.playbackRate; default: return 0; } @@ -492,9 +515,14 @@ return ""; } - canvas.width = videoSkin.videoElement.videoWidth; - canvas.height = videoSkin.videoElement.videoHeight; - ctx.drawImage(videoSkin.videoElement, 0, 0); + const videoElement = videoSkin.videoElement; + if (videoElement.videoWidth === 0 || videoElement.videoHeight === 0) { + return ""; + } + + canvas.width = videoElement.videoWidth; + canvas.height = videoElement.videoHeight; + ctx.drawImage(videoElement, 0, 0); return canvas.toDataURL(); } @@ -528,13 +556,28 @@ setVolume(args) { const videoName = Cast.toString(args.NAME); - const value = Cast.toNumber(args.VALUE); const videoSkin = this.videos[videoName]; if (!videoSkin) return; + const value = Cast.toNumber(args.VALUE); videoSkin.videoElement.volume = Math.min(1, Math.max(0, value / 100)); } + setPlaybackRate(args) { + const videoName = Cast.toString(args.NAME); + const videoSkin = this.videos[videoName]; + if (!videoSkin) return; + + try { + const value = Cast.toNumber(args.RATE); + // Supposedly negative values will work in Safari but people probably shouldn't rely + // on that since others don't. + videoSkin.videoElement.playbackRate = Math.max(0, value); + } catch (e) { + console.warn(e); + } + } + /** @returns {VM.Target|undefined} */ _getTargetFromMenu(targetName, util) { if (targetName === "_myself_") return util.target;