From 6be3e0a816edc6d050279b98baddc2e3d7a30840 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 6 Sep 2014 20:33:01 +0100 Subject: [PATCH 1/5] Tried to fixed some DVD issues. Made the mouse cursor look busy. --- .../media/forms/mediaclipselectorform.py | 87 +++++++++++++------ 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 28d37f32e..ff0925f1e 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -28,31 +28,29 @@ ############################################################################### import os -if os.name == 'nt': - from win32com.client import Dispatch - import string -import sys - -if sys.platform.startswith('linux'): - import dbus import logging import re from time import sleep from datetime import datetime - from PyQt4 import QtCore, QtGui -from openlp.core.common import translate +from openlp.core.common import translate, Registry, is_win, is_linux, is_macosx from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media import format_milliseconds + +if is_win(): + from win32com.client import Dispatch + +if is_linux(): + import dbus + try: from openlp.core.ui.media.vendor import vlc except (ImportError, NameError, NotImplementedError): pass except OSError as e: - if sys.platform.startswith('win'): + if is_win(): if not isinstance(e, WindowsError) and e.winerror != 126: raise else: @@ -144,9 +142,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # You have to give the id of the QFrame (or similar object) # to vlc, different platforms have different functions for this. win_id = int(self.preview_frame.winId()) - if sys.platform == "win32": + if is_win(): self.vlc_media_player.set_hwnd(win_id) - elif sys.platform == "darwin": + elif is_macosx(): # We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa # framework and not the old Carbon. self.vlc_media_player.set_nsobject(win_id) @@ -190,7 +188,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.audio_cd = True self.titles_combo_box.setDisabled(False) self.titles_combo_box.setCurrentIndex(0) - self.on_title_combo_box_currentIndexChanged(0) + self.on_titles_combo_box_currentIndexChanged(0) return True @@ -203,18 +201,21 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ log.debug('on_load_disc_button_clicked') self.disable_all() + self.application.set_busy_cursor() path = self.media_path_combobox.currentText() # Check if given path is non-empty and exists before starting VLC if not path: log.debug('no given path') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given')) self.toggle_disable_load_media(False) + self.application.set_normal_cursor() return if not os.path.exists(path): log.debug('Given path does not exists') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'Given path does not exists')) self.toggle_disable_load_media(False) + self.application.set_normal_cursor() return # VLC behaves a bit differently on windows and linux when loading, which creates problems when trying to # detect if we're dealing with a DVD or CD, so we use different loading approaches depending on the OS. @@ -231,6 +232,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'An error happened during initialization of VLC player')) self.toggle_disable_load_media(False) + self.application.set_normal_cursor() return # put the media in the media player self.vlc_media_player.set_media(self.vlc_media) @@ -241,6 +243,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'VLC player failed playing the media')) self.toggle_disable_load_media(False) + self.application.set_normal_cursor() + self.vlc_media_player.audio_set_mute(False) return self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): @@ -249,8 +253,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'VLC player failed playing the media')) self.toggle_disable_load_media(False) + self.application.set_normal_cursor() + self.vlc_media_player.audio_set_mute(False) return - self.vlc_media_player.audio_set_mute(True) + # pause + self.vlc_media_player.set_time(0) + self.vlc_media_player.set_pause(1) + self.media_state_wait(vlc.State.Paused) + self.toggle_disable_load_media(False) + self.application.set_normal_cursor() + self.vlc_media_player.audio_set_mute(False) if not self.audio_cd: # Get titles, insert in combobox titles = self.vlc_media_player.video_get_title_description() @@ -260,12 +272,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # Main title is usually title #1 if len(titles) > 1: self.titles_combo_box.setCurrentIndex(1) - else: - self.titles_combo_box.setCurrentIndex(0) # Enable audio track combobox if anything is in it if len(titles) > 0: self.titles_combo_box.setDisabled(False) - self.toggle_disable_load_media(False) log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(bool) @@ -378,6 +387,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if not self.vlc_media_player: log.error('vlc_media_player was None') return + self.application.set_busy_cursor() if self.audio_cd: self.vlc_media = self.audio_cd_tracks.item_at_index(index) self.vlc_media_player.set_media(self.vlc_media) @@ -385,14 +395,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.play() if not self.media_state_wait(vlc.State.Playing): log.error('Could not start playing audio cd, needed to get track info') + self.application.set_normal_cursor() return self.vlc_media_player.audio_set_mute(True) - # Sleep 1 second to make sure VLC has the needed metadata - sleep(1) # pause self.vlc_media_player.set_time(0) self.vlc_media_player.set_pause(1) self.vlc_media_player.audio_set_mute(False) + self.application.set_normal_cursor() self.toggle_disable_player(False) else: self.vlc_media_player.set_title(index) @@ -400,13 +410,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.play() if not self.media_state_wait(vlc.State.Playing): log.error('Could not start playing dvd, needed to get track info') + self.application.set_normal_cursor() return self.vlc_media_player.audio_set_mute(True) - # Sleep 1 second to make sure VLC has the needed metadata - sleep(1) - self.vlc_media_player.set_time(0) - # Get audio tracks, insert in combobox + # Get audio tracks audio_tracks = self.vlc_media_player.audio_get_track_description() + # Make sure we actually get the tracks, who has a DVD without audio? + loop_count = 0 + while len(audio_tracks) == 0 and loop_count < 100: + log.debug('In the audiotrack retry loop') + sleep(0.1) + audio_tracks = self.vlc_media_player.audio_get_track_description() + loop_count += 1 + log.debug('number of audio tracks: %d' % len(audio_tracks)) + # Clear the audio track combobox, insert new tracks self.audio_tracks_combobox.clear() for audio_track in audio_tracks: self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0]) @@ -447,6 +464,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.set_pause(1) loop_count += 1 log.debug('titles_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) + self.application.set_normal_cursor() @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): @@ -595,7 +613,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): while media_state != self.vlc_media_player.get_state(): if self.vlc_media_player.get_state() == vlc.State.Error: return False - if (datetime.now() - start).seconds > 30: + if (datetime.now() - start).seconds > 15: return False return True @@ -606,7 +624,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ # Clear list first self.media_path_combobox.clear() - if os.name == 'nt': + if is_win(): # use win api to find optical drives fso = Dispatch('scripting.filesystemobject') for drive in fso.Drives: @@ -614,7 +632,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # if type is 4, it is a cd-rom drive if drive.DriveType == 4: self.media_path_combobox.addItem('%s:\\' % drive.DriveLetter) - elif sys.platform.startswith('linux'): + elif is_linux(): # Get disc devices from dbus and find the ones that are optical bus = dbus.SystemBus() try: @@ -646,7 +664,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if chr(c) != '\x00': block_file += chr(c) self.media_path_combobox.addItem(block_file) - elif sys.platform.startswith('darwin'): + elif is_macosx(): # Look for DVD folders in devices to find optical devices volumes = os.listdir('/Volumes') candidates = list() @@ -663,3 +681,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if file.endswith('aiff'): self.media_path_combobox.addItem('/Volumes/' + volume) break + + @property + def application(self): + """ + Adds the openlp to the class dynamically. + Windows needs to access the application in a dynamic manner. + """ + if is_win(): + return Registry().get('application') + else: + if not hasattr(self, '_application'): + self._application = Registry().get('application') + return self._application From 3eeda06075ed7831199439d7933e48b33730e581 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 6 Sep 2014 21:10:44 +0100 Subject: [PATCH 2/5] Use the RegistryProperties class --- .../media/forms/mediaclipselectorform.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index ff0925f1e..8ab37f6ab 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -35,7 +35,7 @@ from datetime import datetime from PyQt4 import QtCore, QtGui -from openlp.core.common import translate, Registry, is_win, is_linux, is_macosx +from openlp.core.common import translate, is_win, is_linux, is_macosx, RegistryProperties from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.core.lib.ui import critical_error_message_box @@ -59,7 +59,7 @@ except OSError as e: log = logging.getLogger(__name__) -class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): +class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryProperties): """ Class to manage the clip selection """ @@ -681,16 +681,3 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if file.endswith('aiff'): self.media_path_combobox.addItem('/Volumes/' + volume) break - - @property - def application(self): - """ - Adds the openlp to the class dynamically. - Windows needs to access the application in a dynamic manner. - """ - if is_win(): - return Registry().get('application') - else: - if not hasattr(self, '_application'): - self._application = Registry().get('application') - return self._application From 58f517b4d62212815cd56b53e279ee10d7c0fd5c Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 8 Sep 2014 20:16:31 +0100 Subject: [PATCH 3/5] More DVD fixes --- openlp/plugins/media/forms/mediaclipselectorform.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 8ab37f6ab..5bbb4aa6a 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -264,11 +264,15 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryPropert self.application.set_normal_cursor() self.vlc_media_player.audio_set_mute(False) if not self.audio_cd: + # Temporarily disable signals + self.blockSignals(True) # Get titles, insert in combobox titles = self.vlc_media_player.video_get_title_description() self.titles_combo_box.clear() for title in titles: self.titles_combo_box.addItem(title[1].decode(), title[0]) + # Re-enable signals + self.blockSignals(False) # Main title is usually title #1 if len(titles) > 1: self.titles_combo_box.setCurrentIndex(1) @@ -415,13 +419,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryPropert self.vlc_media_player.audio_set_mute(True) # Get audio tracks audio_tracks = self.vlc_media_player.audio_get_track_description() - # Make sure we actually get the tracks, who has a DVD without audio? - loop_count = 0 - while len(audio_tracks) == 0 and loop_count < 100: - log.debug('In the audiotrack retry loop') - sleep(0.1) - audio_tracks = self.vlc_media_player.audio_get_track_description() - loop_count += 1 log.debug('number of audio tracks: %d' % len(audio_tracks)) # Clear the audio track combobox, insert new tracks self.audio_tracks_combobox.clear() From 79ef9315d568dab92b75e1e65205b760320c2ae1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 8 Sep 2014 21:49:33 +0100 Subject: [PATCH 4/5] Added a test --- .../media/forms/mediaclipselectorform.py | 15 +++++++++- .../openlp_plugins/media/__init__.py | 28 +++++++++++++++++++ .../openlp_plugins/media/forms/__init__.py | 28 +++++++++++++++++++ .../media/forms/test_mediaclipselectorform.py | 21 ++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/interfaces/openlp_plugins/media/forms/__init__.py diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 5bbb4aa6a..d63e8a8bb 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -550,7 +550,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryPropert """ Saves the current media and trackinfo as a clip to the mediamanager """ - log.debug('in on_save_button_clicked') + log.debug('in MediaClipSelectorForm.accept') start_time = self.start_position_edit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ @@ -565,10 +565,23 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryPropert path = self.media_path_combobox.currentText() optical = '' if self.audio_cd: + # Check for load problems + if start_time_ms is None or end_time_ms is None or title is None: + critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'CD not loaded correctly'), + translate('MediaPlugin.MediaClipSelectorForm', + 'The CD was not loaded correctly, please re-load and try again.')) + return optical = 'optical:%d:-1:-1:%d:%d:' % (title, start_time_ms, end_time_ms) else: audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) + # Check for load problems + if start_time_ms is None or end_time_ms is None or title is None or audio_track is None\ + or subtitle_track is None: + critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'DVD not loaded correctly'), + translate('MediaPlugin.MediaClipSelectorForm', + 'The DVD was not loaded correctly, please re-load and try again.')) + return optical = 'optical:%d:%d:%d:%d:%d:' % (title, audio_track, subtitle_track, start_time_ms, end_time_ms) # Ask for an alternative name for the mediaclip while True: diff --git a/tests/interfaces/openlp_plugins/media/__init__.py b/tests/interfaces/openlp_plugins/media/__init__.py index e69de29bb..6b241e7fc 100644 --- a/tests/interfaces/openlp_plugins/media/__init__.py +++ b/tests/interfaces/openlp_plugins/media/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### diff --git a/tests/interfaces/openlp_plugins/media/forms/__init__.py b/tests/interfaces/openlp_plugins/media/forms/__init__.py new file mode 100644 index 000000000..6b241e7fc --- /dev/null +++ b/tests/interfaces/openlp_plugins/media/forms/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index e97a06238..2346bba9c 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -60,6 +60,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): # Mock VLC so we don't actually use it self.vlc_patcher = patch('openlp.plugins.media.forms.mediaclipselectorform.vlc') self.vlc_patcher.start() + Registry().register('application', self.app) # Mock the media item self.mock_media_item = MagicMock() # create form to test @@ -67,6 +68,8 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): mock_media_state_wait = MagicMock() mock_media_state_wait.return_value = True self.form.media_state_wait = mock_media_state_wait + self.form.application.set_busy_cursor = MagicMock() + self.form.application.set_normal_cursor = MagicMock() def tearDown(self): """ @@ -155,3 +158,21 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.audio_tracks_combobox.itemData.assert_any_call(0) self.form.audio_tracks_combobox.itemData.assert_any_call(1) self.form.subtitle_tracks_combobox.itemData.assert_any_call(0) + + def click_save_button_test(self): + """ + Test that the correct function is called when save is clicked, and that it behaves as expected. + """ + # GIVEN: Mocked methods. + with patch('openlp.plugins.media.forms.mediaclipselectorform.critical_error_message_box') as \ + mocked_critical_error_message_box,\ + patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: + self.form.exec_() + + # WHEN: The save button is clicked with a NoneType in start_time_ms or end_time_ms + self.form.accept() + + # THEN: we should get an error message + mocked_critical_error_message_box.assert_called_with('DVD not loaded correctly', + 'The DVD was not loaded correctly, ' + 'please re-load and try again.') From 98c41ae5860936669ae6dd0b477236c4d68b4efe Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 8 Sep 2014 21:58:42 +0100 Subject: [PATCH 5/5] Mock device detection during test. --- .../openlp_plugins/media/forms/test_mediaclipselectorform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 2346bba9c..89810aa50 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -70,6 +70,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.media_state_wait = mock_media_state_wait self.form.application.set_busy_cursor = MagicMock() self.form.application.set_normal_cursor = MagicMock() + self.form.find_optical_devices = MagicMock() def tearDown(self): """