Open video-speed in Script Kit
Very useful for making those AI screen recordings look better (=faster :D)
// Name: Speed Up Video// Description: Speed up a video, optionally keeping the first and last X seconds at original speed// Author: Strajkimport '@johnlindquist/kit';// Get the video file path, either from selection or promptimport { Choice } from '@johnlindquist/kit';const videoPath = await getSelectedFile() || await path({ placeholder: 'Select a video file' });const { stdout: videoDurationRaw } = await $`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 ${videoPath}`const videoDuration = parseFloat(videoDurationRaw)// Not sure if best way of handling error statesif (!videoDuration || videoDuration < 1) {await div(`${videoPath} does not look like a video file, exiting`)exit()}const { dir, name, ext } = path.parse(videoPath);const outputPath = path.join(dir, `${name}-adjusted${ext}`);const speedOptions: Choice[] = [{ name: `2x (${Math.round(videoDuration / 2)}s)`, value: 2 },{ name: `3x (${Math.round(videoDuration / 3)}s)`, value: 3 },{ name: `4x (${Math.round(videoDuration / 4)}s)`, value: 4 },{ name: `5x (${Math.round(videoDuration / 5)}s)`, value: 5 },];// Prompt user to select a speedconst speedRaw = await arg({placeholder: `Select new playback speed, or enter a custom value`,hint: `Any number or ";5;3;6" for 5x speed-up, but first 3 and last 6s are kept at original speed`,choices: speedOptions,strict: false, // allow arbitrary input});let mode: 'simple' | 'complex' = speedRaw.includes?.(';') ? 'complex' : 'simple'if (mode === 'simple') {let speed: number = parseFloat(speedRaw)// -filter:v means video filter// -filter:a means audio filter// for uploading to twitter, i'm setting fps to 30await term(`ffmpeg \-i "${videoPath}" \-filter:v "setpts=${1 / speed}*PTS,fps=30" \-filter:a "atempo=${speed}" \-y "${outputPath}"`)} else {let [speedStr, introStr, outroStr] = speedRaw.split(';')let speed = parseFloat(speedStr)let intro = parseInt(introStr)let outro = parseInt(outroStr)// Note: ffmpeg is savageawait term(`ffmpeg -i "${videoPath}" -filter_complex "[0:v]split=3[v1][v2][v3];[v1]trim=0:${intro},setpts=PTS-STARTPTS,fps=30[first];[v2]trim=${intro}:${videoDuration - outro},setpts=PTS-STARTPTS,setpts=${1 / speed}*PTS,fps=30[middle];[v3]trim=${videoDuration - outro},setpts=PTS-STARTPTS,fps=30[last];[first][middle][last]concat=n=3:v=1:a=0[outv]" -y -map "[outv]" "${outputPath}"`)}// Reveal output file in the system's file explorerawait revealFile(outputPath);