Skip to content

Commit 7f85ab2

Browse files
committed
file watcher handle weird neovim saving
1 parent 535277a commit 7f85ab2

4 files changed

Lines changed: 80 additions & 28 deletions

File tree

ffmpeg-templates.zod.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as flags from 'https://deno.land/std@0.91.0/flags/mod.ts'
2+
import ffmpeg_templates from './lib/cli.zod.ts'
3+
4+
5+
const VERSION = 'v0.2.0'
6+
7+
8+
const args = flags.parse(Deno.args)
9+
if (args._.length < 1 || args._.length > 2 || args['help']) {
10+
console.error(`ffmpeg-templates ${VERSION}
11+
12+
Usage: ffmpeg-templates <template_filepath> [<output_folder>] [options]
13+
14+
ARGS:
15+
<template_filepath> Path to a YAML or JSON template file which defines the structure of
16+
the outputted video
17+
18+
<output_folder> The folder in which the output and generated assets will be saved to.
19+
When not specified, a folder will be created adjacent to the template.
20+
21+
OPTIONS:
22+
--preview Instead of outputting the whole video, output a single frame as a jpg.
23+
Use this flag to set up your layouts and iterate quickly.
24+
25+
--open Open the outputted file after it is rendered.
26+
27+
--watch Run continously when the template file changes. This is most useful
28+
in tandem with --preview.
29+
30+
--develop Alias for running "--watch --preview --open"
31+
32+
--quiet Do not print a progress bar
33+
34+
--debug Write debug information to a file
35+
36+
--help Print this message.`)
37+
Deno.exit(args['help'] ? 0 : 1)
38+
}
39+
await ffmpeg_templates(...Deno.args)

lib/cli.zod.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function parse_cli_args(deno_args: string[]) {
2020
if (args['develop']) args = { ...args, watch: true, preview: true, open: true }
2121
const positional_args = args._.map((a) => a.toString())
2222
const template_filepath = positional_args[0]
23-
const { dir, name } = path.parse(args.template_filepath)
23+
const { dir, name } = path.parse(template_filepath)
2424
let output_folder = path.join(dir, 'ffmpeg-templates-projects', dir, `${name}`)
2525
if (positional_args[1]) output_folder
2626
return {
@@ -69,6 +69,23 @@ async function try_render_video(template_filepath: string, sample_frame: boolean
6969
}
7070

7171

72+
async function watch(filepath: string, fn: () => Promise<void>) {
73+
let lock = false
74+
for await (const event of Deno.watchFs(filepath)) {
75+
if (event.kind === 'modify' && lock === false) {
76+
lock = true
77+
setTimeout(() => {
78+
fn().then(() => {
79+
lock = false
80+
})
81+
}, 50) // assume that all file modifications are completed in 50ms
82+
}
83+
if (event.kind === 'remove') break
84+
}
85+
watch(filepath, fn)
86+
}
87+
88+
7289
export default async function (...deno_args: string[]) {
7390
const args = parse_cli_args(deno_args)
7491
const { template_filepath } = args
@@ -89,20 +106,10 @@ export default async function (...deno_args: string[]) {
89106

90107
if (args.watch) {
91108
logger.info(`watching ${template_filepath} for changes`)
92-
let lock = false
93-
for await (const event of Deno.watchFs(template_filepath)) {
94-
console.log({ event, lock})
95-
if (event.kind === 'modify' && !lock) {
96-
lock = true
97-
setTimeout(() => {
98-
logger.info(`template ${template_filepath} was changed. Starting render.`)
99-
try_render_video(template_filepath, args.preview, context_options).then(() => {
100-
lock = false
101-
logger.info(`watching ${template_filepath} for changes`)
102-
})
103-
// assume that all file modifications are completed in 50ms
104-
}, 50)
105-
}
106-
}
109+
await watch(template_filepath, async () => {
110+
logger.info(`template ${template_filepath} was changed. Starting render.`)
111+
await try_render_video(template_filepath, args.preview, context_options)
112+
logger.info(`watching ${template_filepath} for changes`)
113+
})
107114
}
108115
}

lib/mod.zod.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ import type { Logger } from './logger.ts'
66
import type { OnProgress, FfmpegProgress } from './bindings/ffmpeg.ts'
77

88

9-
interface RenderOptions {
10-
ffmpeg_verbosity?: 'quiet' | 'error' | 'warning' | 'info' | 'debug'
11-
debug_logs?: boolean
12-
progress_callback?: OnProgress
13-
cwd?: string
14-
}
15-
interface RenderOptionsInternal extends RenderOptions {
16-
render_sample_frame?: boolean
17-
}
18-
199
async function render(context: Context, render_sample_frame: boolean) {
2010
return {
2111
template: '',

lib/parsers/template.zod.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { z } from 'https://deno.land/x/zod@v3.9.0/mod.ts'
22
import * as t from '../template_input.zod.ts'
3+
import * as errors from '../errors.ts'
34
import { assert } from '../type-equality.ts'
45

56

@@ -103,9 +104,24 @@ const Template = z.object({
103104
// this is a typescript exacty type assertion. It does nothing at runtime
104105
assert({} as z.input<typeof Template>, {} as t.Template)
105106

107+
108+
function pretty_zod_errors(error: z.ZodError) {
109+
return error.errors.map(e => {
110+
const path = e.path.join('.')
111+
return ` ${path}: ${e.message}`
112+
}).join('\n')
113+
}
114+
115+
106116
function parse_template(template_input: z.input<typeof Template>): z.infer<typeof Template> {
107-
const result = Template.parse(template_input)
108-
return result
117+
try {
118+
const result = Template.parse(template_input)
119+
return result
120+
} catch (e) {
121+
if (e instanceof z.ZodError) throw new errors.InputError(`Invalid template format:\n${pretty_zod_errors(e)}`)
122+
else throw e
123+
124+
}
109125
}
110126

111127
export { parse_template }

0 commit comments

Comments
 (0)