批量将字幕嵌入至MKV视频中的Python脚本
前言
当我们用MKVToolNix软件来对MKV视频嵌入字幕时,往往因为视频是一整季或者几季这样数量过多时,嵌入字幕就比较费事、麻烦。所以就写了这一个小脚本,解放双手。
原理
利用MKVToolNix的混流功能,当我们点击混流菜单下的显示命令行即可复制命令调用CMD来运行混流。
E:\mkvtoolnix\mkvmerge.exe --ui-language zh_CN --output ^"D:\temp\output_01.mkv^" --language 0:und --default-track 0:yes --display-dimensions 0:1920x1080 --language 1:ja --default-track 1:yes --language 2:ja ^"^(^" ^"D:\temp\01.mkv^" ^"^)^" --language 0:sc ^"^(^" ^"D:\temp\01.sc.ass^" ^"^)^" --track-order 0:0,0:1,0:2,1:0
其中可以看出调用的是mkvtoolnix文件夹下的mkvmerge.exe文件来运行混流的。--output 后面的路径就是要输出的目录及文件名,其中还需要指定需要混流的源mkv文件及字幕文件路径,以及一些其他参数如下所述。
--ui-language, "zh_CN":指定界面语言为中文。output_file,它是您合并后的输出文件的完整路径。
--language, "0:und":指定第一个轨道(track)的语言为未定义(undetermined)。
--default-track, "0:yes":将第一个轨道设置为默认轨道。
--display-dimensions, "0:1920x1080":设置第一个轨道的显示尺寸为 1920x1080。
--language, "1:ja":指定第二个轨道的语言为日语。
--default-track, "1:yes":将第二个轨道设置为默认轨道。
--language, "2:ja":指定第三个轨道的语言为日语。
--language, "0:sc":指定第一个字幕轨道的语言为简体中文。
--track-order, "0:0,0:1,0:2,1:0":指定轨道的顺序。这里的 "0:0,0:1,0:2,1:0" 表示第一个轨道的第一个部分(video),第一个轨道的第二部分(audio),第一个轨道的第三部分(audio),第二个轨道(字幕)的顺序。
每个参数都有特定的作用,可根据需求来设置不同的参数值。具体可查阅官方文档:https://mkvtoolnix.download/doc/mkvmerge.html
本文中,我们不考虑其他的参数,只需要将视频和字幕混流成功即可。
实现
从上面可以得出,视频混流的原理是可以通过cmd来运行的,只是要达到批量自动混流的话,只是其中的几个参数在变化而已,mkv视频和字幕的路径,比如说源mkv视频的目录下有01.mkv、02.mkv、03.mkv、04.mkv、05.mkv,而字幕目录下有01.sc.ass、02.sc.ass、03.sc.ass、04.sc.ass、05.sc.ass,那么就可以生成5条cmd命令,只是把其中的路径参数中文件名换一下就好。注意,这里我们要保证视频文件和字幕文件的前缀相同只是后缀不同,例如,视频文件名是:“S1E01.mkv”,字幕文件名为:“S1E01.sc.ass”。所以我们可以用Python来读取mkv视频目录下的所有视频,并把它们的文件名放入一个列表中,再进行遍历来进行下面的操作。注意这里为了不会出现目录下还有目录的情况,我们设置为不包括子目录。
先定义基本变量名:
1 video_dir = r"视频目录路径" 2 subtitle_dir = r"字幕目录路径" 3 output_dir = r"输出目录路径" 4 video_extension = r".mkv" 5 subtitle_extension = r"字幕文件扩展名" 6 mkvmerge_dir = r"E:\mkvtoolnix" # 请自行修改目录
获取视频文件列表:
1 # 获取视频文件列表(不包括子目录) 2 video_files = [file for file in os.listdir(video_dir) if 3 file.endswith(video_extension) and os.path.isfile(os.path.join(video_dir, file))]
在获得了这个视频文件列表后,我们进行遍历,把每一个视频文件的文件名取出来,加上字幕的后缀,变成一个字幕文件名(因为文件名前缀相同,没必要再对字幕目录进行获取字幕文件列表)。
1 for video_file in video_files: 2 base_name = os.path.splitext(video_file)[0] # 去除扩展名的文件名来定义基础文件名 3 video_path = os.path.join(video_dir, video_file) # 生成视频路径,包含源目录及文件名 4 subtitle_file = os.path.join(subtitle_dir, base_name + subtitle_extension) # 根据基础文件名来生成字幕文件路径 5 output_file = os.path.join(output_dir, "output_" + video_file) # 构建输出文件路径
现在,我们得到了前面所说的源mkv文件及字幕文件路径以及输出路径,那么就可以构建cmd命令了。
1 # 构建 mkvmerge 执行命令,使用提供的 mkvmerge 目录 2 mkvmerge_command = os.path.join(mkvmerge_dir, "mkvmerge.exe") 3 # mkvmerge命令参数,可根据需要自行修改 4 command = [ 5 mkvmerge_command, 6 "--ui-language", "zh_CN", 7 "--output", f'"{output_file}"', 8 f'"{video_path}"', 9 f'"{subtitle_file}"', 10 ] 11 12 # 执行命令 13 # 使用 subprocess.run() 来执行命令 14 subprocess.run(" ".join(command), shell=True) 15 print("")
这样,在for循环中,运行完一个文件的混流后,就会自动运行下一个,直至所有视频文件列表运行结束。自动批量嵌入字幕到mkv中就大功告成了
总结
利用Python在for循环中生成每一个视频的混流所需的cmd命令,直至所有视频文件混流完成。注意,此脚本需要通过cmd或者Powershell来运行,这样才能看到每个视频混流的百分比进度条。
如果你对本文有不同的见解或者有更好的建议,欢迎你留下评论。
本文中的代码已经上传至Github,欢迎贡献代码。
以下为本文代码:
1 import os 2 import subprocess 3 4 print("**********************************************************************************\n" 5 + "此脚本用于批量将字幕嵌入到mkv视频文件中\n************************************************" 6 "**********************************") 7 8 video_dir = input(r"请输入视频目录路径:") 9 subtitle_dir = input(r"请输入字幕目录路径:") 10 output_dir = input(r"请输入输出目录路径:") 11 video_extension = r".mkv" 12 subtitle_extension = input(r"请输入字幕文件扩展名(例如:.sc.ass):") 13 mkvmerge_dir = r"E:\green\mkvtoolnix" # 请自行修改目录 14 15 print("\n\n视频目录:" + video_dir, "\n字幕目录:" + subtitle_dir, "\n输出目录:" + output_dir, "\n视频后缀:" 16 + video_extension, "\n字幕后缀:" + subtitle_extension, "\nmkvmerge目录:" + mkvmerge_dir + "\n\n") 17 18 # 获取视频文件列表(不包括子目录) 19 video_files = [file for file in os.listdir(video_dir) if 20 file.endswith(video_extension) and os.path.isfile(os.path.join(video_dir, file))] 21 22 for video_file in video_files: 23 base_name = os.path.splitext(video_file)[0] # 去除扩展名的文件名来定义基础文件名 24 video_path = os.path.join(video_dir, video_file) # 生成视频路径,包含源目录及文件名 25 subtitle_file = os.path.join(subtitle_dir, base_name + subtitle_extension) # 根据基础文件名来生成字幕文件路径 26 output_file = os.path.join(output_dir, "output_" + video_file) # 构建输出文件路径 27 if os.path.exists(subtitle_file): 28 # 构建 mkvmerge 执行命令,使用提供的 mkvmerge 目录 29 mkvmerge_command = os.path.join(mkvmerge_dir, "mkvmerge.exe") 30 # mkvmerge命令参数,可根据需要自行修改 31 command = [ 32 mkvmerge_command, 33 "--ui-language", "zh_CN", 34 "--output", f'"{output_file}"', 35 f'"{video_path}"', 36 f'"{subtitle_file}"', 37 ] 38 39 # 执行命令 40 # 使用 subprocess.run() 来执行命令 41 subprocess.run(" ".join(command), shell=True) 42 print("") 43 44 print("处理完成!")