header={ "recipe_version": "1.9", "title": "Cut video X/Twitter", "description": "Cut a video into 2:20 pieces for easy sharing", "category": "video", "chef": "BeatRig", "spice": "BQ==:G+Hy36kJcnQQYYavb/JV2Il6eCYr6h4hRJHCF9rRbhX5BcazL6cuTgUMdz0xA50VWA5PmmV0Q7aWkiUtNFtbk991l+t0e8IBXMReMIT1GNjnZZDv7n2YRAo0xcSQbY0ixjG6LLH4wGKnspKAoA/v69iLn6N2IH0XzIZwTGdHSo4=", "palette": "Blueberry Slate", "flavour": "1ozXUgOnXRCut+6SM2W39uw+zNUj+t8Xg3STQ+GgYxhtH4qAJwU0UaahzrcDVAjScnXgDeIZh/kYEZkY6w2r7p4zQKoUIajUUxNIcIYfz1SjhOxgLhXVEwT66XydUhOgx8YIiQs7HbuYEtvD8Qnfi2V9qZhlcS+bO5Z/lL0S8wI=", "time": 1694478580, "core_version": "0.5.7", "magnetron_version": "1.0.261", "cmds": "ffprobe,ffmpeg", "type": "default", "os": "windows,macOS", "functions": "main,onConfig,onAbout", "dependencies": "ffprobe,ffmpeg", "uuid": "514f947bc71d49e5bbf433f6f4922b7c", "instructions": "Drop files and press run to cut videos into 2:20 min parts", "tags": "video,share limit,2m20,@:20,cut video" }; //---------------------------------------------------------------------------- var config = { "parts": 1, "partItt": 0, "cutLength": 140, "totalsec": 0, }; function cmd_callback(cmd_name, cmd_output) { if(cmd_name == "ffmpeg" && cmd_output.length > 0) { var progress = calculateSeconds(findSubString(cmd_output, "time=", " bitrate")); progress = Math.round(progress / config.totalsec * 100); setProgress(progress); setMainMessage(progress + "%"); } return { "terminate": isCanceled(), }; } function calculateSeconds(dur_tc) { var hours = (dur_tc.substring(0, 2)); var minutes = (dur_tc.substring(3, 3+2)); var seconds = (dur_tc.substring(6, 6+2)); if (hours.substring(0, 1) == "0") hours = hours.substring(1,2); if (minutes.substring(0, 1) == "0") minutes = minutes.substring(1,2); if (seconds.substring(0, 1) == "0") seconds = seconds.substring(1,2); hours = parseInt(hours); minutes = parseInt(minutes); seconds = parseInt(seconds); totalsec = (hours * 60 * 60) + (minutes * 60) + seconds; return totalsec; } function setDur(infile) { var probeoutput = cmd("ffprobe", [infile]); echo(probeoutput); var dur_tc = findSubString(probeoutput, "Duration: ", ", s"); config.totalsec = calculateSeconds(dur_tc); echo("dur:" + config.totalsec); } function setupArgs(infile, cutItt) { var args1 = ["-y", "-i", infile]; if (config.parts > 1) { echo("start time:" + cutItt * config.cutLength); args1.push("-ss"); args1.push(cutItt * config.cutLength); } if (cutItt < config.parts - 1) { echo("length:" + config.cutLength); args1.push("-t"); args1.push(config.cutLength); } args1.push("-preset"); args1.push("slow"); args1.push("-movflags"); args1.push("+faststart"); args1.push(config.outfile); return args1; } //---------------------------------------------------------------------------- function main() { // check if ffmpeg is installed if (fileExists(getAllowedApps("ffmpeg")) == false) abort("no ffmpeg installed"); if (fileExists(getAllowedApps("ffprobe")) == false) abort("no ffprobe installed"); setMainMessage("starting"); setProgress(0); var now = getCurrentEpoch(); // secs since 1 jan 1970 var files = getFiles(); var infile = ""; var numFiles = files.length; if (numFiles<= 0) abort("drop some files first"); for (i = 0; i < numFiles && isCanceled() == false; i++) { // base path infile = files[i].path; var pathinfo = getPathInfo(infile); setFileIcon(files[i].path, files[i].index, "HourglassHalf"); setFileIconColor(files[i].path, files[i].index, "FF5299D3"); setFileStatus(files[i].path, files[i].index, "busy"); // calc the duration in sec setDur(infile); if (config.totalsec > 0) { config.parts = (config.totalsec / config.cutLength); if (parseInt(config.parts) < config.parts) config.parts = parseInt(config.parts) + 1; else config.parts = parseInt(config.parts); setProgress(101); var userOuputPath = pathinfo.folder + gvar.pss + pathinfo.basename + "-x-[magnetron.app]." + pathinfo.ext; var fileNames = []; if (config.parts > 1) { // create all file names (cluster dialogs together) config.partItt = 0; while (config.partItt < config.parts) { var pathinfoOut = getPathInfo(userOuputPath); config.outfile = pathinfoOut.folder + gvar.pss + pathinfoOut.basename + "-[" + (config.partItt + 1) + "_" + config.parts + "].mp4"; if (fileExists(config.outfile)) { var form2 = { "overwrite" : { "type" : "button", "label" : "overwrite", "returns" : 1 }, "cancel" : { "type" : "button", "label" : "cancel", "returns" : 0 } }; if (dialog(header.title, "file already exists\n" + pathinfoOut.basename + "." + pathinfoOut.ext, "w", form2).cancel == 1) { setMainMessage("cancelled"); abort("cancelled"); } } fileNames.push(config.outfile); config.partItt++; } } else { config.outfile = userOuputPath; fileNames.push(config.outfile); } var newfilesize = 0; config.partItt = 0; while (config.partItt < config.parts) { // main process var msg = ("busy please wait"); setMainMessage(msg); echo(msg); config.outfile = fileNames[config.partItt]; var args1 = setupArgs(infile, config.partItt); echo(cmd("ffmpeg", args1)); // perform cmd newfilesize = getFileBytes(config.outfile); echo("new file size:" + bytesToDescription(newfilesize)); if(isCanceled()) { setMainMessage("cancelled"); abort("cancelled"); } config.partItt++; } if (newfilesize <= 0) { setFileIcon(files[i].path, files[i].index, "ExclamationTriangle"); setFileIconColor(files[i].path, files[i].index, "FFb11414"); setFileStatus(files[i].path, files[i].index, "can't encode this file", "w"); } else { setFileIcon(files[i].path, files[i].index, "CheckCircleO"); setFileIconColor(files[i].path, files[i].index, "FF3aac4d"); setFileStatus(files[i].path, files[i].index, "done"); } } else setFileStatus(files[i].path, files[i].index, "failed to read"); } var then = getCurrentEpoch(); // secs since 1 jan 1970 setMainMessage("done in " + (then - now) + " sec"); echo(objectToString(config)); setProgress(100); } function onAbout() { dialog(header.title, header.description + "\n\nby " + header.chef, "i" ); } function onConfig() { dialog(header.title, "No config needed. This recipe will convert video files from the file list."); } function dialog_callback(props) { }