Fix low-severity robustness issues
- show_error_dialog() aborted when QApplication construction itself was
the failure; fall back to stderr so the real error is visible.
- Auto-update QThread cleanup dropped the last Python reference while
run() could still be unwinding ("QThread: Destroyed while thread is
still running"); defer destruction to deleteLater on finished.
- macOS ffmpeg install no longer curl|bash-es the Homebrew bootstrap
script unattended; it now asks the user to install Homebrew
themselves and fails cleanly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -406,9 +406,14 @@ def install_ffmpeg_macos() -> bool:
|
|||||||
timeout=5,
|
timeout=5,
|
||||||
)
|
)
|
||||||
except (subprocess.SubprocessError, FileNotFoundError):
|
except (subprocess.SubprocessError, FileNotFoundError):
|
||||||
logger.info("Installing Homebrew...")
|
# Never curl|bash a remote script without the user's say-so.
|
||||||
brew_install_cmd = '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
# Homebrew installation is the user's decision to make in a
|
||||||
subprocess.run(brew_install_cmd, shell=True, check=True, timeout=300)
|
# terminal, where the script can also prompt for sudo properly.
|
||||||
|
logger.error(
|
||||||
|
"Homebrew is not installed. Install it from https://brew.sh and retry, "
|
||||||
|
"or install ffmpeg another way."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
# Install FFmpeg
|
# Install FFmpeg
|
||||||
logger.info("Installing FFmpeg...")
|
logger.info("Installing FFmpeg...")
|
||||||
|
|||||||
@@ -1176,12 +1176,16 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
|
|||||||
|
|
||||||
# Clean up the thread reference and ensure it's properly finished
|
# Clean up the thread reference and ensure it's properly finished
|
||||||
if hasattr(self, "auto_update_thread"):
|
if hasattr(self, "auto_update_thread"):
|
||||||
|
thread = self.auto_update_thread
|
||||||
# Disconnect all signals to prevent further callbacks
|
# Disconnect all signals to prevent further callbacks
|
||||||
self.auto_update_thread.update_finished.disconnect()
|
thread.update_finished.disconnect()
|
||||||
# Make sure thread is finished
|
# Dropping the Python reference while run() is still unwinding
|
||||||
if self.auto_update_thread.isRunning():
|
# can destroy a live QThread; let Qt delete it once finished.
|
||||||
self.auto_update_thread.quit()
|
if thread.isRunning():
|
||||||
self.auto_update_thread.wait(1000) # Wait up to 1 second
|
thread.finished.connect(thread.deleteLater)
|
||||||
|
thread.quit()
|
||||||
|
else:
|
||||||
|
thread.deleteLater()
|
||||||
# Remove the reference
|
# Remove the reference
|
||||||
delattr(self, "auto_update_thread")
|
delattr(self, "auto_update_thread")
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ from .gui.ytsage_gui_main import YTSageApp # Import the main application class
|
|||||||
|
|
||||||
|
|
||||||
def show_error_dialog(message):
|
def show_error_dialog(message):
|
||||||
|
# A QMessageBox needs a live QApplication; if startup failed before (or
|
||||||
|
# while) creating one, constructing the dialog would abort the process
|
||||||
|
# and swallow the real error.
|
||||||
|
if QApplication.instance() is None:
|
||||||
|
print(f"Application Error: {message}", file=sys.stderr)
|
||||||
|
return
|
||||||
error_dialog = QMessageBox()
|
error_dialog = QMessageBox()
|
||||||
error_dialog.setIcon(QMessageBox.Icon.Critical)
|
error_dialog.setIcon(QMessageBox.Icon.Critical)
|
||||||
error_dialog.setText("Application Error")
|
error_dialog.setText("Application Error")
|
||||||
|
|||||||
Reference in New Issue
Block a user