Skip to content

Instantly share code, notes, and snippets.

@LuisCusihuaman
Created June 10, 2024 05:46
Show Gist options
  • Save LuisCusihuaman/0084489b1633de74d33ef6e953c31887 to your computer and use it in GitHub Desktop.
Save LuisCusihuaman/0084489b1633de74d33ef6e953c31887 to your computer and use it in GitHub Desktop.
Merge subtitles with video
import os
import sys
import logging
import subprocess
import codecs
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger()
def check_ffmpeg():
ffmpeg = os.environ.get('FFMPEG_DIRECTORY')
if not ffmpeg:
logger.error('❌ Point FFMPEG_DIRECTORY environment variable to the location of FFMPEG')
return None
if os.path.isfile(ffmpeg) and os.access(ffmpeg, os.X_OK):
binaries = os.path.dirname(ffmpeg)
else:
binaries = ffmpeg
ffmpeg_path = os.path.join(binaries, 'ffmpeg')
if not os.path.exists(ffmpeg_path):
logger.error('❌ Please download the ffmpeg binaries from www.ffmpeg.org')
return None
logger.info('✅ FFMPEG binaries found')
return binaries
def get_target_directory():
if len(sys.argv) > 1:
return sys.argv[1]
return os.getcwd()
def is_video_file(filename):
video_extensions = ['.avi', '.mp4', '.mkv']
return any(filename.endswith(ext) for ext in video_extensions)
def sanitize_filename(path):
return path.replace('"', '').replace('\'', '').replace(',', '')
def clean_subtitle_file(subtitle_file):
try:
with codecs.open(subtitle_file, 'r', encoding='utf-8', errors='ignore') as file:
content = file.read()
with codecs.open(subtitle_file, 'w', encoding='utf-8') as file:
file.write(content)
logger.info(f'✅ Cleaned and re-encoded subtitle file: {subtitle_file}')
except Exception as e:
logger.error(f'❌ Failed to clean subtitle file: {subtitle_file}. Error: {e}')
def merge_subtitles(binaries):
for root, _, files in os.walk(get_target_directory()):
for name in files:
if is_video_file(name):
original = name
os.chdir(root)
name_without_ext = os.path.splitext(name)[0]
subtitles = f'{name_without_ext}.srt'
sanitized_original = sanitize_filename(original)
os.rename(original, sanitized_original)
original = sanitized_original
output_file = sanitize_filename(f'{name_without_ext}.srt.mp4')
if os.path.exists(subtitles):
sanitized_subtitles = sanitize_filename(subtitles)
os.rename(subtitles, sanitized_subtitles)
clean_subtitle_file(sanitized_subtitles)
subtitles_option = f'subtitles={sanitized_subtitles}:charenc=UTF-8'
logger.info(f'🎬 Merging subtitles for {original}')
full_command = [
os.path.join(binaries, "ffmpeg"), "-i", original,
"-vf", subtitles_option, "-c:a", "aac", "-b:a", "128k",
"-ac", "2", "-c:v", "libx264", output_file
]
else:
subtitles_option = ''
logger.info(f'🎬 No subtitles found for {original}')
full_command = [
os.path.join(binaries, "ffmpeg"), "-i", original,
"-c:a", "aac", "-b:a", "128k", "-ac", "2", "-c:v", "libx264", output_file
]
logger.info(f'Executing command: {" ".join(full_command)}')
subprocess.run(full_command)
logger.info(f'✅ Created {output_file}')
def merge_video_audio_subtitles(binaries, video, audio, subs, output):
clean_subtitle_file(subs)
full_command = [
os.path.join(binaries, "ffmpeg"), "-i", video, "-i", audio, "-i", subs,
"-c:v", "copy", "-c:a", "copy", "-c:s", "srt",
"-metadata:s:s:0", "language=nld", output
]
logger.info(f'Executing command: {" ".join(full_command)}')
subprocess.run(full_command)
logger.info(f'✅ Created {output}')
def apply_crossfade_transition(binaries, video1, video2, output, duration=0.5, offset=0):
full_command = [
os.path.join(binaries, "ffmpeg"), "-i", video1, "-i", video2,
"-filter_complex", f"[0][1]xfade=transition=fade:duration={duration}:offset={offset},"
f"[0:a][1:a]acrossfade=d={duration}:c1=tri:c2=tri",
"-movflags", "+faststart", output
]
logger.info(f'Executing command: {" ".join(full_command)}')
subprocess.run(full_command)
logger.info(f'✅ Created {output}')
if __name__ == "__main__":
binaries = check_ffmpeg()
if binaries:
if len(sys.argv) == 5:
video = sys.argv[1]
audio = sys.argv[2]
subs = sys.argv[3]
output = sys.argv[4]
merge_video_audio_subtitles(binaries, video, audio, subs, output)
elif len(sys.argv) == 4:
video1 = sys.argv[1]
video2 = sys.argv[2]
output = sys.argv[3]
apply_crossfade_transition(binaries, video1, video2, output)
else:
merge_subtitles(binaries)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment