From b2dbc5722b24438869aa2f56dec3b5286e496799 Mon Sep 17 00:00:00 2001 From: Sean Krueger Date: Fri, 13 Sep 2024 17:25:09 -0700 Subject: [PATCH] feat(ui): warn user if FFmpeg not installed (#441) * feat: Warn user if FFmpeg is not installed Creates a Warning dialog on startup if the program cannot find FFmpeg or FFprobe in the PATH. Other interactions with the program are blocked until the issue is either ignore or resolved. * docs: Add FFmpeg installation guide * ruff formatting * chore: Cleanup missing logic and warning message * chore: Remove custom icon Per QT docs, handling custom iconPixmap requires multiple icons per platform. Easier to just use universal, default warning icon (yellow triangle) * fix: Ignore dialog with X button * fix: Move startup checks after CI * chore: Unreverse install check logic * doc: Improve docs formatting * docs: Point help url to new docs sites * Remove ffmpeg docs page * Use which from python stdlib --- .github/workflows/apprun.yaml | 3 +- tagstudio/src/qt/modals/ffmpeg_checker.py | 65 +++++++++++++++++++++++ tagstudio/src/qt/ts_qt.py | 10 ++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tagstudio/src/qt/modals/ffmpeg_checker.py diff --git a/.github/workflows/apprun.yaml b/.github/workflows/apprun.yaml index 9894f168e..9685aea1e 100644 --- a/.github/workflows/apprun.yaml +++ b/.github/workflows/apprun.yaml @@ -33,7 +33,8 @@ jobs: libxcb-xinerama0 \ libopengl0 \ libxcb-cursor0 \ - libpulse0 + libpulse0 \ + ffmpeg - name: Install dependencies run: | diff --git a/tagstudio/src/qt/modals/ffmpeg_checker.py b/tagstudio/src/qt/modals/ffmpeg_checker.py new file mode 100644 index 000000000..deed05ed5 --- /dev/null +++ b/tagstudio/src/qt/modals/ffmpeg_checker.py @@ -0,0 +1,65 @@ +import logging +import math +from pathlib import Path +from shutil import which +import subprocess + +from PIL import Image, ImageQt +from PySide6.QtCore import Signal, Qt, QUrl +from PySide6.QtGui import QPixmap, QDesktopServices +from PySide6.QtWidgets import QMessageBox + + +class FfmpegChecker(QMessageBox): + """A warning dialog for if FFmpeg is missing.""" + + HELP_URL = "https://docs.tagstud.io/help/ffmpeg/" + + def __init__(self): + super().__init__() + + self.setWindowTitle("Warning: Missing dependency") + self.setText("Warning: Could not find FFmpeg installation") + self.setIcon(QMessageBox.Warning) + # Blocks other application interactions until resolved + self.setWindowModality(Qt.ApplicationModal) + + self.setStandardButtons( + QMessageBox.Help | QMessageBox.Ignore | QMessageBox.Cancel + ) + self.setDefaultButton(QMessageBox.Ignore) + # Enables the cancel button but hides it to allow for click X to close dialog + self.button(QMessageBox.Cancel).hide() + + self.ffmpeg = False + self.ffprobe = False + + def installed(self): + """Checks if both FFmpeg and FFprobe are installed and in the PATH.""" + if which("ffmpeg"): + self.ffmpeg = True + if which("ffprobe"): + self.ffprobe = True + + logging.info( + f"[FFmpegChecker] FFmpeg found: {self.ffmpeg}, FFprobe found: {self.ffprobe}" + ) + return self.ffmpeg and self.ffprobe + + def show_warning(self): + """Displays the warning to the user and awaits respone.""" + missing = "FFmpeg" + # If ffmpeg is installed but not ffprobe + if not self.ffprobe and self.ffmpeg: + missing = "FFprobe" + + self.setText(f"Warning: Could not find {missing} installation") + self.setInformativeText( + f"{missing} is required for multimedia thumbnails and playback" + ) + # Shows the dialog + selection = self.exec() + + # Selection will either be QMessageBox.Help or (QMessageBox.Ignore | QMessageBox.Cancel) which can be ignored + if selection == QMessageBox.Help: + QDesktopServices.openUrl(QUrl(self.HELP_URL)) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 235a23417..bca2089a5 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -92,6 +92,7 @@ from src.qt.modals.fix_dupes import FixDupeFilesModal from src.qt.modals.folders_to_tags import FoldersToTagsModal from src.qt.modals.drop_import import DropImport +from src.qt.modals.ffmpeg_checker import FfmpegChecker # this import has side-effect of import PySide resources import src.qt.resources_rc # pylint: disable=unused-import @@ -639,6 +640,9 @@ def create_folders_tags_modal(): if self.args.ci: # gracefully terminate the app in CI environment self.thumb_job_queue.put((self.SIGTERM.emit, [])) + else: + # Startup Checks + self.check_ffmpeg() app.exec() @@ -1852,6 +1856,12 @@ def open_library(self, path: Path): self.filter_items() self.main_window.toggle_landing_page(False) + def check_ffmpeg(self) -> None: + """Checks if FFmpeg is installed and displays a warning if not.""" + self.ffmpeg_checker = FfmpegChecker() + if not self.ffmpeg_checker.installed(): + self.ffmpeg_checker.show_warning() + def create_collage(self) -> None: """Generates and saves an image collage based on Library Entries."""