批量将字幕嵌入至MKV视频中的Python脚本

发布时间 2023-09-04 00:01:04作者: Zhugey

前言


 

当我们用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("处理完成!")