1
1
import { logger , task } from "@trigger.dev/sdk/v3" ;
2
- import { chmod } from "node:fs/promises" ;
2
+ import { chmod , writeFile } from "node:fs/promises" ;
3
+ import { Readable } from "node:stream" ;
4
+ import { ReadableStream } from "stream/web" ;
5
+ import { basename } from "node:path" ;
3
6
import YTDlpWrap from "yt-dlp-wrap" ;
7
+ import ffmpeg from "@ffmpeg-installer/ffmpeg" ;
4
8
5
9
export const ytDlp = task ( {
6
10
id : "yt-dlp" ,
@@ -20,3 +24,136 @@ export const ytDlp = task({
20
24
logger . log ( "version" , { version } ) ;
21
25
} ,
22
26
} ) ;
27
+
28
+ async function getFfprobe ( ) {
29
+ const ffprobe = await import ( "@ffprobe-installer/ffprobe" ) ;
30
+
31
+ logger . log ( "ffprobeInstaller" , ffprobe ) ;
32
+
33
+ return ffprobe ;
34
+ }
35
+
36
+ async function ffprobeVersion ( ) {
37
+ const ffprobe = await getFfprobe ( ) ;
38
+ const childProcess = await execute ( ffprobe . path , [ "-version" ] ) ;
39
+
40
+ logger . log ( "ffprobe -version" , {
41
+ output : childProcess . stdout . split ( "\n" ) [ 0 ] ,
42
+ } ) ;
43
+ }
44
+
45
+ async function ffmpegVersion ( ) {
46
+ logger . log ( "ffmpegInstaller" , ffmpeg ) ;
47
+
48
+ const childProcess = await execute ( ffmpeg . path , [ "-version" ] ) ;
49
+
50
+ logger . log ( "ffmpeg -version" , {
51
+ output : childProcess . stdout . split ( "\n" ) [ 0 ] ,
52
+ } ) ;
53
+ }
54
+
55
+ export const ffprobeInstaller = task ( {
56
+ id : "ffprobe-installer" ,
57
+ run : async ( ) => {
58
+ await ffprobeVersion ( ) ;
59
+ } ,
60
+ } ) ;
61
+
62
+ export const ffmpegInstaller = task ( {
63
+ id : "ffmpeg-installer" ,
64
+ run : async ( ) => {
65
+ await ffmpegVersion ( ) ;
66
+ } ,
67
+ } ) ;
68
+
69
+ const videoUrl =
70
+ "https://upload.wikimedia.org/wikipedia/commons/0/07/Fractal-zoom-1-03-Mandelbrot_Buzzsaw.ogv" ;
71
+ const videoPath = "./video.ogv" ;
72
+
73
+ async function downloadVideo ( ) {
74
+ logger . log ( "downloading video" , { url : videoUrl } ) ;
75
+
76
+ const response = await fetch ( videoUrl ) ;
77
+
78
+ if ( ! response . body ) {
79
+ throw new Error ( "No readable stream" ) ;
80
+ }
81
+
82
+ const readStream = Readable . fromWeb ( response . body as ReadableStream ) ;
83
+ await writeFile ( videoPath , readStream ) ;
84
+
85
+ logger . log ( "finished downloading" , { outputPath : videoPath } ) ;
86
+ }
87
+
88
+ async function execute ( file : string , args ?: readonly string [ ] ) {
89
+ const { execa } = await import ( "execa" ) ;
90
+
91
+ logger . log ( `execute: ${ basename ( file ) } ` , { args } ) ;
92
+ const childProcess = await execa ( file , args ) ;
93
+
94
+ if ( childProcess . exitCode !== 0 ) {
95
+ logger . error ( "Non-zero exit code" , {
96
+ stderr : childProcess . stderr ,
97
+ stdout : childProcess . stdout ,
98
+ } ) ;
99
+ throw new Error ( "Non-zero exit code" ) ;
100
+ }
101
+
102
+ return childProcess ;
103
+ }
104
+
105
+ async function probeVideo ( ) {
106
+ const ffprobe = await getFfprobe ( ) ;
107
+ const args = [ "-hide_banner" , "-print_format" , "json" , "-show_format" , videoPath ] ;
108
+
109
+ logger . log ( "probing video" , { videoPath } ) ;
110
+ const childProcess = await execute ( ffprobe . path , args ) ;
111
+
112
+ logger . log ( "video info" , {
113
+ output : JSON . parse ( childProcess . stdout ) ,
114
+ } ) ;
115
+ }
116
+
117
+ export const ffprobeInfo = task ( {
118
+ id : "ffprobe-info" ,
119
+ run : async ( ) => {
120
+ await ffprobeVersion ( ) ;
121
+ await downloadVideo ( ) ;
122
+ await probeVideo ( ) ;
123
+ } ,
124
+ } ) ;
125
+
126
+ async function convertVideo ( ) {
127
+ const outputPath = "./video.webm" ;
128
+ logger . log ( "converting video" , { input : videoPath , output : outputPath } ) ;
129
+
130
+ const childProcess = await execute ( ffmpeg . path , [
131
+ "-hide_banner" ,
132
+ "-y" , // overwrite output, don't prompt
133
+ "-i" ,
134
+ videoPath ,
135
+ // seek to 25s
136
+ "-ss" ,
137
+ "25" ,
138
+ // stop after 5s
139
+ "-t" ,
140
+ "5" ,
141
+ outputPath ,
142
+ ] ) ;
143
+
144
+ logger . log ( "video converted" , {
145
+ input : videoPath ,
146
+ output : outputPath ,
147
+ stderr : childProcess . stderr ,
148
+ stdout : childProcess . stdout ,
149
+ } ) ;
150
+ }
151
+
152
+ export const ffmpegConvert = task ( {
153
+ id : "ffmpeg-convert" ,
154
+ run : async ( ) => {
155
+ await ffmpegVersion ( ) ;
156
+ await downloadVideo ( ) ;
157
+ await convertVideo ( ) ;
158
+ } ,
159
+ } ) ;
0 commit comments