forked from openlp/openlp
parent
13f47d2a92
commit
867779da43
@ -34,6 +34,7 @@ class Poller(RegistryProperties):
|
|||||||
|
|
||||||
def raw_poll(self):
|
def raw_poll(self):
|
||||||
return {
|
return {
|
||||||
|
'counter': self.live_controller.slide_count if self.live_controller.slide_count else 0,
|
||||||
'service': self.service_manager.service_id,
|
'service': self.service_manager.service_id,
|
||||||
'slide': self.live_controller.selected_row or 0,
|
'slide': self.live_controller.selected_row or 0,
|
||||||
'item': self.live_controller.service_item.unique_identifier if self.live_controller.service_item else '',
|
'item': self.live_controller.service_item.unique_identifier if self.live_controller.service_item else '',
|
||||||
|
@ -33,6 +33,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
@service_views.route('/items')
|
@service_views.route('/items')
|
||||||
def service_items():
|
def service_items():
|
||||||
|
log.debug('service/v2/items')
|
||||||
live_controller = Registry().get('live_controller')
|
live_controller = Registry().get('live_controller')
|
||||||
service_items = []
|
service_items = []
|
||||||
if live_controller.service_item:
|
if live_controller.service_item:
|
||||||
@ -61,6 +62,7 @@ def service_items():
|
|||||||
@service_views.route('/show/<item_id>', methods=['POST'])
|
@service_views.route('/show/<item_id>', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def service_set(item_id=None):
|
def service_set(item_id=None):
|
||||||
|
log.debug('service/v2/show')
|
||||||
data = request.json
|
data = request.json
|
||||||
item_id = item_id or data.get('id') or data.get('uid')
|
item_id = item_id or data.get('id') or data.get('uid')
|
||||||
if not item_id:
|
if not item_id:
|
||||||
@ -81,6 +83,7 @@ def service_set(item_id=None):
|
|||||||
@service_views.route('/progress', methods=['POST'])
|
@service_views.route('/progress', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def service_direction():
|
def service_direction():
|
||||||
|
log.debug('service/v2/progress')
|
||||||
ALLOWED_ACTIONS = ['next', 'previous']
|
ALLOWED_ACTIONS = ['next', 'previous']
|
||||||
data = request.json
|
data = request.json
|
||||||
if not data:
|
if not data:
|
||||||
@ -97,5 +100,6 @@ def service_direction():
|
|||||||
@service_views.route('/new', methods=['GET'])
|
@service_views.route('/new', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def new_service():
|
def new_service():
|
||||||
|
log.debug('service/v2/new')
|
||||||
getattr(Registry().get('service_manager'), 'servicemanager_new_file').emit()
|
getattr(Registry().get('service_manager'), 'servicemanager_new_file').emit()
|
||||||
return '', 204
|
return '', 204
|
||||||
|
@ -31,7 +31,6 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from logging.handlers import RotatingFileHandler
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import copytree
|
from shutil import copytree
|
||||||
from traceback import format_exception
|
from traceback import format_exception
|
||||||
@ -307,7 +306,7 @@ def set_up_logging(log_path):
|
|||||||
"""
|
"""
|
||||||
create_paths(log_path, do_not_log=True)
|
create_paths(log_path, do_not_log=True)
|
||||||
file_path = log_path / 'openlp.log'
|
file_path = log_path / 'openlp.log'
|
||||||
logfile = RotatingFileHandler(str(file_path), 'w', encoding='UTF-8', backupCount=2)
|
logfile = logging.FileHandler(file_path, 'w', encoding='UTF-8')
|
||||||
logfile.setFormatter(logging.Formatter('%(asctime)s %(threadName)s %(name)-55s %(levelname)-8s %(message)s'))
|
logfile.setFormatter(logging.Formatter('%(asctime)s %(threadName)s %(name)-55s %(levelname)-8s %(message)s'))
|
||||||
log.addHandler(logfile)
|
log.addHandler(logfile)
|
||||||
if log.isEnabledFor(logging.DEBUG):
|
if log.isEnabledFor(logging.DEBUG):
|
||||||
|
@ -29,7 +29,7 @@ from openlp.core.common.registry import Registry
|
|||||||
|
|
||||||
|
|
||||||
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed',
|
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed',
|
||||||
'preview_size_changed', 'resizeEvent', 'eventFilter']
|
'preview_size_changed', 'resizeEvent', 'eventFilter', 'tick']
|
||||||
|
|
||||||
|
|
||||||
class LogMixin(object):
|
class LogMixin(object):
|
||||||
|
@ -1001,8 +1001,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
|||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
# if a warning has been shown within the last 5 seconds, skip showing again to avoid spamming user,
|
# if a warning has been shown within the last 5 seconds, skip showing again to avoid spamming user,
|
||||||
# also do not show if the settings window is visible
|
# also do not show if the settings window is visible
|
||||||
if not self.settings_form.isVisible() and \
|
if not self.settings_form.isVisible() and not self.screen_change_timestamp or \
|
||||||
not self.screen_change_timestamp or (datetime.now() - self.screen_change_timestamp).seconds > 5:
|
self.screen_change_timestamp and (datetime.now() - self.screen_change_timestamp).seconds > 5:
|
||||||
QtWidgets.QMessageBox.warning(self, translate('OpenLP.MainWindow', 'Screen setup has changed'),
|
QtWidgets.QMessageBox.warning(self, translate('OpenLP.MainWindow', 'Screen setup has changed'),
|
||||||
translate('OpenLP.MainWindow',
|
translate('OpenLP.MainWindow',
|
||||||
'The screen setup has changed. '
|
'The screen setup has changed. '
|
||||||
|
@ -56,6 +56,11 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
The implementation of the Media Controller which manages how media is played.
|
The implementation of the Media Controller which manages how media is played.
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
super(MediaController, self).__init__(parent)
|
||||||
|
self.log_info('MediaController Initialising')
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.vlc_player = None
|
self.vlc_player = None
|
||||||
@ -66,8 +71,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
self.preview_timer = QtCore.QTimer()
|
self.preview_timer = QtCore.QTimer()
|
||||||
self.preview_timer.setInterval(TICK_TIME)
|
self.preview_timer.setInterval(TICK_TIME)
|
||||||
# Signals
|
# Signals
|
||||||
self.live_timer.timeout.connect(self.media_state_live)
|
self.live_timer.timeout.connect(self._media_state_live)
|
||||||
self.preview_timer.timeout.connect(self.media_state_preview)
|
self.preview_timer.timeout.connect(self._media_state_preview)
|
||||||
Registry().register_function('playbackPlay', self.media_play_msg)
|
Registry().register_function('playbackPlay', self.media_play_msg)
|
||||||
Registry().register_function('playbackPause', self.media_pause_msg)
|
Registry().register_function('playbackPause', self.media_pause_msg)
|
||||||
Registry().register_function('playbackStop', self.media_stop_msg)
|
Registry().register_function('playbackStop', self.media_stop_msg)
|
||||||
@ -135,7 +140,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
'OpenLP.MediaController', 'No Displays have been configured, so Live Media has been disabled'))
|
'OpenLP.MediaController', 'No Displays have been configured, so Live Media has been disabled'))
|
||||||
self.setup_display(self.preview_controller, True)
|
self.setup_display(self.preview_controller, True)
|
||||||
|
|
||||||
def display_controllers(self, controller_type):
|
def _display_controllers(self, controller_type):
|
||||||
"""
|
"""
|
||||||
Decides which controller to use.
|
Decides which controller to use.
|
||||||
|
|
||||||
@ -145,35 +150,35 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
return self.live_controller
|
return self.live_controller
|
||||||
return self.preview_controller
|
return self.preview_controller
|
||||||
|
|
||||||
def media_state_live(self):
|
def _media_state_live(self):
|
||||||
"""
|
"""
|
||||||
Check if there is a running Live media Player and do updating stuff (e.g. update the UI)
|
Check if there is a running Live media Player and do updating stuff (e.g. update the UI)
|
||||||
"""
|
"""
|
||||||
display = self._define_display(self.display_controllers(DisplayControllerType.Live))
|
display = self._define_display(self._display_controllers(DisplayControllerType.Live))
|
||||||
if DisplayControllerType.Live in self.current_media_players:
|
if DisplayControllerType.Live in self.current_media_players:
|
||||||
self.current_media_players[DisplayControllerType.Live].resize(self.live_controller)
|
self.current_media_players[DisplayControllerType.Live].resize(self.live_controller)
|
||||||
self.current_media_players[DisplayControllerType.Live].update_ui(self.live_controller, display)
|
self.current_media_players[DisplayControllerType.Live].update_ui(self.live_controller, display)
|
||||||
self.tick(self.display_controllers(DisplayControllerType.Live))
|
self.tick(self._display_controllers(DisplayControllerType.Live))
|
||||||
if self.current_media_players[DisplayControllerType.Live].get_live_state() is not MediaState.Playing:
|
if self.current_media_players[DisplayControllerType.Live].get_live_state() is not MediaState.Playing:
|
||||||
self.live_timer.stop()
|
self.live_timer.stop()
|
||||||
else:
|
else:
|
||||||
self.live_timer.stop()
|
self.live_timer.stop()
|
||||||
self.media_stop(self.display_controllers(DisplayControllerType.Live))
|
self.media_stop(self._display_controllers(DisplayControllerType.Live))
|
||||||
|
|
||||||
def media_state_preview(self):
|
def _media_state_preview(self):
|
||||||
"""
|
"""
|
||||||
Check if there is a running Preview media Player and do updating stuff (e.g. update the UI)
|
Check if there is a running Preview media Player and do updating stuff (e.g. update the UI)
|
||||||
"""
|
"""
|
||||||
display = self._define_display(self.display_controllers(DisplayControllerType.Preview))
|
display = self._define_display(self._display_controllers(DisplayControllerType.Preview))
|
||||||
if DisplayControllerType.Preview in self.current_media_players:
|
if DisplayControllerType.Preview in self.current_media_players:
|
||||||
self.current_media_players[DisplayControllerType.Preview].resize(self.live_controller)
|
self.current_media_players[DisplayControllerType.Preview].resize(self.live_controller)
|
||||||
self.current_media_players[DisplayControllerType.Preview].update_ui(self.preview_controller, display)
|
self.current_media_players[DisplayControllerType.Preview].update_ui(self.preview_controller, display)
|
||||||
self.tick(self.display_controllers(DisplayControllerType.Preview))
|
self.tick(self._display_controllers(DisplayControllerType.Preview))
|
||||||
if self.current_media_players[DisplayControllerType.Preview].get_preview_state() is not MediaState.Playing:
|
if self.current_media_players[DisplayControllerType.Preview].get_preview_state() is not MediaState.Playing:
|
||||||
self.preview_timer.stop()
|
self.preview_timer.stop()
|
||||||
else:
|
else:
|
||||||
self.preview_timer.stop()
|
self.preview_timer.stop()
|
||||||
self.media_stop(self.display_controllers(DisplayControllerType.Preview))
|
self.media_stop(self._display_controllers(DisplayControllerType.Preview))
|
||||||
|
|
||||||
def setup_display(self, controller, preview):
|
def setup_display(self, controller, preview):
|
||||||
"""
|
"""
|
||||||
@ -218,7 +223,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
:param hidden: The player which is doing the playing
|
:param hidden: The player which is doing the playing
|
||||||
"""
|
"""
|
||||||
is_valid = True
|
is_valid = True
|
||||||
controller = self.display_controllers(source)
|
controller = self._display_controllers(source)
|
||||||
# stop running videos
|
# stop running videos
|
||||||
self.media_reset(controller)
|
self.media_reset(controller)
|
||||||
controller.media_info = ItemMediaInfo()
|
controller.media_info = ItemMediaInfo()
|
||||||
@ -246,27 +251,27 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
if controller.is_live:
|
if controller.is_live:
|
||||||
# if this is an optical device use special handling
|
# if this is an optical device use special handling
|
||||||
if service_item.is_capable(ItemCapabilities.IsOptical):
|
if service_item.is_capable(ItemCapabilities.IsOptical):
|
||||||
log.debug('video is optical and live')
|
self.log_debug('video is optical and live')
|
||||||
path = service_item.get_frame_path()
|
path = service_item.get_frame_path()
|
||||||
(name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path)
|
(name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path)
|
||||||
is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display,
|
is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display,
|
||||||
controller)
|
controller)
|
||||||
elif service_item.is_capable(ItemCapabilities.CanStream):
|
elif service_item.is_capable(ItemCapabilities.CanStream):
|
||||||
log.debug('video is stream and live')
|
self.log_debug('video is stream and live')
|
||||||
path = service_item.get_frames()[0]['path']
|
path = service_item.get_frames()[0]['path']
|
||||||
controller.media_info.media_type = MediaType.Stream
|
controller.media_info.media_type = MediaType.Stream
|
||||||
(name, mrl, options) = parse_stream_path(path)
|
(name, mrl, options) = parse_stream_path(path)
|
||||||
controller.media_info.file_info = (mrl, options)
|
controller.media_info.file_info = (mrl, options)
|
||||||
is_valid = self._check_file_type(controller, display)
|
is_valid = self._check_file_type(controller, display)
|
||||||
else:
|
else:
|
||||||
log.debug('video is not optical or stream, but live')
|
self.log_debug('video is not optical or stream, but live')
|
||||||
controller.media_info.length = service_item.media_length
|
controller.media_info.length = service_item.media_length
|
||||||
is_valid = self._check_file_type(controller, display)
|
is_valid = self._check_file_type(controller, display)
|
||||||
controller.media_info.start_time = service_item.start_time
|
controller.media_info.start_time = service_item.start_time
|
||||||
controller.media_info.end_time = service_item.end_time
|
controller.media_info.end_time = service_item.end_time
|
||||||
elif controller.preview_display:
|
elif controller.preview_display:
|
||||||
if service_item.is_capable(ItemCapabilities.IsOptical):
|
if service_item.is_capable(ItemCapabilities.IsOptical):
|
||||||
log.debug('video is optical and preview')
|
self.log_debug('video is optical and preview')
|
||||||
path = service_item.get_frame_path()
|
path = service_item.get_frame_path()
|
||||||
(name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path)
|
(name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path)
|
||||||
is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display,
|
is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display,
|
||||||
@ -278,7 +283,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
controller.media_info.file_info = (mrl, options)
|
controller.media_info.file_info = (mrl, options)
|
||||||
is_valid = self._check_file_type(controller, display)
|
is_valid = self._check_file_type(controller, display)
|
||||||
else:
|
else:
|
||||||
log.debug('video is not optical or stream, but preview')
|
self.log_debug('video is not optical or stream, but preview')
|
||||||
controller.media_info.length = service_item.media_length
|
controller.media_info.length = service_item.media_length
|
||||||
is_valid = self._check_file_type(controller, display)
|
is_valid = self._check_file_type(controller, display)
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
@ -286,7 +291,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
||||||
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
||||||
return False
|
return False
|
||||||
log.debug('video media type: {tpe} '.format(tpe=str(controller.media_info.media_type)))
|
self.log_debug('video media type: {tpe} '.format(tpe=str(controller.media_info.media_type)))
|
||||||
autoplay = False
|
autoplay = False
|
||||||
if service_item.requires_media():
|
if service_item.requires_media():
|
||||||
autoplay = True
|
autoplay = True
|
||||||
@ -305,7 +310,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
||||||
return False
|
return False
|
||||||
self.set_controls_visible(controller, True)
|
self.set_controls_visible(controller, True)
|
||||||
log.debug('use {nm} controller'.format(nm=self.current_media_players[controller.controller_type].display_name))
|
self.log_debug('use {nm} controller'.
|
||||||
|
format(nm=self.current_media_players[controller.controller_type].display_name))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -417,7 +423,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
Responds to the request to play a loaded video from the web.
|
Responds to the request to play a loaded video from the web.
|
||||||
"""
|
"""
|
||||||
return self.media_play(Registry().get('live_controller'), False)
|
return self.media_play(self.live_controller)
|
||||||
|
|
||||||
def media_play(self, controller, first_time=True):
|
def media_play(self, controller, first_time=True):
|
||||||
"""
|
"""
|
||||||
@ -426,6 +432,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
:param controller: The controller to be played
|
:param controller: The controller to be played
|
||||||
:param first_time:
|
:param first_time:
|
||||||
"""
|
"""
|
||||||
|
self.log_debug(f"media_play with {first_time}")
|
||||||
controller.seek_slider.blockSignals(True)
|
controller.seek_slider.blockSignals(True)
|
||||||
controller.volume_slider.blockSignals(True)
|
controller.volume_slider.blockSignals(True)
|
||||||
display = self._define_display(controller)
|
display = self._define_display(controller)
|
||||||
@ -457,6 +464,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
display.hide_display(HideMode.Screen)
|
display.hide_display(HideMode.Screen)
|
||||||
controller._set_theme(controller.service_item)
|
controller._set_theme(controller.service_item)
|
||||||
display.load_verses([{"verse": "v1", "text": "", "footer": " "}])
|
display.load_verses([{"verse": "v1", "text": "", "footer": " "}])
|
||||||
|
controller.output_has_changed()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def tick(self, controller):
|
def tick(self, controller):
|
||||||
@ -501,7 +509,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
Responds to the request to pause a loaded video from the web.
|
Responds to the request to pause a loaded video from the web.
|
||||||
"""
|
"""
|
||||||
return self.media_pause(Registry().get('live_controller'))
|
return self.media_pause(self.live_controller)
|
||||||
|
|
||||||
def media_pause(self, controller):
|
def media_pause(self, controller):
|
||||||
"""
|
"""
|
||||||
@ -515,6 +523,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
||||||
controller.mediabar.actions['playbackPause'].setVisible(False)
|
controller.mediabar.actions['playbackPause'].setVisible(False)
|
||||||
controller.media_info.is_playing = False
|
controller.media_info.is_playing = False
|
||||||
|
controller.output_has_changed()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -548,7 +557,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
Responds to the request to stop a loaded video from the web.
|
Responds to the request to stop a loaded video from the web.
|
||||||
"""
|
"""
|
||||||
return self.media_stop(Registry().get('live_controller'))
|
return self.media_stop(self.live_controller)
|
||||||
|
|
||||||
def media_stop(self, controller):
|
def media_stop(self, controller):
|
||||||
"""
|
"""
|
||||||
@ -572,6 +581,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
controller.media_timer = 0
|
controller.media_timer = 0
|
||||||
display = self._define_display(controller)
|
display = self._define_display(controller)
|
||||||
display.show_display()
|
display.show_display()
|
||||||
|
controller.output_has_changed()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -592,7 +602,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
:param controller: The Controller to use
|
:param controller: The Controller to use
|
||||||
:param volume: The volume to be set
|
:param volume: The volume to be set
|
||||||
"""
|
"""
|
||||||
log.debug('media_volume {vol}'.format(vol=volume))
|
self.log_debug(f'media_volume {volume}')
|
||||||
if controller.is_live:
|
if controller.is_live:
|
||||||
self.settings.setValue('media/live volume', volume)
|
self.settings.setValue('media/live volume', volume)
|
||||||
else:
|
else:
|
||||||
@ -692,8 +702,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
self.live_timer.stop()
|
self.live_timer.stop()
|
||||||
self.preview_timer.stop()
|
self.preview_timer.stop()
|
||||||
self.media_reset(self.display_controllers(DisplayControllerType.Live))
|
self.media_reset(self._display_controllers(DisplayControllerType.Live))
|
||||||
self.media_reset(self.display_controllers(DisplayControllerType.Preview))
|
self.media_reset(self._display_controllers(DisplayControllerType.Preview))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _define_display(controller):
|
def _define_display(controller):
|
||||||
|
@ -41,6 +41,7 @@ def media_play():
|
|||||||
if live.service_item.name != 'media':
|
if live.service_item.name != 'media':
|
||||||
abort(400)
|
abort(400)
|
||||||
status = live.mediacontroller_live_play.emit()
|
status = live.mediacontroller_live_play.emit()
|
||||||
|
log.debug(f'media_play return {status}')
|
||||||
if status:
|
if status:
|
||||||
return '', 202
|
return '', 202
|
||||||
abort(400)
|
abort(400)
|
||||||
@ -54,6 +55,7 @@ def media_pause():
|
|||||||
if live.service_item.name != 'media':
|
if live.service_item.name != 'media':
|
||||||
abort(400)
|
abort(400)
|
||||||
status = live.mediacontroller_live_pause.emit()
|
status = live.mediacontroller_live_pause.emit()
|
||||||
|
log.debug(f'media_pause return {status}')
|
||||||
if status:
|
if status:
|
||||||
return '', 202
|
return '', 202
|
||||||
abort(400)
|
abort(400)
|
||||||
@ -67,6 +69,7 @@ def media_stop():
|
|||||||
if live.service_item.name != 'media':
|
if live.service_item.name != 'media':
|
||||||
abort(400)
|
abort(400)
|
||||||
status = live.mediacontroller_live_stop.emit()
|
status = live.mediacontroller_live_stop.emit()
|
||||||
|
log.debug(f'media_stop return {status}')
|
||||||
if status:
|
if status:
|
||||||
return '', 202
|
return '', 202
|
||||||
abort(400)
|
abort(400)
|
||||||
|
@ -171,7 +171,7 @@ class VlcPlayer(MediaPlayer):
|
|||||||
if not controller.vlc_instance:
|
if not controller.vlc_instance:
|
||||||
return False
|
return False
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
log.debug('load vid in Vlc Controller')
|
log.debug('load video in VLC Controller')
|
||||||
path = None
|
path = None
|
||||||
if file and not controller.media_info.media_type == MediaType.Stream:
|
if file and not controller.media_info.media_type == MediaType.Stream:
|
||||||
path = os.path.normcase(file)
|
path = os.path.normcase(file)
|
||||||
|
@ -129,9 +129,6 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
|
|||||||
tab_widget = self.stacked_layout.widget(tab_index)
|
tab_widget = self.stacked_layout.widget(tab_index)
|
||||||
if tab_widget.tab_title == plugin_name:
|
if tab_widget.tab_title == plugin_name:
|
||||||
tab_widget.save()
|
tab_widget.save()
|
||||||
# if the image background has been changed we need to regenerate the image cache
|
|
||||||
if 'images_config_updated' in self.processes or 'config_screen_changed' in self.processes:
|
|
||||||
self.register_post_process('images_regenerate')
|
|
||||||
# Now lets process all the post save handlers
|
# Now lets process all the post save handlers
|
||||||
while self.processes:
|
while self.processes:
|
||||||
Registry().execute(self.processes.pop(0))
|
Registry().execute(self.processes.pop(0))
|
||||||
|
@ -204,6 +204,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
|||||||
self.update_slide_limits()
|
self.update_slide_limits()
|
||||||
self.panel = QtWidgets.QWidget(self.main_window.control_splitter)
|
self.panel = QtWidgets.QWidget(self.main_window.control_splitter)
|
||||||
self.slide_list = {}
|
self.slide_list = {}
|
||||||
|
self.slide_count = 0
|
||||||
self.ignore_toolbar_resize_events = False
|
self.ignore_toolbar_resize_events = False
|
||||||
# Layout for holding panel
|
# Layout for holding panel
|
||||||
self.panel_layout = QtWidgets.QVBoxLayout(self.panel)
|
self.panel_layout = QtWidgets.QVBoxLayout(self.panel)
|
||||||
@ -1242,6 +1243,13 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
|||||||
self.preview_display.set_single_image('#000', image_path)
|
self.preview_display.set_single_image('#000', image_path)
|
||||||
else:
|
else:
|
||||||
self.preview_display.go_to_slide(self.selected_row)
|
self.preview_display.go_to_slide(self.selected_row)
|
||||||
|
self.output_has_changed()
|
||||||
|
|
||||||
|
def output_has_changed(self):
|
||||||
|
"""
|
||||||
|
The output has changed so we need to poke to POLL Websocket.
|
||||||
|
"""
|
||||||
|
self.slide_count += 1
|
||||||
|
|
||||||
def display_maindisplay(self):
|
def display_maindisplay(self):
|
||||||
"""
|
"""
|
||||||
@ -1462,11 +1470,15 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
|||||||
|
|
||||||
def on_clear(self):
|
def on_clear(self):
|
||||||
"""
|
"""
|
||||||
Clear the preview bar.
|
Clear the preview bar and other bits.
|
||||||
"""
|
"""
|
||||||
self.preview_widget.clear_list()
|
self.preview_widget.clear_list()
|
||||||
self.toolbar.set_widget_visible('editSong', False)
|
self.service_item = None
|
||||||
self.toolbar.set_widget_visible('clear', False)
|
if self.is_live:
|
||||||
|
self.mediabar.setVisible(False)
|
||||||
|
else:
|
||||||
|
self.toolbar.set_widget_visible('editSong', False)
|
||||||
|
self.toolbar.set_widget_visible('clear', False)
|
||||||
|
|
||||||
def on_preview_add_to_service(self):
|
def on_preview_add_to_service(self):
|
||||||
"""
|
"""
|
||||||
|
@ -219,7 +219,7 @@ def test_on_media_play(media_env):
|
|||||||
media_env.media_controller.on_media_play()
|
media_env.media_controller.on_media_play()
|
||||||
|
|
||||||
# The mocked live controller should be called
|
# The mocked live controller should be called
|
||||||
media_env.media_controller.media_play.assert_called_once_with(mocked_live_controller, False)
|
media_env.media_controller.media_play.assert_called_once_with(mocked_live_controller)
|
||||||
|
|
||||||
|
|
||||||
def test_on_media_pause(media_env):
|
def test_on_media_pause(media_env):
|
||||||
@ -265,7 +265,7 @@ def test_display_controllers_live(media_env):
|
|||||||
Registry().register('preview_controller', mocked_preview_controller)
|
Registry().register('preview_controller', mocked_preview_controller)
|
||||||
|
|
||||||
# WHEN: display_controllers() is called with DisplayControllerType.Live
|
# WHEN: display_controllers() is called with DisplayControllerType.Live
|
||||||
controller = media_env.media_controller.display_controllers(DisplayControllerType.Live)
|
controller = media_env.media_controller._display_controllers(DisplayControllerType.Live)
|
||||||
|
|
||||||
# THEN: the controller should be the live controller
|
# THEN: the controller should be the live controller
|
||||||
assert controller is mocked_live_controller
|
assert controller is mocked_live_controller
|
||||||
@ -282,7 +282,7 @@ def test_display_controllers_preview(media_env):
|
|||||||
Registry().register('preview_controller', mocked_preview_controller)
|
Registry().register('preview_controller', mocked_preview_controller)
|
||||||
|
|
||||||
# WHEN: display_controllers() is called with DisplayControllerType.Preview
|
# WHEN: display_controllers() is called with DisplayControllerType.Preview
|
||||||
controller = media_env.media_controller.display_controllers(DisplayControllerType.Preview)
|
controller = media_env.media_controller._display_controllers(DisplayControllerType.Preview)
|
||||||
|
|
||||||
# THEN: the controller should be the live controller
|
# THEN: the controller should be the live controller
|
||||||
assert controller is mocked_preview_controller
|
assert controller is mocked_preview_controller
|
||||||
|
185
tests/functional/openlp_core/ui/media/test_remote.py
Normal file
185
tests/functional/openlp_core/ui/media/test_remote.py
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2020 OpenLP Developers #
|
||||||
|
# ---------------------------------------------------------------------- #
|
||||||
|
# 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, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# 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, see <https://www.gnu.org/licenses/>. #
|
||||||
|
##########################################################################
|
||||||
|
"""
|
||||||
|
Package to test the openlp.core.ui.media.remote package.
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from openlp.core.api import app as flask_app
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
|
from openlp.core.ui.media.remote import media_play, media_pause, media_stop, register_views
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_play_valid(settings):
|
||||||
|
# GIVEN: A loaded service with media set up
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Play is pressed
|
||||||
|
ret = media_play()
|
||||||
|
# THEN: We should have a successful outcome
|
||||||
|
assert live_controller.mediacontroller_live_play.emit.call_count == 1, 'Should have be called once'
|
||||||
|
assert ret[1] == 202, 'Should be a valid call'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_play_not_media(settings):
|
||||||
|
# GIVEN: A loaded service with songs not media
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'songs'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Play is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_play()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_play.emit.call_count == 0, 'Should have be not have been called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_play_call_fail(settings):
|
||||||
|
# GIVEN: A loaded service with no media_controller
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
live_controller.mediacontroller_live_play.emit.return_value = False
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Play is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_play()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_play.emit.call_count == 1, 'Should have be called once'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_pause_valid(settings):
|
||||||
|
# GIVEN: A loaded service with media set up
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Pause is pressed
|
||||||
|
ret = media_pause()
|
||||||
|
# THEN: We should have a successful outcome
|
||||||
|
assert live_controller.mediacontroller_live_pause.emit.call_count == 1, 'Should have be called once'
|
||||||
|
assert ret[1] == 202, 'Should be a valid call'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_pause_not_media(settings):
|
||||||
|
# GIVEN: A loaded service with songs not media
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'songs'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Pause is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_pause()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_pause.emit.call_count == 0, 'Should have be not have been called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_pause_call_fail(settings):
|
||||||
|
# GIVEN: A loaded service with no media_controller
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
live_controller.mediacontroller_live_pause.emit.return_value = False
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Pause is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_pause()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_pause.emit.call_count == 1, 'Should have be called once'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_stop_valid(settings):
|
||||||
|
# GIVEN: A loaded service with media set up
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Stop is pressed
|
||||||
|
ret = media_stop()
|
||||||
|
# THEN: We should have a successful outcome
|
||||||
|
assert live_controller.mediacontroller_live_stop.emit.call_count == 1, 'Should have be called once'
|
||||||
|
assert ret[1] == 202, 'Should be a valid call'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_stop_not_media(settings):
|
||||||
|
# GIVEN: A loaded service with songs not media
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'songs'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Stop is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_stop()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_stop.emit.call_count == 0, 'Should have be not have been called'
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_stop_call_fail(settings):
|
||||||
|
# GIVEN: A loaded service with no media_controller
|
||||||
|
settings.setValue('api/authentication enabled', False)
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.name = 'media'
|
||||||
|
live_controller = MagicMock()
|
||||||
|
live_controller.service_item = service_item
|
||||||
|
live_controller.mediacontroller_live_stop.emit.return_value = False
|
||||||
|
Registry().register('live_controller', live_controller)
|
||||||
|
# WHEN: Stop is pressed
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
_ = media_stop()
|
||||||
|
# THEN: We should have a rejected outcome
|
||||||
|
assert e.value.code == 400, 'Should be an invalid call'
|
||||||
|
assert live_controller.mediacontroller_live_stop.emit.call_count == 1, 'Should have be called once'
|
||||||
|
|
||||||
|
|
||||||
|
def test_register():
|
||||||
|
# GIVEN: A blank setup
|
||||||
|
# WHEN: I register the views for media
|
||||||
|
register_views()
|
||||||
|
# THEN: The following elements should have been defined.
|
||||||
|
assert len(flask_app.blueprints['v2-media-controller'].deferred_functions) == 3, \
|
||||||
|
'we should have 3 functions defined'
|
||||||
|
assert 'v2-media-controller.media_play' in flask_app.view_functions, 'we should the play defined'
|
||||||
|
assert 'v2-media-controller.media_pause' in flask_app.view_functions, 'we should the pause defined'
|
||||||
|
assert 'v2-media-controller.media_stop' in flask_app.view_functions, 'we should the stop defined'
|
Loading…
Reference in New Issue
Block a user