header={ "recipe_version": "1.18", "title": "Download video (clip)", "description": "Make a quick clip of an online video (custom watermark) #yt-dlp", "tags": "Video,download,YouTube,clip,cut,watermerk", "chef": "BeatRig", "dependencies": "yt-dlp,ffmpeg,curl", "spice": "BQ==:G+Hy36kJcnQQYYavb/JV2Il6eCYr6h4hRJHCF9rRbhX5BcazL6cuTgUMdz0xA50VWA5PmmV0Q7aWkiUtNFtbk991l+t0e8IBXMReMIT1GNjnZZDv7n2YRAo0xcSQbY0ixjG6LLH4wGKnspKAoA/v69iLn6N2IH0XzIZwTGdHSo4=", "time": 1711831891, "core_version": "0.6.3", "magnetron_version": "1.0.307", "functions": "main,onAbout", "instructions": "Run this recipe and enter the url of a video to download. Powered by yt-dlp, many platforms are supported, among; YouTube, Vimeo, Dailymotion, Facebook, Twitter, Instagram, SoundCloud, Twitch ect.", "type": "default", "os": "windows,macOS", "palette": "Clean Slate", "flavour": "c9R+H9bKLjdUySRgn9LmerGAEqp2wgrYtf/yfBP62/ywvoFyjwyTsjolACAmFubUfssXxpRQdMEZ3G/JRmA61ohyz776Mbgxlj/o6rXqgrFccYc+//+hxVcL5pTQVa3AdXvvH036YFeawenF9Yp/ohFG7qrDe+FT0vIa6m6rq4Y=", "uuid": "f0cab22c8116421493426badaa11e5d6" }; // ,Vimeo,Facebook,Dailymotion,Instagram,SoundCloud,Twitter,TikTok,Reddit,Tumblr,Pinterest,LinkedIn,Flickr,Twitch,LiveLeak,Veoh,Metacafe,TED,BBC iPlayer,CNN,ESPN,NBC,ABC,CBS,Fox News,Vimeo OTT,Bilibili,Niconico,Coub,Bandcamp,Mixcloud,8tracks,The New York Times,The Guardian,Vice,Udemy,Khan Academy,Coursera,Lynda,Adobe Connect,Xvideos,RedTube,PornHub,XHamster,YouPorn,XVideos-Downloader,Odysee,LBRY,Steam,NFL,NBA /*---------------------------------------------------------------------------- https://github.com/ytdl-org/youtube-dl/releases https://github.com/ytdl-org/youtube-dl/blob/master/docs/supportedsites.md */ function CheckDependencies() { dependencies = header.dependencies.split(","); for (i=0; i 0 && !isCanceled()) { setProgress(-1); setMainMessage("getting file details"); if (r.complete_toggle) { start_hh = paddedLeftString(r.start_hh, "0", 2); start_mm = paddedLeftString(r.start_mm, "0", 2); start_ss = paddedLeftString(r.start_ss, "0", 2); start_ms = paddedLeftString(r.start_ms, "0", 3); end_hh = paddedLeftString(r.end_hh, "0", 2); end_mm = paddedLeftString(r.end_mm, "0", 2); end_ss = paddedLeftString(r.end_ss, "0", 2); end_ms = paddedLeftString(r.end_ms, "0", 3); start_timestamp = start_hh + ":" + start_mm + ":" + start_ss + "." + start_ms; end_timestamp = end_hh + ":" + end_mm + ":" + end_ss + "." + end_ms; total_sec = ((parseInt(end_hh) * 60 * 60) + (parseInt(end_mm) * 60) + parseInt(end_ss)) - ((parseInt(start_hh) * 60 * 60) + (parseInt(start_mm) * 60) + parseInt(start_ss)); echo("total_sec:" + total_sec); if (total_sec <= 0) abort("Error in clip time, length is zero or negative.\nPlease check given clip start and end times\nstart: " + start_timestamp + "\nend: " + end_timestamp); } else total_sec = 0; // check output file name clip_nr = 1; args_filename = ["--get-filename", "-q", "--no-warnings", "-f", "b","--restrict-filenames", "-o", "%(upload_date>%Y-%m-%d)s-%(uploader)s-%(title)s-CLIP-" + clip_nr + ".%(ext)s", r.url]; cmd_filename = trimString(cmd("yt-dlp", args_filename)); if (containsString(cmd_filename, "\n")) // cut off error in front, used on macOS cmd_filename = trimString(findSubString(cmd_filename, "\n")); echo("retreived filename " + cmd_filename); full_path = r.target + gvar.pss + cmd_filename; echo(full_path); // make the filename unique while (fileExists(full_path) && !isCanceled()) { full_path = replaceInString(full_path, "-CLIP-" + clip_nr + ".", "-CLIP-" + (clip_nr+1) + "."); clip_nr++; } echo(full_path); if (isCanceled()) abort("canceled"); setProgress(10); if (gvar.isWindows) { if (r.complete_toggle) { args = ["-f", "b", // best for mp4 "--download-sections", "\"*" + start_timestamp + "-" + end_timestamp + "\"", "--force-keyframes-at-cuts", "--restrict-filenames", "--output", full_path, r.url]; } else { args = ["-f", "b", // best for mp4 "--restrict-filenames", "--output", full_path, r.url]; } } else { if (r.complete_toggle) { args = ["-f", "b", // best for mp4 "--force-keyframes-at-cuts", "--restrict-filenames", "--download-sections", "*" + start_timestamp + "-" + end_timestamp, "--output", full_path, r.url, "--ffmpeg-location", getAllowedApps("ffmpeg")]; } else { args = ["-f", "b", // best for mp4 "--restrict-filenames", "--output", full_path, r.url, "--ffmpeg-location", getAllowedApps("ffmpeg")]; } } echo(objectToString(args)); setMainMessage("downloading"); cmd_r = (cmd("yt-dlp", args)); echo(cmd_r); error = findSubString(cmd_r, "ERROR:", "\n"); if (error.length > 0) abort("YT-DLP error: " + error + "\n\nBe sure to update YT-DLP in magnetron 'settings->tool installers'"); if (isCanceled()) abort("canceled"); setProgress(60); output_filepath = trimString(findSubString(cmd_r, "[download] Destination: ", "\n")); echo("output_filepath: " + output_filepath); if(r.watermark != "" && r.watermark_toggle && !isCanceled()) { setMainMessage("adding watermark"); watermark = replaceInString(r.watermark, "\"", "\\\""); output_filepath_info = getPathInfo(output_filepath); temp_path = r.target + gvar.pss + output_filepath_info.basename + "watermarked." + output_filepath_info.ext; echo("temp file path: " + temp_path); if (gvar.isWindows) font_path_escaped = "../../../../content/clip-online-video/upheavtt.ttf"; else font_path_escaped = font_path; drawtextString = ""; if (containsString(watermark, "\\n")) { lines = watermark.split("\\n"); echo("found " + (lines.length+1) + " lines in watermark: " + watermark); for (l = 0;l 0) // no empty lines drawtextString += "drawtext=text='" + lines[l] + "':fontfile='" + font_path_escaped + "':x=((main_w-text_w)/2):y=(text_h*" + ((l * 1.5) + 2) + "):fontsize=" + (r.small ? "20" : "50") + ":fontcolor=0xdddddd@0.6"; if (l < lines.length - 1 && drawtextString.length > 0) // add seperator for new line, if not empty and not at end drawtextString += ", "; } } else // one line { echo("found 1 line in watermark: " + watermark); drawtextString = "drawtext=text='" + watermark + "':fontfile='" + font_path_escaped + "':x=((main_w-text_w)/2):y=(text_h*2):fontsize=" + (r.small ? "20" : "50") + ":fontcolor=0xdddddd@0.6"; } args_ffmpeg = ["-i", output_filepath, "-y", "-vf", drawtextString, "-y", temp_path]; echo(objectToString(args_ffmpeg)); cmd_watermark = (cmd("ffmpeg", args_ffmpeg)); echo(cmd_watermark); if (fileExists(temp_path)) { echo("replacing: " + temp_path + " -> " + output_filepath); deleteFile(output_filepath); renameFile(temp_path, output_filepath); } } setProgress(100); sleepMs(100); } setMainMessage("done"); } function cmd_callback(cmd_name, cmd_output) { if (cmd_name == "yt-dlp" && cmd_output.length > 0) { echo(cmd_name + " " + cmd_output); if (total_sec != 0) // making a clip { newTimeStr = findSubString(cmd_output, "time=", "."); echo(newTimeStr); curr_sec = (parseInt(newTimeStr.substring(0, 2)) * 60 * 60) + (parseInt(newTimeStr.substring(3, 5)) * 60) + parseInt(newTimeStr.substring(6, 8)); p = Math.min(Math.max(10. + ((60. / total_sec) * curr_sec), 10), 60); } else // complete video { newPrecStr = findSubString(cmd_output, "[download]", "%"); echo(newPrecStr); p = toFixed(10. + (parseFloat(newPrecStr) * 0.6) , 1); } echo("progress: " + p); setProgress(p); } if (cmd_name == "ffmpeg" && cmd_output.length > 0) { if (total_sec != 0) // making a clip { echo(cmd_name + " " + cmd_output); newTimeStr = findSubString(cmd_output, "time=", "."); echo(newTimeStr); curr_sec = (parseInt(newTimeStr.substring(0, 2)) * 60 * 60) + (parseInt(newTimeStr.substring(3, 5)) * 60) + parseInt(newTimeStr.substring(6, 8)); p = Math.min(Math.max(70. + ((30. / total_sec) * curr_sec), 70), 100); } else p = -1; echo("progress: " + p); setProgress(p); } return { "terminate": isCanceled(), "input": "" }; } function onAbout() { dialog(header.title, header.description, "i"); } function dialog_callback(props) { echo("dialog: " + objectToString(props)); if (props["name"] == "show") revealPath(config.props_path); if (props["name"] == "url") config.url = props.text; if (props["name"] == "start_hh") { if (containsString(props.text, ":") || containsString(props.text, ".")) { if (containsString(props.text, ":")) vals = props.text.split(":"); if (containsString(props.text, ".")) vals = props.text.split("."); if (vals.length > 0) { if (vals.length > 2) update_dialog = { "start_hh" : { "default" : vals[0] }, "start_mm" : { "default" : vals[1] }, "start_ss" : { "default" : vals[2] }, }; else if (vals.length > 1) { if (vals[1].length > 0) update_dialog = { "start_hh" : { "default" : "" }, "start_mm" : { "default" : vals[0] }, "start_ss" : { "default" : vals[1] } }; else update_dialog = { "start_hh" : { "default" : vals[0] } }; } var r = dialog(update_dialog); } } else config.start_hh = props.text; } if (props["name"] == "watermark_toggle") { config.watermark_toggle = props.toggle; var r = dialog({ "watermark" : { "enabled" : props.toggle }, "small" : { "enabled" : props.toggle } }); } if (props["name"] == "complete_toggle") { config.complete_toggle = props.toggle; var r = dialog({ "start_hh" : { "enabled" : props.toggle }, "start_mm" : { "enabled" : props.toggle }, "start_ss" : { "enabled" : props.toggle }, "start_ms" : { "enabled" : props.toggle }, "end_hh" : { "enabled" : props.toggle }, "end_mm" : { "enabled" : props.toggle }, "end_ss" : { "enabled" : props.toggle }, "end_ms" : { "enabled" : props.toggle }, "label_hh" : { "enabled" : props.toggle }, "label_mm" : { "enabled" : props.toggle }, "label_ss" : { "enabled" : props.toggle }, "label_ms" : { "enabled" : props.toggle }, "start_label" : { "enabled" : props.toggle }, "end_label" : { "enabled" : props.toggle }, }); } if (props["name"] == "start_mm") config.start_mm = props.text; if (props["name"] == "start_ss") config.start_ss = props.text; if (props["name"] == "start_ms") { if (containsString(props.text, ":") || containsString(props.text, ".")) { if (containsString(props.text, ":")) vals = props.text.split(":"); if (containsString(props.text, ".")) vals = props.text.split("."); if (vals.length > 0) { if (vals.length > 3) update_dialog = { "start_hh" : { "default" : vals[0] }, "start_mm" : { "default" : vals[1] }, "start_ss" : { "default" : vals[2] }, "start_ms" : { "default" : vals[3] }, }; else if (vals.length > 2) update_dialog = { "start_hh" : { "default" : "" }, "start_mm" : { "default" : vals[0] }, "start_ss" : { "default" : vals[1] }, "start_ms" : { "default" : vals[2] }, }; else if (vals.length > 1) { if (vals[1].length > 0) update_dialog = { "start_hh" : { "default" : "" }, "start_mm" : { "default" : "" }, "start_ss" : { "default" : vals[0] }, "start_ms" : { "default" : vals[1] }, }; else config.start_ms = props.vals[0]; } var r = dialog(update_dialog); } } else config.start_ms = props.text; } if (props["name"] == "end_hh") { if (containsString(props.text, ":") || containsString(props.text, ".")) { if (containsString(props.text, ":")) vals = props.text.split(":"); if (containsString(props.text, ".")) vals = props.text.split("."); if (vals.length > 0) { if (vals.length > 2) update_dialog = { "end_hh" : { "default" : vals[0] }, "end_mm" : { "default" : vals[1] }, "end_ss" : { "default" : vals[2] }, }; else if (vals.length > 1) { if (vals[1].length > 0) update_dialog = { "end_hh" : { "default" : "" }, "end_mm" : { "default" : vals[0] }, "end_ss" : { "default" : vals[1] } }; else config.end_hh = vals[0]; } var r = dialog(update_dialog); } } else config.end_hh = props.text; } if (props["name"] == "end_mm") config.end_mm = props.text; if (props["name"] == "end_ss") config.end_ss = props.text; if (props["name"] == "end_ms") { if (containsString(props.text, ":") || containsString(props.text, ".")) { if (containsString(props.text, ":")) vals = props.text.split(":"); if (containsString(props.text, ".")) vals = props.text.split("."); if (vals.length > 0) { if (vals.length > 3) update_dialog = { "end_hh" : { "default" : vals[0] }, "end_mm" : { "default" : vals[1] }, "end_ss" : { "default" : vals[2] }, "end_ms" : { "default" : vals[3] }, }; else if (vals.length > 2) update_dialog = { "end_hh" : { "default" : "" }, "end_mm" : { "default" : vals[0] }, "end_ss" : { "default" : vals[1] }, "end_ms" : { "default" : vals[2] }, }; else if (vals.length > 1) { if (vals[1].length > 0) update_dialog = { "end_hh" : { "default" : "" }, "end_mm" : { "default" : "" }, "end_ss" : { "default" : vals[0] }, "end_ms" : { "default" : vals[1] }, }; else config.end_ms = vals[0]; } var r = dialog(update_dialog); } } else config.end_ms = props.text; } if (props["name"] == "end_hh") config.end_hh = props.text; if (props["name"] == "end_mm") config.end_mm = props.text; if (props["name"] == "end_ss") config.end_ss = props.text; if (props["name"] == "end_ms") config.end_ms = props.text; if (props["name"] == "watermark") config.watermark = props.text; if (props["name"] == "small") config.small = props.toggle; if (props["name"] == "target") config.props_path = props.path; }