Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -219,12 +219,13 @@ def loop_audio_to_length(audio_clip, target_duration):
|
|
| 219 |
try:
|
| 220 |
looped_audio = concatenate_audioclips(audio_segments)
|
| 221 |
final_looped_audio = looped_audio.subclip(0, target_duration)
|
| 222 |
-
# Close the temporary concatenated clip
|
| 223 |
try: looped_audio.close()
|
| 224 |
except: pass
|
| 225 |
return final_looped_audio
|
| 226 |
except Exception as e:
|
| 227 |
logger.error(f"Error concatenating audio clips for looping: {str(e)}", exc_info=True)
|
|
|
|
| 228 |
return audio_clip.subclip(0, min(audio_clip.duration, target_duration))
|
| 229 |
|
| 230 |
def extract_visual_keywords_from_script(script_text):
|
|
@@ -289,10 +290,12 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 289 |
start_time = datetime.now()
|
| 290 |
temp_dir_intermediate = None
|
| 291 |
|
|
|
|
| 292 |
audio_tts = None
|
| 293 |
musica_audio = None
|
| 294 |
video_base = None
|
| 295 |
video_final = None
|
|
|
|
| 296 |
|
| 297 |
try:
|
| 298 |
# 1. Generate or use script
|
|
@@ -323,9 +326,9 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 323 |
audio_duration = audio_tts.duration
|
| 324 |
logger.info(f"Voice audio duration: {audio_duration:.2f} seconds")
|
| 325 |
|
| 326 |
-
if audio_duration < 0
|
| 327 |
logger.error(f"Voice audio duration ({audio_duration:.2f}s) is too short.")
|
| 328 |
-
raise ValueError("Generated voice audio is too short.")
|
| 329 |
|
| 330 |
|
| 331 |
# 3. Extract keywords
|
|
@@ -365,6 +368,7 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 365 |
videos = buscar_videos_pexels(keyword, PEXELS_API_KEY, per_page=2)
|
| 366 |
if videos:
|
| 367 |
videos_data.extend(videos)
|
|
|
|
| 368 |
logger.info(f"Found {len(videos)} videos for '{keyword}' (generic). Total data: {len(videos_data)}")
|
| 369 |
except Exception as e:
|
| 370 |
logger.warning(f"Error searching generic videos for '{keyword}': {str(e)}")
|
|
@@ -409,7 +413,8 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 409 |
|
| 410 |
# 5. Process and concatenate video clips
|
| 411 |
logger.info("Processing and concatenating downloaded videos...")
|
| 412 |
-
|
|
|
|
| 413 |
current_duration = 0
|
| 414 |
min_clip_duration = 0.5
|
| 415 |
max_clip_segment = 10.0
|
|
@@ -423,6 +428,7 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 423 |
try:
|
| 424 |
logger.debug(f"[{i+1}/{len(video_paths)}] Opening clip: {path}")
|
| 425 |
clip = VideoFileClip(path)
|
|
|
|
| 426 |
|
| 427 |
if clip.reader is None or clip.duration is None or clip.duration <= 0:
|
| 428 |
logger.warning(f"[{i+1}/{len(video_paths)}] Clip {path} seems invalid (reader is None or duration <= 0). Skipping.")
|
|
@@ -438,11 +444,19 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 438 |
|
| 439 |
if segment_duration >= min_clip_duration:
|
| 440 |
try:
|
|
|
|
| 441 |
sub = clip.subclip(0, segment_duration)
|
| 442 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
current_duration += sub.duration
|
| 444 |
logger.debug(f"[{i+1}/{len(video_paths)}] Segment added: {sub.duration:.1f}s (total video: {current_duration:.1f}/{audio_duration:.1f}s)")
|
| 445 |
-
|
| 446 |
except Exception as sub_e:
|
| 447 |
logger.warning(f"[{i+1}/{len(video_paths)}] Error creating subclip from {path} ({segment_duration:.1f}s): {str(sub_e)}")
|
| 448 |
continue
|
|
@@ -454,39 +468,51 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 454 |
except Exception as e:
|
| 455 |
logger.warning(f"[{i+1}/{len(video_paths)}] Error processing video {path}: {str(e)}", exc_info=True)
|
| 456 |
continue
|
|
|
|
|
|
|
| 457 |
|
| 458 |
-
|
| 459 |
-
if clip is not None:
|
| 460 |
-
try:
|
| 461 |
-
clip.close()
|
| 462 |
-
logger.debug(f"[{i+1}/{len(video_paths)}] Clip {path} closed.")
|
| 463 |
-
except Exception as close_e:
|
| 464 |
-
logger.warning(f"[{i+1}/{len(video_paths)}] Error closing clip {path}: {str(close_e)}")
|
| 465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 466 |
|
| 467 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 468 |
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
|
|
|
|
|
|
|
|
|
| 481 |
|
| 482 |
-
num_full_repeats = int(audio_duration //
|
| 483 |
-
remaining_duration = audio_duration %
|
| 484 |
|
| 485 |
-
repeated_clips_list = [
|
| 486 |
|
| 487 |
if remaining_duration > 0:
|
| 488 |
try:
|
| 489 |
-
remaining_clip =
|
| 490 |
repeated_clips_list.append(remaining_clip)
|
| 491 |
logger.debug(f"Adding remaining segment: {remaining_duration:.2f}s")
|
| 492 |
except Exception as e:
|
|
@@ -494,27 +520,62 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 494 |
|
| 495 |
if repeated_clips_list:
|
| 496 |
logger.info(f"Concatenating {len(repeated_clips_list)} parts for repetition.")
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
else:
|
| 506 |
logger.error("Failed to create repeated video clips list.")
|
| 507 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 508 |
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
except: pass
|
| 514 |
-
video_base = trimmed_video_base
|
| 515 |
-
logger.info(f"Final base video duration: {video_base.duration:.2f}s")
|
| 516 |
|
| 517 |
|
|
|
|
|
|
|
| 518 |
# 6. Handle background music
|
| 519 |
logger.info("Processing audio...")
|
| 520 |
|
|
@@ -549,16 +610,22 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 549 |
final_audio = audio_tts
|
| 550 |
logger.warning("Using voice audio only due to music processing error.")
|
| 551 |
|
| 552 |
-
if final_audio.duration is not None and final_audio.duration
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
|
|
|
| 556 |
|
| 557 |
|
| 558 |
# 7. Create final video
|
| 559 |
logger.info("Rendering final video...")
|
| 560 |
video_final = video_base.set_audio(final_audio)
|
| 561 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 562 |
output_filename = "final_video.mp4"
|
| 563 |
output_path = os.path.join(temp_dir_intermediate, output_filename)
|
| 564 |
logger.info(f"Writing final video to: {output_path}")
|
|
@@ -585,23 +652,36 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 585 |
logger.critical(f"CRITICAL UNHANDLED ERROR in crear_video: {str(e)}", exc_info=True)
|
| 586 |
raise e
|
| 587 |
finally:
|
| 588 |
-
logger.info("Starting cleanup of intermediate temporary files...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 589 |
try:
|
| 590 |
-
if audio_tts is not None:
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
except: pass
|
| 596 |
-
if video_base is not None:
|
| 597 |
-
try: video_base.close()
|
| 598 |
-
except: pass
|
| 599 |
if video_final is not None:
|
| 600 |
try: video_final.close()
|
| 601 |
-
except:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
except Exception as e:
|
| 603 |
logger.warning(f"Error during final clip closing in finally: {str(e)}")
|
| 604 |
|
|
|
|
| 605 |
if temp_dir_intermediate and os.path.exists(temp_dir_intermediate):
|
| 606 |
final_output_in_temp = os.path.join(temp_dir_intermediate, "final_video.mp4")
|
| 607 |
|
|
|
|
| 219 |
try:
|
| 220 |
looped_audio = concatenate_audioclips(audio_segments)
|
| 221 |
final_looped_audio = looped_audio.subclip(0, target_duration)
|
| 222 |
+
# Close the temporary concatenated clip to free resources
|
| 223 |
try: looped_audio.close()
|
| 224 |
except: pass
|
| 225 |
return final_looped_audio
|
| 226 |
except Exception as e:
|
| 227 |
logger.error(f"Error concatenating audio clips for looping: {str(e)}", exc_info=True)
|
| 228 |
+
# Fallback: return original clip if looping fails
|
| 229 |
return audio_clip.subclip(0, min(audio_clip.duration, target_duration))
|
| 230 |
|
| 231 |
def extract_visual_keywords_from_script(script_text):
|
|
|
|
| 290 |
start_time = datetime.now()
|
| 291 |
temp_dir_intermediate = None
|
| 292 |
|
| 293 |
+
# Initialize clips and audio objects to None for cleanup in finally
|
| 294 |
audio_tts = None
|
| 295 |
musica_audio = None
|
| 296 |
video_base = None
|
| 297 |
video_final = None
|
| 298 |
+
concatenated_clips = [] # Keep track of main video clips for closing
|
| 299 |
|
| 300 |
try:
|
| 301 |
# 1. Generate or use script
|
|
|
|
| 326 |
audio_duration = audio_tts.duration
|
| 327 |
logger.info(f"Voice audio duration: {audio_duration:.2f} seconds")
|
| 328 |
|
| 329 |
+
if audio_duration < 1.0: # Require at least 1 second of audio
|
| 330 |
logger.error(f"Voice audio duration ({audio_duration:.2f}s) is too short.")
|
| 331 |
+
raise ValueError("Generated voice audio is too short (min 1 second required).")
|
| 332 |
|
| 333 |
|
| 334 |
# 3. Extract keywords
|
|
|
|
| 368 |
videos = buscar_videos_pexels(keyword, PEXELS_API_KEY, per_page=2)
|
| 369 |
if videos:
|
| 370 |
videos_data.extend(videos)
|
| 371 |
+
logger.extend(videos)
|
| 372 |
logger.info(f"Found {len(videos)} videos for '{keyword}' (generic). Total data: {len(videos_data)}")
|
| 373 |
except Exception as e:
|
| 374 |
logger.warning(f"Error searching generic videos for '{keyword}': {str(e)}")
|
|
|
|
| 413 |
|
| 414 |
# 5. Process and concatenate video clips
|
| 415 |
logger.info("Processing and concatenating downloaded videos...")
|
| 416 |
+
source_clips = [] # Clips loaded from downloaded files
|
| 417 |
+
clips_to_concatenate = [] # Segments extracted from source_clips
|
| 418 |
current_duration = 0
|
| 419 |
min_clip_duration = 0.5
|
| 420 |
max_clip_segment = 10.0
|
|
|
|
| 428 |
try:
|
| 429 |
logger.debug(f"[{i+1}/{len(video_paths)}] Opening clip: {path}")
|
| 430 |
clip = VideoFileClip(path)
|
| 431 |
+
source_clips.append(clip) # Add to list for later cleanup
|
| 432 |
|
| 433 |
if clip.reader is None or clip.duration is None or clip.duration <= 0:
|
| 434 |
logger.warning(f"[{i+1}/{len(video_paths)}] Clip {path} seems invalid (reader is None or duration <= 0). Skipping.")
|
|
|
|
| 444 |
|
| 445 |
if segment_duration >= min_clip_duration:
|
| 446 |
try:
|
| 447 |
+
# Create a subclip. This creates a *new* clip object.
|
| 448 |
sub = clip.subclip(0, segment_duration)
|
| 449 |
+
# Verify the subclip is valid
|
| 450 |
+
if sub.reader is None or sub.duration is None or sub.duration <= 0:
|
| 451 |
+
logger.warning(f"[{i+1}/{len(video_paths)}] Generated subclip from {path} is invalid. Skipping.")
|
| 452 |
+
try: sub.close() # Close the invalid subclip
|
| 453 |
+
except: pass
|
| 454 |
+
continue
|
| 455 |
+
|
| 456 |
+
clips_to_concatenate.append(sub)
|
| 457 |
current_duration += sub.duration
|
| 458 |
logger.debug(f"[{i+1}/{len(video_paths)}] Segment added: {sub.duration:.1f}s (total video: {current_duration:.1f}/{audio_duration:.1f}s)")
|
| 459 |
+
|
| 460 |
except Exception as sub_e:
|
| 461 |
logger.warning(f"[{i+1}/{len(video_paths)}] Error creating subclip from {path} ({segment_duration:.1f}s): {str(sub_e)}")
|
| 462 |
continue
|
|
|
|
| 468 |
except Exception as e:
|
| 469 |
logger.warning(f"[{i+1}/{len(video_paths)}] Error processing video {path}: {str(e)}", exc_info=True)
|
| 470 |
continue
|
| 471 |
+
# No 'finally' here to close 'clip' explicitly, because we add valid clips to source_clips
|
| 472 |
+
# and close them all together later.
|
| 473 |
|
| 474 |
+
logger.info(f"Source clip processing finished. Obtained {len(clips_to_concatenate)} valid segments.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 475 |
|
| 476 |
+
if not clips_to_concatenate:
|
| 477 |
+
logger.error("No valid video segments available to create the sequence.")
|
| 478 |
+
raise ValueError("No valid video segments available to create the video.")
|
| 479 |
+
|
| 480 |
+
logger.info(f"Concatenating {len(clips_to_concatenate)} video segments.")
|
| 481 |
+
try:
|
| 482 |
+
# Concatenate the collected valid segments
|
| 483 |
+
video_base = concatenate_videoclips(clips_to_concatenate, method="chain") # Explicitly use "chain"
|
| 484 |
+
logger.info(f"Base video duration after initial concatenation: {video_base.duration:.2f}s")
|
| 485 |
|
| 486 |
+
# IMPORTANT: Close all the individual segments that were concatenated
|
| 487 |
+
for clip_segment in clips_to_concatenate:
|
| 488 |
+
try: clip_segment.close()
|
| 489 |
+
except: pass
|
| 490 |
+
clips_to_concatenate = [] # Clear the list
|
| 491 |
|
| 492 |
+
# Verify the resulting concatenated clip is valid
|
| 493 |
+
if video_base.reader is None or video_base.duration is None or video_base.duration <= 0:
|
| 494 |
+
logger.critical("Concatenated video base clip is invalid after first concatenation.")
|
| 495 |
+
raise ValueError("Failed to create valid video base from segments.")
|
| 496 |
+
|
| 497 |
+
except Exception as e:
|
| 498 |
+
logger.critical(f"Error during initial concatenation: {str(e)}", exc_info=True)
|
| 499 |
+
raise ValueError("Failed during initial video concatenation.")
|
| 500 |
+
|
| 501 |
+
|
| 502 |
+
# --- REVISED REPETITION AND TRIMMING LOGIC ---
|
| 503 |
+
final_video_base = video_base # Start with the concatenated base
|
| 504 |
+
|
| 505 |
+
if final_video_base.duration < audio_duration:
|
| 506 |
+
logger.info(f"Base video ({final_video_base.duration:.2f}s) is shorter than audio ({audio_duration:.2f}s). Repeating...")
|
| 507 |
|
| 508 |
+
num_full_repeats = int(audio_duration // final_video_base.duration)
|
| 509 |
+
remaining_duration = audio_duration % final_video_base.duration
|
| 510 |
|
| 511 |
+
repeated_clips_list = [final_video_base] * num_full_repeats
|
| 512 |
|
| 513 |
if remaining_duration > 0:
|
| 514 |
try:
|
| 515 |
+
remaining_clip = final_video_base.subclip(0, remaining_duration)
|
| 516 |
repeated_clips_list.append(remaining_clip)
|
| 517 |
logger.debug(f"Adding remaining segment: {remaining_duration:.2f}s")
|
| 518 |
except Exception as e:
|
|
|
|
| 520 |
|
| 521 |
if repeated_clips_list:
|
| 522 |
logger.info(f"Concatenating {len(repeated_clips_list)} parts for repetition.")
|
| 523 |
+
try:
|
| 524 |
+
# Concatenate the repeated parts
|
| 525 |
+
video_base_repeated = concatenate_videoclips(repeated_clips_list, method="chain")
|
| 526 |
+
logger.info(f"Duration of repeated video base: {video_base_repeated.duration:.2f}s")
|
| 527 |
+
|
| 528 |
+
# Verify the repeated clip is valid
|
| 529 |
+
if video_base_repeated.reader is None or video_base_repeated.duration is None or video_base_repeated.duration <= 0:
|
| 530 |
+
logger.critical("Concatenated repeated video base clip is invalid.")
|
| 531 |
+
raise ValueError("Failed to create valid repeated video base.")
|
| 532 |
+
|
| 533 |
+
# Close the old base clip
|
| 534 |
+
try: final_video_base.close()
|
| 535 |
+
except: pass
|
| 536 |
+
# Assign the new valid repeated clip
|
| 537 |
+
final_video_base = video_base_repeated
|
| 538 |
+
|
| 539 |
+
except Exception as e:
|
| 540 |
+
logger.critical(f"Error during repetition concatenation: {str(e)}", exc_info=True)
|
| 541 |
+
# If repetition fails, maybe just use the original base and accept it's too short
|
| 542 |
+
logger.warning("Repetition failed. Using original video base (may be too short).")
|
| 543 |
+
# No need to change final_video_base if concatenation failed
|
| 544 |
+
|
| 545 |
else:
|
| 546 |
logger.error("Failed to create repeated video clips list.")
|
| 547 |
+
# Use original video_base if repetition list is empty
|
| 548 |
+
|
| 549 |
+
# After repetition (or if no repetition happened), ensure duration matches audio exactly
|
| 550 |
+
if final_video_base.duration > audio_duration:
|
| 551 |
+
logger.info(f"Trimming video base ({final_video_base.duration:.2f}s) to match audio duration ({audio_duration:.2f}s).")
|
| 552 |
+
try:
|
| 553 |
+
trimmed_video_base = final_video_base.subclip(0, audio_duration)
|
| 554 |
+
# Verify the trimmed clip is valid
|
| 555 |
+
if trimmed_video_base.reader is None or trimmed_video_base.duration is None or trimmed_video_base.duration <= 0:
|
| 556 |
+
logger.critical("Trimmed video base clip is invalid.")
|
| 557 |
+
raise ValueError("Failed to create valid trimmed video base.")
|
| 558 |
+
|
| 559 |
+
# Close the old clip
|
| 560 |
+
try: final_video_base.close()
|
| 561 |
+
except: pass
|
| 562 |
+
# Assign the new valid trimmed clip
|
| 563 |
+
final_video_base = trimmed_video_base
|
| 564 |
+
|
| 565 |
+
except Exception as e:
|
| 566 |
+
logger.critical(f"Error during trimming: {str(e)}", exc_info=True)
|
| 567 |
+
# If trimming fails, use the original longer clip (might cause audio/video sync issues)
|
| 568 |
+
logger.warning("Trimming failed. Using potentially longer video base.")
|
| 569 |
+
pass # final_video_base remains the longer one
|
| 570 |
|
| 571 |
+
# Final check on video_base before setting audio/writing
|
| 572 |
+
if final_video_base.reader is None or final_video_base.duration is None or final_video_base.duration <= 0:
|
| 573 |
+
logger.critical("Final video base clip is invalid before audio/writing.")
|
| 574 |
+
raise ValueError("Final video base clip is invalid.")
|
|
|
|
|
|
|
|
|
|
| 575 |
|
| 576 |
|
| 577 |
+
video_base = final_video_base # Use the final adjusted video_base for subsequent steps
|
| 578 |
+
|
| 579 |
# 6. Handle background music
|
| 580 |
logger.info("Processing audio...")
|
| 581 |
|
|
|
|
| 610 |
final_audio = audio_tts
|
| 611 |
logger.warning("Using voice audio only due to music processing error.")
|
| 612 |
|
| 613 |
+
if final_audio.duration is not None and abs(final_audio.duration - video_base.duration) > 0.1: # Check for significant duration mismatch
|
| 614 |
+
logger.warning(f"Final audio duration ({final_audio.duration:.2f}s) differs from video base ({video_base.duration:.2f}s). This might cause sync issues.")
|
| 615 |
+
# MoviePy write_videofile often handles slight differences, but large ones can fail or sync poorly.
|
| 616 |
+
# We could try to adjust audio length here, but loop_audio_to_length should have handled it.
|
| 617 |
+
# Let's just log the warning for now.
|
| 618 |
|
| 619 |
|
| 620 |
# 7. Create final video
|
| 621 |
logger.info("Rendering final video...")
|
| 622 |
video_final = video_base.set_audio(final_audio)
|
| 623 |
+
|
| 624 |
+
# Final check on the combined video+audio clip
|
| 625 |
+
if video_final.reader is None or video_final.duration is None or video_final.duration <= 0:
|
| 626 |
+
logger.critical("Final video clip (with audio) is invalid before writing.")
|
| 627 |
+
raise ValueError("Final video clip is invalid before writing.")
|
| 628 |
+
|
| 629 |
output_filename = "final_video.mp4"
|
| 630 |
output_path = os.path.join(temp_dir_intermediate, output_filename)
|
| 631 |
logger.info(f"Writing final video to: {output_path}")
|
|
|
|
| 652 |
logger.critical(f"CRITICAL UNHANDLED ERROR in crear_video: {str(e)}", exc_info=True)
|
| 653 |
raise e
|
| 654 |
finally:
|
| 655 |
+
logger.info("Starting cleanup of clips and intermediate temporary files...")
|
| 656 |
+
|
| 657 |
+
# Close all initially opened source clips
|
| 658 |
+
for clip in source_clips:
|
| 659 |
+
try: clip.close()
|
| 660 |
+
except Exception as e: logger.warning(f"Error closing source clip in finally: {str(e)}")
|
| 661 |
+
|
| 662 |
+
# Close any segments left in the list (should be empty if successful)
|
| 663 |
+
for clip_segment in clips_to_concatenate:
|
| 664 |
+
try: clip_segment.close()
|
| 665 |
+
except Exception as e: logger.warning(f"Error closing segment clip in finally: {str(e)}")
|
| 666 |
+
|
| 667 |
+
# Close the main MoviePy objects if they were successfully created
|
| 668 |
try:
|
| 669 |
+
if audio_tts is not None: audio_tts.close()
|
| 670 |
+
if musica_audio is not None: musica_audio.close()
|
| 671 |
+
# The video_base and video_final clips are often intertwined or subclips of each other.
|
| 672 |
+
# Closing video_final should ideally close everything it's composed of.
|
| 673 |
+
# Explicitly closing video_base if it's different might help, but be careful not to double close.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 674 |
if video_final is not None:
|
| 675 |
try: video_final.close()
|
| 676 |
+
except Exception as e: logger.warning(f"Error closing video_final in finally: {str(e)}")
|
| 677 |
+
elif video_base is not None: # If video_final wasn't created, close video_base
|
| 678 |
+
try: video_base.close()
|
| 679 |
+
except Exception as e: logger.warning(f"Error closing video_base in finally: {str(e)}")
|
| 680 |
+
|
| 681 |
except Exception as e:
|
| 682 |
logger.warning(f"Error during final clip closing in finally: {str(e)}")
|
| 683 |
|
| 684 |
+
# Clean up intermediate files, but NOT the final video file
|
| 685 |
if temp_dir_intermediate and os.path.exists(temp_dir_intermediate):
|
| 686 |
final_output_in_temp = os.path.join(temp_dir_intermediate, "final_video.mp4")
|
| 687 |
|