Spaces:
Sleeping
Sleeping
| from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip, AudioFileClip, concatenate_audioclips | |
| import os | |
| from typing import List, Tuple | |
| def export_srt(transcript: List[str], duration: float, output_path: str): | |
| """ | |
| Exports transcript as a .srt subtitle file assuming equal spacing. | |
| """ | |
| lines = [] | |
| segment_duration = duration / len(transcript) | |
| for idx, line in enumerate(transcript): | |
| start_time = segment_duration * idx | |
| end_time = segment_duration * (idx + 1) | |
| def format_time(t): | |
| h = int(t // 3600) | |
| m = int((t % 3600) // 60) | |
| s = int(t % 60) | |
| ms = int((t % 1) * 1000) | |
| return f"{h:02}:{m:02}:{s:02},{ms:03}" | |
| lines.append(f"{idx+1}") | |
| lines.append(f"{format_time(start_time)} --> {format_time(end_time)}") | |
| lines.append(line.strip()) | |
| lines.append("") # Empty line for spacing | |
| with open(output_path, "w", encoding="utf-8") as f: | |
| f.write("\n".join(lines)) | |
| def add_subtitles_and_bgm( | |
| video_path: str, | |
| transcript: List[str], | |
| output_path: str = "final_output.mp4", | |
| bgm_path: str = None, | |
| subtitle_font: str = "Arial", | |
| subtitle_size: int = 24, | |
| subtitle_color: str = "white", | |
| subtitle_position: Tuple[int, int] = ("center", "bottom") | |
| ): | |
| """ | |
| Adds subtitles and optional background music to a video. | |
| """ | |
| clip = VideoFileClip(video_path) | |
| duration = clip.duration | |
| segment_duration = duration / len(transcript) | |
| subtitle_clips = [] | |
| for i, line in enumerate(transcript): | |
| txt = TextClip( | |
| line, | |
| fontsize=subtitle_size, | |
| font=subtitle_font, | |
| color=subtitle_color, | |
| method='caption', | |
| size=(clip.w * 0.8, None) # 80% width | |
| ).set_position(subtitle_position).set_duration(segment_duration).set_start(i * segment_duration) | |
| subtitle_clips.append(txt) | |
| final_video = CompositeVideoClip([clip, *subtitle_clips]) | |
| if bgm_path and os.path.exists(bgm_path): | |
| bgm = AudioFileClip(bgm_path).volumex(0.2).set_duration(duration) | |
| original_audio = clip.audio | |
| if original_audio: | |
| mixed_audio = original_audio.volumex(1.0).audio_fadein(0.5).audio_fadeout(0.5) | |
| final_audio = CompositeVideoClip([mixed_audio.set_start(0), bgm.set_start(0)]).audio | |
| else: | |
| final_audio = bgm | |
| final_video = final_video.set_audio(final_audio) | |
| final_video.write_videofile(output_path, codec="libx264", audio_codec="aac") | |