Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Warn user if FFmpeg is not installed #441

Merged
merged 12 commits into from
Sep 14, 2024
3 changes: 2 additions & 1 deletion .github/workflows/apprun.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ jobs:
libxcb-xinerama0 \
libopengl0 \
libxcb-cursor0 \
libpulse0
libpulse0 \
ffmpeg

- name: Install dependencies
run: |
Expand Down
66 changes: 66 additions & 0 deletions tagstudio/src/qt/modals/ffmpeg_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import logging
import math
from pathlib import Path
import subprocess

from PIL import Image, ImageQt
from pydub.utils import which
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."""
# Same checker that ffmpeg-python uses
if which("ffmpeg"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont like this implementation of which, it could just have been a method in your class, but since it ships with ffmpegs install it is fine to use. But, it uses os.name for platform checking, and I have seen many discussion about this usage and how it is better to use platform.system() to get the current platform name.

It also uses os.path instead of pathlib

I would like @CyanVoxel to comment on this. I can write the method if that is wanted as a new PR after this is merged. there is currently nothing wrong about this usage.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could shutil.which() be used here instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know the Python stdlib had a built in which command, using that instead.

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))
10 changes: 10 additions & 0 deletions tagstudio/src/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -1846,6 +1850,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."""

Expand Down