header={ "recipe_version": "1.12", "title": "Rotate video", "description": "Fix the rotation angle of a vertical or upside down video", "category": "video", "chef": "BeatRig", "spice": "BQ==:G+Hy36kJcnQQYYavb/JV2Il6eCYr6h4hRJHCF9rRbhX5BcazL6cuTgUMdz0xA50VWA5PmmV0Q7aWkiUtNFtbk991l+t0e8IBXMReMIT1GNjnZZDv7n2YRAo0xcSQbY0ixjG6LLH4wGKnspKAoA/v69iLn6N2IH0XzIZwTGdHSo4=", "palette": "Blueberry Slate", "flavour": "e2cFtjUx7qy0fKB6fIXQnfo6wJp78m3l/PmWse3Dk47onMX1gy5Sgo1oXjczO59vegK6cHRZ4oNA7L9XaAAgd6UgefcXGbR3IvwUtgQzACShPIzfoNontWpSE/sXa9FhLrzk8dMA2gmErLOKzIFpsAJJ0cN0cbrOkhWxYj9RH2o=", "time": 1694462067, "core_version": "0.5.7", "magnetron_version": "1.0.261", "type": "default", "os": "windows,macOS", "functions": "main,onConfig,onAbout", "dependencies": "ffprobe,ffmpeg", "uuid": "7f35e5e5cf164b1887658aa8abb3701b", "instructions": "Drop a video file and press play to create a rotated copy", "tags": "video,rotate,vvs,fix" }; //---------------------------------------------------------------------------- var config = { "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 getFileProps(infile) { var probeoutput = cmd("ffprobe", [infile]); echo(probeoutput); var dur_tc = findSubString(probeoutput, "Duration: ", ", s"); config.totalsec = calculateSeconds(dur_tc); echo("dur:" + config.totalsec); return dur_tc; } function setupArgs(infile) { var args1 = ["-y", "-i", infile]; args1.push("-movflags"); args1.push("+faststart"); args1.push("-filter_complex"); var filterArg=""; filterArg = "[0]" + config.transpose + "[out1]"; if (gvar.isWindows) // needs quotes filterArg = "\"" + filterArg + "\""; args1.push(filterArg); echo("filter:" + filterArg); args1.push("-map"); args1.push("[out1]"); args1.push("-map"); args1.push("0:a?"); 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 transpose = 0; var options = ["Clockwise","Counter-clockwise","Upside-down"]; var files = getFiles(); var numFiles = files.length; var infile = ""; config.tag = "-rotated"; config.transposetype = options[0]; for (i = 0; i < Math.max(numFiles, 1) && isCanceled() == false; i++) { setProgress(100. / numFiles * i); infile = numFiles > 0 ? files[i].path : ""; var infileinfo = getPathInfo(numFiles > 0 ? infile : folders.output); var ouputFolderPath = numFiles > 0 ? infileinfo.folder : folders.output; var dialog_width = 600; form1 = { "header" : { "type" : "text", "label" : "This process will convert videos to instagram spec", "just" : "l", "bounds" : { "x": 10, "y" : 5, "w" : dialog_width, }, }, "file1_header" : { "type" : "text", "label" : "source file", "just" : "l", "bounds" : { "w" : 120, }, }, "inputfile" : { "type" : "fileselect", "path" : infile, "editable" : false, "dir" : false, "saving" : false, "label" : "source file", "bounds" : { "x" : 130, "y" : -1, "w" : dialog_width - 130, }, }, "param_header" : { "type" : "text", "label" : "Video type", "just" : "l", "bounds" : { "w" : 120, }, }, "transposetype" : { "type" : "combobox", "default" : config.transposetype, "items" : options, "label" : "Select rotation:", "bounds" : { "x" : 130, "y" : -1, "w" : dialog_width - 130, } }, "file2_header" : { "type" : "text", "label" : "output folder", "just" : "l", "bounds" : { "w" : 120, }, }, "outputfolder" : { "type" : "fileselect", "path" : ouputFolderPath, "editable" : false, "dir" : true, "saving" : true, "label" : "select output folder", "bounds" : { "x" : 130, "y" : -1, "w" : dialog_width - 130, }, }, "tag" : { "type" : "textedit", "default" : config.tag, "label" : "add file name tag:", "bounds" : { "x" : dialog_width/2, "y" : -1, "w" : dialog_width/2 } }, "okay" : { "type" : "button", "label" : "Rotate", "bounds" : { "w" : dialog_width/2 - 10, }, "returns" : 1 }, "cancel" : { "type" : "button", "label" : "cancel", "bounds" : { "y": -1, "x": dialog_width/2 + 10, "w" : dialog_width/2 - 10 }, "returns" : 0 }, }; var r = dialog(form1); if (r.okay == 1) { infile = r.inputfile; config.tag = r.tag; config.transposetype = r.transposetype; var pathinfo = getPathInfo(infile); echo(infile); getFileProps(infile); // calc the duration in sec echo("file size:" + bytesToDescription(filesize)); if (config.totalsec <= 0.) { setMainMessage("cancelled"); abort("file is empty\n" + pathinfo.basename); } /* 0 = 90CounterCLockwise and Vertical Flip (default) 1 = 90Clockwise 2 = 90CounterClockwise 3 = 90Clockwise and Vertical Flip*/ if (r.transposetype == options[0]) { config.transpose = "transpose=1"; config.tranform_tag = "-C";//"Clockwise"; } else if (r.transposetype == options[1]) { config.transpose = "transpose=2"; config.tranform_tag = "-CC";//"Counter-clockwise"; } else if (r.transposetype == options[2]) // 180 { config.transpose = "transpose=2[temp];[temp]transpose=2"; config.tranform_tag = "-UD";//"Upside-down"; } if (gvar.isWindows) config.transpose = "\"" + config.transpose + "\""; config.outfile = r.outputfolder + gvar.pss + pathinfo.basename + r.tag + config.tranform_tag + "." + pathinfo.ext; if (config.outfile.length > 0) { var msg = ("busy please wait"); setMainMessage(msg); echo(msg); var args1 = setupArgs(infile); echo(cmd("ffmpeg", args1)); // perform cmd newfilesize = getFileBytes(config.outfile); echo("new file size:" + bytesToDescription(newfilesize)); if (newfilesize <= 0) { setMainMessage("can't encode this file"); abort("can't encode this file"); } if(isCanceled()) { setMainMessage("cancelled"); abort("cancelled"); } } else { setMainMessage("cancelled"); abort("cancelled"); } } else i = numFiles; // end-loop } 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) { if (props["name"] == "inputfile") { var info = getPathInfo(props["path"]); var newprops = { "outputfolder" : { "path" : info.folder } }; dialog(newprops); } }