mschiesser commited on
Commit
41d1ead
·
1 Parent(s): 7b3883a

factor out commands

Browse files
ai_video_cli/commands.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import os
3
+ from moviepy.editor import VideoFileClip, concatenate_videoclips, vfx
4
+ from PIL import Image
5
+
6
+ def get_video_codec(video):
7
+ codec = getattr(video, "codec", None)
8
+ if codec:
9
+ print(f"Input video codec: {codec}")
10
+ else:
11
+ print("Codec information not available. Using default 'libx264'.")
12
+ codec = "libx264"
13
+ return codec
14
+
15
+ def get_audio_codec(audio_clip):
16
+ audio_codec = getattr(audio_clip, "audio_codec", None)
17
+ if not audio_codec:
18
+ print("Audio codec information not available. Using default 'aac'.")
19
+ audio_codec = "aac"
20
+ else:
21
+ print(f"Using audio codec: {audio_codec}")
22
+ return audio_codec
23
+
24
+ def split_video(input_file, chunk_size):
25
+ try:
26
+ video = VideoFileClip(input_file)
27
+ codec = get_video_codec(video)
28
+ video_duration = video.duration
29
+ base_filename, ext = os.path.splitext(input_file)
30
+
31
+ start_time = 0
32
+ part_num = 1
33
+ split_files = []
34
+
35
+ while start_time < video_duration:
36
+ end_time = min(start_time + chunk_size, video_duration)
37
+ part_filename = f"{base_filename}_part{part_num}{ext}"
38
+ video.subclip(start_time, end_time).write_videofile(
39
+ part_filename, codec=codec
40
+ )
41
+ print(f"Saved chunk: {part_filename}")
42
+ split_files.append(part_filename)
43
+ start_time = end_time
44
+ part_num += 1
45
+
46
+ return split_files
47
+ except Exception as e:
48
+ print(f"Error: {e}")
49
+ return []
50
+
51
+ def combine_videos(output_file, input_files, codec=None):
52
+ try:
53
+ video_clips = [VideoFileClip(file) for file in input_files]
54
+ combined = concatenate_videoclips(video_clips)
55
+ codec = codec if codec else get_video_codec(video_clips[0])
56
+ combined.write_videofile(output_file, codec=codec)
57
+ print(f"Combined video saved as: {output_file}")
58
+ except Exception as e:
59
+ print(f"Error: {e}")
60
+
61
+ def replace_audio(input_video, audio_video, output_file=None):
62
+ try:
63
+ if output_file is None:
64
+ base_filename, ext = os.path.splitext(input_video)
65
+ output_file = f"{base_filename}_with_replaced_audio{ext}"
66
+
67
+ video = VideoFileClip(input_video)
68
+ audio_clip = VideoFileClip(audio_video)
69
+
70
+ # Get audio from the audio video and adjust duration to match video duration
71
+ audio = audio_clip.audio
72
+ if audio.duration > video.duration:
73
+ audio = audio.subclip(0, video.duration)
74
+ else:
75
+ audio = audio.fx(vfx.loop, duration=video.duration)
76
+
77
+ # write video with new audio
78
+ video_with_new_audio = video.set_audio(audio)
79
+ video_with_new_audio.write_videofile(
80
+ output_file,
81
+ codec=get_video_codec(video),
82
+ audio_codec=get_audio_codec(audio_clip),
83
+ )
84
+
85
+ print(f"Audio replaced. Output video saved as: {output_file}")
86
+ except Exception as e:
87
+ print(f"Error: {e}")
88
+
89
+ def generate_thumbnail(input_file, output_file=None):
90
+ try:
91
+ if output_file is None:
92
+ base_filename, _ = os.path.splitext(input_file)
93
+ output_file = f"{base_filename}_thumbnail.jpg"
94
+
95
+ video = VideoFileClip(input_file)
96
+ thumbnail = video.get_frame(0) # Get the first frame
97
+ video.close()
98
+
99
+ # Save the thumbnail
100
+ Image.fromarray(thumbnail).save(output_file)
101
+
102
+ print(f"Thumbnail generated and saved as: {output_file}")
103
+ except Exception as e:
104
+ print(f"Error: {e}")
105
+
106
+ def convert_video(
107
+ input_file, output_file, video_codec, audio_codec, crop_width, crop_height
108
+ ):
109
+ try:
110
+ video = VideoFileClip(input_file)
111
+
112
+ # If output_file is not provided, create a default name
113
+ if output_file is None:
114
+ base_filename, ext = os.path.splitext(input_file)
115
+ output_file = f"{base_filename}_converted{ext}"
116
+
117
+ # Resize and crop the video if dimensions are provided
118
+ if crop_width and crop_height:
119
+ # Calculate the aspect ratios
120
+ target_aspect = crop_width / crop_height
121
+ video_aspect = video.w / video.h
122
+
123
+ if video_aspect > target_aspect:
124
+ # Video is wider, scale based on height
125
+ new_height = crop_height
126
+ new_width = int(math.ceil(new_height * video_aspect))
127
+ else:
128
+ # Video is taller, scale based on width
129
+ new_width = crop_width
130
+ new_height = int(math.ceil(new_width / video_aspect))
131
+
132
+ # Resize the video
133
+ resized_video = video.resize(height=new_height, width=new_width)
134
+
135
+ # Calculate padding
136
+ pad_x = max(0, (crop_width - new_width) // 2)
137
+ pad_y = max(0, (crop_height - new_height) // 2)
138
+
139
+ # Crop to final size
140
+ final_video = resized_video.crop(
141
+ x1=pad_x, y1=pad_y, width=crop_width, height=crop_height
142
+ )
143
+ else:
144
+ final_video = video
145
+
146
+ # Write the video file with specified codecs
147
+ final_video.write_videofile(
148
+ output_file, codec=video_codec, audio_codec=audio_codec
149
+ )
150
+
151
+ print(f"Video converted and saved as: {output_file}")
152
+ print(f"Video codec: {video_codec}")
153
+ print(f"Audio codec: {audio_codec}")
154
+ if crop_width and crop_height:
155
+ print(f"Video resized and cropped to: {crop_width}x{crop_height}")
156
+ except Exception as e:
157
+ print(f"Error: {e}")
158
+
159
+ def extract_audio(input_file, output_file=None):
160
+ try:
161
+ if output_file is None:
162
+ base_filename, _ = os.path.splitext(input_file)
163
+ output_file = f"{base_filename}_audio.mp3"
164
+
165
+ video = VideoFileClip(input_file)
166
+ audio = video.audio
167
+
168
+ # Extract audio
169
+ audio.write_audiofile(output_file)
170
+
171
+ video.close()
172
+ audio.close()
173
+
174
+ print(f"Audio extracted and saved as: {output_file}")
175
+ except Exception as e:
176
+ print(f"Error: {e}")
ai_video_cli/gradio.py CHANGED
@@ -1,5 +1,5 @@
1
  import gradio as gr
2
- from ai_video_cli.main import split_video
3
 
4
  def split_video_interface(input_file, chunk_size):
5
  try:
 
1
  import gradio as gr
2
+ from ai_video_cli.commands import split_video
3
 
4
  def split_video_interface(input_file, chunk_size):
5
  try:
ai_video_cli/main.py CHANGED
@@ -1,189 +1,12 @@
1
  import argparse
2
- import math
3
- import os
4
- from moviepy.editor import VideoFileClip, concatenate_videoclips, vfx
5
- from PIL import Image
6
-
7
-
8
- def get_video_codec(video):
9
- codec = getattr(video, "codec", None)
10
- if codec:
11
- print(f"Input video codec: {codec}")
12
- else:
13
- print("Codec information not available. Using default 'libx264'.")
14
- codec = "libx264"
15
- return codec
16
-
17
-
18
- def get_audio_codec(audio_clip):
19
- audio_codec = getattr(audio_clip, "audio_codec", None)
20
- if not audio_codec:
21
- print("Audio codec information not available. Using default 'aac'.")
22
- audio_codec = "aac"
23
- else:
24
- print(f"Using audio codec: {audio_codec}")
25
- return audio_codec
26
-
27
-
28
- def split_video(input_file, chunk_size):
29
- try:
30
- video = VideoFileClip(input_file)
31
- codec = get_video_codec(video)
32
- video_duration = video.duration
33
- base_filename, ext = os.path.splitext(input_file)
34
-
35
- start_time = 0
36
- part_num = 1
37
- split_files = []
38
-
39
- while start_time < video_duration:
40
- end_time = min(start_time + chunk_size, video_duration)
41
- part_filename = f"{base_filename}_part{part_num}{ext}"
42
- video.subclip(start_time, end_time).write_videofile(
43
- part_filename, codec=codec
44
- )
45
- print(f"Saved chunk: {part_filename}")
46
- split_files.append(part_filename)
47
- start_time = end_time
48
- part_num += 1
49
-
50
- return split_files
51
- except Exception as e:
52
- print(f"Error: {e}")
53
- return []
54
-
55
-
56
- def combine_videos(output_file, input_files, codec=None):
57
- try:
58
- video_clips = [VideoFileClip(file) for file in input_files]
59
- combined = concatenate_videoclips(video_clips)
60
- codec = codec if codec else get_video_codec(video_clips[0])
61
- combined.write_videofile(output_file, codec=codec)
62
- print(f"Combined video saved as: {output_file}")
63
- except Exception as e:
64
- print(f"Error: {e}")
65
-
66
-
67
- def replace_audio(input_video, audio_video, output_file=None):
68
- try:
69
- if output_file is None:
70
- base_filename, ext = os.path.splitext(input_video)
71
- output_file = f"{base_filename}_with_replaced_audio{ext}"
72
-
73
- video = VideoFileClip(input_video)
74
- audio_clip = VideoFileClip(audio_video)
75
-
76
- # Get audio from the audio video and adjust duration to match video duration
77
- audio = audio_clip.audio
78
- if audio.duration > video.duration:
79
- audio = audio.subclip(0, video.duration)
80
- else:
81
- audio = audio.fx(vfx.loop, duration=video.duration)
82
-
83
- # write video with new audio
84
- video_with_new_audio = video.set_audio(audio)
85
- video_with_new_audio.write_videofile(
86
- output_file,
87
- codec=get_video_codec(video),
88
- audio_codec=get_audio_codec(audio_clip),
89
- )
90
-
91
- print(f"Audio replaced. Output video saved as: {output_file}")
92
- except Exception as e:
93
- print(f"Error: {e}")
94
-
95
-
96
- def generate_thumbnail(input_file, output_file=None):
97
- try:
98
- if output_file is None:
99
- base_filename, _ = os.path.splitext(input_file)
100
- output_file = f"{base_filename}_thumbnail.jpg"
101
-
102
- video = VideoFileClip(input_file)
103
- thumbnail = video.get_frame(0) # Get the first frame
104
- video.close()
105
-
106
- # Save the thumbnail
107
- Image.fromarray(thumbnail).save(output_file)
108
-
109
- print(f"Thumbnail generated and saved as: {output_file}")
110
- except Exception as e:
111
- print(f"Error: {e}")
112
-
113
-
114
- def convert_video(
115
- input_file, output_file, video_codec, audio_codec, crop_width, crop_height
116
- ):
117
- try:
118
- video = VideoFileClip(input_file)
119
-
120
- # If output_file is not provided, create a default name
121
- if output_file is None:
122
- base_filename, ext = os.path.splitext(input_file)
123
- output_file = f"{base_filename}_converted{ext}"
124
-
125
- # Resize and crop the video if dimensions are provided
126
- if crop_width and crop_height:
127
- # Calculate the aspect ratios
128
- target_aspect = crop_width / crop_height
129
- video_aspect = video.w / video.h
130
-
131
- if video_aspect > target_aspect:
132
- # Video is wider, scale based on height
133
- new_height = crop_height
134
- new_width = int(math.ceil(new_height * video_aspect))
135
- else:
136
- # Video is taller, scale based on width
137
- new_width = crop_width
138
- new_height = int(math.ceil(new_width / video_aspect))
139
-
140
- # Resize the video
141
- resized_video = video.resize(height=new_height, width=new_width)
142
-
143
- # Calculate padding
144
- pad_x = max(0, (crop_width - new_width) // 2)
145
- pad_y = max(0, (crop_height - new_height) // 2)
146
-
147
- # Crop to final size
148
- final_video = resized_video.crop(
149
- x1=pad_x, y1=pad_y, width=crop_width, height=crop_height
150
- )
151
- else:
152
- final_video = video
153
-
154
- # Write the video file with specified codecs
155
- final_video.write_videofile(
156
- output_file, codec=video_codec, audio_codec=audio_codec
157
- )
158
-
159
- print(f"Video converted and saved as: {output_file}")
160
- print(f"Video codec: {video_codec}")
161
- print(f"Audio codec: {audio_codec}")
162
- if crop_width and crop_height:
163
- print(f"Video resized and cropped to: {crop_width}x{crop_height}")
164
- except Exception as e:
165
- print(f"Error: {e}")
166
-
167
-
168
- def extract_audio(input_file, output_file=None):
169
- try:
170
- if output_file is None:
171
- base_filename, _ = os.path.splitext(input_file)
172
- output_file = f"{base_filename}_audio.mp3"
173
-
174
- video = VideoFileClip(input_file)
175
- audio = video.audio
176
-
177
- # Extract audio
178
- audio.write_audiofile(output_file)
179
-
180
- video.close()
181
- audio.close()
182
-
183
- print(f"Audio extracted and saved as: {output_file}")
184
- except Exception as e:
185
- print(f"Error: {e}")
186
-
187
 
188
  def main():
189
  parser = argparse.ArgumentParser(description="AI Video Editor CLI Tool")
@@ -309,6 +132,5 @@ def main():
309
  else:
310
  parser.print_help()
311
 
312
-
313
  if __name__ == "__main__":
314
  main()
 
1
  import argparse
2
+ from ai_video_cli.commands import (
3
+ split_video,
4
+ combine_videos,
5
+ replace_audio,
6
+ generate_thumbnail,
7
+ convert_video,
8
+ extract_audio
9
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  def main():
12
  parser = argparse.ArgumentParser(description="AI Video Editor CLI Tool")
 
132
  else:
133
  parser.print_help()
134
 
 
135
  if __name__ == "__main__":
136
  main()