Update app.py
Browse files
app.py
CHANGED
|
@@ -232,9 +232,11 @@ def process_entry(entry, i, add_voiceover, target_language):
|
|
| 232 |
font="./NotoSansSC-Regular.ttf",
|
| 233 |
method='caption',
|
| 234 |
color='yellow',
|
| 235 |
-
|
|
|
|
|
|
|
| 236 |
size=(int(video.w * 0.8), None)
|
| 237 |
-
).with_start(entry["start"]).with_duration(entry["end"] - entry["start"]).with_position(('bottom')).with_opacity(0.
|
| 238 |
|
| 239 |
audio_segment = None
|
| 240 |
if add_voiceover:
|
|
@@ -248,54 +250,36 @@ def add_transcript_voiceover(video_path, translated_json, output_path, add_voice
|
|
| 248 |
"""
|
| 249 |
Add transcript and voiceover to a video, segment by segment.
|
| 250 |
"""
|
| 251 |
-
# Load the video file
|
| 252 |
video = VideoFileClip(video_path)
|
|
|
|
| 253 |
|
| 254 |
-
# Create text clips based on timestamps
|
| 255 |
text_clips = []
|
| 256 |
audio_segments = []
|
| 257 |
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
color='yellow',
|
| 275 |
-
font_size=subtitle_font_size,
|
| 276 |
-
size=(max_subtitle_width, None)
|
| 277 |
-
).with_start(entry["start"]).with_duration(entry["end"] - entry["start"]).with_position(('bottom')).with_opacity(0.7)
|
| 278 |
-
text_clips.append(txt_clip)
|
| 279 |
-
|
| 280 |
-
# Generate voiceover for this segment, if needed
|
| 281 |
-
if add_voiceover:
|
| 282 |
-
segment_audio_path = f"segment_{i}_voiceover.wav"
|
| 283 |
-
generate_voiceover([entry], target_language, segment_audio_path)
|
| 284 |
-
audio_segment = AudioFileClip(segment_audio_path).set_duration(entry["end"] - entry["start"])
|
| 285 |
-
audio_segments.append(audio_segment)
|
| 286 |
-
else:
|
| 287 |
-
raise ValueError(f"Invalid entry format: {entry}")
|
| 288 |
-
|
| 289 |
-
# Combine the text clips
|
| 290 |
final_video = CompositeVideoClip([video] + text_clips)
|
| 291 |
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
final_audio =
|
| 295 |
-
final_audio = final_audio.set_duration(video.duration)
|
| 296 |
final_video = final_video.set_audio(final_audio)
|
| 297 |
|
| 298 |
-
# Write the result to a file
|
| 299 |
logger.info(f"Saving the final video to: {output_path}")
|
| 300 |
final_video.write_videofile(output_path, codec="libx264", audio_codec="aac")
|
| 301 |
|
|
|
|
| 232 |
font="./NotoSansSC-Regular.ttf",
|
| 233 |
method='caption',
|
| 234 |
color='yellow',
|
| 235 |
+
stroke_color='black', # Border color
|
| 236 |
+
stroke_width=2, # Border thickness
|
| 237 |
+
font_size=int(video.h // 20),
|
| 238 |
size=(int(video.w * 0.8), None)
|
| 239 |
+
).with_start(entry["start"]).with_duration(entry["end"] - entry["start"]).with_position(('bottom')).with_opacity(0.8)
|
| 240 |
|
| 241 |
audio_segment = None
|
| 242 |
if add_voiceover:
|
|
|
|
| 250 |
"""
|
| 251 |
Add transcript and voiceover to a video, segment by segment.
|
| 252 |
"""
|
|
|
|
| 253 |
video = VideoFileClip(video_path)
|
| 254 |
+
font_path = "./NotoSansSC-Regular.ttf"
|
| 255 |
|
|
|
|
| 256 |
text_clips = []
|
| 257 |
audio_segments = []
|
| 258 |
|
| 259 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 260 |
+
futures = [executor.submit(process_entry, entry, i, video.w, video.h, font_path, add_voiceover, target_language)
|
| 261 |
+
for i, entry in enumerate(translated_json)]
|
| 262 |
+
|
| 263 |
+
for future in concurrent.futures.as_completed(futures):
|
| 264 |
+
try:
|
| 265 |
+
txt_clip, audio_segment = future.result()
|
| 266 |
+
text_clips.append(txt_clip)
|
| 267 |
+
if add_voiceover and audio_segment:
|
| 268 |
+
audio_segments.append(audio_segment)
|
| 269 |
+
except Exception as e:
|
| 270 |
+
logger.error(f"Error processing entry: {e}")
|
| 271 |
+
|
| 272 |
+
# Sort text clips and audio segments based on their start times
|
| 273 |
+
text_clips.sort(key=lambda clip: clip.start)
|
| 274 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
final_video = CompositeVideoClip([video] + text_clips)
|
| 276 |
|
| 277 |
+
if add_voiceover and audio_segments:
|
| 278 |
+
audio_segments.sort(key=lambda segment: segment.start)
|
| 279 |
+
final_audio = concatenate_audioclips(audio_segments)
|
| 280 |
+
final_audio = final_audio.set_duration(video.duration)
|
| 281 |
final_video = final_video.set_audio(final_audio)
|
| 282 |
|
|
|
|
| 283 |
logger.info(f"Saving the final video to: {output_path}")
|
| 284 |
final_video.write_videofile(output_path, codec="libx264", audio_codec="aac")
|
| 285 |
|