From bb924e560a83a4d214f7198aeb227d4ae8649505 Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Sun, 27 Dec 2020 13:34:02 -0500 Subject: [PATCH] add support for -n/--no-exec for single-operation tools. allow handlebars context to use jsasset objects --- bin/jaddsilence | 11 +++---- bin/jconcat | 7 +++-- bin/jkenburns | 25 ++++++++-------- bin/jletterbox | 15 +++++----- bin/jmergeaudio | 13 ++++---- bin/jrmtrack | 13 ++++---- bin/jscale | 15 +++++----- bin/jspeed | 11 +++---- bin/jsplit | 13 ++++---- bin/jtrim | 11 +++---- bin/jvc | 6 ++-- bin/jvc_common | 30 +++++++++++++------ src/main/java/jvc/model/JsObjectView.java | 22 ++++++++++++++ src/main/java/jvc/model/js/JAssetJs.java | 28 +++++++++-------- .../java/jvc/operation/exec/ExecBase.java | 3 +- .../java/jvc/operation/exec/TrimExec.java | 9 +++--- src/main/java/jvc/service/Toolbox.java | 6 ++++ 17 files changed, 147 insertions(+), 91 deletions(-) diff --git a/bin/jaddsilence b/bin/jaddsilence index 7a83271..42f2348 100755 --- a/bin/jaddsilence +++ b/bin/jaddsilence @@ -4,12 +4,13 @@ # # Usage: # -# jaddsilence in-file out-file [channel-mode] [sampling-rate] +# jaddsilence [-n|--no-exec] in-file out-file [channel-mode] [sampling-rate] # -# in-file : input video file -# out-file : write output file here -# channel-mode : channel layout, usually 'mono' or 'stereo'. Default is stereo -# sampling-rate : sampling rate, in Hz. Default is 48000 +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : input video file +# out-file : write output file here +# channel-mode : channel layout, usually 'mono' or 'stereo'. Default is stereo +# sampling-rate : sampling rate, in Hz. Default is 48000 # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jconcat b/bin/jconcat index 93a42a0..5d07d26 100755 --- a/bin/jconcat +++ b/bin/jconcat @@ -4,10 +4,11 @@ # # Usage: # -# jconcat out-file in-file-1 [in-file-2 ...] +# jconcat [-n|--no-exec] out-file in-file-1 [in-file-2 ...] # -# out-file : output file -# in-file-N : input files +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# out-file : output file +# in-file-N : input files # # BEWARE SHELL WILDCARDS! # Shell wildcards will match files in non-deterministic order, meaning that diff --git a/bin/jkenburns b/bin/jkenburns index d823833..fe448e7 100755 --- a/bin/jkenburns +++ b/bin/jkenburns @@ -4,19 +4,20 @@ # # Usage: # -# jkenburns in-file out-file duration [zoom] [x] [y] [start] [end] [fps] [width] [height] +# jkenburns [-n|--no-exec] in-file out-file duration [zoom] [x] [y] [start] [end] [fps] [width] [height] # -# in-file : file to trim -# out-file : write scaled file here -# duration : how long the output video will be -# zoom : zoom factor, default is 1 (no zoom) -# x : zoom focus X point, default is center -# y : zoom focus Y point, default is center -# start : when to start zooming, default is beginning of video -# end : when to end zooming, default is end of video -# fps : frame per second for output video, default is 25 -# width : output width, default is in-file width -# height : output height, default is in-file height +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-file : write scaled file here +# duration : how long the output video will be +# zoom : zoom factor, default is 1 (no zoom) +# x : zoom focus X point, default is center +# y : zoom focus Y point, default is center +# start : when to start zooming, default is beginning of video +# end : when to end zooming, default is end of video +# fps : frame per second for output video, default is 25 +# width : output width, default is in-file width +# height : output height, default is in-file height # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jletterbox b/bin/jletterbox index 50ab80c..44ae141 100755 --- a/bin/jletterbox +++ b/bin/jletterbox @@ -5,14 +5,15 @@ # # Usage: # -# jletterbox in-file out-file width height [color] +# jletterbox [-n|--no-exec] in-file out-file width height [color] # -# in-file : file to trim -# out-file : write scaled file here -# width : output width -# height : output height -# color : padding color, can be a hex value (0xff0000 is red), or a color -# name from https://ffmpeg.org/ffmpeg-utils.html#color-syntax +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-file : write scaled file here +# width : output width +# height : output height +# color : padding color, can be a hex value (0xff0000 is red), or a +# color name from https://ffmpeg.org/ffmpeg-utils.html#color-syntax # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jmergeaudio b/bin/jmergeaudio index f5b5555..3873bac 100755 --- a/bin/jmergeaudio +++ b/bin/jmergeaudio @@ -4,13 +4,14 @@ # # Usage: # -# jmergeaudio video-file audio-file out-file [at] +# jmergeaudio [-n|--no-exec] video-file audio-file out-file [at] # -# video-file : input video file -# audio-file : audio file to insert into video -# out-file : write output file here -# at : when (on the video timeline) to start playing the audio -# If omitted, audio will start when video starts +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# video-file : input video file +# audio-file : audio file to insert into video +# out-file : write output file here +# at : when (on the video timeline) to start playing the audio +# If omitted, audio will start when video starts # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jrmtrack b/bin/jrmtrack index 890168d..f24fa19 100755 --- a/bin/jrmtrack +++ b/bin/jrmtrack @@ -4,13 +4,14 @@ # # Usage: # -# jrmtrack in-file out-file track-type [track-number] +# jrmtrack [-n|--no-exec] in-file out-file track-type [track-number] # -# in-file : file to trim -# out-file : write output file here -# track-type : the track type to remove. Usually 'audio' or 'video' -# track-number : the track number to remove. If omitted, all tracks whose -# type matches `track-type` will be removed +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-file : write output file here +# track-type : the track type to remove. Usually 'audio' or 'video' +# track-number : the track number to remove. If omitted, all tracks whose +# type matches `track-type` will be removed # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jscale b/bin/jscale index 4357e84..1f4fc2b 100755 --- a/bin/jscale +++ b/bin/jscale @@ -4,15 +4,16 @@ # # Usage: # -# jscale in-file out-file factor +# jscale [-n|--no-exec] in-file out-file factor # or -# jscale in-file out-file width height +# jscale [-n|--no-exec] in-file out-file width height # -# in-file : file to trim -# out-file : write scaled file here -# factor : scale factor -# width : output width -# height : output height +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-file : write scaled file here +# factor : scale factor +# width : output width +# height : output height # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jspeed b/bin/jspeed index 86145b9..b596ac6 100755 --- a/bin/jspeed +++ b/bin/jspeed @@ -4,12 +4,13 @@ # # Usage: # -# jspeed in-file out-file speed-factor [audio-speed] +# jspeed [-n|--no-exec] in-file out-file speed-factor [audio-speed] # -# in-file : input video file -# out-file : write output file here -# speed-factor : factor=1 is unchanged, factor>1 is faster, factor<1 is slower -# audio-speed : can be: silent (default), unchanged, or match +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : input video file +# out-file : write output file here +# speed-factor : factor=1 is unchanged, factor>1 is faster, factor<1 is slower +# audio-speed : can be: silent (default), unchanged, or match # # Note: if audio-speed is match, then speed-factor must be between 0.5 and 100 # diff --git a/bin/jsplit b/bin/jsplit index 4a79cd1..d4b0269 100755 --- a/bin/jsplit +++ b/bin/jsplit @@ -4,13 +4,14 @@ # # Usage: # -# jsplit in-file out-dir interval [start] [end] +# jsplit [-n|--no-exec] in-file out-dir interval [start] [end] # -# in-file : file to trim -# out-dir : write split files to this directory (will be created if it does not exist) -# interval : time duration of output files, in seconds -# start : when to start splitting the in-file. default is 0 (start) -# end : when to stop splitting the in-file. default is to continue until end of file is reached +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-dir : write split files to this directory (will be created if it does not exist) +# interval : time duration of output files, in seconds +# start : when to start splitting the in-file. default is 0 (start) +# end : when to stop splitting the in-file. default is to continue until end of file is reached # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jtrim b/bin/jtrim index bdae897..2c78134 100755 --- a/bin/jtrim +++ b/bin/jtrim @@ -4,12 +4,13 @@ # # Usage: # -# jtrim in-file out-file [start] [end] +# jtrim [-n|--no-exec] in-file out-file [start] [end] # -# in-file : file to trim -# out-file : write trimmed file here -# start : seconds to trim from the beginning. if omitted, default value is start of the file -# end : retain the file until this number of seconds. if omitted, default is to end of file +# -n or --no-exec : if set, do not execute ffmpeg but print what would have run +# in-file : file to trim +# out-file : write trimmed file here +# start : seconds to trim from the beginning. if omitted, default value is start of the file +# end : retain the file until this number of seconds. if omitted, default is to end of file # SCRIPT="${0}" SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)" diff --git a/bin/jvc b/bin/jvc index 1872e46..6db8d66 100755 --- a/bin/jvc +++ b/bin/jvc @@ -4,14 +4,14 @@ # # Usage: # -# jvc [-t temp-dir] [-n] spec-file +# jvc [-t temp-dir] [-n|--no-exec] spec-file # # spec-file : the JVC to run. If omitted, read a spec from stdin # # -t temp-dir : where to write generated assets. If omitted, jvc will # create a new temporary directory # -# -n : print commands that would have been run, but don't +# -n or --no-exec : print commands that would have been run, but don't # actually run anything # # Note: If the JVC jar does not exist, it will be built from source. @@ -27,4 +27,4 @@ if [[ -n "${JVC_DEBUG}" ]] ; then DEBUG="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005" fi -java -cp "${JVC_JAR}" ${DEBUG} jvc.main.Jvc "${@}" +java -cp "${JVC_JAR}" ${DEBUG} jvc.main.Jvc ${_JVC_NO_EXEC} "${@}" diff --git a/bin/jvc_common b/bin/jvc_common index 4f51c65..4ee3569 100755 --- a/bin/jvc_common +++ b/bin/jvc_common @@ -31,10 +31,10 @@ function handle_help_request() { echo "# Environment Variables # # JVC_SCRATCH_DIR : Use this as the scratch directory -# Default is to create a new temp directory +# Default is to create a new temp directory # # JVC_NO_EXEC : If set to anything, print the commands that would -# have run but do not execute anything +# have run but do not execute anything # " fi @@ -42,6 +42,12 @@ function handle_help_request() { fi } +function handle_jvc_noexec() { + if [[ -n "${1}" && ("${1}" == "-n" || "${1}" == "--no-exec" ) ]] ; then + echo -n "--no-exec" + fi +} + # Ensure Java is installed and that it is Java 11 if [[ -z "$(which java)" ]] ; then die "Java 11 (or higher) not installed (java command not found on PATH)" @@ -90,17 +96,23 @@ if [[ -z "${JVC_JAR}" ]] ; then fi fi +handle_help_request "${0}" "${1}" + SCRATCH_DIR="" +if [[ -n "${JVC_SCRATCH_DIR}" ]] ; then + SCRATCH_DIR="--temp-dir ${JVC_SCRATCH_DIR}" +fi + NO_EXEC="" -if [[ -z "${JVC_SKIP_ENV_VAR_HELP}" ]] ; then - if [[ -n "${JVC_SCRATCH_DIR}" ]] ; then - SCRATCH_DIR="--temp-dir ${JVC_SCRATCH_DIR}" - fi +if [[ -n "${JVC_NO_EXEC}" ]] ; then + NO_EXEC="--no-exec" +fi - if [[ -n "${JVC_NO_EXEC}" ]] ; then +_JVC_NO_EXEC="$(handle_jvc_noexec "${1}")" +if [[ -n "${_JVC_NO_EXEC}" ]] ; then + if [[ -z "${NO_EXEC}" ]] ; then NO_EXEC="--no-exec" fi + shift fi JVC_OPTIONS="${SCRATCH_DIR} ${NO_EXEC}" - -handle_help_request "${0}" "${1}" diff --git a/src/main/java/jvc/model/JsObjectView.java b/src/main/java/jvc/model/JsObjectView.java index 3180e93..995ba38 100644 --- a/src/main/java/jvc/model/JsObjectView.java +++ b/src/main/java/jvc/model/JsObjectView.java @@ -1,7 +1,29 @@ package jvc.model; +import java.util.Collection; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; + public interface JsObjectView { Object toJs(); + static boolean isJsObjectCollection(Object value) { + return (value instanceof Collection) + && !empty(value) + && (((Collection) value).iterator().next() instanceof JsObjectView); + } + + static Collection toJs(Collection values) { + if (empty(values)) { + return emptyList(); + } else { + return values.stream() + .map(v -> (T) v.toJs()) + .collect(Collectors.toList()); + } + } + } diff --git a/src/main/java/jvc/model/js/JAssetJs.java b/src/main/java/jvc/model/js/JAssetJs.java index 6eb6083..5d4cc3b 100644 --- a/src/main/java/jvc/model/js/JAssetJs.java +++ b/src/main/java/jvc/model/js/JAssetJs.java @@ -3,6 +3,7 @@ package jvc.model.js; import jvc.model.JAsset; import jvc.model.info.JMediaInfo; import jvc.model.info.JTrack; +import lombok.Getter; import org.cobbzilla.util.collection.ArrayUtil; import java.math.BigDecimal; @@ -14,20 +15,23 @@ public class JAssetJs { public static final JAssetJs[] EMPTY_ASSETS = new JAssetJs[0]; - public final Double duration; - public final Integer width; - public final Integer height; - public final Double aspectRatio; - public final Integer samplingRate; - public JTrackJs[] allTracks = EMPTY_TRACKS; - public JTrackJs[] tracks = EMPTY_TRACKS; - public JTrackJs[] videoTracks = EMPTY_TRACKS; - public JTrackJs[] audioTracks = EMPTY_TRACKS; - public JAssetJs[] assets = EMPTY_ASSETS; - public final boolean hasAudio; - public final boolean hasVideo; + @Getter public final String path; + @Getter public final Double duration; + @Getter public final Integer width; + @Getter public final Integer height; + @Getter public final Double aspectRatio; + @Getter public final Integer samplingRate; + @Getter public JTrackJs[] allTracks = EMPTY_TRACKS; + @Getter public JTrackJs[] tracks = EMPTY_TRACKS; + @Getter public JTrackJs[] videoTracks = EMPTY_TRACKS; + @Getter public JTrackJs[] audioTracks = EMPTY_TRACKS; + @Getter public JAssetJs[] assets = EMPTY_ASSETS; + @Getter public final boolean hasAudio; + @Getter public final boolean hasVideo; public JAssetJs(JAsset asset) { + this.path = asset.getPath(); + final BigDecimal d = asset.duration(); this.duration = d == null ? null : d.doubleValue(); diff --git a/src/main/java/jvc/operation/exec/ExecBase.java b/src/main/java/jvc/operation/exec/ExecBase.java index 31a0499..86556ab 100644 --- a/src/main/java/jvc/operation/exec/ExecBase.java +++ b/src/main/java/jvc/operation/exec/ExecBase.java @@ -13,6 +13,7 @@ import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; +import static jvc.service.Toolbox.jsContext; import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.io.FileUtil.basename; @@ -24,7 +25,7 @@ public abstract class ExecBase { public abstract Map operate(OP operation, Toolbox toolbox, AssetManager assetManager); protected String renderScript(Toolbox toolbox, Map ctx, String template) { - return HandlebarsUtil.apply(toolbox.getHandlebars(), template, ctx); + return HandlebarsUtil.apply(toolbox.getHandlebars(), template, jsContext(ctx)); } protected File resolveOutputPath(JAsset output, File defaultOutfile) { diff --git a/src/main/java/jvc/operation/exec/TrimExec.java b/src/main/java/jvc/operation/exec/TrimExec.java index b41fd77..ac5d2ad 100644 --- a/src/main/java/jvc/operation/exec/TrimExec.java +++ b/src/main/java/jvc/operation/exec/TrimExec.java @@ -14,10 +14,11 @@ import java.util.Map; public class TrimExec extends SingleOrMultiSourceExecBase { public static final String TRIM_TEMPLATE - = "{{ffmpeg}} -i {{{source.path}}} " + - "-ss {{startSeconds}} " + - "{{#exists interval}}-t {{interval}} {{/exists}}" + - "-y {{{output.path}}}"; + = "{{ffmpeg}} -i {{{source.path}}} " + + "-ss {{startSeconds}} " + + "{{#exists interval}}-t {{interval}} {{/exists}}" + + "{{#if source.hasAudio}}-c:a copy {{/if}}" + + "-y {{{output.path}}}"; @Override protected String getProcessTemplate() { return TRIM_TEMPLATE; } diff --git a/src/main/java/jvc/service/Toolbox.java b/src/main/java/jvc/service/Toolbox.java index a5960c6..e8eb0b8 100644 --- a/src/main/java/jvc/service/Toolbox.java +++ b/src/main/java/jvc/service/Toolbox.java @@ -14,11 +14,13 @@ import org.cobbzilla.util.javascript.StandardJsEngine; import java.io.File; import java.math.BigDecimal; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static java.math.RoundingMode.HALF_EVEN; +import static jvc.model.JsObjectView.isJsObjectCollection; import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.io.FileUtil.*; import static org.cobbzilla.util.json.JsonUtil.*; @@ -74,6 +76,10 @@ public class Toolbox { final Object value = entry.getValue(); if (value instanceof JsObjectView) { jsCtx.put(entry.getKey(), ((JsObjectView) value).toJs()); + + } else if (isJsObjectCollection(value)) { + jsCtx.put(entry.getKey(), JsObjectView.toJs((Collection) value)); + } else { jsCtx.put(entry.getKey(), value); }