From 6d21a326edd01f7568456049cebd095541b0c280 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 17 Feb 2014 23:29:52 +0100 Subject: [PATCH] Made it possible to save a selected clip to the mediamanager. --- .../media/forms/mediaclipselectorform.py | 124 +++++++++++++++--- openlp/plugins/media/lib/mediaitem.py | 48 +++++-- resources/images/media_optical.png | Bin 0 -> 2056 bytes resources/images/openlp-2.qrc | 1 + 4 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 resources/images/media_optical.png diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 6f7f22c57..688d879d4 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -35,6 +35,7 @@ import time from PyQt4 import QtCore, QtGui from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector +from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media.vendor import vlc log = logging.getLogger(__name__) @@ -59,9 +60,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) # most actions auto-connect due to the functions name, so only a few left to do self.close_pushbutton.clicked.connect(self.reject) - #self.load_disc_pushbutton.clicked.connect(self.on_load_disc_pushbutton_clicked) - #self.pause_pushbutton.clicked.connect(self.on_pause_pushbutton_clicked) - #self.play_pushbutton.clicked.connect(self.on_play_pushbutton_clicked) def reject(self): """ @@ -72,10 +70,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): QtGui.QDialog.reject(self) def exec_(self): + """ + Start dialog + """ self.setup_vlc() return QtGui.QDialog.exec_(self) def setup_vlc(self): + """ + Setup VLC instance and mediaplayer + """ self.vlc_instance = vlc.Instance() # creating an empty vlc media player self.vlc_media_player = self.vlc_instance.media_player_new() @@ -102,17 +106,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(bool) def on_load_disc_pushbutton_clicked(self, clicked): + """ + Load the media when the load-button has been clicked + """ self.disable_all() path = self.media_path_combobox.currentText() if path == '': - print('no given path') - # TODO: Error message + log.debug('no given path') + critical_error_message_box('Error', 'No path was given') self.toggle_disable_load_media(False) return self.vlc_media = self.vlc_instance.media_new_path(path) if not self.vlc_media: - print('media player is none') - # TODO: Error message + log.debug('vlc media player is none') + critical_error_message_box('Error', 'An error happened during initialization of VLC player') self.toggle_disable_load_media(False) return # put the media in the media player @@ -120,14 +127,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.audio_set_mute(True) # start playback to get vlc to parse the media if self.vlc_media_player.play() < 0: - print('play returned error') - # TODO: Error message + log.debug('vlc play returned error') + critical_error_message_box('Error', 'An error happen when starting VLC player') self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) while self.vlc_media_player.get_time() == 0: if self.vlc_media_player.get_state() == vlc.State.Error: - print('player in error state') + log.debug('player in error state') self.toggle_disable_load_media(False) return time.sleep(0.1) @@ -148,25 +155,45 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.title_combo_box.setDisabled(False) self.toggle_disable_load_media(False) - def on_pause_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_pause_pushbutton_clicked(self, clicked): + """ + Pause the playback + """ self.vlc_media_player.pause() - def on_play_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_play_pushbutton_clicked(self, clicked): + """ + Start the playback + """ self.vlc_media_player.play() - def on_set_start_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_set_start_pushbutton_clicked(self, clicked): + """ + Copy the current player position to start_timeedit + """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.start_timeedit.setTime(new_pos_time) - def on_set_end_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_set_end_pushbutton_clicked(self, clicked): + """ + Copy the current player position to end_timeedit + """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.end_timeedit.setTime(new_pos_time) - def on_jump_end_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_jump_end_pushbutton_clicked(self, clicked): + """ + Set the player position to the position stored in end_timeedit + """ end_time = self.end_timeedit.time() end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ end_time.minute() * 60 * 1000 + \ @@ -174,7 +201,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): end_time.msec() self.vlc_media_player.set_time(end_time_ms) - def on_jump_start_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_jump_start_pushbutton_clicked(self, clicked): + """ + Set the player position to the position stored in start_timeedit + """ start_time = self.start_timeedit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ @@ -184,12 +215,18 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(int) def on_title_combo_box_currentIndexChanged(self, index): - print('in on_title_combo_box_changed, index: ', str(index)) + """ + When a new title is chosen, it is loaded by VLC and info about audio and subtitle tracks is reloaded + """ + log.debug('in on_title_combo_box_changed, index: ', str(index)) self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() self.vlc_media_player.audio_set_mute(True) while self.vlc_media_player.get_time() == 0: + if self.vlc_media_player.get_state() == vlc.State.Error: + log.debug('player in error state') + return time.sleep(0.1) # pause self.vlc_media_player.pause() @@ -225,25 +262,36 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): + """ + When a new audio track is chosen update audio track bing played by VLC + """ audio_track = self.audio_tracks_combobox.itemData(index) - print('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) + log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) if audio_track and int(audio_track) > 0: self.vlc_media_player.audio_set_track(int(audio_track)) @QtCore.pyqtSlot(int) def on_subtitle_tracks_combobox_currentIndexChanged(self, index): + """ + When a new subtitle track is chosen update subtitle track bing played by VLC + """ subtitle_track = self.subtitle_tracks_combobox.itemData(index) - print('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) + log.debug('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) if subtitle_track: self.vlc_media_player.video_set_spu(int(subtitle_track)) def on_position_horizontalslider_sliderMoved(self, position): + """ + Set player position according to new slider position. + """ self.vlc_media_player.set_time(position) def update_position(self): + """ + Update slider position and displayed time according to VLC player position. + """ if self.vlc_media_player: vlc_ms_pos = self.vlc_media_player.get_time() - #print('in update_position, time: ', vlc_ms_pos) rounded_vlc_ms_pos = int(round(vlc_ms_pos / 100.0) * 100.0) time = QtCore.QTime() new_pos_time = time.addMSecs(rounded_vlc_ms_pos) @@ -251,6 +299,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.position_horizontalslider.setSliderPosition(vlc_ms_pos) def disable_all(self): + """ + Disable all elements in the dialog + """ self.toggle_disable_load_media(True) self.title_combo_box.setDisabled(True) self.audio_tracks_combobox.setDisabled(True) @@ -258,10 +309,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_player(True) def toggle_disable_load_media(self, action): + """ + Enable/disable load media combobox and button. + + @param action: If True elements are disabled, if False they are enabled. + """ self.media_path_combobox.setDisabled(action) self.load_disc_pushbutton.setDisabled(action) def toggle_disable_player(self, action): + """ + Enable/disable player elementa. + + @param action: If True elements are disabled, if False they are enabled. + """ self.play_pushbutton.setDisabled(action) self.pause_pushbutton.setDisabled(action) self.position_horizontalslider.setDisabled(action) @@ -274,3 +335,26 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.jump_end_pushbutton.setDisabled(action) self.preview_pushbutton.setDisabled(action) self.save_pushbutton.setDisabled(action) + + @QtCore.pyqtSlot(bool) + def on_save_pushbutton_clicked(self, checked): + """ + Saves the current media and trackinfo as a clip to the mediamanager + """ + log.debug('in on_save_pushbutton_clicked') + start_time = self.start_timeedit.time() + start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ + start_time.minute() * 60 * 1000 + \ + start_time.second() * 1000 + \ + start_time.msec() + end_time = self.end_timeedit.time() + end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ + end_time.minute() * 60 * 1000 + \ + end_time.second() * 1000 + \ + end_time.msec() + title = self.title_combo_box.itemData(self.title_combo_box.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()) + path = self.media_path_combobox.currentText() + optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path + self.media_item.add_optical_clip(optical) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 58dec0dac..33b983dad 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -40,6 +40,7 @@ from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players from openlp.core.utils import get_locale_key from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm +from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE @@ -49,7 +50,7 @@ log = logging.getLogger(__name__) CLAPPERBOARD = ':/media/slidecontroller_multimedia.png' VIDEO_ICON = build_icon(':/media/media_video.png') AUDIO_ICON = build_icon(':/media/media_audio.png') -DVD_ICON = build_icon(':/media/media_video.png') +OPTICAL_ICON = build_icon(':/media/media_optical.png') ERROR_ICON = build_icon(':/general/general_delete.png') @@ -111,13 +112,18 @@ class MediaMediaItem(MediaManagerItem): MediaManagerItem.add_list_view_to_toolbar(self) self.list_view.addAction(self.replace_action) + def add_start_header_bar(self): + self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load optical disc', + tooltip='Load optical disc', triggers=self.on_load_optical) + if not VLC_AVAILABLE: + self.load_optical.setDisabled(True) + def add_end_header_bar(self): # Replace backgrounds do not work at present so remove functionality. self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_blank.png', triggers=self.onReplaceClick) self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png', visible=False, triggers=self.onResetClick) - self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=':/songs/song_maintenance.png', triggers=self.on_load_optical) self.media_widget = QtGui.QWidget(self) self.media_widget.setObjectName('media_widget') self.display_layout = QtGui.QFormLayout(self.media_widget) @@ -269,15 +275,23 @@ class MediaMediaItem(MediaManagerItem): Settings().setValue(self.settings_section + '/media files', self.get_file_list()) def load_list(self, media, target_group=None): - # Sort the media by its filename considering language specific characters. + # Sort the media by its filename considering language specific characters. media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1])) for track in media: track_info = QtCore.QFileInfo(track) - if not os.path.exists(track): + if track.startswith('optical:'): + (filename, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(track) + optical = filename + '@' + str(title) + ':' + str(start) + '-' + str(end) + item_name = QtGui.QListWidgetItem(optical) + item_name.setIcon(build_icon(OPTICAL_ICON)) + item_name.setData(QtCore.Qt.UserRole, track) + item_name.setToolTip(optical) + elif not os.path.exists(track): filename = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(filename) item_name.setIcon(ERROR_ICON) item_name.setData(QtCore.Qt.UserRole, track) + item_name.setToolTip(track) elif track_info.isFile(): filename = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(filename) @@ -286,12 +300,7 @@ class MediaMediaItem(MediaManagerItem): else: item_name.setIcon(VIDEO_ICON) item_name.setData(QtCore.Qt.UserRole, track) - else: - filename = os.path.split(str(track))[1] - item_name = QtGui.QListWidgetItem(filename) - item_name.setIcon(build_icon(DVD_ICON)) - item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(track) + item_name.setToolTip(track) self.list_view.addItem(item_name) def get_list(self, type=MediaType.Audio): @@ -319,3 +328,22 @@ class MediaMediaItem(MediaManagerItem): def on_load_optical(self): log.debug('in on_load_optical') self.media_clip_selector_form.exec_() + + def parse_optical_path(self, input): + # split the clip info + clip_info = input.split(sep=':') + title = int(clip_info[1]) + audio_track = int(clip_info[2]) + subtitle_track = int(clip_info[3]) + start = float(clip_info[4]) + end = float(clip_info[5]) + filename = clip_info[6] + if len(clip_info) > 7: + filename += clip_info[7] + return filename, title, audio_track, subtitle_track, start, end + + def add_optical_clip(self, optical): + full_list = self.get_file_list() + full_list.append(optical) + self.load_list([optical]) + Settings().setValue(self.settings_section + '/media files', self.get_file_list()) diff --git a/resources/images/media_optical.png b/resources/images/media_optical.png new file mode 100644 index 0000000000000000000000000000000000000000..033b9847299474a3e3d6f6076a5c1b874b070705 GIT binary patch literal 2056 zcmV+j2>17iP)Px#32;bRa{vGa>;M1;>;WEiI5hwO00(qQO+^RU1qTr>5T}NKfdBvi24YJ`L;(K) z{{a7>y{D4^00)RkL_t(|+SQg>ZyVK{1&_RH!W@79Q@Dj!LN=z{lA==;c}eK2T@Ex5;JNvnnf&@Lo&I5 zOs0s1g^F4#tstJr(lzqJjNbe!cCXH8{m%t_+HwDTBctY&(-nnZh^fI~9N{ntkTU!5 zL}CHybP>5+8HGXxi;GoMDyvvsU03V%2Bc^_Gcm3E{+XZv_K&xFhtG{@{otK3)$LW_ z54;J!jHRU&tgO_rw${ML#wND6chuF@8f?7t1NO|8mX_0rcrtSDw$o*U!7ix=dmJ7i zfk2SK(VYQ1iI=){k7yrw9g(YDly|jPMAG z0a!?YAm$KNUJtL;)(_x2JG+PATU$GHeoL)XmNBb0zr)SDju$c4KUR@=y($G~5RI51 z%XY*RH$+*2J&=c-C?cIb4!(i)^-Tt0aDpC!)9#SCC&QtNC1k%8^4pUm!76G#Z;KrTtj= zT8+WiP^~i2HFc@7yn6`#`R#|_antT2t`KB*7;&$Nls}A|Cy1iYjbf5Vspvte6oC*? z5Q-*h)#}Q#&CShr+If4ew)U)8EY{Z6)(+r}Mib65#cWB}QU+EbhGXcy-}mhU0sRBx z7b2k~A^`=lpn^mwhBQS^jG+*TVks0xHSR?&X{AhvK>&ZJxI}TC;u^&#>|CX?NIhS}mqcTfM-0|C7c2Yy&Cudoy|C_x%5n4j71*-U5kr{CLZp|D8STFf^Zjk^Fo zqWGAmT(1<8^L}>_2|1|7V;tnD0ilo{Ucm$>=YrkngGJ|oVaA222^&7S^7-3`reQ8u z*rl|q^j2dvKMZfaQfZXcb-Pc7 z-y>4E;PX-jyc2M`#$e;0!aO$y{j?c3KkNCk=C~y*iFGQ0dLq0+@KW`t&n1EfXvlaX z@Hs+o+5B+YdCc=O;2qDX{!GBIIyBtX&>XwIb%U~C`e}WA<4o}8cqN|;5`3;OTwDN- zIWIV)3l^gl7V{*`<`HOT`|-t>SKib7;n`7sb0)a2sZh@XZw?s``P@Npix)P73v;s$ z7^m&fO`D*fouJOYbyIVi;4xND$XLVdvJ8Q)hHQ4C5zB)8KCEn?I(sAkXjdwNw mt97oc>y6j^;9S?4p7}2y|J`56Sngr~0000media_stop.png media_audio.png media_video.png + media_optical.png slidecontroller_multimedia.png auto-start_active.png auto-start_inactive.png