diff --git a/openlp/core/app.py b/openlp/core/app.py index 15d8cfc6c..e35465a3f 100644 --- a/openlp/core/app.py +++ b/openlp/core/app.py @@ -385,17 +385,12 @@ def main(): application.setApplicationName('OpenLP') set_up_logging(AppLocation.get_directory(AppLocation.CacheDir)) # Set the libvlc environment variable if we're frozen - if getattr(sys, 'frozen', False): - if is_macosx(): - vlc_lib = 'libvlc.dylib' - elif is_win(): - vlc_lib = 'libvlc.dll' - # Path to libvlc - os.environ['PYTHON_VLC_LIB_PATH'] = str(AppLocation.get_directory(AppLocation.AppDir) / 'vlc' / vlc_lib) - log.debug('VLC Path: {}'.format(os.environ['PYTHON_VLC_LIB_PATH'])) - # Path to VLC directory containing VLC's "plugins" directory + if getattr(sys, 'frozen', False) and is_win(): + # Path to libvlc and the plugins + os.environ['PYTHON_VLC_LIB_PATH'] = str(AppLocation.get_directory(AppLocation.AppDir) / 'vlc' / 'libvlc.dll') os.environ['PYTHON_VLC_MODULE_PATH'] = str(AppLocation.get_directory(AppLocation.AppDir) / 'vlc') log.debug('VLC Path: {}'.format(os.environ['PYTHON_VLC_LIB_PATH'])) + log.debug('VLC Plugins Path: {}'.format(os.environ['PYTHON_VLC_MODULE_PATH'])) # Initialise the Registry Registry.create() Registry().register('application', application) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index c91ce3954..9b237514c 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -34,6 +34,7 @@ from PyQt5 import QtCore from openlp.core.state import State from openlp.core.api.http import register_endpoint +from openlp.core.common import is_linux, is_macosx from openlp.core.common.i18n import translate from openlp.core.common.mixins import LogMixin, RegistryProperties from openlp.core.common.registry import Registry, RegistryBase @@ -89,23 +90,35 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): self.vlc_player = VlcPlayer(self) State().add_service('mediacontroller', 0) State().add_service('media_live', 0) - getvlc = get_vlc() - if getvlc and pymediainfo_available: + has_vlc = get_vlc() + if has_vlc and pymediainfo_available: State().update_pre_conditions('mediacontroller', True) State().update_pre_conditions('media_live', True) else: if hasattr(self.main_window, 'splash') and self.main_window.splash.isVisible(): self.main_window.splash.hide() - text_vlc = translate('OpenLP.MediaController', - 'The media integration library is missing (python - vlc is not installed)') - text_info = translate('OpenLP.MediaController', - 'The media integration library is missing (python - pymediainfo is not installed)') - if not getvlc and not pymediainfo_available: - State().missing_text('media_live', "{text}\n{base}".format(text=text_vlc, base=text_info)) - if getvlc and not pymediainfo_available: - State().missing_text('media_live', "{text}".format(text=text_info)) - if not getvlc and pymediainfo_available: - State().missing_text('media_live', "{text}".format(text=text_vlc)) + generic_message = translate('OpenLP.MediaController', + 'OpenLP requires the following libraries in order to show videos and other ' + 'media, but they are not installed. Please install these libraries to enable ' + 'media playback in OpenLP.') + fedora_rpmfusion = translate('OpenLP.MediaController', + 'To install these libraries, you will need to enable the RPMFusion ' + 'repository: https://rpmfusion.org/') + message = '' + if is_macosx(): + message = translate('OpenLP.MediaController', + 'macOS is missing VLC. Please download and install from the VLC web site: ' + 'https://www.videolan.org/vlc/') + else: + packages = [] + if not has_vlc: + packages.append('python3-vlc') + if not pymediainfo_available: + packages.append('python3-pymediainfo') + message = generic_message + '\n\n' + ', '.join(packages) + if not has_vlc and is_linux(distro='fedora'): + message += '\n\n' + fedora_rpmfusion + State().missing_text('media_live', message) return True def bootstrap_post_set_up(self): diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index 0a3ed0f35..fc92ae28b 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -25,6 +25,7 @@ from unittest import TestCase from unittest.mock import MagicMock, patch from openlp.core.common.registry import Registry +from openlp.core.ui import DisplayControllerType from openlp.core.ui.media.mediacontroller import MediaController from openlp.core.ui.media import ItemMediaInfo from tests.helpers.testmixin import TestMixin @@ -202,3 +203,122 @@ class TestMediaController(TestCase, TestMixin): # THEN you can determine the run time assert results == test_data[1], 'The correct duration is returned for ' + test_data[0] + + def test_on_media_play(self): + """ + Test the on_media_play method + """ + # GIVEN: A mocked live controller and a mocked media_play() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_controller = MediaController() + media_controller.media_play = MagicMock() + + # WHEN: the on_media_play() method is called + media_controller.on_media_play() + + # The mocked live controller should be called + media_controller.media_play.assert_called_once_with(mocked_live_controller, False) + + def test_on_media_pause(self): + """ + Test the on_media_pause method + """ + # GIVEN: A mocked live controller and a mocked media_pause() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_controller = MediaController() + media_controller.media_pause = MagicMock() + + # WHEN: the on_media_pause() method is called + media_controller.on_media_pause() + + # The mocked live controller should be called + media_controller.media_pause.assert_called_once_with(mocked_live_controller) + + def test_on_media_stop(self): + """ + Test the on_media_stop method + """ + # GIVEN: A mocked live controller and a mocked media_stop() method + mocked_live_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + media_controller = MediaController() + media_controller.media_stop = MagicMock() + + # WHEN: the on_media_stop() method is called + media_controller.on_media_stop() + + # The mocked live controller should be called + media_controller.media_stop.assert_called_once_with(mocked_live_controller) + + def test_display_controllers_live(self): + """ + Test that the display_controllers() method returns the live controller when requested + """ + # GIVEN: A mocked live controller + media_controller = MediaController() + mocked_live_controller = MagicMock() + mocked_preview_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + Registry().register('preview_controller', mocked_preview_controller) + + # WHEN: display_controllers() is called with DisplayControllerType.Live + controller = media_controller.display_controllers(DisplayControllerType.Live) + + # THEN: the controller should be the live controller + assert controller is mocked_live_controller + + def test_display_controllers_preview(self): + """ + Test that the display_controllers() method returns the preview controller when requested + """ + # GIVEN: A mocked live controller + media_controller = MediaController() + mocked_live_controller = MagicMock() + mocked_preview_controller = MagicMock() + Registry().register('live_controller', mocked_live_controller) + Registry().register('preview_controller', mocked_preview_controller) + + # WHEN: display_controllers() is called with DisplayControllerType.Preview + controller = media_controller.display_controllers(DisplayControllerType.Preview) + + # THEN: the controller should be the live controller + assert controller is mocked_preview_controller + + def test_set_controls_visible(self): + """ + Test that "set_controls_visible" sets the media controls on the controller to be visible or not + """ + # GIVEN: A mocked controller + mocked_controller = MagicMock() + + # WHEN: Set to visible + MediaController.set_controls_visible(mocked_controller, True) + + # THEN: The media controls should have been set to visible + mocked_controller.mediabar.setVisible.assert_called_once_with(True) + + @patch('openlp.core.ui.media.mediacontroller.ItemMediaInfo') + def test_setup_display(self, MockItemMediaInfo): + """ + Test that the display/controllers are set up correctly + """ + # GIVEN: A media controller object and some mocks + mocked_media_info = MagicMock() + MockItemMediaInfo.return_value = mocked_media_info + media_controller = MediaController() + media_controller.vlc_player = MagicMock() + mocked_display = MagicMock() + media_controller._define_display = MagicMock(return_value=mocked_display) + media_controller.vlc_player = MagicMock() + controller = MagicMock() + + # WHEN: setup_display() is called + media_controller.setup_display(controller, True) + + # THEN: The right calls should have been made + assert controller.media_info == mocked_media_info + assert controller.has_audio is False + media_controller._define_display.assert_called_once_with(controller) + media_controller.vlc_player.setup(controller, mocked_display, False)