transcode.py: handle Ctrl+C better

This commit is contained in:
2025-12-06 18:55:19 +01:00
parent a3dea4eaba
commit 158688ec44
+39 -10
View File
@@ -12,6 +12,7 @@ import json
import logging
import os
import re
import signal
import subprocess
import sys
import time
@@ -200,7 +201,6 @@ def get_ffmpeg_command(input_path, output_path):
def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=False):
exit_after_next = False
input_path = Path(input_file)
logging.debug(f"Processing request for: {input_path}")
@@ -285,6 +285,8 @@ def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=Fal
cmd = get_ffmpeg_command(input_path, transcode_output_path)
logging.debug(f"Executing FFmpeg command: {' '.join(cmd)}")
graceful_exit = False
try:
with open(ffmpeg_log_file, "w", encoding="utf-8", errors="replace") as f_log:
# Write the command itself to the top of the log
@@ -292,12 +294,15 @@ def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=Fal
f_log.flush()
# Run FFmpeg and process output in real-time with timestamps
# NOTE: start_new_session=True ensures Ctrl+C doesn't kill ffmpeg immediately
# allowing us to handle the first press gracefully in Python.
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
start_new_session=True,
)
regex_elapsed = re.compile(r"elapsed=([0-9:.]+)")
@@ -305,6 +310,7 @@ def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=Fal
# Write FFmpeg output with timestamps as it's generated
try:
while True:
try:
output = process.stdout.readline() # pyright: ignore[reportOptionalMemberAccess]
if output == "" and process.poll() is not None:
break
@@ -318,11 +324,30 @@ def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=Fal
)
f_log.write(f"[{timestamp}] {output.rstrip()}\n")
f_log.flush()
except KeyboardInterrupt:
if not graceful_exit:
logging.info(
" > [GRACEFUL EXIT] Signal received. Finishing current file, then exiting script. Press Ctrl+C again to FORCE QUIT."
)
graceful_exit = True
# Continue loop, process is still running because of start_new_session=True
continue
else:
logging.warning(
" >> [FORCE QUIT] Signal received again. Terminating process..."
)
# Explicitly terminate the process group or process
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
raise # Re-raise to trigger outer cleanup
# Wait for process to complete and get return code
result = process.wait()
except Exception as e:
# Ensure we clean up temporary files on error
# Ensure we clean up temporary files on error (e.g. if we forced kill inside loop)
if replace_mode and use_temp_file and transcode_output_path.exists():
try:
transcode_output_path.unlink()
@@ -410,19 +435,23 @@ def transcode_file(input_file, output_file=None, skip_av1=True, replace_mode=Fal
except Exception:
pass
if exit_after_next:
logging.info("Quitting early due to user interrupt.")
# If a graceful exit was requested, we exit now that the file is fully processed
if graceful_exit:
logging.info("Exiting script gracefully as requested.")
sys.exit(0)
except Exception as e:
logging.exception(f"Unexpected error during transcoding of {input_path}: {e}")
except KeyboardInterrupt:
logging.info(
"Will quit after the current file is transcoded. Press Ctrl+C again to force quit."
)
if exit_after_next:
sys.exit(0)
exit_after_next = True
# This catches the re-raised exception from the inner loop (2nd Ctrl+C / Force Quit)
logging.info("Transcoding aborted by user.")
# Ensure cleanup happened (redundant check but safe)
if replace_mode and use_temp_file and transcode_output_path.exists():
try:
transcode_output_path.unlink()
except Exception:
pass
sys.exit(1)
class NewFileHandler(FileSystemEventHandler):