@@ -27,6 +27,8 @@ export default defineConfig({
2727 deploying). You can use pre-built extensions or create your own.
2828</Note >
2929
30+ You'll also need to add ` @trigger.dev/build ` to your ` package.json ` file under ` devDependencies ` if you don't already have it there.
31+
3032## Compress a video using FFmpeg
3133
3234This task demonstrates how to use FFmpeg to compress a video, reducing its file size while maintaining reasonable quality, and upload the compressed video to R2 storage.
@@ -49,10 +51,11 @@ import { Readable } from "node:stream";
4951import os from " os" ;
5052import path from " path" ;
5153
52- // Initialize S3 client for R2 storage
54+ // Initialize S3 client
5355const s3Client = new S3Client ({
56+ // How to authenticate to R2: https://developers.cloudflare.com/r2/api/s3/tokens/
5457 region: " auto" ,
55- endpoint: process .env .S3_ENDPOINT ,
58+ endpoint: process .env .R2_ENDPOINT ,
5659 credentials: {
5760 accessKeyId: process .env .R2_ACCESS_KEY_ID ?? " " ,
5861 secretAccessKey: process .env .R2_SECRET_ACCESS_KEY ?? " " ,
@@ -64,14 +67,14 @@ export const ffmpegCompressVideo = task({
6467 run : async (payload : { videoUrl: string }) => {
6568 const { videoUrl } = payload ;
6669
67- // Generate output file name with a timestamp
70+ // Generate temporary file names
6871 const tempDirectory = os .tmpdir ();
6972 const outputPath = path .join (tempDirectory , ` output_${Date .now ()}.mp4 ` );
7073
71- // Fetch the video from the provided URL
74+ // Fetch the video
7275 const response = await fetch (videoUrl );
7376
74- // Compress the video using FFmpeg
77+ // Compress the video
7578 await new Promise ((resolve , reject ) => {
7679 if (! response .body ) {
7780 return reject (new Error (" Failed to fetch video" ));
@@ -82,7 +85,7 @@ export const ffmpegCompressVideo = task({
8285 " -c:v libx264" , // Use H.264 codec
8386 " -crf 28" , // Higher CRF for more compression (28 is near the upper limit for acceptable quality)
8487 " -preset veryslow" , // Slowest preset for best compression
85- " -vf scale=iw/2:ih/2" , // Reduce resolution to 50% of original width and height
88+ " -vf scale=iw/2:ih/2" , // Reduce resolution to 320p width ( height auto-calculated)
8689 " -c:a aac" , // Use AAC for audio
8790 " -b:a 64k" , // Reduce audio bitrate to 64k
8891 " -ac 1" , // Convert to mono audio
@@ -93,39 +96,37 @@ export const ffmpegCompressVideo = task({
9396 .run ();
9497 });
9598
96- // Read the compressed video into a buffer
99+ // Read the compressed video
97100 const compressedVideo = await fs .readFile (outputPath );
98101
99- // Get the compressed video size
100102 const compressedSize = compressedVideo .length ;
101103
102- // Log compression results for debugging purposes
104+ // Log compression results
103105 logger .log (` Compressed video size: ${compressedSize } bytes ` );
104106 logger .log (` Compressed video saved at: ${outputPath } ` );
105107
106- // Generate the S3 key for the uploaded video file
107- const s3Key = ` processed-videos/${path .basename (outputPath )} ` ;
108+ // Upload the compressed video to S3, replacing slashes with underscores
109+ const r2Key = ` processed-videos/${path .basename (outputPath )} ` ;
108110
109- // Set up the parameters for uploading the video to R2
110111 const uploadParams = {
111- Bucket: process .env .S3_BUCKET ,
112- Key: s3Key ,
112+ Bucket: process .env .R2_BUCKET ,
113+ Key: r2Key ,
113114 Body: compressedVideo ,
114115 };
115116
116- // Upload the video to R2 and get the public URL
117+ // Upload the video to R2 and get the URL
117118 await s3Client .send (new PutObjectCommand (uploadParams ));
118- const s3Url = ` https://${process .env .S3_BUCKET }.s3.amazonaws .com/${s3Key } ` ;
119- logger .log (" Compressed video uploaded to R2" , { url: s3Url });
119+ const r2Url = ` https://${process .env .R2_ACCOUNT_ID }.r2.cloudflarestorage .com/${process . env . R2_BUCKET }/${ r2Key } ` ;
120+ logger .log (" Compressed video uploaded to R2" , { url: r2Url });
120121
121122 // Delete the temporary compressed video file
122123 await fs .unlink (outputPath );
123124
124- // Return the compressed video file path, compressed size, and R2 URL
125+ // Return the compressed video file path, compressed size, and S3 URL
125126 return {
126127 compressedVideoPath: outputPath ,
127128 compressedSize ,
128- s3Url ,
129+ r2Url ,
129130 };
130131 },
131132});
@@ -159,10 +160,11 @@ import { Readable } from "node:stream";
159160import os from " os" ;
160161import path from " path" ;
161162
162- // Initialize S3 client for R2 storage
163+ // Initialize S3 client
163164const s3Client = new S3Client ({
165+ // How to authenticate to R2: https://developers.cloudflare.com/r2/api/s3/tokens/
164166 region: " auto" ,
165- endpoint: process .env .S3_ENDPOINT ,
167+ endpoint: process .env .R2_ENDPOINT ,
166168 credentials: {
167169 accessKeyId: process .env .R2_ACCESS_KEY_ID ?? " " ,
168170 secretAccessKey: process .env .R2_SECRET_ACCESS_KEY ?? " " ,
@@ -174,14 +176,14 @@ export const ffmpegExtractAudio = task({
174176 run : async (payload : { videoUrl: string }) => {
175177 const { videoUrl } = payload ;
176178
177- // Generate output file name with a timestamp
179+ // Generate temporary and output file names
178180 const tempDirectory = os .tmpdir ();
179181 const outputPath = path .join (tempDirectory , ` output_${Date .now ()}.wav ` );
180182
181- // Fetch the video from the provided URL
183+ // Fetch the video
182184 const response = await fetch (videoUrl );
183185
184- // Convert the video to WAV format using FFmpeg
186+ // Convert the video to WAV
185187 await new Promise ((resolve , reject ) => {
186188 if (! response .body ) {
187189 return reject (new Error (" Failed to fetch video" ));
@@ -198,35 +200,34 @@ export const ffmpegExtractAudio = task({
198200 });
199201 });
200202
201- // Read the WAV file into a buffer
203+ // Read the WAV file
202204 const wavBuffer = await fs .readFile (outputPath );
203205
204- // Log the output file path for debugging purposes
206+ // Log the output file path
205207 logger .log (` Converted video saved at: ${outputPath } ` );
206208
207- // Generate the S3 key for the uploaded audio file
208- const s3Key = ` processed-audio/${path .basename (outputPath )} ` ;
209+ // Upload the compressed video to S3, replacing slashes with underscores
210+ const r2Key = ` processed-audio/${path .basename (outputPath )} ` ;
209211
210- // Set up the parameters for uploading the audio to R2
211212 const uploadParams = {
212- Bucket: process .env .S3_BUCKET ,
213- Key: s3Key ,
213+ Bucket: process .env .R2_BUCKET ,
214+ Key: r2Key ,
214215 Body: wavBuffer ,
215216 };
216217
217- // Upload the audio to R2 and get the public URL
218+ // Upload the audio to R2 and get the URL
218219 await s3Client .send (new PutObjectCommand (uploadParams ));
219- const s3Url = ` https://${process .env .S3_BUCKET }.s3.amazonaws .com/${s3Key } ` ;
220- logger .log (" Extracted audio uploaded to R2" , { url: s3Url });
220+ const r2Url = ` https://${process .env .R2_ACCOUNT_ID }.r2.cloudflarestorage .com/${process . env . R2_BUCKET }/${ r2Key } ` ;
221+ logger .log (" Extracted audio uploaded to R2" , { url: r2Url });
221222
222- // Delete the temporary output file
223+ // Delete the temporary file
223224 await fs .unlink (outputPath );
224225
225- // Return the WAV buffer, file path, and R2 URL
226+ // Return the WAV buffer and file path
226227 return {
227228 wavBuffer ,
228229 wavFilePath: outputPath ,
229- s3Url ,
230+ r2Url ,
230231 };
231232 },
232233});
@@ -254,10 +255,11 @@ import { Readable } from "node:stream";
254255import os from " os" ;
255256import path from " path" ;
256257
257- // Initialize S3 client for R2 storage
258+ // Initialize S3 client
258259const s3Client = new S3Client ({
260+ // How to authenticate to R2: https://developers.cloudflare.com/r2/api/s3/tokens/
259261 region: " auto" ,
260- endpoint: process .env .S3_ENDPOINT ,
262+ endpoint: process .env .R2_ENDPOINT ,
261263 credentials: {
262264 accessKeyId: process .env .R2_ACCESS_KEY_ID ?? " " ,
263265 secretAccessKey: process .env .R2_SECRET_ACCESS_KEY ?? " " ,
@@ -269,14 +271,14 @@ export const ffmpegGenerateThumbnail = task({
269271 run : async (payload : { videoUrl: string }) => {
270272 const { videoUrl } = payload ;
271273
272- // Generate output file name with a timestamp
274+ // Generate output file name
273275 const tempDirectory = os .tmpdir ();
274276 const outputPath = path .join (tempDirectory , ` thumbnail_${Date .now ()}.jpg ` );
275277
276- // Fetch the video from the provided URL
278+ // Fetch the video
277279 const response = await fetch (videoUrl );
278280
279- // Generate the thumbnail using FFmpeg
281+ // Generate the thumbnail
280282 await new Promise ((resolve , reject ) => {
281283 if (! response .body ) {
282284 return reject (new Error (" Failed to fetch video" ));
@@ -293,35 +295,34 @@ export const ffmpegGenerateThumbnail = task({
293295 .on (" error" , reject );
294296 });
295297
296- // Read the generated thumbnail into a buffer
298+ // Read the generated thumbnail
297299 const thumbnail = await fs .readFile (outputPath );
298300
299- // Generate the S3 key for the uploaded thumbnail file
300- const s3Key = ` thumbnails/${path .basename (outputPath )} ` ;
301+ // Upload the compressed video to S3, replacing slashes with underscores
302+ const r2Key = ` thumbnails/${path .basename (outputPath )} ` ;
301303
302- // Set up the parameters for uploading the thumbnail to R2
303304 const uploadParams = {
304- Bucket: process .env .S3_BUCKET ,
305- Key: s3Key ,
305+ Bucket: process .env .R2_BUCKET ,
306+ Key: r2Key ,
306307 Body: thumbnail ,
307308 };
308309
309- // Upload the thumbnail to R2 and get the public URL
310+ // Upload the thumbnail to R2 and get the URL
310311 await s3Client .send (new PutObjectCommand (uploadParams ));
311- const s3Url = ` https://${process .env .S3_BUCKET }.s3.amazonaws .com/${s3Key } ` ;
312- logger .log (" Thumbnail uploaded to R2" , { url: s3Url });
312+ const r2Url = ` https://${process .env .R2_ACCOUNT_ID }.r2.cloudflarestorage .com/${process . env . R2_BUCKET }/${ r2Key } ` ;
313+ logger .log (" Thumbnail uploaded to R2" , { url: r2Url });
313314
314- // Delete the temporary thumbnail file
315+ // Delete the temporary file
315316 await fs .unlink (outputPath );
316317
317- // Log thumbnail generation results for debugging purposes
318- logger .log (` Thumbnail uploaded to S3: ${s3Url } ` );
318+ // Log thumbnail generation results
319+ logger .log (` Thumbnail uploaded to S3: ${r2Url } ` );
319320
320- // Return the thumbnail buffer, file path, and R2 URL
321+ // Return the thumbnail buffer, file path, sizes, and S3 URL
321322 return {
322323 thumbnailBuffer: thumbnail ,
323324 thumbnailPath: outputPath ,
324- s3Url ,
325+ r2Url ,
325326 };
326327 },
327328});
0 commit comments