added "logging"
This commit is contained in:
@@ -8,6 +8,17 @@ import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
class Tee:
|
||||
def __init__(self, *files):
|
||||
self.files = files
|
||||
def write(self, obj):
|
||||
for f in self.files:
|
||||
f.write(obj)
|
||||
f.flush()
|
||||
def flush(self):
|
||||
for f in self.files:
|
||||
f.flush()
|
||||
|
||||
REQUIRED_TOOLS_MAP = {
|
||||
"ffmpeg": "extra/ffmpeg",
|
||||
"ffprobe": "extra/ffmpeg", # Part of ffmpeg package
|
||||
@@ -20,6 +31,7 @@ REQUIRED_TOOLS_MAP = {
|
||||
}
|
||||
DIR_COMPLETED = Path("completed")
|
||||
DIR_ORIGINAL = Path("original")
|
||||
DIR_LOGS = Path("conv_logs")
|
||||
|
||||
REMUX_CODECS = {"aac", "opus"} # Using a set for efficient lookups
|
||||
# Removed CONVERT_CODECS, now all non-remux codecs will be converted
|
||||
@@ -151,6 +163,7 @@ def main(no_downmix=False):
|
||||
check_tools()
|
||||
DIR_COMPLETED.mkdir(exist_ok=True, parents=True)
|
||||
DIR_ORIGINAL.mkdir(exist_ok=True, parents=True)
|
||||
DIR_LOGS.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
current_dir = Path(".")
|
||||
|
||||
@@ -165,150 +178,165 @@ def main(no_downmix=False):
|
||||
break
|
||||
|
||||
file_path = files_to_process[0]
|
||||
print("-" * shutil.get_terminal_size(fallback=(80, 24)).columns)
|
||||
print(f"Starting full processing for: {file_path.name}")
|
||||
date = datetime.now()
|
||||
input_file_abs = file_path.resolve()
|
||||
intermediate_output_file = current_dir / f"output-{file_path.name}"
|
||||
audio_temp_dir = None # Initialize to None
|
||||
created_ut_video_path = None
|
||||
created_encoded_video_path = None
|
||||
|
||||
# Setup logging
|
||||
log_file_path = DIR_LOGS / f"{file_path.name}.log"
|
||||
log_file = open(log_file_path, 'w', encoding='utf-8')
|
||||
original_stdout = sys.stdout
|
||||
original_stderr = sys.stderr
|
||||
sys.stdout = Tee(original_stdout, log_file)
|
||||
sys.stderr = Tee(original_stderr, log_file)
|
||||
|
||||
try:
|
||||
audio_temp_dir = tempfile.mkdtemp(prefix="tv_audio_") # UUID is not strictly needed for uniqueness
|
||||
print(f"Audio temporary directory created at: {audio_temp_dir}")
|
||||
print(f"Analyzing file: {input_file_abs}")
|
||||
print("-" * shutil.get_terminal_size(fallback=(80, 24)).columns)
|
||||
print(f"Starting full processing for: {file_path.name}")
|
||||
date = datetime.now()
|
||||
input_file_abs = file_path.resolve()
|
||||
intermediate_output_file = current_dir / f"output-{file_path.name}"
|
||||
audio_temp_dir = None # Initialize to None
|
||||
created_ut_video_path = None
|
||||
created_encoded_video_path = None
|
||||
|
||||
ffprobe_info_json = run_cmd([
|
||||
"ffprobe", "-v", "quiet", "-print_format", "json", "-show_streams", "-show_format", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
ffprobe_info = json.loads(ffprobe_info_json)
|
||||
try:
|
||||
audio_temp_dir = tempfile.mkdtemp(prefix="tv_audio_") # UUID is not strictly needed for uniqueness
|
||||
print(f"Audio temporary directory created at: {audio_temp_dir}")
|
||||
print(f"Analyzing file: {input_file_abs}")
|
||||
|
||||
mkvmerge_info_json = run_cmd([
|
||||
"mkvmerge", "-J", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
mkv_info = json.loads(mkvmerge_info_json)
|
||||
ffprobe_info_json = run_cmd([
|
||||
"ffprobe", "-v", "quiet", "-print_format", "json", "-show_streams", "-show_format", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
ffprobe_info = json.loads(ffprobe_info_json)
|
||||
|
||||
mediainfo_json = run_cmd([
|
||||
"mediainfo", "--Output=JSON", "-f", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
media_info = json.loads(mediainfo_json)
|
||||
mkvmerge_info_json = run_cmd([
|
||||
"mkvmerge", "-J", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
mkv_info = json.loads(mkvmerge_info_json)
|
||||
|
||||
created_ut_video_path, created_encoded_video_path = convert_video(file_path.stem, str(input_file_abs))
|
||||
mediainfo_json = run_cmd([
|
||||
"mediainfo", "--Output=JSON", "-f", str(input_file_abs)
|
||||
], capture_output=True)
|
||||
media_info = json.loads(mediainfo_json)
|
||||
|
||||
print("--- Starting Audio Processing ---")
|
||||
processed_audio_files = []
|
||||
audio_tracks_to_remux = []
|
||||
audio_streams = [s for s in ffprobe_info.get("streams", []) if s.get("codec_type") == "audio"]
|
||||
created_ut_video_path, created_encoded_video_path = convert_video(file_path.stem, str(input_file_abs))
|
||||
|
||||
# Build mkvmerge audio track list
|
||||
mkv_audio_tracks_list = [t for t in mkv_info.get("tracks", []) if t.get("type") == "audio"]
|
||||
print("--- Starting Audio Processing ---")
|
||||
processed_audio_files = []
|
||||
audio_tracks_to_remux = []
|
||||
audio_streams = [s for s in ffprobe_info.get("streams", []) if s.get("codec_type") == "audio"]
|
||||
|
||||
# Build mediainfo track mapping by StreamOrder
|
||||
media_tracks_data = media_info.get("media", {}).get("track", [])
|
||||
mediainfo_audio_tracks = {int(t.get("StreamOrder", -1)): t for t in media_tracks_data if t.get("@type") == "Audio"}
|
||||
# Build mkvmerge audio track list
|
||||
mkv_audio_tracks_list = [t for t in mkv_info.get("tracks", []) if t.get("type") == "audio"]
|
||||
|
||||
for audio_idx, stream in enumerate(audio_streams):
|
||||
stream_index = stream["index"]
|
||||
codec = stream.get("codec_name")
|
||||
channels = stream.get("channels", 2)
|
||||
language = stream.get("tags", {}).get("language", "und")
|
||||
# Build mediainfo track mapping by StreamOrder
|
||||
media_tracks_data = media_info.get("media", {}).get("track", [])
|
||||
mediainfo_audio_tracks = {int(t.get("StreamOrder", -1)): t for t in media_tracks_data if t.get("@type") == "Audio"}
|
||||
|
||||
# More robustly find the mkvmerge track by matching ffprobe's stream index
|
||||
# to mkvmerge's 'stream_id' property.
|
||||
mkv_track = next((t for t in mkv_info.get("tracks", []) if t.get("properties", {}).get("stream_id") == stream_index), None)
|
||||
if not mkv_track:
|
||||
# Fallback to the less reliable index-based method if stream_id isn't found
|
||||
mkv_track = mkv_audio_tracks_list[audio_idx] if audio_idx < len(mkv_audio_tracks_list) else {}
|
||||
for audio_idx, stream in enumerate(audio_streams):
|
||||
stream_index = stream["index"]
|
||||
codec = stream.get("codec_name")
|
||||
channels = stream.get("channels", 2)
|
||||
language = stream.get("tags", {}).get("language", "und")
|
||||
|
||||
track_id = mkv_track.get("id", -1)
|
||||
track_title = mkv_track.get("properties", {}).get("track_name", "")
|
||||
track_delay = 0
|
||||
audio_track_info = mediainfo_audio_tracks.get(stream_index)
|
||||
delay_raw = audio_track_info.get("Video_Delay") if audio_track_info else None
|
||||
if delay_raw is not None:
|
||||
try:
|
||||
delay_val = float(delay_raw)
|
||||
if delay_val < 1:
|
||||
track_delay = int(round(delay_val * 1000))
|
||||
else:
|
||||
track_delay = int(round(delay_val))
|
||||
except Exception:
|
||||
track_delay = 0
|
||||
# More robustly find the mkvmerge track by matching ffprobe's stream index
|
||||
# to mkvmerge's 'stream_id' property.
|
||||
mkv_track = next((t for t in mkv_info.get("tracks", []) if t.get("properties", {}).get("stream_id") == stream_index), None)
|
||||
if not mkv_track:
|
||||
# Fallback to the less reliable index-based method if stream_id isn't found
|
||||
mkv_track = mkv_audio_tracks_list[audio_idx] if audio_idx < len(mkv_audio_tracks_list) else {}
|
||||
|
||||
print(f"Processing Audio Stream #{stream_index} (TID: {track_id}, Codec: {codec}, Channels: {channels})")
|
||||
if codec in REMUX_CODECS:
|
||||
audio_tracks_to_remux.append(str(track_id))
|
||||
track_id = mkv_track.get("id", -1)
|
||||
track_title = mkv_track.get("properties", {}).get("track_name", "")
|
||||
track_delay = 0
|
||||
audio_track_info = mediainfo_audio_tracks.get(stream_index)
|
||||
delay_raw = audio_track_info.get("Video_Delay") if audio_track_info else None
|
||||
if delay_raw is not None:
|
||||
try:
|
||||
delay_val = float(delay_raw)
|
||||
if delay_val < 1:
|
||||
track_delay = int(round(delay_val * 1000))
|
||||
else:
|
||||
track_delay = int(round(delay_val))
|
||||
except Exception:
|
||||
track_delay = 0
|
||||
|
||||
print(f"Processing Audio Stream #{stream_index} (TID: {track_id}, Codec: {codec}, Channels: {channels})")
|
||||
if codec in REMUX_CODECS:
|
||||
audio_tracks_to_remux.append(str(track_id))
|
||||
else:
|
||||
opus_file = convert_audio_track(
|
||||
stream_index, channels, language, audio_temp_dir, str(input_file_abs), not no_downmix
|
||||
)
|
||||
processed_audio_files.append({
|
||||
"Path": opus_file,
|
||||
"Language": language,
|
||||
"Title": track_title,
|
||||
"Delay": track_delay
|
||||
})
|
||||
|
||||
print("--- Finished Audio Processing ---")
|
||||
|
||||
# Final mux
|
||||
print("Assembling final file with mkvmerge...")
|
||||
mkvmerge_args = ["mkvmerge", "-o", str(intermediate_output_file), str(created_encoded_video_path)]
|
||||
|
||||
for file_info in processed_audio_files:
|
||||
mkvmerge_args.extend(["--language", f"0:{file_info['Language']}"])
|
||||
if file_info['Title']: # Only add track name if it exists
|
||||
mkvmerge_args.extend(["--track-name", f"0:{file_info['Title']}"])
|
||||
if file_info['Delay']:
|
||||
mkvmerge_args.extend(["--sync", f"0:{file_info['Delay']}"])
|
||||
mkvmerge_args.append(str(file_info["Path"]))
|
||||
|
||||
source_copy_args = ["--no-video"]
|
||||
|
||||
if audio_tracks_to_remux:
|
||||
source_copy_args += ["--audio-tracks", ",".join(audio_tracks_to_remux)]
|
||||
else:
|
||||
opus_file = convert_audio_track(
|
||||
stream_index, channels, language, audio_temp_dir, str(input_file_abs), not no_downmix
|
||||
)
|
||||
processed_audio_files.append({
|
||||
"Path": opus_file,
|
||||
"Language": language,
|
||||
"Title": track_title,
|
||||
"Delay": track_delay
|
||||
})
|
||||
source_copy_args += ["--no-audio"]
|
||||
mkvmerge_args += source_copy_args + [str(input_file_abs)]
|
||||
run_cmd(mkvmerge_args)
|
||||
|
||||
print("--- Finished Audio Processing ---")
|
||||
# Move files
|
||||
print("Moving files to final destinations...")
|
||||
shutil.move(str(file_path), DIR_ORIGINAL / file_path.name)
|
||||
shutil.move(str(intermediate_output_file), DIR_COMPLETED / file_path.name)
|
||||
|
||||
# Final mux
|
||||
print("Assembling final file with mkvmerge...")
|
||||
mkvmerge_args = ["mkvmerge", "-o", str(intermediate_output_file), str(created_encoded_video_path)]
|
||||
except Exception as e:
|
||||
print(f"An error occurred while processing '{file_path.name}': {e}", file=sys.stderr)
|
||||
finally:
|
||||
print("--- Starting Cleanup ---")
|
||||
if audio_temp_dir and Path(audio_temp_dir).exists():
|
||||
print(" - Cleaning up disposable audio temporary directory...")
|
||||
shutil.rmtree(audio_temp_dir, ignore_errors=True)
|
||||
|
||||
for file_info in processed_audio_files:
|
||||
mkvmerge_args.extend(["--language", f"0:{file_info['Language']}"])
|
||||
if file_info['Title']: # Only add track name if it exists
|
||||
mkvmerge_args.extend(["--track-name", f"0:{file_info['Title']}"])
|
||||
if file_info['Delay']:
|
||||
mkvmerge_args.extend(["--sync", f"0:{file_info['Delay']}"])
|
||||
mkvmerge_args.append(str(file_info["Path"]))
|
||||
if intermediate_output_file.exists():
|
||||
print(" - Cleaning up intermediate output file...")
|
||||
intermediate_output_file.unlink()
|
||||
|
||||
source_copy_args = ["--no-video"]
|
||||
print(" - Cleaning up persistent video temporary files...")
|
||||
if created_ut_video_path and created_ut_video_path.exists():
|
||||
print(f" - Deleting UT video file: {created_ut_video_path}")
|
||||
created_ut_video_path.unlink()
|
||||
if created_encoded_video_path and created_encoded_video_path.exists():
|
||||
print(f" - Deleting encoded video temp file: {created_encoded_video_path}")
|
||||
created_encoded_video_path.unlink()
|
||||
|
||||
if audio_tracks_to_remux:
|
||||
source_copy_args += ["--audio-tracks", ",".join(audio_tracks_to_remux)]
|
||||
else:
|
||||
source_copy_args += ["--no-audio"]
|
||||
mkvmerge_args += source_copy_args + [str(input_file_abs)]
|
||||
run_cmd(mkvmerge_args)
|
||||
alabama_dirs = list(current_dir.glob('.alabamatemp-*'))
|
||||
if alabama_dirs:
|
||||
print(" - Cleaning up AlabamaEncoder temporary directories...")
|
||||
for temp_dir_alabama in alabama_dirs:
|
||||
if temp_dir_alabama.is_dir():
|
||||
shutil.rmtree(temp_dir_alabama, ignore_errors=True)
|
||||
print("--- Finished Cleanup ---")
|
||||
|
||||
# Move files
|
||||
print("Moving files to final destinations...")
|
||||
shutil.move(str(file_path), DIR_ORIGINAL / file_path.name)
|
||||
shutil.move(str(intermediate_output_file), DIR_COMPLETED / file_path.name)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred while processing '{file_path.name}': {e}", file=sys.stderr)
|
||||
runtime = datetime.now() - date
|
||||
runtime_str = str(runtime).split('.')[0] # Format to remove milliseconds
|
||||
print(f"Total runtime for {file_path.name}: {runtime_str}")
|
||||
finally:
|
||||
print("--- Starting Cleanup ---")
|
||||
if audio_temp_dir and Path(audio_temp_dir).exists():
|
||||
print(" - Cleaning up disposable audio temporary directory...")
|
||||
shutil.rmtree(audio_temp_dir, ignore_errors=True)
|
||||
|
||||
if intermediate_output_file.exists():
|
||||
print(" - Cleaning up intermediate output file...")
|
||||
intermediate_output_file.unlink()
|
||||
|
||||
print(" - Cleaning up persistent video temporary files...")
|
||||
if created_ut_video_path and created_ut_video_path.exists():
|
||||
print(f" - Deleting UT video file: {created_ut_video_path}")
|
||||
created_ut_video_path.unlink()
|
||||
if created_encoded_video_path and created_encoded_video_path.exists():
|
||||
print(f" - Deleting encoded video temp file: {created_encoded_video_path}")
|
||||
created_encoded_video_path.unlink()
|
||||
|
||||
alabama_dirs = list(current_dir.glob('.alabamatemp-*'))
|
||||
if alabama_dirs:
|
||||
print(" - Cleaning up AlabamaEncoder temporary directories...")
|
||||
for temp_dir_alabama in alabama_dirs:
|
||||
if temp_dir_alabama.is_dir():
|
||||
shutil.rmtree(temp_dir_alabama, ignore_errors=True)
|
||||
print("--- Finished Cleanup ---")
|
||||
|
||||
runtime = datetime.now() - date
|
||||
runtime_str = str(runtime).split('.')[0] # Format to remove milliseconds
|
||||
print(f"Total runtime for {file_path.name}: {runtime_str}")
|
||||
# Restore stdout/stderr and close log file
|
||||
sys.stdout = original_stdout
|
||||
sys.stderr = original_stderr
|
||||
log_file.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
Reference in New Issue
Block a user