Skip to content

Commit 0d0cdfc

Browse files
authored
Remove --release flag (#22)
Also don't generate the full length videos during `watch`. Only during `build`.
1 parent 601c7cb commit 0d0cdfc

File tree

10 files changed

+96
-128
lines changed

10 files changed

+96
-128
lines changed

.github/workflows/examples.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,17 @@ jobs:
4545
convert -size 500x500 xc:none -fill white -draw "polygon 150,100 150,400 400,250" play_button.png
4646
4747
./examples/demo.sh
48-
mv _out/release.mp4 _public/demo.mp4
48+
mv _out/out.mp4 _public/demo.mp4
4949
convert _out/image/1.png play_button.png -gravity center -composite tmp.png
5050
mv tmp.png _public/demo.png
5151
5252
./examples/google.sh
53-
mv _out/release.mp4 _public/google.mp4
53+
mv _out/out.mp4 _public/google.mp4
5454
convert _out/image/1.png play_button.png -gravity center -composite tmp.png
5555
mv tmp.png _public/google.png
5656
5757
./examples/first.sh
58-
mv _out/release.mp4 _public/first.mp4
58+
mv _out/out.mp4 _public/first.mp4
5959
convert _out/image/1.png play_button.png -gravity center -composite tmp.png
6060
mv tmp.png _public/first.png
6161

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ To create a video, create a Typst presentation with speaker notes (we show only
3232
Next, run the following command:
3333

3434
```raw
35-
$ trv --release build examples/first.typ
35+
$ trv build examples/first.typ
3636
```
3737

3838
This generates the following video:
@@ -93,7 +93,7 @@ Google has some high-quality voices available via their API:
9393
```raw
9494
$ export GOOGLE_KEY="<YOUR KEY>"
9595
96-
$ trv --release build examples/google.typ
96+
$ trv build examples/google.typ
9797
```
9898

9999
[![Google demo video](https://transformrs.github.io/trv/google.png)](https://transformrs.github.io/trv/google.mp4)
@@ -121,7 +121,7 @@ So it's probably easiest to use DeepInfra:
121121
```raw
122122
$ export DEEPINFRA_KEY="<YOUR KEY>"
123123
124-
$ trv --release build presentation.typ
124+
$ trv build presentation.typ
125125
```
126126

127127
Do note that Zonos is way more unstable than Kokoros at the time of writing.

examples/demo.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
export GOOGLE_KEY=$(cat keys.env | grep GOOGLE_KEY | cut -d '=' -f 2)
66

7-
trv --release build examples/demo.typ
7+
trv build examples/demo.typ

examples/demo.typ

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@
7979
#import "@preview/polylux:0.4.0": *
8080
#set page(paper: "presentation-16-9")
8181
82+
// --- trv config:
83+
// provider = "openai-compatible(kokoros.transformrs.org)"
84+
// model = "tts-1"
85+
// voice = "af_sky"
86+
// audio_format = "wav"
87+
// ---
88+
8289
#slide[
8390
Hello
8491
@@ -103,13 +110,7 @@
103110
#set page(margin: 3em)
104111
#set text(size: 24pt)
105112
```bash
106-
$ trv \
107-
--input presentation.typ \
108-
--provider='openai-compatible(kokoros.transformrs.org)' \
109-
--model=tts-1 \
110-
--voice=af_sky \
111-
--audio-format=wav \
112-
--release
113+
$ trv build presentation.typ
113114
```
114115

115116
#toolbox.pdfpc.speaker-note("

examples/first.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
# Run via `./examples/first.sh`
44

5-
trv --release build examples/first.typ
5+
trv build examples/first.typ

examples/google.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
export GOOGLE_KEY=$(cat keys.env | grep GOOGLE_KEY | cut -d '=' -f 2)
66

7-
trv --release build examples/google.typ
7+
trv build examples/google.typ

src/main.rs

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,32 @@ fn test_parse_config() {
9191
}
9292

9393
#[derive(Clone, Debug, Parser)]
94-
struct BuildArgs {
94+
pub(crate) struct BuildArgs {
9595
/// Path to the Typst input file.
9696
input: PathBuf,
97+
98+
/// Audio codec.
99+
///
100+
/// This setting is passed to ffmpeg.
101+
///
102+
/// Opus generally gives the best quality for the lowest file size, but is
103+
/// not supported by all platforms. For example, Whatsapp Web and X don't
104+
/// accept it.
105+
///
106+
/// So therefore on MacOS set the value to `aac_at` and on Linux to
107+
/// `libfdk_aac`.
108+
#[arg(long, default_value = "opus")]
109+
audio_codec: String,
97110
}
98111

99112
#[derive(Clone, Debug, Parser)]
100-
struct WatchArgs {
113+
pub(crate) struct WatchArgs {
101114
/// Path to the Typst input file.
102115
input: PathBuf,
116+
117+
/// Port to run the server on.
118+
#[arg(long, default_value = "8080")]
119+
port: u16,
103120
}
104121

105122
#[derive(Clone, Debug, clap::Subcommand)]
@@ -128,26 +145,6 @@ pub(crate) struct Arguments {
128145
/// Enable caching.
129146
#[arg(long, default_value = "true")]
130147
cache: Option<bool>,
131-
132-
/// Release.
133-
///
134-
/// If true, attempt to convert the output video into a format that is more
135-
/// widely supported.
136-
#[arg(long, default_value = "false")]
137-
release: bool,
138-
139-
/// Audio codec.
140-
///
141-
/// This setting is passed to ffmpeg.
142-
///
143-
/// Opus generally gives the best quality for the lowest file size, but is
144-
/// not supported by all platforms. For example, Whatsapp Web and X don't
145-
/// accept it.
146-
///
147-
/// So therefore on MacOS set the value to `aac_at` and on Linux to
148-
/// `libfdk_aac`.
149-
#[arg(long, default_value = "opus")]
150-
audio_codec: String,
151148
}
152149

153150
// TODO: This logic should be in the transformrs crate as `Provider::from_str`.
@@ -218,7 +215,12 @@ fn copy_input_with_includes(dir: &str, input: &PathBuf) -> PathBuf {
218215
output_path
219216
}
220217

221-
pub(crate) async fn build(input: PathBuf, args: &Arguments) -> Vec<Slide> {
218+
pub(crate) async fn build(
219+
input: PathBuf,
220+
args: &Arguments,
221+
release: bool,
222+
audio_codec: Option<String>,
223+
) -> Vec<Slide> {
222224
let out_dir = &args.out_dir;
223225
let copied_input = copy_input_with_includes(out_dir, &input);
224226
let config = parse_config(&copied_input);
@@ -258,9 +260,10 @@ pub(crate) async fn build(input: PathBuf, args: &Arguments) -> Vec<Slide> {
258260
)
259261
.await;
260262
let output = "out.mp4";
261-
video::generate_video(out_dir, &slides, cache, &tts_config, output, &audio_ext);
262-
if args.release {
263-
video::generate_release_video(out_dir, output, "release.mp4", &args.audio_codec);
263+
video::create_video_clips(out_dir, &slides, cache, &tts_config, &audio_ext);
264+
if release {
265+
let audio_codec = audio_codec.unwrap();
266+
video::combine_video(out_dir, &slides, output, &audio_codec);
264267
}
265268
slides
266269
}
@@ -282,8 +285,10 @@ async fn main() {
282285

283286
match args.task {
284287
Task::Build(ref build_args) => {
285-
let _ = build(build_args.input.clone(), &args).await;
288+
let release = true;
289+
let audio_codec = Some(build_args.audio_codec.clone());
290+
let _ = build(build_args.input.clone(), &args, release, audio_codec).await;
286291
}
287-
Task::Watch(ref watch_args) => watch(watch_args.input.clone(), &args).await,
292+
Task::Watch(ref watch_args) => watch(watch_args, &args).await,
288293
};
289294
}

src/video.rs

Lines changed: 30 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ fn generate_concat_list(dir: &str, slides: &Vec<Slide>) -> String {
7878
lines.join("\n")
7979
}
8080

81+
fn set_default_ffmpeg_video_args(cmd: &mut std::process::Command) {
82+
cmd.arg("-c:v")
83+
.arg("libx264")
84+
.arg("-crf")
85+
.arg("23")
86+
.arg("-preset")
87+
.arg("fast")
88+
.arg("-vf")
89+
.arg(format!("scale=-1:{HEIGHT},format=yuv420p"))
90+
.arg("-pix_fmt")
91+
.arg("yuv420p");
92+
}
93+
8194
fn write_concat_list(dir: &str, path: &str, slides: &Vec<Slide>) {
8295
let concat_list = generate_concat_list(dir, slides);
8396
std::fs::write(path, concat_list).expect("couldn't write concat list");
@@ -101,34 +114,24 @@ fn create_video_clip(dir: &str, slide: &Slide, cache: bool, config: &TTSConfig,
101114
return;
102115
}
103116
let output_video = crate::path::video_path(dir, slide);
104-
let output = std::process::Command::new("ffmpeg")
105-
.arg("-y")
117+
let mut cmd = std::process::Command::new("ffmpeg");
118+
cmd.arg("-y")
106119
.arg("-loop")
107120
.arg("1")
108121
.arg("-i")
109122
.arg(input_image)
110123
.arg("-i")
111-
.arg(input_audio)
112-
.arg("-c:v")
113-
.arg("libx264")
114-
.arg("-crf")
115-
.arg("23")
116-
.arg("-preset")
117-
.arg("fast")
118-
.arg("-vf")
119-
.arg(format!("scale=-1:{HEIGHT},format=yuv420p"))
120-
.arg("-pix_fmt")
121-
.arg("yuv420p")
122-
.arg("-c:a")
124+
.arg(input_audio);
125+
set_default_ffmpeg_video_args(&mut cmd);
126+
cmd.arg("-c:a")
123127
.arg("opus")
124128
.arg("-strict")
125129
.arg("experimental")
126130
.arg("-shortest")
127131
.arg("-tune")
128132
.arg("stillimage")
129-
.arg(output_video.clone())
130-
.output()
131-
.expect("Failed to run ffmpeg command");
133+
.arg(output_video.clone());
134+
let output = cmd.output().expect("Failed to run ffmpeg command");
132135
if !output.status.success() {
133136
let stderr = String::from_utf8_lossy(&output.stderr);
134137
tracing::error!("Failed to create video clip: {stderr}");
@@ -139,7 +142,7 @@ fn create_video_clip(dir: &str, slide: &Slide, cache: bool, config: &TTSConfig,
139142
}
140143
}
141144

142-
fn create_video_clips(
145+
pub(crate) fn create_video_clips(
143146
dir: &str,
144147
slides: &Vec<Slide>,
145148
cache: bool,
@@ -159,7 +162,13 @@ fn create_video_clips(
159162
}
160163
}
161164

162-
fn concat_video_clips(concat_list: &str, output_path: &str) {
165+
pub(crate) fn combine_video(dir: &str, slides: &Vec<Slide>, output: &str, audio_codec: &str) {
166+
let output = Path::new(dir).join(output);
167+
let output_path = output.to_str().unwrap();
168+
let concat_list = Path::new(dir).join("concat_list.txt");
169+
let concat_list = concat_list.to_str().unwrap();
170+
write_concat_list(dir, concat_list, slides);
171+
163172
let output = std::process::Command::new("ffmpeg")
164173
.arg("-y")
165174
.arg("-f")
@@ -168,65 +177,18 @@ fn concat_video_clips(concat_list: &str, output_path: &str) {
168177
.arg(concat_list)
169178
.arg("-c")
170179
.arg("copy")
171-
.arg(output_path)
172-
.output()
173-
.expect("Failed to run ffmpeg command");
174-
if !output.status.success() {
175-
let stderr = String::from_utf8_lossy(&output.stderr);
176-
tracing::error!("Failed to concat video clips: {stderr}");
177-
std::process::exit(1);
178-
} else {
179-
tracing::info!("Concatenated video clips into {output_path}");
180-
}
181-
}
182-
183-
pub fn generate_video(
184-
dir: &str,
185-
slides: &Vec<Slide>,
186-
cache: bool,
187-
config: &TTSConfig,
188-
output: &str,
189-
audio_ext: &str,
190-
) {
191-
create_video_clips(dir, slides, cache, config, audio_ext);
192-
let output = Path::new(dir).join(output);
193-
let output = output.to_str().unwrap();
194-
let concat_list = Path::new(dir).join("concat_list.txt");
195-
let concat_list = concat_list.to_str().unwrap();
196-
write_concat_list(dir, concat_list, slides);
197-
concat_video_clips(concat_list, output);
198-
}
199-
200-
pub fn generate_release_video(dir: &str, input: &str, output: &str, audio_codec: &str) {
201-
let input_path = Path::new(dir).join(input);
202-
let output_path = Path::new(dir).join(output);
203-
let output_path = output_path.to_str().unwrap();
204-
let mut cmd = std::process::Command::new("ffmpeg");
205-
let output = cmd
206-
.arg("-y")
207-
.arg("-i")
208-
.arg(input_path)
209-
.arg("-c:v")
210-
.arg("libx264")
211-
.arg("-crf")
212-
.arg("23")
213-
.arg("-preset")
214-
.arg("fast")
215-
.arg("-vf")
216-
.arg(format!("scale=-1:{HEIGHT},format=yuv420p"))
217180
.arg("-c:a")
218181
.arg(audio_codec)
219182
.arg("-strict")
220183
.arg("experimental")
221184
.arg(output_path)
222185
.output()
223186
.expect("Failed to run ffmpeg command");
224-
225187
if !output.status.success() {
226188
let stderr = String::from_utf8_lossy(&output.stderr);
227-
tracing::error!("Failed to create release video: {stderr}");
189+
tracing::error!("Failed to concat video clips: {stderr}");
228190
std::process::exit(1);
229191
} else {
230-
tracing::info!("Created release video {}", output_path);
192+
tracing::info!("Combined video clips into {output_path}");
231193
}
232194
}

0 commit comments

Comments
 (0)