diff --git a/panek_video_program.py b/panek_video_program.py
index 9c141a1..b03f82c 100644
--- a/panek_video_program.py
+++ b/panek_video_program.py
@@ -26,6 +26,7 @@
import shutil
import datetime
import subprocess
+import html
from pathlib import Path
# Import all necessary PySide6 components
@@ -126,8 +127,10 @@ def __init__(self, out_path: str, parent=None):
def _refresh_text(self):
"""Update the label text."""
+ # Escape the output path to prevent HTML injection
+ safe_path = html.escape(self.out_path)
self.msg.setText(
- f"Video created successfully:
{self.out_path}
"
+ f"Video created successfully:
{safe_path}
"
f"Powered by FFmpeg (LGPL/GPL)"
)
self.close_btn.setText(f"Close (in {self.seconds})")
@@ -156,12 +159,13 @@ class FFmpegRunner(QObject):
def __init__(self):
super().__init__()
self.process = QProcess()
-
+
# We will read progress from stdout and logs from stderr
self.process.readyReadStandardOutput.connect(self._read_progress)
self.process.readyReadStandardError.connect(self._read_logs)
self.process.finished.connect(self._on_finished)
self.process.started.connect(self.process_started.emit)
+ self.process.errorOccurred.connect(self._on_error)
self.audio_duration = 0.0
self.output_path = ""
@@ -188,6 +192,23 @@ def _read_logs(self):
if output:
self.log_message.emit(output)
+ def _on_error(self, error):
+ """
+ Handle QProcess errors (e.g., ffmpeg not found, permission denied).
+ """
+ error_messages = {
+ QProcess.ProcessError.FailedToStart: "Failed to start ffmpeg. Please ensure ffmpeg is installed and in your PATH.",
+ QProcess.ProcessError.Crashed: "FFmpeg process crashed unexpectedly.",
+ QProcess.ProcessError.Timedout: "FFmpeg process timed out.",
+ QProcess.ProcessError.WriteError: "Error writing to ffmpeg process.",
+ QProcess.ProcessError.ReadError: "Error reading from ffmpeg process.",
+ QProcess.ProcessError.UnknownError: "Unknown error occurred with ffmpeg process."
+ }
+ error_msg = error_messages.get(error, "Unknown error occurred.")
+ self.log_message.emit(f"--- PROCESS ERROR: {error_msg} ---")
+ # Emit finished signal with error code -1
+ self.process_finished.emit(-1, "")
+
def _on_finished(self, exit_code, exit_status):
"""
Handle the QProcess.finished signal.
@@ -199,7 +220,7 @@ def _on_finished(self, exit_code, exit_status):
self.progress_updated.emit(100)
else:
self.log_message.emit(f"--- PROCESS FAILED (Code: {exit_code}) ---")
-
+
self.process_finished.emit(exit_code, self.output_path)
def _build_ffmpeg_cmd(self, media_path: str, audio_path: str, out_path: str, title: str,
@@ -223,8 +244,9 @@ def _build_ffmpeg_cmd(self, media_path: str, audio_path: str, out_path: str, tit
# Add text overlay if provided
if text_overlay:
- # Escape text for FFmpeg
- safe_text = text_overlay.replace(":", "\\:").replace("'", "\\'")
+ # Escape text for FFmpeg drawtext filter
+ # Must escape backslash first to avoid double-escaping
+ safe_text = text_overlay.replace("\\", "\\\\").replace(":", "\\:").replace("'", "\\'")
# Calculate position
if text_position == "top":