fix(ffmpeg handling): add language tag to is russian identification
This commit is contained in:
1 parent
d43fcd530c
commit
b672696f91
2 files changed
+89
-63
No files matched your search
@@ -136,8 +136,11 @@ RUSSIAN_RE = re.compile(
|
||||
)
|
||||
|
||||
|
||||
def is_russian_track(description: str) -> bool:
|
||||
return bool(RUSSIAN_RE.search(description))
|
||||
def is_russian_track(track: dict) -> bool:
|
||||
descr = bool(RUSSIAN_RE.search(track["description"]))
|
||||
language = bool(RUSSIAN_RE.search(track["language"]))
|
||||
lang = bool(RUSSIAN_RE.search(track["lang"]))
|
||||
return descr or lang or language
|
||||
|
||||
|
||||
class ArgsBuffer:
|
||||
@@ -147,7 +150,7 @@ class ArgsBuffer:
|
||||
loud: bool | None = False
|
||||
key: str | None = None
|
||||
value: str | None = None
|
||||
audio_index: int | None = None
|
||||
audio_index: list | None = None
|
||||
dry_run: bool | None = None
|
||||
audio_codec: str | None = None
|
||||
video_codec: str | None = None
|
||||
@@ -168,27 +171,28 @@ def translate_audio_tracks(tracks: list[dict]) -> list[dict]:
|
||||
translated = []
|
||||
|
||||
for track in tracks:
|
||||
description = track.get("description", "")
|
||||
new_track = track.copy()
|
||||
|
||||
for src, dst in AUDIO_TRANSLATIONS.items():
|
||||
description = re.sub(
|
||||
rf"\b{re.escape(src)}\b",
|
||||
dst,
|
||||
description,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
for key, value in new_track.items():
|
||||
if not isinstance(value, str):
|
||||
continue
|
||||
|
||||
if CYRILLIC_RE.search(description):
|
||||
raise ValueError(
|
||||
f"Contains unidentified Cyrillic characters: {description}"
|
||||
)
|
||||
for src, dst in AUDIO_TRANSLATIONS.items():
|
||||
value = re.sub(
|
||||
rf"\b{re.escape(src)}\b",
|
||||
dst,
|
||||
value,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
|
||||
translated.append(
|
||||
{
|
||||
**track,
|
||||
"description": description,
|
||||
}
|
||||
)
|
||||
if CYRILLIC_RE.search(value):
|
||||
raise ValueError(
|
||||
f"Contains unidentified Cyrillic characters in {key}: {value}"
|
||||
)
|
||||
|
||||
new_track[key] = value
|
||||
|
||||
translated.append(new_track)
|
||||
|
||||
return translated
|
||||
|
||||
@@ -210,17 +214,17 @@ def ensure(value, prompt):
|
||||
return value
|
||||
|
||||
|
||||
def move_override_file(files_move_from, files_move_to, args):
|
||||
def move_overwrite_file(files_move_from, files_move_to, args):
|
||||
|
||||
backup_files = args.backup
|
||||
silent = not args.loud
|
||||
for file_to, file_from in zip(files_move_to, files_move_from):
|
||||
if not file_to.is_file():
|
||||
logger.error(f"Override Target File does not exist: {file_to}")
|
||||
logger.error(f"overwrite Target File does not exist: {file_to}")
|
||||
return False
|
||||
|
||||
if not file_from.is_file():
|
||||
logger.trace(f"Override File does not exist: {file_from}")
|
||||
logger.trace(f"overwrite File does not exist: {file_from}")
|
||||
continue
|
||||
backup = file_to.parent / f"{file_to.stem}_backup{file_from.suffix}"
|
||||
|
||||
@@ -229,7 +233,7 @@ def move_override_file(files_move_from, files_move_to, args):
|
||||
logger.trace(f"Move original to backup: {backup}")
|
||||
safe_rename(file_to, backup, silent=silent)
|
||||
|
||||
# move override -> original name
|
||||
# move overwrite -> original name
|
||||
retstr, ret = safe_rename(file_from, file_to, silent=silent, overwrite=True)
|
||||
logger.trace(retstr)
|
||||
if not ret:
|
||||
@@ -584,13 +588,14 @@ def cmd_remove_audio_track(args):
|
||||
"""
|
||||
|
||||
probe = ffmpeg.probe(str(args.input))
|
||||
|
||||
remove_idx = select_audio_stream(args.input, args.audio_index)
|
||||
remove_indices = []
|
||||
for audio_index in args.audio_index:
|
||||
remove_indices.append(select_audio_stream(args.input, audio_index))
|
||||
|
||||
remaining_audio = [
|
||||
s
|
||||
for s in probe["streams"]
|
||||
if s["codec_type"] == "audio" and s["index"] != remove_idx
|
||||
if s["codec_type"] == "audio" and s["index"] not in remove_indices
|
||||
]
|
||||
if not remaining_audio:
|
||||
logger.error("No audiotracks remaining")
|
||||
@@ -598,7 +603,7 @@ def cmd_remove_audio_track(args):
|
||||
remaining_audio = translate_audio_tracks(remaining_audio)
|
||||
|
||||
removed_was_default = any(
|
||||
s["index"] == remove_idx and s.get("disposition", {}).get("default", 0) == 1
|
||||
s["index"] in remove_indices and s.get("disposition", {}).get("default", 0) == 1
|
||||
for s in probe["streams"]
|
||||
)
|
||||
|
||||
@@ -610,7 +615,7 @@ def cmd_remove_audio_track(args):
|
||||
]
|
||||
|
||||
for stream in probe["streams"]:
|
||||
if stream["index"] != remove_idx:
|
||||
if stream["index"] not in remove_indices:
|
||||
cmd.extend(["-map", f"0:{stream['index']}"])
|
||||
|
||||
cmd.extend(
|
||||
@@ -671,19 +676,24 @@ def cmd_extract_audio_track(args):
|
||||
output_audio = Path(args.output)
|
||||
output_audio = str(output_audio.with_name(f"{output_audio.stem}.mp3"))
|
||||
|
||||
remove_idx = select_audio_stream(args.input, args.audio_index)
|
||||
outputs = []
|
||||
for index in args.audio_index:
|
||||
remove_idx = select_audio_stream(args.input, index)
|
||||
|
||||
extracted_audio = None
|
||||
extracted_audio = None
|
||||
|
||||
for s in probe["streams"]:
|
||||
idx = s["index"]
|
||||
if idx == remove_idx:
|
||||
extracted_audio = inp[str(idx)]
|
||||
for s in probe["streams"]:
|
||||
idx = s["index"]
|
||||
if idx == remove_idx:
|
||||
extracted_audio = inp[str(idx)]
|
||||
|
||||
out = ffmpeg.output(
|
||||
extracted_audio, output_audio, acodec="libmp3lame", audio_bitrate="192k"
|
||||
)
|
||||
return True, out
|
||||
outputs.append(
|
||||
ffmpeg.output(
|
||||
extracted_audio, output_audio, acodec="libmp3lame", audio_bitrate="192k"
|
||||
)
|
||||
)
|
||||
|
||||
return True, outputs
|
||||
|
||||
|
||||
def cmd_downsize(args):
|
||||
@@ -736,8 +746,14 @@ def cmd_filter_audio(args):
|
||||
5. alimiter: Hard limit at 0.95 to prevent digital clipping (distortion).
|
||||
6. dynaudnorm: Smooths out loudness levels over time.
|
||||
"""
|
||||
if len(args.audio_index) > 1:
|
||||
logger.warning(
|
||||
f"Filter Audio only filters the first element of list audio_index: {args.audio_index}"
|
||||
)
|
||||
|
||||
idx_filt = select_audio_stream(args.input, args.audio_index)
|
||||
index = args.audio_index[0]
|
||||
|
||||
idx_filt = select_audio_stream(args.input, index)
|
||||
|
||||
inp = ffmpeg.input(args.input)
|
||||
probe = ffmpeg.probe(str(args.input))
|
||||
@@ -888,7 +904,13 @@ def cmd_set_primary_audio(args):
|
||||
|
||||
inp = ffmpeg.input(args.input)
|
||||
|
||||
primary_audio = select_audio_stream(args.input, args.audio_index)
|
||||
if len(args.audio_index) > 1:
|
||||
logger.warning(
|
||||
f"Set primary can only set the first element of list audio_index: {args.audio_index}"
|
||||
)
|
||||
index = args.audio_index[0]
|
||||
|
||||
primary_audio = select_audio_stream(args.input, index)
|
||||
probe = ffmpeg.probe(str(args.input))
|
||||
|
||||
audio_streams = [
|
||||
@@ -1111,17 +1133,17 @@ def cmd_remove_russian_from_db(args_in):
|
||||
logger.warning("%s", e)
|
||||
return False, "nooutputneeded"
|
||||
|
||||
logger.trace(f"File: {file.name}: Audio tracks: {audio_tracks}")
|
||||
logger.trace(f"Remove Russian from File: {file.name}")
|
||||
logger.trace(f"With Audio tracks: {audio_tracks}")
|
||||
remove_tracks = []
|
||||
for track in audio_tracks:
|
||||
if is_russian_track(track["description"]):
|
||||
if is_russian_track(track):
|
||||
remove_tracks.append(track["number"])
|
||||
logger.debug(f"Removing russian track {track['number']} from {file}")
|
||||
for number in remove_tracks:
|
||||
args = args_in
|
||||
args.audio_index = number
|
||||
cmd_remove_audio_track(args)
|
||||
args = args_in
|
||||
args.audio_index = remove_tracks
|
||||
if remove_tracks:
|
||||
cmd_remove_audio_track(args)
|
||||
return True, "nooutputneeded"
|
||||
else:
|
||||
return False, "nooutputneeded"
|
||||
@@ -1428,7 +1450,7 @@ def cmd_test(args):
|
||||
cmd = commands["remove-audio"]
|
||||
if cmd["name"] in args.choices:
|
||||
args_test = ArgsBuffer()
|
||||
args_test.audio_index = 1
|
||||
args_test.audio_index = [1]
|
||||
|
||||
for test_file in test_files:
|
||||
video_streams, audio_streams, subtitle_streams, cover_image = get_streams(
|
||||
@@ -1454,7 +1476,7 @@ def cmd_test(args):
|
||||
cmd = commands["extract-audio"]
|
||||
if cmd["name"] in args.choices:
|
||||
args_test = ArgsBuffer()
|
||||
args_test.audio_index = 1
|
||||
args_test.audio_index = [1]
|
||||
|
||||
for test_file in test_files:
|
||||
args_test.input = test_file
|
||||
@@ -1587,7 +1609,7 @@ def cmd_test(args):
|
||||
Path(test_dir)
|
||||
/ f"out_{str(cmd['name']).replace('-', '_')}_{Path(test_file).stem}{Path(test_file).suffix}"
|
||||
)
|
||||
args_test.audio_index = 1
|
||||
args_test.audio_index = [1]
|
||||
test_dict = [
|
||||
{
|
||||
"video_count": len(video_streams),
|
||||
@@ -1640,7 +1662,7 @@ def cmd_test(args):
|
||||
Path(test_dir)
|
||||
/ f"out_{str(cmd['name']).replace('-', '_')}_{Path(test_file).stem}{Path(test_file).suffix}"
|
||||
)
|
||||
args_test.audio_index = 2
|
||||
args_test.audio_index = [2]
|
||||
test_dict = [
|
||||
{
|
||||
"video_count": len(video_streams),
|
||||
@@ -1771,6 +1793,7 @@ def add_audio_index(parser):
|
||||
"-a",
|
||||
"--audio-index",
|
||||
type=int,
|
||||
nargs="+",
|
||||
help="Audio track index",
|
||||
)
|
||||
|
||||
@@ -1789,7 +1812,7 @@ def main():
|
||||
|
||||
base_p.add_argument("input", nargs="?", type=Path, help="Input file or directory")
|
||||
base_p.add_argument("-o", "--output", type=Path, help="Output file")
|
||||
base_p.add_argument("--override", action="store_true", help="Overwrite input")
|
||||
base_p.add_argument("--overwrite", action="store_true", help="Overwrite input")
|
||||
base_p.add_argument("--backup", action="store_true", help="Backup original")
|
||||
base_p.add_argument("--loud", action="store_true", help="Show ffmpeg output")
|
||||
base_p.add_argument(
|
||||
@@ -2103,9 +2126,9 @@ def main():
|
||||
parser.error(f"Input file {args.input} does not exist!")
|
||||
if commands[args.command]["output"] and not getattr(args, "output", None):
|
||||
input_path = Path(args.input)
|
||||
if args.override:
|
||||
if args.overwrite:
|
||||
args.output = input_path.with_name(
|
||||
f"{input_path.stem}_override{input_path.suffix}"
|
||||
f"{input_path.stem}_overwrite{input_path.suffix}"
|
||||
)
|
||||
else:
|
||||
args.output = ensure(
|
||||
@@ -2158,9 +2181,10 @@ def main():
|
||||
"extract-audio",
|
||||
"set-primary-audio",
|
||||
]:
|
||||
args.audio_index = ensure(getattr(args, "audio_index", None), "Audio index")
|
||||
index = str(ensure(getattr(args, "audio_index", None), "Audio index"))
|
||||
args.audio_index = [int(x) for x in re.split(r"[,\s]+", index.strip()) if x]
|
||||
if args.audio_index is None:
|
||||
args.audio_index = 1
|
||||
args.audio_index = [1]
|
||||
|
||||
if args.command == "chapters":
|
||||
args.chapter_file = ensure(
|
||||
@@ -2212,8 +2236,8 @@ def main():
|
||||
continue
|
||||
logger.trace(f"Processing File: {file}")
|
||||
args.input = Path(file)
|
||||
if args.override:
|
||||
out_path = file.with_name(f"{file.stem}_override{file.suffix}")
|
||||
if args.overwrite:
|
||||
out_path = file.with_name(f"{file.stem}_overwrite{file.suffix}")
|
||||
else:
|
||||
out_path = file.with_name(
|
||||
f"{file.stem}_{args.command}{file.suffix}"
|
||||
@@ -2223,13 +2247,13 @@ def main():
|
||||
return_value, output_str = args.func(args)
|
||||
if output_str != "nooutputneeded":
|
||||
outputs.append(output_str)
|
||||
if args.override and return_value:
|
||||
if args.overwrite and return_value:
|
||||
files_move_from.append(out_path)
|
||||
files_move_to.append(file)
|
||||
counter += 1
|
||||
# ---- SINGLE FILE ----
|
||||
elif input_path.is_file():
|
||||
return_value,output_str = args.func(args)
|
||||
return_value, output_str = args.func(args)
|
||||
if output_str != "nooutputneeded":
|
||||
outputs.append(output_str)
|
||||
else:
|
||||
@@ -2245,10 +2269,10 @@ def main():
|
||||
run_ffmpeg(
|
||||
ffmpeg.merge_outputs(*outputs), overwrite=True, loud=args.loud
|
||||
)
|
||||
if args.override and not move_override_file(
|
||||
if args.overwrite and not move_overwrite_file(
|
||||
files_move_from, files_move_to, args
|
||||
):
|
||||
logger.error("move_override failed")
|
||||
logger.error("move_overwrite failed")
|
||||
sys.exit(1)
|
||||
except ffmpeg.Error as e:
|
||||
logger.error("FFmpeg failed.\n")
|
||||
|
||||
@@ -223,6 +223,8 @@ def get_audio_tracks(
|
||||
or stream.get("tags", {}).get("language")
|
||||
or f"Track {stream['index']}"
|
||||
),
|
||||
"lang": stream.get("lang", ""),
|
||||
"language": stream.get("tags", {}).get("language", ""),
|
||||
"primary": stream.get("codec_type") == "audio"
|
||||
and stream.get("disposition", {}).get("default") == 1,
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user