From edce402a60c7271d4f22a99df8ec21649176657f Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 11 Jun 2019 19:40:20 +0100 Subject: [PATCH 01/12] fix up media for breakages --- openlp/core/ui/media/__init__.py | 13 +++++++++++++ openlp/core/ui/media/mediacontroller.py | 4 ++-- openlp/core/ui/media/vlcplayer.py | 12 ------------ openlp/core/ui/servicemanager.py | 2 +- openlp/core/ui/themeform.py | 2 +- openlp/plugins/media/lib/mediaitem.py | 16 +++++++++++----- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 3c079b7d0..d63d0e9ba 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -26,6 +26,19 @@ import logging log = logging.getLogger(__name__ + '.__init__') +# Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source +AUDIO_EXT = ['*.3ga', '*.669', '*.a52', '*.aac', '*.ac3', '*.adt', '*.adts', '*.aif', '*.aifc', '*.aiff', '*.amr', + '*.aob', '*.ape', '*.awb', '*.caf', '*.dts', '*.flac', '*.it', '*.kar', '*.m4a', '*.m4b', '*.m4p', '*.m5p', + '*.mid', '*.mka', '*.mlp', '*.mod', '*.mpa', '*.mp1', '*.mp2', '*.mp3', '*.mpc', '*.mpga', '*.mus', + '*.oga', '*.ogg', '*.oma', '*.opus', '*.qcp', '*.ra', '*.rmi', '*.s3m', '*.sid', '*.spx', '*.thd', '*.tta', + '*.voc', '*.vqf', '*.w64', '*.wav', '*.wma', '*.wv', '*.xa', '*.xm'] +VIDEO_EXT = ['*.3g2', '*.3gp', '*.3gp2', '*.3gpp', '*.amv', '*.asf', '*.avi', '*.bik', '*.divx', '*.drc', '*.dv', + '*.f4v', '*.flv', '*.gvi', '*.gxf', '*.iso', '*.m1v', '*.m2v', '*.m2t', '*.m2ts', '*.m4v', '*.mkv', + '*.mov', '*.mp2', '*.mp2v', '*.mp4', '*.mp4v', '*.mpe', '*.mpeg', '*.mpeg1', '*.mpeg2', '*.mpeg4', '*.mpg', + '*.mpv2', '*.mts', '*.mtv', '*.mxf', '*.mxg', '*.nsv', '*.nuv', '*.ogg', '*.ogm', '*.ogv', '*.ogx', '*.ps', + '*.rec', '*.rm', '*.rmvb', '*.rpl', '*.thp', '*.tod', '*.ts', '*.tts', '*.txd', '*.vob', '*.vro', '*.webm', + '*.wm', '*.wmv', '*.wtv', '*.xesc', '*.nut', '*.rv', '*.xvid'] + class MediaState(object): """ diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 4938c5f39..a6281ec82 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -42,9 +42,9 @@ from openlp.core.common.settings import Settings from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui import DisplayControllerType -from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path +from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path, VIDEO_EXT, AUDIO_EXT from openlp.core.ui.media.endpoint import media_endpoint -from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT, VlcPlayer, get_vlc +from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc log = logging.getLogger(__name__) diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 244916d24..9db106e33 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -40,18 +40,6 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer log = logging.getLogger(__name__) # Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source -AUDIO_EXT = ('3ga', '669', 'a52', 'aac', 'ac3', 'adt', 'adts', 'aif', 'aifc', 'aiff', 'amr', 'aob', 'ape', 'awb', 'caf', - 'dts', 'flac', 'it', 'kar', 'm4a', 'm4b', 'm4p', 'm5p', 'mid', 'mka', 'mlp', 'mod', 'mpa', 'mp1', 'mp2', - 'mp3', 'mpc', 'mpga', 'mus', 'oga', 'ogg', 'oma', 'opus', 'qcp', 'ra', 'rmi', 's3m', 'sid', 'spx', 'thd', - 'tta', 'voc', 'vqf', 'w64', 'wav', 'wma', 'wv', 'xa', 'xm') - -VIDEO_EXT = ('3g2', '3gp', '3gp2', '3gpp', 'amv', 'asf', 'avi', 'bik', 'divx', 'drc', 'dv', 'f4v', 'flv', 'gvi', 'gxf', - 'iso', 'm1v', 'm2v', 'm2t', 'm2ts', 'm4v', 'mkv', 'mov', 'mp2', 'mp2v', 'mp4', 'mp4v', 'mpe', 'mpeg', - 'mpeg1', 'mpeg2', 'mpeg4', 'mpg', 'mpv2', 'mts', 'mtv', 'mxf', 'mxg', 'nsv', 'nuv', 'ogg', 'ogm', 'ogv', - 'ogx', 'ps', 'rec', 'rm', 'rmvb', 'rpl', 'thp', 'tod', 'ts', 'tts', 'txd', 'vob', 'vro', 'webm', 'wm', - 'wmv', 'wtv', 'xesc', - # These extensions was not in the official list, added manually. - 'nut', 'rv', 'xvid') def get_vlc(): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 77c50e43c..92b34badd 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -48,7 +48,7 @@ from openlp.core.lib.plugin import PluginStatus from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem from openlp.core.lib.ui import create_widget_action, critical_error_message_box, find_and_set_in_combo_box from openlp.core.ui.icons import UiIcons -from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT +from openlp.core.ui.media import AUDIO_EXT, VIDEO_EXT from openlp.core.ui.serviceitemeditform import ServiceItemEditForm from openlp.core.ui.servicenoteform import ServiceNoteForm from openlp.core.ui.starttimeform import StartTimeForm diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 183993500..82a71175f 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -32,7 +32,7 @@ from openlp.core.common.mixins import RegistryProperties from openlp.core.common.registry import Registry from openlp.core.lib.theme import BackgroundGradientType, BackgroundType from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media.vlcplayer import VIDEO_EXT +from openlp.core.ui.media import VIDEO_EXT from openlp.core.ui.themelayoutform import ThemeLayoutForm from openlp.core.ui.themewizard import Ui_ThemeWizard diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 30962967a..594552b4a 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -37,8 +37,8 @@ from openlp.core.lib.mediamanageritem import MediaManagerItem from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.icons import UiIcons -from openlp.core.ui.media import parse_optical_path, format_milliseconds -from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT, get_vlc +from openlp.core.ui.media import parse_optical_path, format_milliseconds, AUDIO_EXT, VIDEO_EXT +from openlp.core.ui.media.vlcplayer import get_vlc if get_vlc() is not None: @@ -232,9 +232,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ # self.populate_display_types() self.on_new_file_masks = translate('MediaPlugin.MediaItem', - 'Videos (*.{video});;Audio (*.{audio});;{files} ' - '(*)').format(video=' *.'.join(VIDEO_EXT), - audio=' *.'.join(AUDIO_EXT), + 'Videos ({video});;Audio ({audio});;{files} ' + '(*)').format(video=' '.join(VIDEO_EXT), + audio=' '.join(AUDIO_EXT), files=UiStrings().AllFiles) def on_delete_click(self): @@ -258,6 +258,12 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ # TODO needs to be fixed as no idea why this fails # media.sort(key=lambda file_path: get_natural_key(file_path.name)) + file_name = "Live Stream" + item_name = QtWidgets.QListWidgetItem(file_name) + item_name.setIcon(UiIcons().video) + item_name.setData(QtCore.Qt.UserRole, 0) + item_name.setToolTip("Live Stream feed") + self.list_view.addItem(item_name) for track in media: track_str = str(track) track_info = QtCore.QFileInfo(track_str) From 08891d8731eebd36ce6f971b51cfc0aaac03b9a4 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 11 Jun 2019 20:48:34 +0100 Subject: [PATCH 02/12] updates --- openlp/core/lib/__init__.py | 1 + openlp/core/ui/media/mediacontroller.py | 16 ++++++++++++++-- openlp/core/ui/media/vlcplayer.py | 5 +++-- openlp/plugins/media/lib/mediaitem.py | 12 ++++++++---- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 75973f389..13b7c848f 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -173,6 +173,7 @@ class ItemCapabilities(object): HasNotes = 20 HasThumbnails = 21 HasMetaData = 22 + CanStream = 23 def get_text_file_string(text_file_path): diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index a6281ec82..f0fe16b63 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -229,7 +229,10 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): display = self._define_display(controller) if controller.is_live: # if this is an optical device use special handling - if service_item.is_capable(ItemCapabilities.IsOptical): + if service_item.is_capable(ItemCapabilities.CanStream): + is_valid = self._check_file_type(controller, display) + controller.media_info.media_type = MediaType.Stream + elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and live') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) @@ -249,7 +252,10 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): controller.media_info.start_time = service_item.start_time controller.media_info.end_time = service_item.end_time elif controller.preview_display: - if service_item.is_capable(ItemCapabilities.IsOptical): + if service_item.is_capable(ItemCapabilities.CanStream): + is_valid = self._check_file_type(controller, display) + controller.media_info.media_type = MediaType.Stream + elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and preview') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) @@ -353,6 +359,12 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): :param controller: First element is the controller which should be used :param display: Which display to use """ + if controller.media_info.media_type == MediaType.Stream: + self.resize(display, self.vlc_player) + if self.vlc_player.load(display, None): + self.current_media_players[controller.controller_type] = self.vlc_player + controller.media_info.media_type = MediaType.Video + return True for file in controller.media_info.file_info: if file.is_file: suffix = '*%s' % file.suffix.lower() diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 9db106e33..b3d5d24e2 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -147,14 +147,15 @@ class VlcPlayer(MediaPlayer): Load a video into VLC :param output_display: The display where the media is - :param file: file to be played + :param file: file to be played or None for live streaming :return: """ vlc = get_vlc() log.debug('load vid in Vlc Controller') controller = output_display volume = controller.media_info.volume - path = os.path.normcase(file) + if file: + path = os.path.normcase(file) # create the media if controller.media_info.media_type == MediaType.CD: if is_win(): diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 594552b4a..4ccc55d36 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -175,7 +175,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): return False filename = str(item.data(QtCore.Qt.UserRole)) # Special handling if the filename is a optical clip - if filename.startswith('optical:'): + if filename == 'live': + service_item.processor = 'vlc' + service_item.title = filename + service_item.add_capability(ItemCapabilities.CanStream) + elif filename.startswith('optical:'): (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(filename) if not os.path.exists(name): if not remote: @@ -258,11 +262,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ # TODO needs to be fixed as no idea why this fails # media.sort(key=lambda file_path: get_natural_key(file_path.name)) - file_name = "Live Stream" + file_name = translate('MediaPlugin.MediaItem', 'Live Stream') item_name = QtWidgets.QListWidgetItem(file_name) item_name.setIcon(UiIcons().video) - item_name.setData(QtCore.Qt.UserRole, 0) - item_name.setToolTip("Live Stream feed") + item_name.setData(QtCore.Qt.UserRole, 'live') + item_name.setToolTip(translate('MediaPlugin.MediaItem', 'Show Live Stream')) self.list_view.addItem(item_name) for track in media: track_str = str(track) From 2b4842b20d55488e1a31ef07e01c5dbff84b95cc Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 12 Jun 2019 19:04:47 +0100 Subject: [PATCH 03/12] streaming works --- openlp/core/ui/media/mediacontroller.py | 12 ++++--- openlp/core/ui/media/mediatab.py | 44 ++++++++++++++++--------- openlp/core/ui/media/vlcplayer.py | 10 +++--- openlp/core/widgets/widgets.py | 4 +-- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index f0fe16b63..08e223054 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -230,7 +230,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): if controller.is_live: # if this is an optical device use special handling if service_item.is_capable(ItemCapabilities.CanStream): - is_valid = self._check_file_type(controller, display) + is_valid = self._check_file_type(controller, display, True) controller.media_info.media_type = MediaType.Stream elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and live') @@ -253,8 +253,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): controller.media_info.end_time = service_item.end_time elif controller.preview_display: if service_item.is_capable(ItemCapabilities.CanStream): - is_valid = self._check_file_type(controller, display) controller.media_info.media_type = MediaType.Stream + is_valid = self._check_file_type(controller, display, True) elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and preview') path = service_item.get_frame_path() @@ -352,19 +352,21 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): controller.media_info.media_type = MediaType.DVD return True - def _check_file_type(self, controller, display): + def _check_file_type(self, controller, display, stream=False): """ Select the correct media Player type from the prioritized Player list :param controller: First element is the controller which should be used :param display: Which display to use + :param stream: Are we streaming or not """ - if controller.media_info.media_type == MediaType.Stream: + if stream: self.resize(display, self.vlc_player) + display.media_info.media_type = MediaType.Stream if self.vlc_player.load(display, None): self.current_media_players[controller.controller_type] = self.vlc_player - controller.media_info.media_type = MediaType.Video return True + return True for file in controller.media_info.file_info: if file.is_file: suffix = '*%s' % file.suffix.lower() diff --git a/openlp/core/ui/media/mediatab.py b/openlp/core/ui/media/mediatab.py index ac4e66f42..1f3ea2c4a 100644 --- a/openlp/core/ui/media/mediatab.py +++ b/openlp/core/ui/media/mediatab.py @@ -32,10 +32,10 @@ from openlp.core.common.i18n import translate from openlp.core.common.settings import Settings from openlp.core.lib.settingstab import SettingsTab from openlp.core.ui.icons import UiIcons - -LINUX_STREAM = 'v4l2://{video} :v4l2-standard= :input-slave={audio} :live-caching=300' +#vlc v4l2:///dev/video0:v4l2-standard= :input-slave=alsa://hw:0,0 :live-caching=300 +LINUX_STREAM = 'v4l2://{video}:v4l2-standard= :input-slave=alsa://{audio} :live-caching=300' WIN_STREAM = 'dshow://:dshow-vdev={video} :dshow-adev={audio} :live-caching=300' -OSX_STREAM = 'avcapture://{video} :qtsound://{audio} :live-caching=300' +OSX_STREAM = 'avcapture://{video}:qtsound://{audio}:live-caching=300' log = logging.getLogger(__name__) @@ -68,11 +68,15 @@ class MediaTab(SettingsTab): self.left_layout.addWidget(self.live_media_group_box) self.stream_media_group_box = QtWidgets.QGroupBox(self.left_column) self.stream_media_group_box.setObjectName('stream_media_group_box') - self.stream_media_layout = QtWidgets.QHBoxLayout(self.stream_media_group_box) + self.stream_media_layout = QtWidgets.QFormLayout(self.stream_media_group_box) self.stream_media_layout.setObjectName('stream_media_layout') self.stream_media_layout.setContentsMargins(0, 0, 0, 0) - self.stream_edit = QtWidgets.QLabel(self) - self.stream_media_layout.addWidget(self.stream_edit) + self.video_edit = QtWidgets.QLineEdit(self) + self.stream_media_layout.addRow(translate('MediaPlugin.MediaTab', 'Video:'), self.video_edit) + self.audio_edit = QtWidgets.QLineEdit(self) + self.stream_media_layout.addRow(translate('MediaPlugin.MediaTab', 'Audio'), self.audio_edit) + self.stream_cmd = QtWidgets.QLabel(self) + self.stream_media_layout.addWidget(self.stream_cmd) self.left_layout.addWidget(self.stream_media_group_box) self.vlc_arguments_group_box = QtWidgets.QGroupBox(self.left_column) self.vlc_arguments_group_box.setObjectName('vlc_arguments_group_box') @@ -84,6 +88,8 @@ class MediaTab(SettingsTab): self.left_layout.addWidget(self.vlc_arguments_group_box) self.left_layout.addStretch() self.right_layout.addStretch() + self.video_edit.editingFinished.connect(self.on_field_changed) + self.audio_edit.editingFinished.connect(self.on_field_changed) # # Signals and slots def retranslate_ui(self): @@ -100,14 +106,9 @@ class MediaTab(SettingsTab): Load the settings """ self.auto_start_check_box.setChecked(Settings().value(self.settings_section + '/media auto start')) - self.stream_edit.setText(Settings().value(self.settings_section + '/stream command')) - if not self.stream_edit.text(): - if is_linux: - self.stream_edit.setText(LINUX_STREAM) - elif is_win: - self.stream_edit.setText(WIN_STREAM) - else: - self.stream_edit.setText(OSX_STREAM) + self.stream_cmd.setText(Settings().value(self.settings_section + '/stream command')) + if not self.stream_cmd.text(): + self.set_base_stream() self.vlc_arguments_edit.setPlainText(Settings().value(self.settings_section + '/vlc arguments')) if Settings().value('advanced/experimental'): for cam in QCameraInfo.availableCameras(): @@ -116,6 +117,14 @@ class MediaTab(SettingsTab): for au in QAudioDeviceInfo.availableDevices(QAudio.AudioInput): log.debug(au.deviceName()) + def set_base_stream(self): + if is_linux: + self.stream_cmd.setText(LINUX_STREAM) + elif is_win: + self.stream_cmd.setText(WIN_STREAM) + else: + self.stream_cmd.setText(OSX_STREAM) + def save(self): """ Save the settings @@ -123,9 +132,14 @@ class MediaTab(SettingsTab): setting_key = self.settings_section + '/media auto start' if Settings().value(setting_key) != self.auto_start_check_box.checkState(): Settings().setValue(setting_key, self.auto_start_check_box.checkState()) - Settings().setValue(self.settings_section + '/stream command', self.stream_edit.text()) + Settings().setValue(self.settings_section + '/stream command', self.stream_cmd.text()) Settings().setValue(self.settings_section + '/vlc arguments', self.vlc_arguments_edit.toPlainText()) + def on_field_changed(self): + self.set_base_stream() + self.stream_cmd.setText(self.stream_cmd.text().format(video=self.video_edit.text(), + audio=self.audio_edit.text())) + def post_set_up(self, post_update=False): """ Late setup for players as the MediaController has to be initialised first. diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 838457bec..eb0f3dceb 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -152,12 +152,10 @@ class VlcPlayer(MediaPlayer): """ vlc = get_vlc() log.debug('load vid in Vlc Controller') - controller = output_display - volume = controller.media_info.volume if file: path = os.path.normcase(file) # create the media - if controller.media_info.media_type == MediaType.CD: + if output_display.media_info.media_type == MediaType.CD: if is_win(): path = '/' + path output_display.vlc_media = output_display.vlc_instance.media_new_location('cdda://' + path) @@ -169,8 +167,8 @@ class VlcPlayer(MediaPlayer): audio_cd_tracks = output_display.vlc_media.subitems() if not audio_cd_tracks or audio_cd_tracks.count() < 1: return False - output_display.vlc_media = audio_cd_tracks.item_at_index(controller.media_info.title_track) - elif controller.media_info.media_type == MediaType.Stream: + output_display.vlc_media = audio_cd_tracks.item_at_index(output_display.media_info.title_track) + elif output_display.media_info.media_type == MediaType.Stream: stream_cmd = Settings().value('media/stream command') output_display.vlc_media = output_display.vlc_instance.media_new_location(stream_cmd) else: @@ -179,7 +177,7 @@ class VlcPlayer(MediaPlayer): output_display.vlc_media_player.set_media(output_display.vlc_media) # parse the metadata of the file output_display.vlc_media.parse() - self.volume(output_display, volume) + self.volume(output_display, output_display.media_info.volume) return True def media_state_wait(self, output_display, media_state): diff --git a/openlp/core/widgets/widgets.py b/openlp/core/widgets/widgets.py index fff21666e..0415d73a5 100644 --- a/openlp/core/widgets/widgets.py +++ b/openlp/core/widgets/widgets.py @@ -103,8 +103,8 @@ class ProxyWidget(QtWidgets.QGroupBox): :param QtWidgets.QRadioButton button: The button that has toggled :param bool checked: The buttons new state """ - id = self.radio_group.id(button) # The work around (see above comment) - enable_manual_edits = id == ProxyMode.MANUAL_PROXY and checked + group_id = self.radio_group.id(button) # The work around (see above comment) + enable_manual_edits = group_id == ProxyMode.MANUAL_PROXY and checked self.http_edit.setEnabled(enable_manual_edits) self.https_edit.setEnabled(enable_manual_edits) self.username_edit.setEnabled(enable_manual_edits) From 7143fbb8d151a3529858e67d5adcc912ce99eb1c Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 14 Jun 2019 18:54:04 +0100 Subject: [PATCH 04/12] Fix streaming part1 --- openlp/core/common/settings.py | 2 + openlp/core/ui/media/mediacontroller.py | 5 ++- openlp/core/ui/media/mediatab.py | 11 +++-- .../ui/media/test_mediacontroller.py | 45 ++++++++++++++++++- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index f974d949b..312afcd21 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -210,6 +210,8 @@ class Settings(QtCore.QSettings): 'media/media auto start': QtCore.Qt.Unchecked, 'media/stream command': '', 'media/vlc arguments': '', + 'media/video': '', + 'media/audio': '', 'remotes/download version': '0.0', 'players/background color': '#000000', 'servicemanager/last directory': None, diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 08e223054..588bf636e 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -184,7 +184,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): display.has_audio = False self.vlc_player.setup(display, preview) - def set_controls_visible(self, controller, value): + @staticmethod + def set_controls_visible(controller, value): """ After a new display is configured, all media related widget will be created too @@ -276,6 +277,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): # display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");') # now start playing - Preview is autoplay! autoplay = False + if service_item.is_capable(ItemCapabilities.CanStream): + autoplay = True # Preview requested if not controller.is_live: autoplay = True diff --git a/openlp/core/ui/media/mediatab.py b/openlp/core/ui/media/mediatab.py index 1f3ea2c4a..251d2e3e9 100644 --- a/openlp/core/ui/media/mediatab.py +++ b/openlp/core/ui/media/mediatab.py @@ -88,9 +88,6 @@ class MediaTab(SettingsTab): self.left_layout.addWidget(self.vlc_arguments_group_box) self.left_layout.addStretch() self.right_layout.addStretch() - self.video_edit.editingFinished.connect(self.on_field_changed) - self.audio_edit.editingFinished.connect(self.on_field_changed) - # # Signals and slots def retranslate_ui(self): """ @@ -107,10 +104,13 @@ class MediaTab(SettingsTab): """ self.auto_start_check_box.setChecked(Settings().value(self.settings_section + '/media auto start')) self.stream_cmd.setText(Settings().value(self.settings_section + '/stream command')) + self.audio_edit.setText(Settings().value(self.settings_section + '/audio')) + self.video_edit.setText(Settings().value(self.settings_section + '/video')) if not self.stream_cmd.text(): self.set_base_stream() self.vlc_arguments_edit.setPlainText(Settings().value(self.settings_section + '/vlc arguments')) if Settings().value('advanced/experimental'): + # vlc.MediaPlayer().audio_output_device_enum() for cam in QCameraInfo.availableCameras(): log.debug(cam.deviceName()) log.debug(cam.description()) @@ -134,9 +134,8 @@ class MediaTab(SettingsTab): Settings().setValue(setting_key, self.auto_start_check_box.checkState()) Settings().setValue(self.settings_section + '/stream command', self.stream_cmd.text()) Settings().setValue(self.settings_section + '/vlc arguments', self.vlc_arguments_edit.toPlainText()) - - def on_field_changed(self): - self.set_base_stream() + Settings().setValue(self.settings_section + '/video', self.video_edit.text()) + Settings().setValue(self.settings_section + '/audio', self.audio_edit.text()) self.stream_cmd.setText(self.stream_cmd.text().format(video=self.video_edit.text(), audio=self.audio_edit.text())) diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index b0e41c19c..3c8eb17f1 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -27,6 +27,7 @@ from unittest.mock import MagicMock, patch from openlp.core.common.registry import Registry from openlp.core.ui.media.mediacontroller import MediaController +from openlp.core.ui.media import ItemMediaInfo from tests.helpers.testmixin import TestMixin from tests.utils.constants import RESOURCE_PATH @@ -57,7 +58,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The player's resize method should be called correctly mocked_player.resize.assert_called_with(mocked_display) - def test_check_file_type(self): + def test_check_file_type_null(self): """ Test that we don't try to play media when no players available """ @@ -71,7 +72,47 @@ class TestMediaController(TestCase, TestMixin): ret = media_controller._check_file_type(mocked_controller, mocked_display) # THEN: it should return False - assert ret is False, '_check_file_type should return False when no mediaplayers are available.' + assert ret is False, '_check_file_type should return False when no media file matches.' + + def test_check_file_video(self): + """ + Test that we process a file that is valid + """ + # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item + media_controller = MediaController() + mocked_controller = MagicMock() + mocked_display = MagicMock() + media_controller.media_players = MagicMock() + mocked_controller.media_info = ItemMediaInfo() + mocked_controller.media_info.file_info = [TEST_PATH / 'mp3_file.mp3'] + media_controller.current_media_players = {} + media_controller.vlc_player = MagicMock() + + # WHEN: calling _check_file_type when no players exists + ret = media_controller._check_file_type(mocked_controller, mocked_display) + + # THEN: it should return False + assert ret is True, '_check_file_type should return True when audio file is present and matches.' + + def test_check_file_audio(self): + """ + Test that we process a file that is valid + """ + # GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item + media_controller = MediaController() + mocked_controller = MagicMock() + mocked_display = MagicMock() + media_controller.media_players = MagicMock() + mocked_controller.media_info = ItemMediaInfo() + mocked_controller.media_info.file_info = [TEST_PATH / 'mp4_file.mp4'] + media_controller.current_media_players = {} + media_controller.vlc_player = MagicMock() + + # WHEN: calling _check_file_type when no players exists + ret = media_controller._check_file_type(mocked_controller, mocked_display) + + # THEN: it should return False + assert ret is True, '_check_file_type should return True when media file is present and matches.' def test_media_play_msg(self): """ From 688965081e75347ccdf1bf33f1c684593472f1b6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 14 Jun 2019 20:20:29 +0100 Subject: [PATCH 05/12] Fix streaming part1 --- openlp/core/ui/media/mediatab.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/media/mediatab.py b/openlp/core/ui/media/mediatab.py index 251d2e3e9..113d1238c 100644 --- a/openlp/core/ui/media/mediatab.py +++ b/openlp/core/ui/media/mediatab.py @@ -32,10 +32,10 @@ from openlp.core.common.i18n import translate from openlp.core.common.settings import Settings from openlp.core.lib.settingstab import SettingsTab from openlp.core.ui.icons import UiIcons -#vlc v4l2:///dev/video0:v4l2-standard= :input-slave=alsa://hw:0,0 :live-caching=300 + LINUX_STREAM = 'v4l2://{video}:v4l2-standard= :input-slave=alsa://{audio} :live-caching=300' WIN_STREAM = 'dshow://:dshow-vdev={video} :dshow-adev={audio} :live-caching=300' -OSX_STREAM = 'avcapture://{video}:qtsound://{audio}:live-caching=300' +OSX_STREAM = 'avcapture://{video}:qtsound://{audio} :live-caching=300' log = logging.getLogger(__name__) From 7c7dbacb03353420b9ac0f7e017c36705299c116 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 14 Jun 2019 20:28:08 +0100 Subject: [PATCH 06/12] colon --- openlp/core/ui/media/mediatab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/media/mediatab.py b/openlp/core/ui/media/mediatab.py index 113d1238c..c844129ef 100644 --- a/openlp/core/ui/media/mediatab.py +++ b/openlp/core/ui/media/mediatab.py @@ -74,7 +74,7 @@ class MediaTab(SettingsTab): self.video_edit = QtWidgets.QLineEdit(self) self.stream_media_layout.addRow(translate('MediaPlugin.MediaTab', 'Video:'), self.video_edit) self.audio_edit = QtWidgets.QLineEdit(self) - self.stream_media_layout.addRow(translate('MediaPlugin.MediaTab', 'Audio'), self.audio_edit) + self.stream_media_layout.addRow(translate('MediaPlugin.MediaTab', 'Audio:'), self.audio_edit) self.stream_cmd = QtWidgets.QLabel(self) self.stream_media_layout.addWidget(self.stream_cmd) self.left_layout.addWidget(self.stream_media_group_box) From beb3861ae7e90b02bb6aecc35ddf2b9b07b2f512 Mon Sep 17 00:00:00 2001 From: Johnmfl Date: Tue, 18 Jun 2019 20:28:09 -0400 Subject: [PATCH 07/12] Fix #1832874 and #1832876 del temp song files add info to dup song delete form --- .../plugins/songs/forms/songreviewwidget.py | 43 ++++++++++++++----- openlp/plugins/songs/songsplugin.py | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/openlp/plugins/songs/forms/songreviewwidget.py b/openlp/plugins/songs/forms/songreviewwidget.py index 23298d849..0ead1aea3 100644 --- a/openlp/plugins/songs/forms/songreviewwidget.py +++ b/openlp/plugins/songs/forms/songreviewwidget.py @@ -25,10 +25,11 @@ A widget representing a song in the duplicate song removal wizard review page. from PyQt5 import QtCore, QtWidgets from openlp.core.ui.icons import UiIcons -from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import VerseType, db from openlp.plugins.songs.lib.openlyricsxml import SongXML + class SongReviewWidget(QtWidgets.QWidget): """ A widget representing a song on the duplicate song review page. @@ -88,52 +89,72 @@ class SongReviewWidget(QtWidgets.QWidget): self.song_alternate_title_content.setText(self.song.alternate_title) self.song_alternate_title_content.setWordWrap(True) self.song_info_form_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.song_alternate_title_content) + # Add last modified date. + self.song_last_modified_label = QtWidgets.QLabel(self) + self.song_last_modified_label.setObjectName('last_modified_label') + self.song_last_modified_label.setText('Last Modified:') + self.song_info_form_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.song_last_modified_label) + self.song_last_modified_content = QtWidgets.QLabel(self) + self.song_last_modified_content.setObjectName('last_modified_content') + self.song_last_modified_content.setText(self.song.last_modified.strftime("%Y-%m-%d %H:%M:%S")) + self.song_last_modified_content.setWordWrap(True) + self.song_info_form_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.song_last_modified_content) + # Add Theme widget. + self.song_theme_label = QtWidgets.QLabel(self) + self.song_theme_label.setObjectName('song_theme_label') + self.song_theme_label.setText('Theme:') + self.song_info_form_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.song_theme_label) + self.song_theme_content = QtWidgets.QLabel(self) + self.song_theme_content.setObjectName('song_theme_content') + self.song_theme_content.setText(self.song.theme_name) + self.song_theme_content.setWordWrap(True) + self.song_info_form_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.song_theme_content) # Add CCLI number widget. self.song_ccli_number_label = QtWidgets.QLabel(self) self.song_ccli_number_label.setObjectName('song_ccli_number_label') - self.song_info_form_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.song_ccli_number_label) + self.song_info_form_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.song_ccli_number_label) self.song_ccli_number_content = QtWidgets.QLabel(self) self.song_ccli_number_content.setObjectName('song_ccli_number_content') self.song_ccli_number_content.setText(self.song.ccli_number) self.song_ccli_number_content.setWordWrap(True) - self.song_info_form_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.song_ccli_number_content) + self.song_info_form_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.song_ccli_number_content) # Add copyright widget. self.song_copyright_label = QtWidgets.QLabel(self) self.song_copyright_label.setObjectName('song_copyright_label') - self.song_info_form_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.song_copyright_label) + self.song_info_form_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.song_copyright_label) self.song_copyright_content = QtWidgets.QLabel(self) self.song_copyright_content.setObjectName('song_copyright_content') self.song_copyright_content.setWordWrap(True) self.song_copyright_content.setText(self.song.copyright) - self.song_info_form_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.song_copyright_content) + self.song_info_form_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.song_copyright_content) # Add comments widget. self.song_comments_label = QtWidgets.QLabel(self) self.song_comments_label.setObjectName('song_comments_label') - self.song_info_form_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.song_comments_label) + self.song_info_form_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.song_comments_label) self.song_comments_content = QtWidgets.QLabel(self) self.song_comments_content.setObjectName('song_comments_content') self.song_comments_content.setText(self.song.comments) self.song_comments_content.setWordWrap(True) - self.song_info_form_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.song_comments_content) + self.song_info_form_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.song_comments_content) # Add authors widget. self.song_authors_label = QtWidgets.QLabel(self) self.song_authors_label.setObjectName('song_authors_label') - self.song_info_form_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.song_authors_label) + self.song_info_form_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.song_authors_label) self.song_authors_content = QtWidgets.QLabel(self) self.song_authors_content.setObjectName('song_authors_content') self.song_authors_content.setWordWrap(True) authors_text = ', '.join([author.display_name for author in self.song.authors]) self.song_authors_content.setText(authors_text) - self.song_info_form_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.song_authors_content) + self.song_info_form_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.song_authors_content) # Add verse order widget. self.song_verse_order_label = QtWidgets.QLabel(self) self.song_verse_order_label.setObjectName('song_verse_order_label') - self.song_info_form_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.song_verse_order_label) + self.song_info_form_layout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.song_verse_order_label) self.song_verse_order_content = QtWidgets.QLabel(self) self.song_verse_order_content.setObjectName('song_verse_order_content') self.song_verse_order_content.setText(self.song.verse_order) self.song_verse_order_content.setWordWrap(True) - self.song_info_form_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.song_verse_order_content) + self.song_info_form_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.song_verse_order_content) self.song_group_box_layout.addLayout(self.song_info_form_layout) # Add verses widget. self.song_info_verse_list_widget = QtWidgets.QTableWidget(self.song_group_box) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index f9a1fd2f8..f84e7fd44 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -423,7 +423,7 @@ class SongsPlugin(Plugin): """ Remove temporary songs from the database """ - songs = self.manager.get_all_objects(Song, Song.temporary is True) + songs = self.manager.get_all_objects(Song, Song.temporary == True) for song in songs: self.manager.delete_object(Song, song.id) From 64b7a1347bf03cbd2371a1e90132f923a275a16d Mon Sep 17 00:00:00 2001 From: Johnmfl Date: Wed, 19 Jun 2019 16:31:46 -0400 Subject: [PATCH 08/12] Fixed Lint errors --- openlp/plugins/songs/forms/songreviewwidget.py | 3 +-- openlp/plugins/songs/songsplugin.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/forms/songreviewwidget.py b/openlp/plugins/songs/forms/songreviewwidget.py index 0ead1aea3..61bc71952 100644 --- a/openlp/plugins/songs/forms/songreviewwidget.py +++ b/openlp/plugins/songs/forms/songreviewwidget.py @@ -25,11 +25,10 @@ A widget representing a song in the duplicate song removal wizard review page. from PyQt5 import QtCore, QtWidgets from openlp.core.ui.icons import UiIcons -from openlp.plugins.songs.lib import VerseType, db +from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.openlyricsxml import SongXML - class SongReviewWidget(QtWidgets.QWidget): """ A widget representing a song on the duplicate song review page. diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index f84e7fd44..69d9783e0 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -423,7 +423,7 @@ class SongsPlugin(Plugin): """ Remove temporary songs from the database """ - songs = self.manager.get_all_objects(Song, Song.temporary == True) + songs = self.manager.get_all_objects(Song, Song.temporary == True) # noqa: E712 for song in songs: self.manager.delete_object(Song, song.id) From 865ac820d3103a9919495f2207dceb56c7df9039 Mon Sep 17 00:00:00 2001 From: Johnmfl Date: Wed, 19 Jun 2019 16:52:50 -0400 Subject: [PATCH 09/12] added space to Fix Lint errors --- openlp/plugins/songs/songsplugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 69d9783e0..fdeacdd3f 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -423,7 +423,7 @@ class SongsPlugin(Plugin): """ Remove temporary songs from the database """ - songs = self.manager.get_all_objects(Song, Song.temporary == True) # noqa: E712 + songs = self.manager.get_all_objects(Song, Song.temporary == True) # noqa: E712 for song in songs: self.manager.delete_object(Song, song.id) From 5b571c4f74781a1e6c86ee22e743e153be729a13 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 21 Jun 2019 21:53:42 +0100 Subject: [PATCH 10/12] Fixes for path issues --- openlp/core/common/json.py | 17 ++++++++++---- openlp/core/common/settings.py | 2 +- openlp/core/display/html/display.js | 22 ++++--------------- openlp/core/display/window.py | 4 ++-- openlp/core/lib/theme.py | 9 ++++---- openlp/core/ui/media/mediacontroller.py | 2 +- .../lib/presentationcontroller.py | 2 +- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/openlp/core/common/json.py b/openlp/core/common/json.py index 4a54e41b3..c323479e6 100644 --- a/openlp/core/common/json.py +++ b/openlp/core/common/json.py @@ -111,6 +111,8 @@ class OpenLPJSONDecoder(JSONDecoder): :param dict obj: A decoded JSON object :return: The custom object from the serialized data if the custom object is registered, else obj """ + if '__Path__' in obj: + return PathSerializer.encode_json(obj, **self.kwargs) try: key = obj['json_meta']['class'] except KeyError: @@ -150,8 +152,8 @@ class OpenLPJSONEncoder(JSONEncoder): if isinstance(obj, JSONMixin): return obj.json_object() elif obj.__class__.__name__ in _registered_classes: - return _registered_classes[obj.__class__.__name__].json_object(obj) - return super().default(obj) + return _registered_classes[obj.__class__.__name__].json_object(obj, **self.kwargs) + return super().default(obj, **self.kwargs) def is_serializable(obj): @@ -174,17 +176,22 @@ class PathSerializer(JSONMixin, register_names=('Path', 'PosixPath', 'WindowsPat :param kwargs: Contains any extra parameters. Not used! :return Path: The deserialized Path object """ - path = Path(*obj['parts']) + if '__Path__' in obj: + parts = obj['__Path__'] + else: + parts = obj['parts'] + path = Path(*parts) if base_path and not path.is_absolute(): return base_path / path return path @classmethod - def json_object(cls, obj, base_path=None, **kwargs): + def json_object(cls, obj, base_path=None, js_use=False, **kwargs): """ Create a dictionary that can be JSON decoded. :param Path base_path: If specified, an absolute path to make a relative path from. + :param bool js_use: Encode the path as a uri. For example for use in the js rendering code. :param kwargs: Contains any extra parameters. Not used! :return: The dictionary representation of this Path object. :rtype: dict[tuple] @@ -193,6 +200,8 @@ class PathSerializer(JSONMixin, register_names=('Path', 'PosixPath', 'WindowsPat if base_path: with suppress(ValueError): path = path.relative_to(base_path) + if js_use is True: + return path.as_uri() json_dict = {'parts': path.parts} cls.attach_meta(json_dict) return json_dict diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 312afcd21..6fbb8a8ed 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -612,7 +612,7 @@ class Settings(QtCore.QSettings): elif isinstance(default_value, dict): return {} elif isinstance(setting, str): - if 'json_meta' in setting or setting.startswith('{'): + if 'json_meta' in setting or '__Path__' in setting or setting.startswith('{'): return json.loads(setting, cls=OpenLPJSONDecoder) # Convert the setting to the correct type. if isinstance(default_value, bool): diff --git a/openlp/core/display/html/display.js b/openlp/core/display/html/display.js index 02980a393..e198eeee6 100644 --- a/openlp/core/display/html/display.js +++ b/openlp/core/display/html/display.js @@ -117,20 +117,6 @@ function _prepareText(text) { return "

" + _nl2br(text) + "

"; } -/** - * The paths we get are JSON versions of Python Path objects, so let's just fix that. - * @private - * @param {object} path - The Path object - * @returns {string} The actual file path - */ -function _pathToString(path) { - var filename = path.__Path__.join("/").replace("//", "/"); - if (!filename.startsWith("/")) { - filename = "/" + filename; - } - return filename; -} - /** * An audio player with a play list */ @@ -676,13 +662,13 @@ var Display = { } break; case BackgroundType.Image: - background_filename = _pathToString(theme.background_filename); - backgroundStyle["background-image"] = "url('file://" + background_filename + "')"; + backgroundStyle["background-image"] = "url('" + theme.background_filename + "')"; + console.warn(backgroundStyle["background-image"]); break; case BackgroundType.Video: - background_filename = _pathToString(theme.background_filename); backgroundStyle["background-color"] = theme.background_border_color; - backgroundHtml = ""; + backgroundHtml = ""; + console.warn(backgroundHtml); break; default: backgroundStyle["background"] = "#000"; diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py index c8d99fd22..e18437a4a 100644 --- a/openlp/core/display/window.py +++ b/openlp/core/display/window.py @@ -332,9 +332,9 @@ class DisplayWindow(QtWidgets.QWidget): theme_copy = copy.deepcopy(theme) theme_copy.background_type = 'image' theme_copy.background_filename = self.checkerboard_path - exported_theme = theme_copy.export_theme() + exported_theme = theme_copy.export_theme(js_use=True) else: - exported_theme = theme.export_theme() + exported_theme = theme.export_theme(js_use=True) self.run_javascript('Display.setTheme({theme});'.format(theme=exported_theme)) def get_video_types(self): diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index d5219a5d1..af40809bd 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -225,17 +225,18 @@ class Theme(object): jsn = json.loads(theme, cls=OpenLPJSONDecoder) self.expand_json(jsn) - def export_theme(self, theme_path=None): + def export_theme(self, theme_path=None, js_use=False): """ Loop through the fields and build a dictionary of them + :param pathlib.Path | None theme_path: + :param bool js_use: For internal use, for example with the theme js code. + :return str: The json encoded theme object """ theme_data = {} for attr, value in self.__dict__.items(): theme_data["{attr}".format(attr=attr)] = value - if theme_path: - return json.dumps(theme_data, cls=OpenLPJSONEncoder, base_path=theme_path) - return json.dumps(theme_data, cls=OpenLPJSONEncoder) + return json.dumps(theme_data, cls=OpenLPJSONEncoder, base_path=theme_path, js_use=js_use) def parse(self, xml): """ diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 588bf636e..1c3534565 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -372,7 +372,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): return True for file in controller.media_info.file_info: if file.is_file: - suffix = '*%s' % file.suffix.lower() + suffix = file.suffix.lower()[1:] file = str(file) if suffix in VIDEO_EXT: if not controller.media_info.is_background or controller.media_info.is_background and \ diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index fa0284cea..160b68ac1 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -129,7 +129,7 @@ class PresentationDocument(object): thumbnail_folder_path = self.get_thumbnail_folder() temp_folder_path = self.get_temp_folder() if thumbnail_folder_path.exists(): - thumbnail_folder_path.rmtree() + shutil.rmtree(thumbnail_folder_path) if temp_folder_path.exists(): shutil.rmtree(temp_folder_path) except OSError: From 3e2e2727768079fcaa15b6aec6289a83d9369429 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 21 Jun 2019 22:09:28 +0100 Subject: [PATCH 11/12] revert suffix stuff --- openlp/core/ui/media/mediacontroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 1c3534565..588bf636e 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -372,7 +372,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): return True for file in controller.media_info.file_info: if file.is_file: - suffix = file.suffix.lower()[1:] + suffix = '*%s' % file.suffix.lower() file = str(file) if suffix in VIDEO_EXT: if not controller.media_info.is_background or controller.media_info.is_background and \ From a432a574520b64f37b05d4588aca8ac813a626cd Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 21 Jun 2019 23:09:36 +0100 Subject: [PATCH 12/12] rename param js_use to is_js --- openlp/core/common/json.py | 6 +++--- openlp/core/display/window.py | 4 ++-- openlp/core/lib/theme.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openlp/core/common/json.py b/openlp/core/common/json.py index c323479e6..06a6f9eac 100644 --- a/openlp/core/common/json.py +++ b/openlp/core/common/json.py @@ -186,12 +186,12 @@ class PathSerializer(JSONMixin, register_names=('Path', 'PosixPath', 'WindowsPat return path @classmethod - def json_object(cls, obj, base_path=None, js_use=False, **kwargs): + def json_object(cls, obj, base_path=None, is_js=False, **kwargs): """ Create a dictionary that can be JSON decoded. :param Path base_path: If specified, an absolute path to make a relative path from. - :param bool js_use: Encode the path as a uri. For example for use in the js rendering code. + :param bool is_js: Encode the path as a uri. For example for use in the js rendering code. :param kwargs: Contains any extra parameters. Not used! :return: The dictionary representation of this Path object. :rtype: dict[tuple] @@ -200,7 +200,7 @@ class PathSerializer(JSONMixin, register_names=('Path', 'PosixPath', 'WindowsPat if base_path: with suppress(ValueError): path = path.relative_to(base_path) - if js_use is True: + if is_js is True: return path.as_uri() json_dict = {'parts': path.parts} cls.attach_meta(json_dict) diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py index e18437a4a..393b6ccce 100644 --- a/openlp/core/display/window.py +++ b/openlp/core/display/window.py @@ -332,9 +332,9 @@ class DisplayWindow(QtWidgets.QWidget): theme_copy = copy.deepcopy(theme) theme_copy.background_type = 'image' theme_copy.background_filename = self.checkerboard_path - exported_theme = theme_copy.export_theme(js_use=True) + exported_theme = theme_copy.export_theme(is_js=True) else: - exported_theme = theme.export_theme(js_use=True) + exported_theme = theme.export_theme(is_js=True) self.run_javascript('Display.setTheme({theme});'.format(theme=exported_theme)) def get_video_types(self): diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index af40809bd..bc5ba69b8 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -225,18 +225,18 @@ class Theme(object): jsn = json.loads(theme, cls=OpenLPJSONDecoder) self.expand_json(jsn) - def export_theme(self, theme_path=None, js_use=False): + def export_theme(self, theme_path=None, is_js=False): """ Loop through the fields and build a dictionary of them :param pathlib.Path | None theme_path: - :param bool js_use: For internal use, for example with the theme js code. + :param bool is_js: For internal use, for example with the theme js code. :return str: The json encoded theme object """ theme_data = {} for attr, value in self.__dict__.items(): theme_data["{attr}".format(attr=attr)] = value - return json.dumps(theme_data, cls=OpenLPJSONEncoder, base_path=theme_path, js_use=js_use) + return json.dumps(theme_data, cls=OpenLPJSONEncoder, base_path=theme_path, is_js=is_js) def parse(self, xml): """