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
related to playing media, such as sliders.
"""
import datetime
import logging
try:
@ -33,7 +32,7 @@ except ImportError:
pymediainfo_available = False
from subprocess import check_output
from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtCore
from openlp.core.state import State
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.ui import critical_error_message_box
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.endpoint import media_endpoint
from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc
from openlp.core.widgets.toolbar import OpenLPToolbar
log = logging.getLogger(__name__)
@ -56,45 +53,6 @@ log = logging.getLogger(__name__)
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):
"""
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):
self.vlc_player = None
self.display_controllers = {}
self.current_media_players = {}
# Timer for video state
self.live_timer = QtCore.QTimer()
@ -176,109 +133,58 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
self._generate_extensions_lists()
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):
"""
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:
self.current_media_players[DisplayControllerType.Live].resize(display)
self.current_media_players[DisplayControllerType.Live].update_ui(display)
self.tick(self.display_controllers[DisplayControllerType.Live])
self.current_media_players[DisplayControllerType.Live].update_ui(self.live_controller, display)
self.tick(self.display_controllers(DisplayControllerType.Live))
if self.current_media_players[DisplayControllerType.Live].get_live_state() is not MediaState.Playing:
self.live_timer.stop()
else:
self.live_timer.stop()
self.media_stop(self.display_controllers[DisplayControllerType.Live])
if self.display_controllers[DisplayControllerType.Live].media_info.can_loop_playback:
self.media_play(self.display_controllers[DisplayControllerType.Live], True)
self.media_stop(self.display_controllers(DisplayControllerType.Live))
if self.display_controllers(DisplayControllerType.Live).media_info.can_loop_playback:
self.media_play(self.display_controllers(DisplayControllerType.Live), True)
def media_state_preview(self):
"""
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:
self.current_media_players[DisplayControllerType.Preview].resize(display)
self.current_media_players[DisplayControllerType.Preview].update_ui(display)
self.tick(self.display_controllers[DisplayControllerType.Preview])
self.current_media_players[DisplayControllerType.Preview].update_ui(self.preview_controller, display)
self.tick(self.display_controllers(DisplayControllerType.Preview))
if self.current_media_players[DisplayControllerType.Preview].get_preview_state() is not MediaState.Playing:
self.preview_timer.stop()
else:
self.preview_timer.stop()
self.media_stop(self.display_controllers[DisplayControllerType.Preview])
if self.display_controllers[DisplayControllerType.Preview].media_info.can_loop_playback:
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)
self.media_stop(self.display_controllers(DisplayControllerType.Preview))
if self.display_controllers(DisplayControllerType.Preview).media_info.can_loop_playback:
self.media_play(self.display_controllers(DisplayControllerType.Preview), True)
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 preview: Whether the display is a main or preview display
"""
# clean up possible running old media files
self.finalise()
display.media_info = ItemMediaInfo()
display.has_audio = True
if display.is_live and preview:
return
# if display.is_live and preview:
# return
if preview:
display.has_audio = False
self.vlc_player.setup(display)
self.vlc_player.setup(display, preview)
def set_controls_visible(self, controller, value):
"""
@ -305,9 +210,9 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
"""
# Generic controls
controller.mediabar.setVisible(value)
if controller.is_live and controller.display:
if self.current_media_players and value:
controller.display.set_transparency(False)
#if controller.is_live and controller.display:
#if self.current_media_players and value:
# controller.display.set_transparency(False)
@staticmethod
def resize(display, player):
@ -319,7 +224,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
"""
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
@ -329,7 +234,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
:param video_behind_text: Is the video to be played behind text.
"""
is_valid = True
controller = self.display_controllers[source]
controller = self.display_controllers(source)
# stop running videos
self.media_reset(controller)
controller.media_info = ItemMediaInfo()
@ -354,8 +259,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
log.debug('video is not optical and live')
controller.media_info.length = service_item.media_length
is_valid = self._check_file_type(controller, display)
display.override['theme'] = ''
display.override['video'] = True
#display.override['theme'] = ''
#display.override['video'] = True
if controller.media_info.is_background:
# ignore start/end time
controller.media_info.start_time = 0
@ -379,10 +284,10 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
log.debug('video mediatype: ' + 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
if controller.is_live and not controller.media_info.is_background:
display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");')
#if controller.is_live and not controller.media_info.is_background:
# display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");')
# now start playing - Preview is autoplay!
autoplay = False
# Preview requested
@ -471,28 +376,26 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
for file in controller.media_info.file_info:
if file.is_file:
suffix = '*%s' % file.suffix.lower()
player = self.vlc_player
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 \
player.can_background:
self.resize(display, player)
if player.load(display, file):
self.current_media_players[controller.controller_type] = player
self.vlc_player.can_background:
self.resize(display, self.vlc_player)
if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Video
return True
if suffix in player.audio_extensions_list:
if player.load(display, file):
self.current_media_players[controller.controller_type] = player
if suffix in self.vlc_player.audio_extensions_list:
if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Audio
return True
else:
player = self.vlc_player
file = str(file)
if player.can_folder:
self.resize(display, player)
if player.load(display, file):
self.current_media_players[controller.controller_type] = player
if self.vlc_player.can_folder:
self.resize(display, self.vlc_player)
if self.vlc_player.load(display, file):
self.current_media_players[controller.controller_type] = self.vlc_player
controller.media_info.media_type = MediaType.Video
return True
return False
@ -509,8 +412,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_play(self):
"""
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)
@ -524,7 +425,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
controller.seek_slider.blockSignals(True)
controller.volume_slider.blockSignals(True)
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.volume_slider.blockSignals(False)
return False
@ -533,8 +434,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
else:
self.media_volume(controller, controller.media_info.volume)
if first_time:
if not controller.media_info.is_background:
display.frame.runJavaScript('show_blank("desktop");')
#if not controller.media_info.is_background:
# display.frame.runJavaScript('show_blank("desktop");')
self.current_media_players[controller.controller_type].set_visible(display, True)
controller.mediabar.actions['playbackPlay'].setVisible(False)
controller.mediabar.actions['playbackPause'].setVisible(True)
@ -591,8 +492,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_pause(self):
"""
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'))
@ -639,8 +538,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
def on_media_stop(self):
"""
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'))
@ -653,8 +550,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
"""
display = self._define_display(controller)
if controller.controller_type in self.current_media_players:
if not looping_background:
display.frame.runJavaScript('show_blank("black");')
#if not looping_background:
# display.frame.runJavaScript('show_blank("black");')
self.current_media_players[controller.controller_type].stop(display)
self.current_media_players[controller.controller_type].set_visible(display, False)
controller.seek_slider.setSliderPosition(0)
@ -725,7 +622,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
display.override = {}
self.current_media_players[controller.controller_type].reset(display)
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]
def media_hide(self, msg):
@ -788,8 +685,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
"""
self.live_timer.stop()
self.preview_timer.stop()
for controller in self.display_controllers:
self.media_reset(self.display_controllers[controller])
self.media_reset(self.display_controllers(DisplayControllerType.Live))
self.media_reset(self.display_controllers(DisplayControllerType.Preview))
@staticmethod
def _define_display(controller):

View File

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

View File

@ -51,12 +51,12 @@ class MediaTab(SettingsTab):
player_translated = translate('OpenLP.MediaTab', 'Media')
super(MediaTab, self).__init__(parent, 'Media', player_translated)
def setupUi(self):
def setup_ui(self):
"""
Set up the UI
"""
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.setObjectName('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.video_extensions_list = VIDEO_EXT
def setup(self, display):
def setup(self, output_display, live_display):
"""
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:
"""
vlc = get_vlc()
display.vlc_widget = QtWidgets.QFrame(display)
display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame)
output_display.vlc_widget = QtWidgets.QFrame(output_display)
output_display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame)
# creating a basic vlc instance
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'
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'
display.vlc_instance = vlc.Instance(command_line_options)
output_display.vlc_instance = vlc.Instance(command_line_options)
# creating an empty vlc media player
display.vlc_media_player = display.vlc_instance.media_player_new()
display.vlc_widget.resize(display.size())
display.vlc_widget.raise_()
display.vlc_widget.hide()
output_display.vlc_media_player = output_display.vlc_instance.media_player_new()
output_display.vlc_widget.resize(output_display.size())
output_display.vlc_widget.raise_()
output_display.vlc_widget.hide()
# The media player has to be 'connected' to the QFrame.
# (otherwise a video would be displayed in it's own window)
# This is platform specific!
# You have to give the id of the QFrame (or similar object)
# 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():
display.vlc_media_player.set_hwnd(win_id)
output_display.vlc_media_player.set_hwnd(win_id)
elif is_macosx():
# We have to use 'set_nsobject' since Qt5 on OSX uses Cocoa
# framework and not the old Carbon.
display.vlc_media_player.set_nsobject(win_id)
output_display.vlc_media_player.set_nsobject(win_id)
else:
# 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
def check_available(self):
@ -197,45 +198,45 @@ class VlcPlayer(MediaPlayer):
"""
return get_vlc() is not None
def load(self, display, file):
def load(self, output_display, file):
"""
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
:return:
"""
vlc = get_vlc()
log.debug('load vid in Vlc Controller')
controller = display.controller
controller = output_display
volume = controller.media_info.volume
path = os.path.normcase(file)
# create the media
if controller.media_info.media_type == MediaType.CD:
if is_win():
path = '/' + path
display.vlc_media = display.vlc_instance.media_new_location('cdda://' + path)
display.vlc_media_player.set_media(display.vlc_media)
display.vlc_media_player.play()
output_display.vlc_media = output_display.vlc_instance.media_new_location('cdda://' + path)
output_display.vlc_media_player.set_media(output_display.vlc_media)
output_display.vlc_media_player.play()
# 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
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:
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:
display.vlc_media = display.vlc_instance.media_new_location("ZZZZZZ")
output_display.vlc_media = output_display.vlc_instance.media_new_location("ZZZZZZ")
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
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
display.vlc_media.parse()
self.volume(display, volume)
output_display.vlc_media.parse()
self.volume(output_display, volume)
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 no longer than 60 seconds. (loading an iso file needs a long time)
@ -246,171 +247,172 @@ class VlcPlayer(MediaPlayer):
"""
vlc = get_vlc()
start = datetime.now()
while media_state != display.vlc_media.get_state():
if display.vlc_media.get_state() == vlc.State.Error:
while media_state != output_display.vlc_media.get_state():
if output_display.vlc_media.get_state() == vlc.State.Error:
return False
self.application.process_events()
if (datetime.now() - start).seconds > 60:
return False
return True
def resize(self, display):
def resize(self, output_display):
"""
Resize the player
:param display: The display where the media is
:param output_display: The display where the media is
: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
: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:
"""
vlc = get_vlc()
controller = display.controller
start_time = 0
log.debug('vlc play')
if display.controller.is_live:
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0:
start_time = controller.media_info.start_time
if output_display.is_display:
if self.get_live_state() != MediaState.Paused and output_display.media_info.start_time > 0:
start_time = output_display.media_info.start_time
else:
if self.get_preview_state() != MediaState.Paused and controller.media_info.start_time > 0:
start_time = controller.media_info.start_time
threading.Thread(target=display.vlc_media_player.play).start()
if not self.media_state_wait(display, vlc.State.Playing):
if self.get_preview_state() != MediaState.Paused and output_display.media_info.start_time > 0:
start_time = output_display.media_info.start_time
threading.Thread(target=output_display.vlc_media_player.play).start()
if not self.media_state_wait(output_display, vlc.State.Playing):
return False
if display.controller.is_live:
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0:
if output_display.is_display:
if self.get_live_state() != MediaState.Paused and output_display.media_info.start_time > 0:
log.debug('vlc play, start time set')
start_time = controller.media_info.start_time
start_time = output_display.media_info.start_time
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')
start_time = controller.media_info.start_time
log.debug('mediatype: ' + str(controller.media_info.media_type))
start_time = output_display.media_info.start_time
log.debug('mediatype: ' + str(output_display.media_info.media_type))
# 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:
log.debug('vlc play, playing started')
if controller.media_info.title_track > 0:
log.debug('vlc play, title_track set: ' + str(controller.media_info.title_track))
display.vlc_media_player.set_title(controller.media_info.title_track)
display.vlc_media_player.play()
if not self.media_state_wait(display, vlc.State.Playing):
if output_display.media_info.title_track > 0:
log.debug('vlc play, title_track set: ' + str(output_display.media_info.title_track))
output_display.vlc_media_player.set_title(output_display.media_info.title_track)
output_display.vlc_media_player.play()
if not self.media_state_wait(output_display, vlc.State.Playing):
return False
if controller.media_info.audio_track > 0:
display.vlc_media_player.audio_set_track(controller.media_info.audio_track)
log.debug('vlc play, audio_track set: ' + str(controller.media_info.audio_track))
if controller.media_info.subtitle_track > 0:
display.vlc_media_player.video_set_spu(controller.media_info.subtitle_track)
log.debug('vlc play, subtitle_track set: ' + str(controller.media_info.subtitle_track))
if controller.media_info.start_time > 0:
log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time))
start_time = controller.media_info.start_time
controller.media_info.length = controller.media_info.end_time - controller.media_info.start_time
self.volume(display, controller.media_info.volume)
if start_time > 0 and display.vlc_media_player.is_seekable():
display.vlc_media_player.set_time(int(start_time))
controller.seek_slider.setMaximum(controller.media_info.length)
self.set_state(MediaState.Playing, display)
display.vlc_widget.raise_()
if output_display.media_info.audio_track > 0:
output_display.vlc_media_player.audio_set_track(output_display.media_info.audio_track)
log.debug('vlc play, audio_track set: ' + str(output_display.media_info.audio_track))
if output_display.media_info.subtitle_track > 0:
output_display.vlc_media_player.video_set_spu(output_display.media_info.subtitle_track)
log.debug('vlc play, subtitle_track set: ' + str(output_display.media_info.subtitle_track))
if output_display.media_info.start_time > 0:
log.debug('vlc play, starttime set: ' + str(output_display.media_info.start_time))
start_time = output_display.media_info.start_time
output_display.media_info.length = output_display.media_info.end_time - output_display.media_info.start_time
self.volume(output_display, output_display.media_info.volume)
if start_time > 0 and output_display.vlc_media_player.is_seekable():
output_display.vlc_media_player.set_time(int(start_time))
controller.seek_slider.setMaximum(output_display.media_info.length)
self.set_state(MediaState.Playing, output_display)
output_display.vlc_widget.raise_()
return True
def pause(self, display):
def pause(self, output_display):
"""
Pause the current item
:param display: The display where the media is
:param output_display: The display where the media is
:return:
"""
vlc = get_vlc()
if display.vlc_media.get_state() != vlc.State.Playing:
if output_display.vlc_media.get_state() != vlc.State.Playing:
return
display.vlc_media_player.pause()
if self.media_state_wait(display, vlc.State.Paused):
self.set_state(MediaState.Paused, display)
output_display.vlc_media_player.pause()
if self.media_state_wait(output_display, vlc.State.Paused):
self.set_state(MediaState.Paused, output_display)
def stop(self, display):
def stop(self, output_display):
"""
Stop the current item
:param display: The display where the media is
:param output_display: The display where the media is
:return:
"""
threading.Thread(target=display.vlc_media_player.stop).start()
self.set_state(MediaState.Stopped, display)
threading.Thread(target=output_display.vlc_media_player.stop).start()
self.set_state(MediaState.Stopped, output_display)
def volume(self, display, vol):
def volume(self, output_display, vol):
"""
Set the volume
: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:
"""
if display.has_audio:
display.vlc_media_player.audio_set_volume(vol)
if output_display.has_audio:
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
: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 \
or display.controller.media_info.media_type == MediaType.DVD:
seek_value += int(display.controller.media_info.start_time)
if display.vlc_media_player.is_seekable():
display.vlc_media_player.set_time(seek_value)
if output_display.controller.media_info.media_type == MediaType.CD \
or output_display.controller.media_info.media_type == MediaType.DVD:
seek_value += int(output_display.controller.media_info.start_time)
if output_display.vlc_media_player.is_seekable():
output_display.vlc_media_player.set_time(seek_value)
def reset(self, display):
def reset(self, output_display):
"""
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()
display.vlc_widget.setVisible(False)
self.set_state(MediaState.Off, display)
output_display.vlc_media_player.stop()
output_display.vlc_widget.setVisible(False)
self.set_state(MediaState.Off, output_display)
def set_visible(self, display, status):
def set_visible(self, output_display, status):
"""
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
"""
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
: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()
# Stop video if playback is finished.
if display.vlc_media.get_state() == vlc.State.Ended:
self.stop(display)
controller = display.controller
if output_display.vlc_media.get_state() == vlc.State.Ended:
self.stop(output_display)
if controller.media_info.end_time > 0:
if display.vlc_media_player.get_time() > controller.media_info.end_time:
self.stop(display)
self.set_visible(display, False)
if output_display.vlc_media_player.get_time() > controller.media_info.end_time:
self.stop(output_display)
self.set_visible(output_display, False)
if not controller.seek_slider.isSliderDown():
controller.seek_slider.blockSignals(True)
if display.controller.media_info.media_type == MediaType.CD \
or display.controller.media_info.media_type == MediaType.DVD:
if controller.media_info.media_type == MediaType.CD \
or controller.media_info.media_type == MediaType.DVD:
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:
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)
def get_info(self):

View File

@ -62,7 +62,6 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
self.themes_tab = None
self.projector_tab = None
self.advanced_tab = None
self.player_tab = None
self.api_tab = None
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
"""
# General tab
try:
self.general_tab = GeneralTab(self)
# Themes tab
self.themes_tab = ThemesTab(self)
# Projector Tab
self.projector_tab = ProjectorTab(self)
# Advanced tab
self.advanced_tab = AdvancedTab(self)
# Advanced tab
self.player_tab = MediaTab(self)
# Api tab
self.api_tab = ApiTab(self)
self.screens_tab = ScreensTab(self)
except Exception as e:
print(e)
self.general_tab.post_set_up()
self.themes_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
"""
import copy
import datetime
from collections import deque
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):
"""
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'),
triggers=self.on_clear)
self.controller_layout.addWidget(self.toolbar)
# Build the Media Toolbar
self.media_controller.register_controller(self)
# Build a Media ToolBar
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:
# Build the Song 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)
# The SlidePreview's ratio.
# TODO: Need to basically update everything
def __add_actions_to_widget(self, 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
"""
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)
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:
self.preview_display.show()
@ -1491,7 +1580,7 @@ class PreviewController(RegistryBase, SlideController):
self.type_prefix = 'preview'
self.category = 'Preview Toolbar'
def bootstrap_post_set_up(self):
def bootstrap_initialise(self):
"""
process the bootstrap post setup request
"""
@ -1523,7 +1612,7 @@ class LiveController(RegistryBase, SlideController):
self.category = UiStrings().LiveToolbar
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
"""

View File

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