Media is now playing again - just

This commit is contained in:
Tim Bentley 2019-03-24 07:53:19 +00:00
parent fc579f120a
commit 112fac8baf
7 changed files with 300 additions and 310 deletions

View File

@ -23,7 +23,6 @@
The :mod:`~openlp.core.ui.media.mediacontroller` module contains a base class for media components and other widgets The :mod:`~openlp.core.ui.media.mediacontroller` module contains a base class for media components and other widgets
related to playing media, such as sliders. related to playing media, such as sliders.
""" """
import datetime
import logging import logging
try: try:
@ -33,7 +32,7 @@ except ImportError:
pymediainfo_available = False pymediainfo_available = False
from subprocess import check_output from subprocess import check_output
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore
from openlp.core.state import State from openlp.core.state import State
from openlp.core.api.http import register_endpoint from openlp.core.api.http import register_endpoint
@ -44,11 +43,9 @@ from openlp.core.common.settings import Settings
from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.serviceitem import ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import DisplayControllerType from openlp.core.ui import DisplayControllerType
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path
from openlp.core.ui.media.endpoint import media_endpoint from openlp.core.ui.media.endpoint import media_endpoint
from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc
from openlp.core.widgets.toolbar import OpenLPToolbar
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -56,45 +53,6 @@ log = logging.getLogger(__name__)
TICK_TIME = 200 TICK_TIME = 200
class MediaSlider(QtWidgets.QSlider):
"""
Allows the mouse events of a slider to be overridden and extra functionality added
"""
def __init__(self, direction, manager, controller):
"""
Constructor
"""
super(MediaSlider, self).__init__(direction)
self.manager = manager
self.controller = controller
def mouseMoveEvent(self, event):
"""
Override event to allow hover time to be displayed.
:param event: The triggering event
"""
time_value = QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width())
self.setToolTip('%s' % datetime.timedelta(seconds=int(time_value / 1000)))
QtWidgets.QSlider.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
"""
Mouse Press event no new functionality
:param event: The triggering event
"""
QtWidgets.QSlider.mousePressEvent(self, event)
def mouseReleaseEvent(self, event):
"""
Set the slider position when the mouse is clicked and released on the slider.
:param event: The triggering event
"""
self.setValue(QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width()))
QtWidgets.QSlider.mouseReleaseEvent(self, event)
class MediaController(RegistryBase, LogMixin, RegistryProperties): class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
The implementation of the Media Controller. The Media Controller adds an own class for every Player. The implementation of the Media Controller. The Media Controller adds an own class for every Player.
@ -116,7 +74,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def setup(self): def setup(self):
self.vlc_player = None self.vlc_player = None
self.display_controllers = {}
self.current_media_players = {} self.current_media_players = {}
# Timer for video state # Timer for video state
self.live_timer = QtCore.QTimer() self.live_timer = QtCore.QTimer()
@ -176,109 +133,58 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
self._generate_extensions_lists() self._generate_extensions_lists()
return True return True
def bootstrap_post_set_up(self):
"""
Set up the controllers.
:return:
"""
self.setup_display(self.live_controller.display, False)
self.setup_display(self.preview_controller.preview_display, True)
def display_controllers(self, controller_type):
"""
Decides which controller to use.
:param controller_type: The controller type where a player will be placed
"""
if controller_type == DisplayControllerType.Live:
return self.live_controller
else:
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(display) self.current_media_players[DisplayControllerType.Live].resize(display)
self.current_media_players[DisplayControllerType.Live].update_ui(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))
if self.display_controllers[DisplayControllerType.Live].media_info.can_loop_playback: if self.display_controllers(DisplayControllerType.Live).media_info.can_loop_playback:
self.media_play(self.display_controllers[DisplayControllerType.Live], True) self.media_play(self.display_controllers(DisplayControllerType.Live), True)
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(display) self.current_media_players[DisplayControllerType.Preview].resize(display)
self.current_media_players[DisplayControllerType.Preview].update_ui(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))
if self.display_controllers[DisplayControllerType.Preview].media_info.can_loop_playback: if self.display_controllers(DisplayControllerType.Preview).media_info.can_loop_playback:
self.media_play(self.display_controllers[DisplayControllerType.Preview], True) self.media_play(self.display_controllers(DisplayControllerType.Preview), True)
def register_controller(self, controller):
"""
Registers media controls where the players will be placed to run.
:param controller: The controller where a player will be placed
"""
self.display_controllers[controller.controller_type] = controller
self.setup_generic_controls(controller)
def setup_generic_controls(self, controller):
"""
Set up controls on the control_panel for a given controller
:param controller: First element is the controller which should be used
"""
controller.media_info = ItemMediaInfo()
# Build a Media ToolBar
controller.mediabar = OpenLPToolbar(controller)
controller.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play',
icon=UiIcons().play,
tooltip=translate('OpenLP.SlideController', 'Start playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackPause', text='media_playback_pause',
icon=UiIcons().pause,
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackStop', text='media_playback_stop',
icon=UiIcons().stop,
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
triggers=controller.send_to_plugins)
controller.mediabar.add_toolbar_action('playbackLoop', text='media_playback_loop',
icon=UiIcons().repeat, checked=False,
tooltip=translate('OpenLP.SlideController', 'Loop playing media.'),
triggers=controller.send_to_plugins)
controller.position_label = QtWidgets.QLabel()
controller.position_label.setText(' 00:00 / 00:00')
controller.position_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
controller.position_label.setToolTip(translate('OpenLP.SlideController', 'Video timer.'))
controller.position_label.setMinimumSize(90, 0)
controller.position_label.setObjectName('position_label')
controller.mediabar.add_toolbar_widget(controller.position_label)
# Build the seek_slider.
controller.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
controller.seek_slider.setMaximum(1000)
controller.seek_slider.setTracking(True)
controller.seek_slider.setMouseTracking(True)
controller.seek_slider.setToolTip(translate('OpenLP.SlideController', 'Video position.'))
controller.seek_slider.setGeometry(QtCore.QRect(90, 260, 221, 24))
controller.seek_slider.setObjectName('seek_slider')
controller.mediabar.add_toolbar_widget(controller.seek_slider)
# Build the volume_slider.
controller.volume_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
controller.volume_slider.setTickInterval(10)
controller.volume_slider.setTickPosition(QtWidgets.QSlider.TicksAbove)
controller.volume_slider.setMinimum(0)
controller.volume_slider.setMaximum(100)
controller.volume_slider.setTracking(True)
controller.volume_slider.setToolTip(translate('OpenLP.SlideController', 'Audio Volume.'))
controller.volume_slider.setValue(controller.media_info.volume)
controller.volume_slider.setGeometry(QtCore.QRect(90, 160, 221, 24))
controller.volume_slider.setObjectName('volume_slider')
controller.mediabar.add_toolbar_widget(controller.volume_slider)
controller.controller_layout.addWidget(controller.mediabar)
controller.mediabar.setVisible(False)
if not controller.is_live:
controller.volume_slider.setEnabled(False)
# Signals
controller.seek_slider.valueChanged.connect(controller.send_to_plugins)
controller.volume_slider.valueChanged.connect(controller.send_to_plugins)
def setup_display(self, display, preview): def setup_display(self, display, preview):
""" """
@ -287,14 +193,13 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
:param display: Display on which the output is to be played :param display: Display on which the output is to be played
:param preview: Whether the display is a main or preview display :param preview: Whether the display is a main or preview display
""" """
# clean up possible running old media files display.media_info = ItemMediaInfo()
self.finalise()
display.has_audio = True display.has_audio = True
if display.is_live and preview: # if display.is_live and preview:
return # return
if preview: if preview:
display.has_audio = False display.has_audio = False
self.vlc_player.setup(display) self.vlc_player.setup(display, preview)
def set_controls_visible(self, controller, value): def set_controls_visible(self, controller, value):
""" """
@ -305,9 +210,9 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
# Generic controls # Generic controls
controller.mediabar.setVisible(value) controller.mediabar.setVisible(value)
if controller.is_live and controller.display: #if controller.is_live and controller.display:
if self.current_media_players and value: #if self.current_media_players and value:
controller.display.set_transparency(False) # controller.display.set_transparency(False)
@staticmethod @staticmethod
def resize(display, player): def resize(display, player):
@ -319,7 +224,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
player.resize(display) player.resize(display)
def video(self, source, service_item, hidden=False, video_behind_text=False): def load_video(self, source, service_item, hidden=False, video_behind_text=False):
""" """
Loads and starts a video to run with the option of sound Loads and starts a video to run with the option of sound
@ -329,7 +234,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
:param video_behind_text: Is the video to be played behind text. :param video_behind_text: Is the video to be played behind text.
""" """
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()
@ -354,8 +259,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
log.debug('video is not optical and live') log.debug('video is not optical and 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)
display.override['theme'] = '' #display.override['theme'] = ''
display.override['video'] = True #display.override['video'] = True
if controller.media_info.is_background: if controller.media_info.is_background:
# ignore start/end time # ignore start/end time
controller.media_info.start_time = 0 controller.media_info.start_time = 0
@ -381,8 +286,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
return False return False
log.debug('video media type: ' + str(controller.media_info.media_type)) log.debug('video media type: ' + str(controller.media_info.media_type))
# dont care about actual theme, set a black background # dont care about actual theme, set a black background
if controller.is_live and not controller.media_info.is_background: #if controller.is_live and not controller.media_info.is_background:
display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");') # display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");')
# now start playing - Preview is autoplay! # now start playing - Preview is autoplay!
autoplay = False autoplay = False
# Preview requested # Preview requested
@ -471,28 +376,26 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
for file in controller.media_info.file_info: for file in controller.media_info.file_info:
if file.is_file: if file.is_file:
suffix = '*%s' % file.suffix.lower() suffix = '*%s' % file.suffix.lower()
player = self.vlc_player
file = str(file) file = str(file)
if suffix in player.video_extensions_list: if suffix in self.vlc_player.video_extensions_list:
if not controller.media_info.is_background or controller.media_info.is_background and \ if not controller.media_info.is_background or controller.media_info.is_background and \
player.can_background: self.vlc_player.can_background:
self.resize(display, player) self.resize(display, self.vlc_player)
if player.load(display, file): if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = player self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Video controller.media_info.media_type = MediaType.Video
return True return True
if suffix in player.audio_extensions_list: if suffix in self.vlc_player.audio_extensions_list:
if player.load(display, file): if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = player self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Audio controller.media_info.media_type = MediaType.Audio
return True return True
else: else:
player = self.vlc_player
file = str(file) file = str(file)
if player.can_folder: if self.vlc_player.can_folder:
self.resize(display, player) self.resize(display, self.vlc_player)
if player.load(display, file): if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = player self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Video controller.media_info.media_type = MediaType.Video
return True return True
return False return False
@ -509,8 +412,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_play(self): def on_media_play(self):
""" """
Responds to the request to play a loaded video from the web. Responds to the request to play a loaded video from the web.
:param msg: First element is the controller which should be used
""" """
self.media_play(Registry().get('live_controller'), False) self.media_play(Registry().get('live_controller'), False)
@ -524,7 +425,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
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)
if not self.current_media_players[controller.controller_type].play(display): if not self.current_media_players[controller.controller_type].play(controller, display):
controller.seek_slider.blockSignals(False) controller.seek_slider.blockSignals(False)
controller.volume_slider.blockSignals(False) controller.volume_slider.blockSignals(False)
return False return False
@ -533,8 +434,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
else: else:
self.media_volume(controller, controller.media_info.volume) self.media_volume(controller, controller.media_info.volume)
if first_time: if first_time:
if not controller.media_info.is_background: #if not controller.media_info.is_background:
display.frame.runJavaScript('show_blank("desktop");') # display.frame.runJavaScript('show_blank("desktop");')
self.current_media_players[controller.controller_type].set_visible(display, True) self.current_media_players[controller.controller_type].set_visible(display, True)
controller.mediabar.actions['playbackPlay'].setVisible(False) controller.mediabar.actions['playbackPlay'].setVisible(False)
controller.mediabar.actions['playbackPause'].setVisible(True) controller.mediabar.actions['playbackPause'].setVisible(True)
@ -591,8 +492,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_pause(self): def on_media_pause(self):
""" """
Responds to the request to pause a loaded video from the web. Responds to the request to pause a loaded video from the web.
:param msg: First element is the controller which should be used
""" """
self.media_pause(Registry().get('live_controller')) self.media_pause(Registry().get('live_controller'))
@ -639,8 +538,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_stop(self): def on_media_stop(self):
""" """
Responds to the request to stop a loaded video from the web. Responds to the request to stop a loaded video from the web.
:param msg: First element is the controller which should be used
""" """
self.media_stop(Registry().get('live_controller')) self.media_stop(Registry().get('live_controller'))
@ -653,8 +550,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
display = self._define_display(controller) display = self._define_display(controller)
if controller.controller_type in self.current_media_players: if controller.controller_type in self.current_media_players:
if not looping_background: #if not looping_background:
display.frame.runJavaScript('show_blank("black");') # display.frame.runJavaScript('show_blank("black");')
self.current_media_players[controller.controller_type].stop(display) self.current_media_players[controller.controller_type].stop(display)
self.current_media_players[controller.controller_type].set_visible(display, False) self.current_media_players[controller.controller_type].set_visible(display, False)
controller.seek_slider.setSliderPosition(0) controller.seek_slider.setSliderPosition(0)
@ -725,7 +622,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
display.override = {} display.override = {}
self.current_media_players[controller.controller_type].reset(display) self.current_media_players[controller.controller_type].reset(display)
self.current_media_players[controller.controller_type].set_visible(display, False) self.current_media_players[controller.controller_type].set_visible(display, False)
display.frame.runJavaScript('show_video("setBackBoard", null, null, "hidden");') # display.frame.runJavaScript('show_video("setBackBoard", null, null, "hidden");')
del self.current_media_players[controller.controller_type] del self.current_media_players[controller.controller_type]
def media_hide(self, msg): def media_hide(self, msg):
@ -788,8 +685,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
self.live_timer.stop() self.live_timer.stop()
self.preview_timer.stop() self.preview_timer.stop()
for controller in self.display_controllers: self.media_reset(self.display_controllers(DisplayControllerType.Live))
self.media_reset(self.display_controllers[controller]) self.media_reset(self.display_controllers(DisplayControllerType.Preview))
@staticmethod @staticmethod
def _define_display(controller): def _define_display(controller):

View File

@ -52,11 +52,12 @@ class MediaPlayer(RegistryProperties):
""" """
return False return False
def setup(self, display): def setup(self, display, live_display):
""" """
Create the related widgets for the current display Create the related widgets for the current display
:param display: The display to be updated. :param display: The display to be updated.
:param live_display: Is the display a live one.
""" """
pass pass
@ -78,10 +79,11 @@ class MediaPlayer(RegistryProperties):
""" """
pass pass
def play(self, display): def play(self, controller, display):
""" """
Starts playing of current Media File Starts playing of current Media File
:param controller: Which Controller is running the show.
:param display: The display to be updated. :param display: The display to be updated.
""" """
pass pass
@ -206,7 +208,7 @@ class MediaPlayer(RegistryProperties):
:param display: Identify the Display type :param display: Identify the Display type
:return: None :return: None
""" """
if display.controller.is_live: if display.is_display:
self.set_live_state(state) self.set_live_state(state)
else: else:
self.set_preview_state(state) self.set_preview_state(state)

View File

@ -51,12 +51,12 @@ class MediaTab(SettingsTab):
player_translated = translate('OpenLP.MediaTab', 'Media') player_translated = translate('OpenLP.MediaTab', 'Media')
super(MediaTab, self).__init__(parent, 'Media', player_translated) super(MediaTab, self).__init__(parent, 'Media', player_translated)
def setupUi(self): def setup_ui(self):
""" """
Set up the UI Set up the UI
""" """
self.setObjectName('MediaTab') self.setObjectName('MediaTab')
super(MediaTab, self).setupUi() super(MediaTab, self).setup_ui()
self.live_media_group_box = QtWidgets.QGroupBox(self.left_column) self.live_media_group_box = QtWidgets.QGroupBox(self.left_column)
self.live_media_group_box.setObjectName('live_media_group_box') self.live_media_group_box.setObjectName('live_media_group_box')
self.media_layout = QtWidgets.QVBoxLayout(self.live_media_group_box) self.media_layout = QtWidgets.QVBoxLayout(self.live_media_group_box)

View File

@ -152,43 +152,44 @@ class VlcPlayer(MediaPlayer):
self.audio_extensions_list = AUDIO_EXT self.audio_extensions_list = AUDIO_EXT
self.video_extensions_list = VIDEO_EXT self.video_extensions_list = VIDEO_EXT
def setup(self, display): def setup(self, output_display, live_display):
""" """
Set up the media player Set up the media player
:param display: The display where the media is :param output_display: The display where the media is
:param live_display: Is the display a live one.
:return: :return:
""" """
vlc = get_vlc() vlc = get_vlc()
display.vlc_widget = QtWidgets.QFrame(display) output_display.vlc_widget = QtWidgets.QFrame(output_display)
display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame) output_display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame)
# creating a basic vlc instance # creating a basic vlc instance
command_line_options = '--no-video-title-show' command_line_options = '--no-video-title-show'
if not display.has_audio: if not output_display.has_audio:
command_line_options += ' --no-audio --no-video-title-show' command_line_options += ' --no-audio --no-video-title-show'
if Settings().value('advanced/hide mouse') and display.controller.is_live: if Settings().value('advanced/hide mouse') and live_display:
command_line_options += ' --mouse-hide-timeout=0' command_line_options += ' --mouse-hide-timeout=0'
display.vlc_instance = vlc.Instance(command_line_options) output_display.vlc_instance = vlc.Instance(command_line_options)
# creating an empty vlc media player # creating an empty vlc media player
display.vlc_media_player = display.vlc_instance.media_player_new() output_display.vlc_media_player = output_display.vlc_instance.media_player_new()
display.vlc_widget.resize(display.size()) output_display.vlc_widget.resize(output_display.size())
display.vlc_widget.raise_() output_display.vlc_widget.raise_()
display.vlc_widget.hide() output_display.vlc_widget.hide()
# The media player has to be 'connected' to the QFrame. # The media player has to be 'connected' to the QFrame.
# (otherwise a video would be displayed in it's own window) # (otherwise a video would be displayed in it's own window)
# This is platform specific! # This is platform specific!
# You have to give the id of the QFrame (or similar object) # You have to give the id of the QFrame (or similar object)
# to vlc, different platforms have different functions for this. # to vlc, different platforms have different functions for this.
win_id = int(display.vlc_widget.winId()) win_id = int(output_display.vlc_widget.winId())
if is_win(): if is_win():
display.vlc_media_player.set_hwnd(win_id) output_display.vlc_media_player.set_hwnd(win_id)
elif is_macosx(): elif is_macosx():
# We have to use 'set_nsobject' since Qt5 on OSX uses Cocoa # We have to use 'set_nsobject' since Qt5 on OSX uses Cocoa
# framework and not the old Carbon. # framework and not the old Carbon.
display.vlc_media_player.set_nsobject(win_id) output_display.vlc_media_player.set_nsobject(win_id)
else: else:
# for Linux/*BSD using the X Server # for Linux/*BSD using the X Server
display.vlc_media_player.set_xwindow(win_id) output_display.vlc_media_player.set_xwindow(win_id)
self.has_own_widget = True self.has_own_widget = True
def check_available(self): def check_available(self):
@ -197,45 +198,45 @@ class VlcPlayer(MediaPlayer):
""" """
return get_vlc() is not None return get_vlc() is not None
def load(self, display, file): def load(self, output_display, file):
""" """
Load a video into VLC Load a video into VLC
:param display: The display where the media is :param output_display: The display where the media is
:param file: file to be played :param file: file to be played
:return: :return:
""" """
vlc = get_vlc() vlc = get_vlc()
log.debug('load vid in Vlc Controller') log.debug('load vid in Vlc Controller')
controller = display.controller controller = output_display
volume = controller.media_info.volume volume = controller.media_info.volume
path = os.path.normcase(file) path = os.path.normcase(file)
# create the media # create the media
if controller.media_info.media_type == MediaType.CD: if controller.media_info.media_type == MediaType.CD:
if is_win(): if is_win():
path = '/' + path path = '/' + path
display.vlc_media = display.vlc_instance.media_new_location('cdda://' + path) output_display.vlc_media = output_display.vlc_instance.media_new_location('cdda://' + path)
display.vlc_media_player.set_media(display.vlc_media) output_display.vlc_media_player.set_media(output_display.vlc_media)
display.vlc_media_player.play() output_display.vlc_media_player.play()
# Wait for media to start playing. In this case VLC actually returns an error. # Wait for media to start playing. In this case VLC actually returns an error.
self.media_state_wait(display, vlc.State.Playing) self.media_state_wait(output_display, vlc.State.Playing)
# If subitems exists, this is a CD # If subitems exists, this is a CD
audio_cd_tracks = display.vlc_media.subitems() audio_cd_tracks = output_display.vlc_media.subitems()
if not audio_cd_tracks or audio_cd_tracks.count() < 1: if not audio_cd_tracks or audio_cd_tracks.count() < 1:
return False return False
display.vlc_media = audio_cd_tracks.item_at_index(controller.media_info.title_track) output_display.vlc_media = audio_cd_tracks.item_at_index(controller.media_info.title_track)
elif controller.media_info.media_type == MediaType.Stream: elif controller.media_info.media_type == MediaType.Stream:
display.vlc_media = display.vlc_instance.media_new_location("ZZZZZZ") output_display.vlc_media = output_display.vlc_instance.media_new_location("ZZZZZZ")
else: else:
display.vlc_media = display.vlc_instance.media_new_path(path) output_display.vlc_media = output_display.vlc_instance.media_new_path(path)
# put the media in the media player # put the media in the media player
display.vlc_media_player.set_media(display.vlc_media) output_display.vlc_media_player.set_media(output_display.vlc_media)
# parse the metadata of the file # parse the metadata of the file
display.vlc_media.parse() output_display.vlc_media.parse()
self.volume(display, volume) self.volume(output_display, volume)
return True return True
def media_state_wait(self, display, media_state): def media_state_wait(self, output_display, media_state):
""" """
Wait for the video to change its state Wait for the video to change its state
Wait no longer than 60 seconds. (loading an iso file needs a long time) Wait no longer than 60 seconds. (loading an iso file needs a long time)
@ -246,171 +247,172 @@ class VlcPlayer(MediaPlayer):
""" """
vlc = get_vlc() vlc = get_vlc()
start = datetime.now() start = datetime.now()
while media_state != display.vlc_media.get_state(): while media_state != output_display.vlc_media.get_state():
if display.vlc_media.get_state() == vlc.State.Error: if output_display.vlc_media.get_state() == vlc.State.Error:
return False return False
self.application.process_events() self.application.process_events()
if (datetime.now() - start).seconds > 60: if (datetime.now() - start).seconds > 60:
return False return False
return True return True
def resize(self, display): def resize(self, output_display):
""" """
Resize the player Resize the player
:param display: The display where the media is :param output_display: The display where the media is
:return: :return:
""" """
display.vlc_widget.resize(display.size()) # output_display.vlc_widget.resize(output_display.size())
pass
def play(self, display): def play(self, controller, output_display):
""" """
Play the current item Play the current item
:param display: The display where the media is :param controller: Which Controller is running the show.
:param output_display: The display where the media is
:return: :return:
""" """
vlc = get_vlc() vlc = get_vlc()
controller = display.controller
start_time = 0 start_time = 0
log.debug('vlc play') log.debug('vlc play')
if display.controller.is_live: if output_display.is_display:
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0: if self.get_live_state() != MediaState.Paused and output_display.media_info.start_time > 0:
start_time = controller.media_info.start_time start_time = output_display.media_info.start_time
else: else:
if self.get_preview_state() != MediaState.Paused and controller.media_info.start_time > 0: if self.get_preview_state() != MediaState.Paused and output_display.media_info.start_time > 0:
start_time = controller.media_info.start_time start_time = output_display.media_info.start_time
threading.Thread(target=display.vlc_media_player.play).start() threading.Thread(target=output_display.vlc_media_player.play).start()
if not self.media_state_wait(display, vlc.State.Playing): if not self.media_state_wait(output_display, vlc.State.Playing):
return False return False
if display.controller.is_live: if output_display.is_display:
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0: if self.get_live_state() != MediaState.Paused and output_display.media_info.start_time > 0:
log.debug('vlc play, start time set') log.debug('vlc play, start time set')
start_time = controller.media_info.start_time start_time = output_display.media_info.start_time
else: else:
if self.get_preview_state() != MediaState.Paused and controller.media_info.start_time > 0: if self.get_preview_state() != MediaState.Paused and output_display.media_info.start_time > 0:
log.debug('vlc play, start time set') log.debug('vlc play, start time set')
start_time = controller.media_info.start_time start_time = output_display.media_info.start_time
log.debug('mediatype: ' + str(controller.media_info.media_type)) log.debug('mediatype: ' + str(output_display.media_info.media_type))
# Set tracks for the optical device # Set tracks for the optical device
if controller.media_info.media_type == MediaType.DVD and \ if output_display.media_info.media_type == MediaType.DVD and \
self.get_live_state() != MediaState.Paused and self.get_preview_state() != MediaState.Paused: self.get_live_state() != MediaState.Paused and self.get_preview_state() != MediaState.Paused:
log.debug('vlc play, playing started') log.debug('vlc play, playing started')
if controller.media_info.title_track > 0: if output_display.media_info.title_track > 0:
log.debug('vlc play, title_track set: ' + str(controller.media_info.title_track)) log.debug('vlc play, title_track set: ' + str(output_display.media_info.title_track))
display.vlc_media_player.set_title(controller.media_info.title_track) output_display.vlc_media_player.set_title(output_display.media_info.title_track)
display.vlc_media_player.play() output_display.vlc_media_player.play()
if not self.media_state_wait(display, vlc.State.Playing): if not self.media_state_wait(output_display, vlc.State.Playing):
return False return False
if controller.media_info.audio_track > 0: if output_display.media_info.audio_track > 0:
display.vlc_media_player.audio_set_track(controller.media_info.audio_track) output_display.vlc_media_player.audio_set_track(output_display.media_info.audio_track)
log.debug('vlc play, audio_track set: ' + str(controller.media_info.audio_track)) log.debug('vlc play, audio_track set: ' + str(output_display.media_info.audio_track))
if controller.media_info.subtitle_track > 0: if output_display.media_info.subtitle_track > 0:
display.vlc_media_player.video_set_spu(controller.media_info.subtitle_track) output_display.vlc_media_player.video_set_spu(output_display.media_info.subtitle_track)
log.debug('vlc play, subtitle_track set: ' + str(controller.media_info.subtitle_track)) log.debug('vlc play, subtitle_track set: ' + str(output_display.media_info.subtitle_track))
if controller.media_info.start_time > 0: if output_display.media_info.start_time > 0:
log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time)) log.debug('vlc play, starttime set: ' + str(output_display.media_info.start_time))
start_time = controller.media_info.start_time start_time = output_display.media_info.start_time
controller.media_info.length = controller.media_info.end_time - controller.media_info.start_time output_display.media_info.length = output_display.media_info.end_time - output_display.media_info.start_time
self.volume(display, controller.media_info.volume) self.volume(output_display, output_display.media_info.volume)
if start_time > 0 and display.vlc_media_player.is_seekable(): if start_time > 0 and output_display.vlc_media_player.is_seekable():
display.vlc_media_player.set_time(int(start_time)) output_display.vlc_media_player.set_time(int(start_time))
controller.seek_slider.setMaximum(controller.media_info.length) controller.seek_slider.setMaximum(output_display.media_info.length)
self.set_state(MediaState.Playing, display) self.set_state(MediaState.Playing, output_display)
display.vlc_widget.raise_() output_display.vlc_widget.raise_()
return True return True
def pause(self, display): def pause(self, output_display):
""" """
Pause the current item Pause the current item
:param display: The display where the media is :param output_display: The display where the media is
:return: :return:
""" """
vlc = get_vlc() vlc = get_vlc()
if display.vlc_media.get_state() != vlc.State.Playing: if output_display.vlc_media.get_state() != vlc.State.Playing:
return return
display.vlc_media_player.pause() output_display.vlc_media_player.pause()
if self.media_state_wait(display, vlc.State.Paused): if self.media_state_wait(output_display, vlc.State.Paused):
self.set_state(MediaState.Paused, display) self.set_state(MediaState.Paused, output_display)
def stop(self, display): def stop(self, output_display):
""" """
Stop the current item Stop the current item
:param display: The display where the media is :param output_display: The display where the media is
:return: :return:
""" """
threading.Thread(target=display.vlc_media_player.stop).start() threading.Thread(target=output_display.vlc_media_player.stop).start()
self.set_state(MediaState.Stopped, display) self.set_state(MediaState.Stopped, output_display)
def volume(self, display, vol): def volume(self, output_display, vol):
""" """
Set the volume Set the volume
:param vol: The volume to be sets :param vol: The volume to be sets
:param display: The display where the media is :param output_display: The display where the media is
:return: :return:
""" """
if display.has_audio: if output_display.has_audio:
display.vlc_media_player.audio_set_volume(vol) output_display.vlc_media_player.audio_set_volume(vol)
def seek(self, display, seek_value): def seek(self, output_display, seek_value):
""" """
Go to a particular position Go to a particular position
:param seek_value: The position of where a seek goes to :param seek_value: The position of where a seek goes to
:param display: The display where the media is :param output_display: The display where the media is
""" """
if display.controller.media_info.media_type == MediaType.CD \ if output_display.controller.media_info.media_type == MediaType.CD \
or display.controller.media_info.media_type == MediaType.DVD: or output_display.controller.media_info.media_type == MediaType.DVD:
seek_value += int(display.controller.media_info.start_time) seek_value += int(output_display.controller.media_info.start_time)
if display.vlc_media_player.is_seekable(): if output_display.vlc_media_player.is_seekable():
display.vlc_media_player.set_time(seek_value) output_display.vlc_media_player.set_time(seek_value)
def reset(self, display): def reset(self, output_display):
""" """
Reset the player Reset the player
:param display: The display where the media is :param output_display: The display where the media is
""" """
display.vlc_media_player.stop() output_display.vlc_media_player.stop()
display.vlc_widget.setVisible(False) output_display.vlc_widget.setVisible(False)
self.set_state(MediaState.Off, display) self.set_state(MediaState.Off, output_display)
def set_visible(self, display, status): def set_visible(self, output_display, status):
""" """
Set the visibility Set the visibility
:param display: The display where the media is :param output_display: The display where the media is
:param status: The visibility status :param status: The visibility status
""" """
if self.has_own_widget: if self.has_own_widget:
display.vlc_widget.setVisible(status) output_display.vlc_widget.setVisible(status)
def update_ui(self, display): def update_ui(self, controller, output_display):
""" """
Update the UI Update the UI
:param display: The display where the media is :param controller: Which Controller is running the show.
:param output_display: The display where the media is
""" """
vlc = get_vlc() vlc = get_vlc()
# Stop video if playback is finished. # Stop video if playback is finished.
if display.vlc_media.get_state() == vlc.State.Ended: if output_display.vlc_media.get_state() == vlc.State.Ended:
self.stop(display) self.stop(output_display)
controller = display.controller
if controller.media_info.end_time > 0: if controller.media_info.end_time > 0:
if display.vlc_media_player.get_time() > controller.media_info.end_time: if output_display.vlc_media_player.get_time() > controller.media_info.end_time:
self.stop(display) self.stop(output_display)
self.set_visible(display, False) self.set_visible(output_display, False)
if not controller.seek_slider.isSliderDown(): if not controller.seek_slider.isSliderDown():
controller.seek_slider.blockSignals(True) controller.seek_slider.blockSignals(True)
if display.controller.media_info.media_type == MediaType.CD \ if controller.media_info.media_type == MediaType.CD \
or display.controller.media_info.media_type == MediaType.DVD: or controller.media_info.media_type == MediaType.DVD:
controller.seek_slider.setSliderPosition( controller.seek_slider.setSliderPosition(
display.vlc_media_player.get_time() - int(display.controller.media_info.start_time)) output_display.vlc_media_player.get_time() - int(output_display.controller.media_info.start_time))
else: else:
controller.seek_slider.setSliderPosition(display.vlc_media_player.get_time()) controller.seek_slider.setSliderPosition(output_display.vlc_media_player.get_time())
controller.seek_slider.blockSignals(False) controller.seek_slider.blockSignals(False)
def get_info(self): def get_info(self):

View File

@ -62,7 +62,6 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
self.themes_tab = None self.themes_tab = None
self.projector_tab = None self.projector_tab = None
self.advanced_tab = None self.advanced_tab = None
self.player_tab = None
self.api_tab = None self.api_tab = None
def exec(self): def exec(self):
@ -156,18 +155,16 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
""" """
Run any post-setup code for the tabs on the form Run any post-setup code for the tabs on the form
""" """
# General tab try:
self.general_tab = GeneralTab(self) self.general_tab = GeneralTab(self)
# Themes tab
self.themes_tab = ThemesTab(self) self.themes_tab = ThemesTab(self)
# Projector Tab
self.projector_tab = ProjectorTab(self) self.projector_tab = ProjectorTab(self)
# Advanced tab
self.advanced_tab = AdvancedTab(self) self.advanced_tab = AdvancedTab(self)
# Advanced tab
self.player_tab = MediaTab(self) self.player_tab = MediaTab(self)
# Api tab
self.api_tab = ApiTab(self) self.api_tab = ApiTab(self)
self.screens_tab = ScreensTab(self)
except Exception as e:
print(e)
self.general_tab.post_set_up() self.general_tab.post_set_up()
self.themes_tab.post_set_up() self.themes_tab.post_set_up()
self.advanced_tab.post_set_up() self.advanced_tab.post_set_up()

View File

@ -23,6 +23,7 @@
The :mod:`slidecontroller` module contains the most important part of OpenLP - the slide controller The :mod:`slidecontroller` module contains the most important part of OpenLP - the slide controller
""" """
import copy import copy
import datetime
from collections import deque from collections import deque
from threading import Lock from threading import Lock
@ -70,6 +71,45 @@ NON_TEXT_MENU = [
] ]
class MediaSlider(QtWidgets.QSlider):
"""
Allows the mouse events of a slider to be overridden and extra functionality added
"""
def __init__(self, direction, manager, controller):
"""
Constructor
"""
super(MediaSlider, self).__init__(direction)
self.manager = manager
self.controller = controller
def mouseMoveEvent(self, event):
"""
Override event to allow hover time to be displayed.
:param event: The triggering event
"""
time_value = QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width())
self.setToolTip('%s' % datetime.timedelta(seconds=int(time_value / 1000)))
QtWidgets.QSlider.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
"""
Mouse Press event no new functionality
:param event: The triggering event
"""
QtWidgets.QSlider.mousePressEvent(self, event)
def mouseReleaseEvent(self, event):
"""
Set the slider position when the mouse is clicked and released on the slider.
:param event: The triggering event
"""
self.setValue(QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width()))
QtWidgets.QSlider.mouseReleaseEvent(self, event)
class InfoLabel(QtWidgets.QLabel): class InfoLabel(QtWidgets.QLabel):
""" """
InfoLabel is a subclassed QLabel. Created to provide the ablilty to add a ellipsis if the text is cut off. Original InfoLabel is a subclassed QLabel. Created to provide the ablilty to add a ellipsis if the text is cut off. Original
@ -316,8 +356,59 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
'Clear'), 'Clear'),
triggers=self.on_clear) triggers=self.on_clear)
self.controller_layout.addWidget(self.toolbar) self.controller_layout.addWidget(self.toolbar)
# Build the Media Toolbar # Build a Media ToolBar
self.media_controller.register_controller(self) self.mediabar = OpenLPToolbar(self)
self.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play',
icon=UiIcons().play,
tooltip=translate('OpenLP.SlideController', 'Start playing media.'),
triggers=self.send_to_plugins)
self.mediabar.add_toolbar_action('playbackPause', text='media_playback_pause',
icon=UiIcons().pause,
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
triggers=self.send_to_plugins)
self.mediabar.add_toolbar_action('playbackStop', text='media_playback_stop',
icon=UiIcons().stop,
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
triggers=self.send_to_plugins)
self.mediabar.add_toolbar_action('playbackLoop', text='media_playback_loop',
icon=UiIcons().repeat, checked=False,
tooltip=translate('OpenLP.SlideController', 'Loop playing media.'),
triggers=self.send_to_plugins)
self.position_label = QtWidgets.QLabel()
self.position_label.setText(' 00:00 / 00:00')
self.position_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.position_label.setToolTip(translate('OpenLP.SlideController', 'Video timer.'))
self.position_label.setMinimumSize(90, 0)
self.position_label.setObjectName('position_label')
self.mediabar.add_toolbar_widget(self.position_label)
# Build the seek_slider.
self.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, self)
self.seek_slider.setMaximum(1000)
self.seek_slider.setTracking(True)
self.seek_slider.setMouseTracking(True)
self.seek_slider.setToolTip(translate('OpenLP.SlideController', 'Video position.'))
self.seek_slider.setGeometry(QtCore.QRect(90, 260, 221, 24))
self.seek_slider.setObjectName('seek_slider')
self.mediabar.add_toolbar_widget(self.seek_slider)
# Build the volume_slider.
self.volume_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.volume_slider.setTickInterval(10)
self.volume_slider.setTickPosition(QtWidgets.QSlider.TicksAbove)
self.volume_slider.setMinimum(0)
self.volume_slider.setMaximum(100)
self.volume_slider.setTracking(True)
self.volume_slider.setToolTip(translate('OpenLP.SlideController', 'Audio Volume.'))
# self.volume_slider.setValue(self.media_info.volume)
self.volume_slider.setGeometry(QtCore.QRect(90, 160, 221, 24))
self.volume_slider.setObjectName('volume_slider')
self.mediabar.add_toolbar_widget(self.volume_slider)
self.controller_layout.addWidget(self.mediabar)
self.mediabar.setVisible(False)
if not self.is_live:
self.volume_slider.setEnabled(False)
# Signals
self.seek_slider.valueChanged.connect(self.send_to_plugins)
self.volume_slider.valueChanged.connect(self.send_to_plugins)
if self.is_live: if self.is_live:
# Build the Song Toolbar # Build the Song Toolbar
self.song_menu = QtWidgets.QToolButton(self.toolbar) self.song_menu = QtWidgets.QToolButton(self.toolbar)
@ -556,8 +647,6 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
# self.__add_actions_to_widget(self.display) # self.__add_actions_to_widget(self.display)
# The SlidePreview's ratio. # The SlidePreview's ratio.
# TODO: Need to basically update everything
def __add_actions_to_widget(self, widget): def __add_actions_to_widget(self, widget):
""" """
Add actions to the widget specified by `widget` Add actions to the widget specified by `widget`
@ -1398,10 +1487,10 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
:param item: The service item to be processed :param item: The service item to be processed
""" """
if self.is_live and self.hide_mode() == HideMode.Theme: if self.is_live and self.hide_mode() == HideMode.Theme:
self.media_controller.video(self.controller_type, item, HideMode.Blank) self.media_controller.load_video(self.controller_type, item, HideMode.Blank)
self.on_blank_display(True) self.on_blank_display(True)
else: else:
self.media_controller.video(self.controller_type, item, self.hide_mode()) self.media_controller.load_video(self.controller_type, item, self.hide_mode())
if not self.is_live: if not self.is_live:
self.preview_display.show() self.preview_display.show()
@ -1491,7 +1580,7 @@ class PreviewController(RegistryBase, SlideController):
self.type_prefix = 'preview' self.type_prefix = 'preview'
self.category = 'Preview Toolbar' self.category = 'Preview Toolbar'
def bootstrap_post_set_up(self): def bootstrap_initialise(self):
""" """
process the bootstrap post setup request process the bootstrap post setup request
""" """
@ -1523,7 +1612,7 @@ class LiveController(RegistryBase, SlideController):
self.category = UiStrings().LiveToolbar self.category = UiStrings().LiveToolbar
ActionList.get_instance().add_category(str(self.category), CategoryOrder.standard_toolbar) ActionList.get_instance().add_category(str(self.category), CategoryOrder.standard_toolbar)
def bootstrap_post_set_up(self): def bootstrap_initialise(self):
""" """
process the bootstrap post setup request process the bootstrap post setup request
""" """

View File

@ -202,6 +202,9 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
if self.service_item.is_command(): if self.service_item.is_command():
if self.service_item.is_capable(ItemCapabilities.HasThumbnails): if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
pixmap = QtGui.QPixmap(remove_url_prefix(slide['thumbnail'])) pixmap = QtGui.QPixmap(remove_url_prefix(slide['thumbnail']))
else:
if isinstance(slide['image'], QtGui.QIcon):
pixmap = slide['image'].pixmap(QtCore.QSize(32, 32))
else: else:
pixmap = QtGui.QPixmap(remove_url_prefix(slide['image'])) pixmap = QtGui.QPixmap(remove_url_prefix(slide['image']))
else: else: