Fixes for DVD

bzr-revno: 2421
This commit is contained in:
Tomas Groth 2014-09-17 21:43:53 +01:00 committed by Tim Bentley
commit 5dceb1a0e6
4 changed files with 136 additions and 30 deletions

View File

@ -28,31 +28,29 @@
############################################################################### ###############################################################################
import os 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 logging
import re import re
from time import sleep from time import sleep
from datetime import datetime from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.common import translate from openlp.core.common import translate, is_win, is_linux, is_macosx, RegistryProperties
from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector
from openlp.core.lib.ui import critical_error_message_box 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: try:
from openlp.core.ui.media.vendor import vlc from openlp.core.ui.media.vendor import vlc
except (ImportError, NameError, NotImplementedError): except (ImportError, NameError, NotImplementedError):
pass pass
except OSError as e: except OSError as e:
if sys.platform.startswith('win'): if is_win():
if not isinstance(e, WindowsError) and e.winerror != 126: if not isinstance(e, WindowsError) and e.winerror != 126:
raise raise
else: else:
@ -61,7 +59,7 @@ except OSError as e:
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector, RegistryProperties):
""" """
Class to manage the clip selection Class to manage the clip selection
""" """
@ -144,9 +142,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
# You have to give the id of the QFrame (or similar object) # You have to give the id of the QFrame (or similar object)
# to vlc, different platforms have different functions for this. # to vlc, different platforms have different functions for this.
win_id = int(self.preview_frame.winId()) win_id = int(self.preview_frame.winId())
if sys.platform == "win32": if is_win():
self.vlc_media_player.set_hwnd(win_id) 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 # We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa
# framework and not the old Carbon. # framework and not the old Carbon.
self.vlc_media_player.set_nsobject(win_id) self.vlc_media_player.set_nsobject(win_id)
@ -190,7 +188,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
self.audio_cd = True self.audio_cd = True
self.titles_combo_box.setDisabled(False) self.titles_combo_box.setDisabled(False)
self.titles_combo_box.setCurrentIndex(0) self.titles_combo_box.setCurrentIndex(0)
self.on_title_combo_box_currentIndexChanged(0) self.on_titles_combo_box_currentIndexChanged(0)
return True return True
@ -203,18 +201,21 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
""" """
log.debug('on_load_disc_button_clicked') log.debug('on_load_disc_button_clicked')
self.disable_all() self.disable_all()
self.application.set_busy_cursor()
path = self.media_path_combobox.currentText() path = self.media_path_combobox.currentText()
# Check if given path is non-empty and exists before starting VLC # Check if given path is non-empty and exists before starting VLC
if not path: if not path:
log.debug('no given path') log.debug('no given path')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given')) critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given'))
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return return
if not os.path.exists(path): if not os.path.exists(path):
log.debug('Given path does not exists') log.debug('Given path does not exists')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'Given path does not exists')) 'Given path does not exists'))
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return return
# VLC behaves a bit differently on windows and linux when loading, which creates problems when trying to # 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. # 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', critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'An error happened during initialization of VLC player')) 'An error happened during initialization of VLC player'))
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return return
# put the media in the media player # put the media in the media player
self.vlc_media_player.set_media(self.vlc_media) 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', critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'VLC player failed playing the media')) 'VLC player failed playing the media'))
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
self.vlc_media_player.audio_set_mute(False)
return return
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
if not self.media_state_wait(vlc.State.Playing): if not self.media_state_wait(vlc.State.Playing):
@ -249,23 +253,32 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'VLC player failed playing the media')) 'VLC player failed playing the media'))
self.toggle_disable_load_media(False) self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
self.vlc_media_player.audio_set_mute(False)
return 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: if not self.audio_cd:
# Temporarily disable signals
self.blockSignals(True)
# Get titles, insert in combobox # Get titles, insert in combobox
titles = self.vlc_media_player.video_get_title_description() titles = self.vlc_media_player.video_get_title_description()
self.titles_combo_box.clear() self.titles_combo_box.clear()
for title in titles: for title in titles:
self.titles_combo_box.addItem(title[1].decode(), title[0]) self.titles_combo_box.addItem(title[1].decode(), title[0])
# Re-enable signals
self.blockSignals(False)
# Main title is usually title #1 # Main title is usually title #1
if len(titles) > 1: if len(titles) > 1:
self.titles_combo_box.setCurrentIndex(1) self.titles_combo_box.setCurrentIndex(1)
else:
self.titles_combo_box.setCurrentIndex(0)
# Enable audio track combobox if anything is in it # Enable audio track combobox if anything is in it
if len(titles) > 0: if len(titles) > 0:
self.titles_combo_box.setDisabled(False) 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()) log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state())
@QtCore.pyqtSlot(bool) @QtCore.pyqtSlot(bool)
@ -378,6 +391,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
if not self.vlc_media_player: if not self.vlc_media_player:
log.error('vlc_media_player was None') log.error('vlc_media_player was None')
return return
self.application.set_busy_cursor()
if self.audio_cd: if self.audio_cd:
self.vlc_media = self.audio_cd_tracks.item_at_index(index) self.vlc_media = self.audio_cd_tracks.item_at_index(index)
self.vlc_media_player.set_media(self.vlc_media) self.vlc_media_player.set_media(self.vlc_media)
@ -385,14 +399,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
self.vlc_media_player.play() self.vlc_media_player.play()
if not self.media_state_wait(vlc.State.Playing): if not self.media_state_wait(vlc.State.Playing):
log.error('Could not start playing audio cd, needed to get track info') log.error('Could not start playing audio cd, needed to get track info')
self.application.set_normal_cursor()
return return
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
# Sleep 1 second to make sure VLC has the needed metadata
sleep(1)
# pause # pause
self.vlc_media_player.set_time(0) self.vlc_media_player.set_time(0)
self.vlc_media_player.set_pause(1) self.vlc_media_player.set_pause(1)
self.vlc_media_player.audio_set_mute(False) self.vlc_media_player.audio_set_mute(False)
self.application.set_normal_cursor()
self.toggle_disable_player(False) self.toggle_disable_player(False)
else: else:
self.vlc_media_player.set_title(index) self.vlc_media_player.set_title(index)
@ -400,13 +414,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
self.vlc_media_player.play() self.vlc_media_player.play()
if not self.media_state_wait(vlc.State.Playing): if not self.media_state_wait(vlc.State.Playing):
log.error('Could not start playing dvd, needed to get track info') log.error('Could not start playing dvd, needed to get track info')
self.application.set_normal_cursor()
return return
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
# Sleep 1 second to make sure VLC has the needed metadata # Get audio tracks
sleep(1)
self.vlc_media_player.set_time(0)
# Get audio tracks, insert in combobox
audio_tracks = self.vlc_media_player.audio_get_track_description() audio_tracks = self.vlc_media_player.audio_get_track_description()
log.debug('number of audio tracks: %d' % len(audio_tracks))
# Clear the audio track combobox, insert new tracks
self.audio_tracks_combobox.clear() self.audio_tracks_combobox.clear()
for audio_track in audio_tracks: for audio_track in audio_tracks:
self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0]) self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0])
@ -447,6 +461,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
self.vlc_media_player.set_pause(1) self.vlc_media_player.set_pause(1)
loop_count += 1 loop_count += 1
log.debug('titles_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) 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) @QtCore.pyqtSlot(int)
def on_audio_tracks_combobox_currentIndexChanged(self, index): def on_audio_tracks_combobox_currentIndexChanged(self, index):
@ -535,7 +550,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
""" """
Saves the current media and trackinfo as a clip to the mediamanager 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 = self.start_position_edit.time()
start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time_ms = start_time.hour() * 60 * 60 * 1000 + \
start_time.minute() * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \
@ -550,10 +565,23 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
path = self.media_path_combobox.currentText() path = self.media_path_combobox.currentText()
optical = '' optical = ''
if self.audio_cd: 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) optical = 'optical:%d:-1:-1:%d:%d:' % (title, start_time_ms, end_time_ms)
else: else:
audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex())
subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_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) 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 # Ask for an alternative name for the mediaclip
while True: while True:
@ -595,7 +623,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
while media_state != self.vlc_media_player.get_state(): while media_state != self.vlc_media_player.get_state():
if self.vlc_media_player.get_state() == vlc.State.Error: if self.vlc_media_player.get_state() == vlc.State.Error:
return False return False
if (datetime.now() - start).seconds > 30: if (datetime.now() - start).seconds > 15:
return False return False
return True return True
@ -606,7 +634,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
""" """
# Clear list first # Clear list first
self.media_path_combobox.clear() self.media_path_combobox.clear()
if os.name == 'nt': if is_win():
# use win api to find optical drives # use win api to find optical drives
fso = Dispatch('scripting.filesystemobject') fso = Dispatch('scripting.filesystemobject')
for drive in fso.Drives: for drive in fso.Drives:
@ -614,7 +642,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
# if type is 4, it is a cd-rom drive # if type is 4, it is a cd-rom drive
if drive.DriveType == 4: if drive.DriveType == 4:
self.media_path_combobox.addItem('%s:\\' % drive.DriveLetter) 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 # Get disc devices from dbus and find the ones that are optical
bus = dbus.SystemBus() bus = dbus.SystemBus()
try: try:
@ -646,7 +674,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector):
if chr(c) != '\x00': if chr(c) != '\x00':
block_file += chr(c) block_file += chr(c)
self.media_path_combobox.addItem(block_file) 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 # Look for DVD folders in devices to find optical devices
volumes = os.listdir('/Volumes') volumes = os.listdir('/Volumes')
candidates = list() candidates = list()

View File

@ -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 #
###############################################################################

View File

@ -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 #
###############################################################################

View File

@ -60,6 +60,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin):
# Mock VLC so we don't actually use it # Mock VLC so we don't actually use it
self.vlc_patcher = patch('openlp.plugins.media.forms.mediaclipselectorform.vlc') self.vlc_patcher = patch('openlp.plugins.media.forms.mediaclipselectorform.vlc')
self.vlc_patcher.start() self.vlc_patcher.start()
Registry().register('application', self.app)
# Mock the media item # Mock the media item
self.mock_media_item = MagicMock() self.mock_media_item = MagicMock()
# create form to test # create form to test
@ -67,6 +68,9 @@ class TestMediaClipSelectorForm(TestCase, TestMixin):
mock_media_state_wait = MagicMock() mock_media_state_wait = MagicMock()
mock_media_state_wait.return_value = True mock_media_state_wait.return_value = True
self.form.media_state_wait = mock_media_state_wait 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): def tearDown(self):
""" """
@ -155,3 +159,21 @@ class TestMediaClipSelectorForm(TestCase, TestMixin):
self.form.audio_tracks_combobox.itemData.assert_any_call(0) self.form.audio_tracks_combobox.itemData.assert_any_call(0)
self.form.audio_tracks_combobox.itemData.assert_any_call(1) self.form.audio_tracks_combobox.itemData.assert_any_call(1)
self.form.subtitle_tracks_combobox.itemData.assert_any_call(0) 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.')