A lot of bug fixes and edge cases
This commit is contained in:
1 parent
58e66996cc
commit
004556c4a7
5 files changed
+237
-106
No files matched your search
+148
-65
@@ -35,8 +35,9 @@ def extract_audio_segment_file(video: Path, start_time: float, end_time: float,
|
||||
"-i", video,
|
||||
"-ss", str(start_time),
|
||||
"-to", str(end_time),
|
||||
"-map", "0:a:0", # first audio track
|
||||
"-c:a", "copy", # no re-encode
|
||||
"-map", "0:a:0",
|
||||
"-ac", "2", # force stereo
|
||||
"-c:a", "aac", # re-encode
|
||||
out_audio
|
||||
])
|
||||
|
||||
@@ -152,32 +153,55 @@ def get_audio_duration(file_path: Path):
|
||||
res += float(result[i])*(60**i)
|
||||
return res
|
||||
|
||||
def stick_together_audio(left_audio: Path, right_audio: Path, output_audio: Path) -> None:
|
||||
"""
|
||||
Concatenate two audio files so that left_audio plays directly
|
||||
before right_audio in the output file.
|
||||
"""
|
||||
### V1
|
||||
# def stick_together_audio(left_audio: Path, right_audio: Path, output_audio: Path) -> None:
|
||||
# """
|
||||
# Concatenate two audio files so that left_audio plays directly
|
||||
# before right_audio in the output file.
|
||||
# """
|
||||
|
||||
# left_audio = Path(left_audio)
|
||||
# right_audio = Path(right_audio)
|
||||
# output_audio = Path(output_audio)
|
||||
|
||||
# # Use stem instead of prefix to create a temporary file
|
||||
# output_audio_tmp = output_audio.parent / (output_audio.stem + "_temp" + output_audio.suffix)
|
||||
|
||||
# run([
|
||||
# "ffmpeg",
|
||||
# "-y",
|
||||
# "-i", str(left_audio),
|
||||
# "-i", str(right_audio),
|
||||
# "-filter_complex", "[0:a][1:a]concat=n=2:v=0:a=1[a]",
|
||||
# "-map", "[a]",
|
||||
# "-c:a", "opus", # or "aac" if you prefer
|
||||
# "-strict", "-2",
|
||||
# str(output_audio_tmp)
|
||||
# ])
|
||||
|
||||
# shutil.move(output_audio_tmp, output_audio)
|
||||
|
||||
def stick_together_audio(left_audio: Path, right_audio: Path, output_audio: Path) -> None:
|
||||
left_audio = Path(left_audio)
|
||||
right_audio = Path(right_audio)
|
||||
output_audio = Path(output_audio)
|
||||
|
||||
# Use stem instead of prefix to create a temporary file
|
||||
output_audio_tmp = output_audio.parent / (output_audio.stem + "_temp" + output_audio.suffix)
|
||||
|
||||
run([
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
"-i", str(left_audio),
|
||||
"-i", str(right_audio),
|
||||
"-filter_complex", "[0:a][1:a]concat=n=2:v=0:a=1[a]",
|
||||
"-map", "[a]",
|
||||
"-c:a", "opus", # or "aac" if you prefer
|
||||
"-strict", "-2",
|
||||
str(output_audio_tmp)
|
||||
])
|
||||
|
||||
shutil.move(output_audio_tmp, output_audio)
|
||||
with tempfile.NamedTemporaryFile("w", delete=False, suffix=".txt") as f:
|
||||
f.write(f"file '{left_audio.resolve()}'\n")
|
||||
f.write(f"file '{right_audio.resolve()}'\n")
|
||||
list_file = f.name
|
||||
try:
|
||||
run([
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
"-f", "concat",
|
||||
"-safe", "0",
|
||||
"-i", list_file,
|
||||
"-c", "copy", # no re-encode
|
||||
str(output_audio)
|
||||
])
|
||||
except Exception as e:
|
||||
raise BrokenPipeError(f"{e}\n{f.readlines(-1)}")
|
||||
|
||||
def get_audio_streams(file: Path) -> List[int]:
|
||||
"""
|
||||
@@ -224,6 +248,9 @@ def get_track_info(file: Path, audioline: int):
|
||||
return {"codec": "aac", "bitrate": "192k", "lang": "eng", "title": "Audio"}
|
||||
|
||||
def shift_audio(file: Path, audioline: int, offset: float):
|
||||
"""
|
||||
Shifts audio by offset sekonds to the right.
|
||||
"""
|
||||
if not file.is_file(): return
|
||||
|
||||
info = get_track_info(file, audioline)
|
||||
@@ -258,7 +285,7 @@ def shift_audio(file: Path, audioline: int, offset: float):
|
||||
"-b:a", str(info['bitrate']),
|
||||
str(temp_mka)
|
||||
]
|
||||
subprocess.run(process_cmd, check=True)
|
||||
run(process_cmd)
|
||||
|
||||
# --- STEP 2: Replace in MKV via mkvmerge ---
|
||||
# --audio-tracks !ID excludes the old track
|
||||
@@ -271,13 +298,71 @@ def shift_audio(file: Path, audioline: int, offset: float):
|
||||
str(temp_mka)
|
||||
]
|
||||
|
||||
subprocess.run(merge_cmd, check=True)
|
||||
run(merge_cmd)
|
||||
|
||||
# Cleanup and Replace
|
||||
shutil.move(str(output_mkv), str(file))
|
||||
temp_mka.unlink()
|
||||
print(f"Done: {file.name} updated physically.")
|
||||
|
||||
def add_silence(file: Path, offset: float) -> None:
|
||||
"""
|
||||
Hard-edits an MKA file by adding silence.
|
||||
Positive offset: Adds silence at the beginning.
|
||||
Negative offset: Adds silence at the end.
|
||||
"""
|
||||
if not file.is_file():
|
||||
print(f"File not found: {file}")
|
||||
return
|
||||
|
||||
if offset == 0:
|
||||
print("Offset is 0, no silence to add.")
|
||||
return
|
||||
|
||||
# Create a normal file path right next to the original file
|
||||
new_file = file.parent / f"silenced_{file.name}"
|
||||
|
||||
# 1. Determine the filter
|
||||
if offset > 0:
|
||||
# Silence at the beginning: delay all channels
|
||||
ms = int(offset * 1000)
|
||||
audio_filter = f"adelay={ms}:all=1"
|
||||
action_text = "beginning"
|
||||
else:
|
||||
# Silence at the end: pad with specific duration in seconds
|
||||
sec = abs(offset)
|
||||
audio_filter = f"apad=pad_dur={sec}"
|
||||
action_text = "end"
|
||||
|
||||
# 2. Execute FFmpeg
|
||||
cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-i", str(file),
|
||||
"-af", audio_filter,
|
||||
"-c:a", "libopus",
|
||||
str(new_file)
|
||||
]
|
||||
|
||||
# print(f"Adding {abs(offset)}s of silence to the {action_text} of {file.name}...")
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
# 3. Verify and replace
|
||||
if result.returncode == 0:
|
||||
# Quick safety check to ensure FFmpeg didn't output an empty file
|
||||
if new_file.exists() and new_file.stat().st_size > 0:
|
||||
shutil.move(str(new_file), str(file))
|
||||
# print(f"Successfully updated: {file.name}")
|
||||
else:
|
||||
print("Error: FFmpeg succeeded, but the output file is empty.")
|
||||
if new_file.exists():
|
||||
new_file.unlink()
|
||||
else:
|
||||
print(f"FFmpeg Error:\n{result.stderr}")
|
||||
# Clean up the leftover file if the process failed
|
||||
if new_file.exists():
|
||||
new_file.unlink()
|
||||
|
||||
def replace_with_shifted_mka(mkv_file: Path, mka_source: Path, audioline: int, offset: float):
|
||||
"""
|
||||
Physically shifts an existing MKA and replaces a track in the MKV.
|
||||
@@ -289,45 +374,43 @@ def replace_with_shifted_mka(mkv_file: Path, mka_source: Path, audioline: int, o
|
||||
return
|
||||
|
||||
# mkvmerge IDs: 0 is usually video, so audioline 0 is track 1, etc.
|
||||
mkv_track_id = audioline + 1
|
||||
mkv_track_id = audioline + 1
|
||||
|
||||
shifted_mka = mkv_file.parent / "shifted.mka"
|
||||
output_mkv = mkv_file.parent / "final_output.mkv"
|
||||
|
||||
# --- STEP 1: Physical Shift ---
|
||||
# Positive offset: adelay (adds real silence packets)
|
||||
# Negative offset: atrim (removes packets) + asetpts (resets timestamps)
|
||||
ms = int(abs(offset) * 1000)
|
||||
if offset > 0:
|
||||
filter_chain = f"adelay={ms}:all=1"
|
||||
else:
|
||||
filter_chain = f"atrim=start={abs(offset)},asetpts=PTS-STARTPTS"
|
||||
|
||||
print(f"Physically shifting {mka_source.name}...")
|
||||
process_cmd = [
|
||||
"ffmpeg", "-y", "-i", str(mka_source),
|
||||
"-af", filter_chain,
|
||||
"-c:a", "libopus", # Set to Opus as per your track name
|
||||
"-b:a", "160k", # Standard high-quality bitrate for stereo Opus
|
||||
str(shifted_mka)
|
||||
]
|
||||
subprocess.run(process_cmd, check=True, capture_output=True)
|
||||
|
||||
# --- STEP 2: Replace track in MKV ---
|
||||
# --audio-tracks !ID excludes the old line from the original MKV
|
||||
print(f"Replacing track {audioline} in {mkv_file.name}...")
|
||||
merge_cmd = [
|
||||
"mkvmerge", "-o", str(output_mkv),
|
||||
"--audio-tracks", f"!{mkv_track_id}", str(mkv_file),
|
||||
"--language", "0:ger",
|
||||
"--track-name", "0:German (Opus Stereo)",
|
||||
str(shifted_mka)
|
||||
]
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
shifted_mka = temp_path / "shifted.mka"
|
||||
output_mkv = temp_path / "final_output.mkv"
|
||||
subprocess.run(merge_cmd, check=True, capture_output=True)
|
||||
|
||||
# --- STEP 1: Physical Shift ---
|
||||
# Positive offset: adelay (adds real silence packets)
|
||||
# Negative offset: atrim (removes packets) + asetpts (resets timestamps)
|
||||
ms = int(abs(offset) * 1000)
|
||||
if offset > 0:
|
||||
filter_chain = f"adelay={ms}:all=1"
|
||||
else:
|
||||
filter_chain = f"atrim=start={abs(offset)},asetpts=PTS-STARTPTS"
|
||||
|
||||
print(f"Physically shifting {mka_source.name}...")
|
||||
process_cmd = [
|
||||
"ffmpeg", "-y", "-i", str(mka_source),
|
||||
"-af", filter_chain,
|
||||
"-c:a", "libopus", # Set to Opus as per your track name
|
||||
"-b:a", "160k", # Standard high-quality bitrate for stereo Opus
|
||||
str(shifted_mka)
|
||||
]
|
||||
subprocess.run(process_cmd, check=True, capture_output=True)
|
||||
|
||||
# --- STEP 2: Replace track in MKV ---
|
||||
# --audio-tracks !ID excludes the old line from the original MKV
|
||||
print(f"Replacing track {audioline} in {mkv_file.name}...")
|
||||
merge_cmd = [
|
||||
"mkvmerge", "-o", str(output_mkv),
|
||||
"--audio-tracks", f"!{mkv_track_id}", str(mkv_file),
|
||||
"--language", "0:ger",
|
||||
"--track-name", "0:German (Opus Stereo)",
|
||||
str(shifted_mka)
|
||||
]
|
||||
|
||||
subprocess.run(merge_cmd, check=True, capture_output=True)
|
||||
|
||||
# --- STEP 3: Cleanup and Overwrite ---
|
||||
shutil.move(str(output_mkv), str(mkv_file))
|
||||
print(f"Success: Updated {mkv_file.name}")
|
||||
# --- STEP 3: Cleanup and Overwrite ---
|
||||
shutil.move(str(output_mkv), str(mkv_file))
|
||||
# print(f"Success: Updated {mkv_file.name}")
|
||||
Reference in new issue
Block a user