add SeFree-Custom-Script
This commit is contained in:
151
SeFree-Custom-Script/add_subtitles_audio_to_mp4_MKVTOOLS.py
Executable file
151
SeFree-Custom-Script/add_subtitles_audio_to_mp4_MKVTOOLS.py
Executable file
@@ -0,0 +1,151 @@
|
||||
import os
|
||||
import glob
|
||||
import subprocess
|
||||
import sys
|
||||
import langcodes
|
||||
import pycountry
|
||||
from ass_editor import ASS_Editor, attach_font
|
||||
|
||||
|
||||
def find_files(folder_path):
|
||||
"""Find all video (MP4, TS, MKV), AAC, and subtitle files in the folder."""
|
||||
video_files = (glob.glob(os.path.join(folder_path, "*.mkv")) +
|
||||
glob.glob(os.path.join(folder_path, "*.mp4")) +
|
||||
glob.glob(os.path.join(folder_path, "*.ts")))
|
||||
base_video_files = [f for f in video_files if not f.endswith("_DUB.mkv") and
|
||||
not f.endswith("_DUB.mp4") and not f.endswith("_DUB.ts")]
|
||||
dub_video_files = [f for f in video_files if f.endswith("_DUB.mkv") or
|
||||
f.endswith("_DUB.mp4") or f.endswith("_DUB.ts")]
|
||||
aac_files = (glob.glob(os.path.join(folder_path, "*.aac")) +
|
||||
glob.glob(os.path.join(folder_path, "*.m4a")) +
|
||||
glob.glob(os.path.join(folder_path, "*.mka")))
|
||||
subtitle_files = (glob.glob(os.path.join(folder_path, "*.srt")) +
|
||||
glob.glob(os.path.join(folder_path, "*.ass")) +
|
||||
glob.glob(os.path.join(folder_path, "*.vtt")))
|
||||
return base_video_files, dub_video_files, aac_files, subtitle_files
|
||||
|
||||
def get_base_name(file_path):
|
||||
"""Extract base name by removing '_DUB' and file extension for video files."""
|
||||
file_name = os.path.basename(file_path)
|
||||
for ext in ["_DUB.mkv", "_DUB.mp4", "_DUB.ts"]:
|
||||
if file_name.endswith(ext):
|
||||
return file_name[:-len(ext)]
|
||||
return os.path.splitext(file_name)[0]
|
||||
|
||||
def get_lang_code(file_path):
|
||||
"""Helper to extract language code from filename."""
|
||||
parts = os.path.splitext(os.path.basename(file_path))[0].split('.')
|
||||
lang = parts[-1]
|
||||
if len(lang) == 2:
|
||||
try:
|
||||
return langcodes.Language.make(lang).to_alpha3()
|
||||
except:
|
||||
return "und"
|
||||
elif len(lang) == 3:
|
||||
return lang
|
||||
return "und"
|
||||
|
||||
def group_files(video_files, dub_video_files, aac_files, subtitle_files):
|
||||
"""Group video, AAC, and subtitle files by base name."""
|
||||
file_groups = {}
|
||||
for video_file in video_files:
|
||||
base_name = get_base_name(video_file)
|
||||
file_groups[base_name] = {'video': video_file, 'dub_video': None, 'audio': [], 'subtitles': []}
|
||||
|
||||
for dub_video_file in dub_video_files:
|
||||
base_name = get_base_name(dub_video_file)
|
||||
if base_name in file_groups:
|
||||
file_groups[base_name]['dub_video'] = dub_video_file
|
||||
|
||||
for aac_file in aac_files:
|
||||
base_name = os.path.splitext(os.path.basename(aac_file))[0].split('.')[0]
|
||||
lang = get_lang_code(aac_file)
|
||||
if base_name in file_groups:
|
||||
file_groups[base_name]['audio'].append((aac_file, lang))
|
||||
|
||||
for sub_file in subtitle_files:
|
||||
base_name = os.path.splitext(os.path.basename(sub_file))[0].split('.')[0]
|
||||
lang = get_lang_code(sub_file)
|
||||
if base_name in file_groups:
|
||||
file_groups[base_name]['subtitles'].append((sub_file, lang))
|
||||
return file_groups
|
||||
|
||||
def embed_files(folder_path):
|
||||
"""Embed audio and subtitles using mkvmerge."""
|
||||
output_folder = os.path.join(folder_path, "Output")
|
||||
os.makedirs(output_folder, exist_ok=True)
|
||||
video_files, dub_video_files, aac_files, subtitle_files = find_files(folder_path)
|
||||
|
||||
file_groups = group_files(video_files, dub_video_files, aac_files, subtitle_files)
|
||||
|
||||
for base_name, files in file_groups.items():
|
||||
video_file = files['video']
|
||||
dub_video_file = files['dub_video']
|
||||
audio_inputs = files['audio']
|
||||
subtitle_inputs = files['subtitles']
|
||||
|
||||
output_file = os.path.join(output_folder, base_name + ".mkv")
|
||||
|
||||
if not video_file:
|
||||
continue
|
||||
|
||||
# Start mkvmerge command
|
||||
cmd = ["mkvmerge", "-o", output_file]
|
||||
|
||||
# 1. Base Video File
|
||||
# Set a title for the first video track if desired
|
||||
cmd.extend(["--track-name", "0:SeFree", video_file])
|
||||
|
||||
# 2. Dubbed Video File (if exists, add its audio/subs)
|
||||
if dub_video_file:
|
||||
# Assume track 0 is video (skipped), track 1 is Japanese, track 2 is Thai
|
||||
# This logic depends on the internal track IDs of the dub file
|
||||
cmd.extend([
|
||||
"--no-video",
|
||||
"--language", "2:jpn", "--track-name", "2:Japanese",
|
||||
"--language", "3:tha", "--track-name", "3:Thai",
|
||||
dub_video_file
|
||||
])
|
||||
|
||||
# 3. External Audio Files
|
||||
if not dub_video_file:
|
||||
for aac_file, lang in audio_inputs:
|
||||
# mkvmerge track ID for external single-track files is usually 0
|
||||
cmd.extend([
|
||||
"--language", f"0:{lang}",
|
||||
"--track-name", f"0:{pycountry.languages.get(alpha_3=lang).name if lang != 'und' else 'Unknown'}",
|
||||
aac_file
|
||||
])
|
||||
|
||||
# 4. External Subtitle Files
|
||||
for sub_file, lang in subtitle_inputs:
|
||||
cmd.extend([
|
||||
"--language", f"0:{lang}",
|
||||
"--track-name", f"0:{pycountry.languages.get(alpha_3=lang).name if lang != 'und' else 'Unknown'}_BLBL",
|
||||
sub_file
|
||||
])
|
||||
# cmd=attach_font(cmd, "BLBL")
|
||||
|
||||
print(f"Processing {base_name} with mkvmerge...")
|
||||
try:
|
||||
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
print(f"✅ Successfully created {os.path.basename(output_file)}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ Error processing {base_name}: {e.stderr}")
|
||||
|
||||
def main():
|
||||
os.umask(0o000)
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python add_subtitles_to_mkv.py <folder_path>")
|
||||
sys.exit(1)
|
||||
|
||||
folder_path = sys.argv[1].strip()
|
||||
if not os.path.exists(folder_path):
|
||||
print(f"Error: Folder '{folder_path}' does not exist!")
|
||||
sys.exit(1)
|
||||
|
||||
embed_files(folder_path)
|
||||
print("🎉 Processing complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user