diff --git a/README.md b/README.md index 512da6f..554f75d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@ With JVC, you'd write this spec file and save it to a file "operation": "split", "creates": "src_split_files", "source": "src", - "interval": "60" + "interval": "60", + "validate": [{ "comment": "expected 12 files", "test": "output.length === 12" }] }] } ``` @@ -53,6 +54,9 @@ jvc my-spec.jvc Yes, the JVC is longer, but I think many would agree it is easier to read and maintain. +As you can see above, JVC can also `validate` your operations to ensure that +the output assets are what you expect them to be. + **As the number of media assets and operations grows, hand-crafted shell scripts with magical ffmpeg incantations become ever more inscrutable.** @@ -143,6 +147,13 @@ Trim audio/video; crop a section of an asset, becomes a new asset. Here is a [long, complex example](docs/complex_example.md) that uses every operation. +## JVC JavaScript Expressions +There are actually two DSLs in JVC. One is the JSON format for JVC files, +which tells jvc where the assets are and what to do with them. + +The second DSL is not really a full DSL, it's more a JavaScript context +in which you can evaluate expressions. + ## What's with the name? A cross between a javelin and an icicle? JSON and a miracle? Something with positive connotations? diff --git a/docs/asset_refs.md b/docs/asset_refs.md new file mode 100644 index 0000000..d914e2e --- /dev/null +++ b/docs/asset_refs.md @@ -0,0 +1,29 @@ +# Asset References +Most operations have a `source` parameter that indicates what asset is +considered the primary input to that operation. + +The value of `source` is the name of an asset, either defined in `assets` +or as the output of a previous operation (named in the `creates` block). + +## List Assets +The `split` operation creates multiple assets under the same name, this +is called a "list asset", in contrast to a "singular asset" that only +refers to one file. + +If you want to reference a specific file within a list asset, use square +bracket notation: +```shell script +some_list_asset[0] # first sub-asset +some_list_asset[-1] # last sub-asset +some_list_asset[1..3] # 2nd, 3rd and 4th assets +some_list_asset[..3] # 1st, 2nd, 3rd and 4th assets +some_list_asset[3..] # 4th asset and everything after +``` + +## Concat Operation `sources` +The `concat` operation does not take a `source` param (which would name +one asset), it takes a `sources` array of asset names. + +The named assets can be either singular assets or list assets. + +`concat` flattens the list of assets and concatenates them all together. diff --git a/docs/concepts.md b/docs/concepts.md index e42ce45..bd489b1 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -32,14 +32,32 @@ Assets expose properties that can be referenced in operations. The properties cu * `height`: width of the video in pixels (video and image assets only) ## Operations -Operations are transformations to perform on the inputs. +Operations represent transformations to perform on the inputs, and validations +to ensure correctness. + +### Operation Assets +An operation requires one or more input assets. These assets are referenced +using the `source` (or for `concat`, `sources`) parameter. An operation can produce one or more new assets, which can then be referenced in later operations. -Most of the operation settings can be JavaScript expressions, for example: +Learn more about [Asset References](asset_refs.md). + +### Operation Configuration +Many of the operation settings can be JavaScript expressions, for example: "start": "someAsset.duration - 10" The above would set the `start` value to ten seconds before the end of `someAsset`. +Learn more about [JavaScript expressions in JVC](jvc_js.md). + +### Operation Validation +An operation may define validations to perform by defining a `validation` array. + +Each object in the array has properties `comment` (to describe the test) and +`test` which is a JavaScript expression. If it evaluates to `true` then the +test passes. If `false`, the test fails and the `comment` is printed. + +Learn more about [JavaScript expressions in JVC](jvc_js.md). diff --git a/docs/jvc_js.md b/docs/jvc_js.md new file mode 100644 index 0000000..e1418f3 --- /dev/null +++ b/docs/jvc_js.md @@ -0,0 +1,50 @@ +# JVC JavaScript Expressions +JavaScript expressions are used in a couple of places in JVC. + + * Operation configuration + * Operation validations + +## Operation Configuration +When you're writing the JSON for an operation, many of the operation's +config parameters can be JS expressions that will be evaluated +when the operation is run. + +For example, say you wanted to use `trim` to just chop a video in half. + +The `start` and `end` parameters of the `trim` operation support JavaScript +expressions, so you could write: +```js +{ + "comment": "cut video at midpoint", + "operation": "trim", + "creates": "chopped" + "source": "some_vid", + "end": "source.duration / 2" +} +``` +or run: +```shell script +jtrim some_vid.mp4 output_vid.mp4 0 "source.duration / 2" +``` +In the above, `source` is referring to the source asset, `some_vid`. + +When JVC loads an asset (like `some_vid`), or an operation creates a new asset, +the asset metadata is read using `mediainfo`. The metadata is stored in an object +that is then put into the JavaScript context using the variable name `source`. + +## Operation Validations +Once an operation completes, the validations run to ensure that the output +assets pass whatever tests you want to run. + +Each test is a JavaScript expressions, which is evaluated to a boolean value. +If the expression is true, the test passes. If false, the test fails and the +`comment` associated with the failing test is printed. + +## JavaScript Context +What variables are available in the JS context? And what properties do they have? + +### Assets +Assets can be defined in the JVC's `assets` array, or as the output of an +operation. + +Assets are referenced by their asset name. \ No newline at end of file diff --git a/src/main/java/jvc/model/operation/JOperation.java b/src/main/java/jvc/model/operation/JOperation.java index d2582dd..ff9c4fc 100644 --- a/src/main/java/jvc/model/operation/JOperation.java +++ b/src/main/java/jvc/model/operation/JOperation.java @@ -32,6 +32,7 @@ public abstract class JOperation { @Getter @Setter private String operation; @Getter @Setter private JsonNode creates; + @Getter @Setter private JValidation[] validate; @Getter @Setter private boolean noExec = false; @Getter @Setter private String comment; diff --git a/src/main/java/jvc/model/operation/JValidation.java b/src/main/java/jvc/model/operation/JValidation.java new file mode 100644 index 0000000..7acd458 --- /dev/null +++ b/src/main/java/jvc/model/operation/JValidation.java @@ -0,0 +1,18 @@ +package jvc.model.operation; + +import lombok.Getter; +import lombok.Setter; +import org.cobbzilla.util.javascript.JsEngine; + +import java.util.Map; + +public class JValidation { + + @Getter @Setter private String comment; + @Getter @Setter private String test; + + public boolean eval(Map ctx, JsEngine js) { + return js.evaluateBoolean(test, ctx); + } + +}