-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpostvoc.py
executable file
·121 lines (102 loc) · 4.16 KB
/
postvoc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python
import os
import re
import subprocess
import sys
iso3cc_to_language = {
'eng': 'English',
'deu': 'Deutsch',
'fra': 'Français',
'spa': 'Español',
'ita': 'Italiano',
'por': 'Português',
'nld': 'Nederlands',
'swe': 'Svenska',
'fin': 'Suomi',
'dan': 'Dansk',
'nor': 'Norsk',
'pol': 'Polski',
'ces': 'Čeština',
'hun': 'Magyar',
'ron': 'Română'
}
def get_language_code(filename):
match = re.search(r'-(\w{3})\.\w+$', filename)
if match:
return match.group(1)
else:
return None
def main():
if len(sys.argv) < 3:
print("Usage: python script.py [video_file] [audio_files...] [--force]")
return
video_file = sys.argv[1]
audio_files = []
force_flag = False
dry_run_flag = False
for arg in sys.argv[2:]:
if arg == "--force":
force_flag = True
elif arg == "--dry-run":
dry_run_flag = True
else:
audio_files.append(arg)
# Get existing audio streams with their language codes from the video file
ffprobe_command = ["ffprobe", "-v", "error", "-show_entries", "stream=index:stream_tags=language", "-select_streams", "a", "-of", "default=noprint_wrappers=1", video_file]
ffprobe_output = subprocess.check_output(ffprobe_command, universal_newlines=True)
existing_audio_streams = {} # Map of stream index to language code
lines = ffprobe_output.strip().split('\n')
for line in lines:
parts = line.split('=')
if parts[0] == 'index':
stream_index = int(parts[1])
elif parts[0] == 'TAG:language':
lang = parts[1].strip()
existing_audio_streams[stream_index] = lang
# Map input file index to languages/files
new_audio_streams = []
for audio_file_index, audio_file in enumerate(audio_files):
audio_language = get_language_code(audio_file)
new_audio_streams.append(audio_language)
print(f"Video file {video_file} has existing audio streams: {existing_audio_streams}")
print(f"New audio streams to add or replace: {new_audio_streams}")
# Check if any of the new audio languages already exist unless force_flag is set
for audio_language in new_audio_streams:
if audio_language in existing_audio_streams.values() and not force_flag:
print(f"The language {audio_language} already exists in the master video. Use --force to override.")
return
# Construct the ffmpeg command: Load video file as input #0
ffmpeg_command = ["ffmpeg", "-i", video_file]
# And map video from input #0 to output
stream_args = ["-map", "0:v"]
# Map metadata from original only
stream_args.extend(["-map_metadata", "0"])
# map all existing audio streams unless we want to overwrite one
for stream_index, lang in existing_audio_streams.items():
if lang in new_audio_streams:
audio_file_index = new_audio_streams.index(lang)
stream_args.extend(["-map", f"{audio_file_index}:a:0"])
else:
stream_args.extend(["-map", f"0:{stream_index}"])
new_stream_index = max(existing_audio_streams.keys(), default=-1) + 1
for audio_file_index, audio_file in enumerate(audio_files):
audio_language = get_language_code(audio_file)
if audio_language not in existing_audio_streams.values():
# replacing existing languages already happened above
ffmpeg_command.extend(["-i", audio_file])
stream_args.extend(["-map", f"{audio_file_index+1}:a:0"])
stream_args.extend([f"-metadata:s:{new_stream_index}", f"language={audio_language}"])
stream_args.extend([f"-metadata:s:{new_stream_index}", f"title={iso3cc_to_language.get(audio_language, audio_language)}"])
new_stream_index += 1
output_filename = os.path.splitext(video_file)[0] + '-out' + os.path.splitext(video_file)[1]
final_command = (
ffmpeg_command +
stream_args +
["-c", "copy", "-y", output_filename]
)
print(' '.join(final_command))
if not dry_run_flag:
subprocess.call(final_command)
print(f"Wrote {output_filename}")
if __name__ == "__main__":
main()