forked from openlp/openlp
Merged from trunk
This commit is contained in:
commit
c8172d882f
@ -610,7 +610,7 @@ class ServiceItem(RegistryProperties):
|
|||||||
str(datetime.timedelta(seconds=self.start_time))
|
str(datetime.timedelta(seconds=self.start_time))
|
||||||
if self.media_length != 0:
|
if self.media_length != 0:
|
||||||
end = translate('OpenLP.ServiceItem', '<strong>Length</strong>: %s') % \
|
end = translate('OpenLP.ServiceItem', '<strong>Length</strong>: %s') % \
|
||||||
str(datetime.timedelta(seconds=self.media_length))
|
str(datetime.timedelta(seconds=self.media_length // 1000))
|
||||||
if not start and not end:
|
if not start and not end:
|
||||||
return ''
|
return ''
|
||||||
elif start and not end:
|
elif start and not end:
|
||||||
|
@ -68,7 +68,6 @@ class DisplayControllerType(object):
|
|||||||
"""
|
"""
|
||||||
Live = 0
|
Live = 0
|
||||||
Preview = 1
|
Preview = 1
|
||||||
Plugin = 2
|
|
||||||
|
|
||||||
|
|
||||||
class SingleColumnTableWidget(QtWidgets.QTableWidget):
|
class SingleColumnTableWidget(QtWidgets.QTableWidget):
|
||||||
|
@ -60,12 +60,14 @@ class MediaInfo(object):
|
|||||||
"""
|
"""
|
||||||
file_info = None
|
file_info = None
|
||||||
volume = 100
|
volume = 100
|
||||||
is_flash = False
|
|
||||||
is_background = False
|
is_background = False
|
||||||
|
can_loop_playback = False
|
||||||
length = 0
|
length = 0
|
||||||
start_time = 0
|
start_time = 0
|
||||||
end_time = 0
|
end_time = 0
|
||||||
title_track = 0
|
title_track = 0
|
||||||
|
is_playing = False
|
||||||
|
timer = 1000
|
||||||
audio_track = 0
|
audio_track = 0
|
||||||
subtitle_track = 0
|
subtitle_track = 0
|
||||||
media_type = MediaType()
|
media_type = MediaType()
|
||||||
@ -104,15 +106,15 @@ def set_media_players(players_list, overridden_player='auto'):
|
|||||||
Settings().setValue('media/players', players)
|
Settings().setValue('media/players', players)
|
||||||
|
|
||||||
|
|
||||||
def parse_optical_path(input):
|
def parse_optical_path(input_string):
|
||||||
"""
|
"""
|
||||||
Split the optical path info.
|
Split the optical path info.
|
||||||
|
|
||||||
:param input: The string to parse
|
:param input_string: The string to parse
|
||||||
:return: The elements extracted from the string: filename, title, audio_track, subtitle_track, start, end
|
:return: The elements extracted from the string: filename, title, audio_track, subtitle_track, start, end
|
||||||
"""
|
"""
|
||||||
log.debug('parse_optical_path, about to parse: "%s"' % input)
|
log.debug('parse_optical_path, about to parse: "%s"' % input_string)
|
||||||
clip_info = input.split(sep=':')
|
clip_info = input_string.split(sep=':')
|
||||||
title = int(clip_info[1])
|
title = int(clip_info[1])
|
||||||
audio_track = int(clip_info[2])
|
audio_track = int(clip_info[2])
|
||||||
subtitle_track = int(clip_info[3])
|
subtitle_track = int(clip_info[3])
|
||||||
|
@ -33,12 +33,15 @@ from openlp.core.lib import OpenLPToolbar, 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.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
|
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
|
||||||
parse_optical_path
|
parse_optical_path
|
||||||
|
from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
|
||||||
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||||
from openlp.core.common import AppLocation
|
from openlp.core.common import AppLocation
|
||||||
from openlp.core.ui import DisplayControllerType
|
from openlp.core.ui import DisplayControllerType
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
TICK_TIME = 200
|
||||||
|
|
||||||
|
|
||||||
class MediaSlider(QtWidgets.QSlider):
|
class MediaSlider(QtWidgets.QSlider):
|
||||||
"""
|
"""
|
||||||
@ -51,10 +54,13 @@ class MediaSlider(QtWidgets.QSlider):
|
|||||||
super(MediaSlider, self).__init__(direction)
|
super(MediaSlider, self).__init__(direction)
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
self.no_matching_player = translate('MediaPlugin.MediaItem', 'File %s not supported using player %s')
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
def mouseMoveEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Override event to allow hover time to be displayed.
|
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())
|
time_value = QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width())
|
||||||
self.setToolTip('%s' % datetime.timedelta(seconds=int(time_value / 1000)))
|
self.setToolTip('%s' % datetime.timedelta(seconds=int(time_value / 1000)))
|
||||||
@ -63,12 +69,16 @@ class MediaSlider(QtWidgets.QSlider):
|
|||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Mouse Press event no new functionality
|
Mouse Press event no new functionality
|
||||||
|
|
||||||
|
:param event: The triggering event
|
||||||
"""
|
"""
|
||||||
QtWidgets.QSlider.mousePressEvent(self, event)
|
QtWidgets.QSlider.mousePressEvent(self, event)
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
def mouseReleaseEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Set the slider position when the mouse is clicked and released on the slider.
|
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()))
|
self.setValue(QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width()))
|
||||||
QtWidgets.QSlider.mouseReleaseEvent(self, event)
|
QtWidgets.QSlider.mouseReleaseEvent(self, event)
|
||||||
@ -96,13 +106,17 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
self.display_controllers = {}
|
self.display_controllers = {}
|
||||||
self.current_media_players = {}
|
self.current_media_players = {}
|
||||||
# Timer for video state
|
# Timer for video state
|
||||||
self.timer = QtCore.QTimer()
|
self.live_timer = QtCore.QTimer()
|
||||||
self.timer.setInterval(200)
|
self.live_timer.setInterval(TICK_TIME)
|
||||||
|
self.preview_timer = QtCore.QTimer()
|
||||||
|
self.preview_timer.setInterval(TICK_TIME)
|
||||||
# Signals
|
# Signals
|
||||||
self.timer.timeout.connect(self.media_state)
|
self.live_timer.timeout.connect(self.media_state_live)
|
||||||
|
self.preview_timer.timeout.connect(self.media_state_preview)
|
||||||
Registry().register_function('playbackPlay', self.media_play_msg)
|
Registry().register_function('playbackPlay', self.media_play_msg)
|
||||||
Registry().register_function('playbackPause', self.media_pause_msg)
|
Registry().register_function('playbackPause', self.media_pause_msg)
|
||||||
Registry().register_function('playbackStop', self.media_stop_msg)
|
Registry().register_function('playbackStop', self.media_stop_msg)
|
||||||
|
Registry().register_function('playbackLoop', self.media_loop_msg)
|
||||||
Registry().register_function('seek_slider', self.media_seek_msg)
|
Registry().register_function('seek_slider', self.media_seek_msg)
|
||||||
Registry().register_function('volume_slider', self.media_volume_msg)
|
Registry().register_function('volume_slider', self.media_volume_msg)
|
||||||
Registry().register_function('media_hide', self.media_hide)
|
Registry().register_function('media_hide', self.media_hide)
|
||||||
@ -172,8 +186,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
log.warning('Failed to import %s on path %s', module_name, path)
|
log.warning('Failed to import %s on path %s', module_name, path)
|
||||||
player_classes = MediaPlayer.__subclasses__()
|
player_classes = MediaPlayer.__subclasses__()
|
||||||
for player_class in player_classes:
|
for player_class in player_classes:
|
||||||
player = player_class(self)
|
self.register_players(player_class(self))
|
||||||
self.register_players(player)
|
|
||||||
if not self.media_players:
|
if not self.media_players:
|
||||||
return False
|
return False
|
||||||
saved_players, overridden_player = get_media_players()
|
saved_players, overridden_player = get_media_players()
|
||||||
@ -188,31 +201,39 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
self._generate_extensions_lists()
|
self._generate_extensions_lists()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def media_state(self):
|
def media_state_live(self):
|
||||||
"""
|
"""
|
||||||
Check if there is a running 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)
|
||||||
"""
|
"""
|
||||||
if not list(self.current_media_players.keys()):
|
display = self._define_display(self.display_controllers[DisplayControllerType.Live])
|
||||||
self.timer.stop()
|
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])
|
||||||
|
if self.current_media_players[DisplayControllerType.Live].get_live_state() is not MediaState.Playing:
|
||||||
|
self.live_timer.stop()
|
||||||
else:
|
else:
|
||||||
any_active = False
|
self.live_timer.stop()
|
||||||
for source in list(self.current_media_players.keys()):
|
self.media_stop(self.display_controllers[DisplayControllerType.Live])
|
||||||
display = self._define_display(self.display_controllers[source])
|
if self.display_controllers[DisplayControllerType.Live].media_info.can_loop_playback:
|
||||||
self.current_media_players[source].resize(display)
|
self.media_play(self.display_controllers[DisplayControllerType.Live], True)
|
||||||
self.current_media_players[source].update_ui(display)
|
|
||||||
if self.current_media_players[source].state == MediaState.Playing:
|
def media_state_preview(self):
|
||||||
any_active = True
|
"""
|
||||||
# There are still any active players - no need to stop timer.
|
Check if there is a running Preview media Player and do updating stuff (e.g. update the UI)
|
||||||
if any_active:
|
"""
|
||||||
return
|
display = self._define_display(self.display_controllers[DisplayControllerType.Preview])
|
||||||
# no players are active anymore
|
if DisplayControllerType.Preview in self.current_media_players:
|
||||||
for source in list(self.current_media_players.keys()):
|
self.current_media_players[DisplayControllerType.Preview].resize(display)
|
||||||
if self.current_media_players[source].state != MediaState.Paused:
|
self.current_media_players[DisplayControllerType.Preview].update_ui(display)
|
||||||
display = self._define_display(self.display_controllers[source])
|
self.tick(self.display_controllers[DisplayControllerType.Preview])
|
||||||
display.controller.seek_slider.setSliderPosition(0)
|
if self.current_media_players[DisplayControllerType.Preview].get_preview_state() is not MediaState.Playing:
|
||||||
display.controller.mediabar.actions['playbackPlay'].setVisible(True)
|
self.preview_timer.stop()
|
||||||
display.controller.mediabar.actions['playbackPause'].setVisible(False)
|
else:
|
||||||
self.timer.stop()
|
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 get_media_display_css(self):
|
def get_media_display_css(self):
|
||||||
"""
|
"""
|
||||||
@ -274,6 +295,15 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
icon=':/slides/media_playback_stop.png',
|
icon=':/slides/media_playback_stop.png',
|
||||||
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
|
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
|
||||||
triggers=controller.send_to_plugins)
|
triggers=controller.send_to_plugins)
|
||||||
|
controller.mediabar.add_toolbar_action('playbackLoop', text='media_playback_loop',
|
||||||
|
icon=':/slides/media_playback_stop.png', 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.setToolTip(translate('OpenLP.SlideController', 'Video timer.'))
|
||||||
|
controller.position_label.setObjectName('position_label')
|
||||||
|
controller.mediabar.add_toolbar_widget(controller.position_label)
|
||||||
# Build the seek_slider.
|
# Build the seek_slider.
|
||||||
controller.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
|
controller.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
|
||||||
controller.seek_slider.setMaximum(1000)
|
controller.seek_slider.setMaximum(1000)
|
||||||
@ -297,6 +327,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller.mediabar.add_toolbar_widget(controller.volume_slider)
|
controller.mediabar.add_toolbar_widget(controller.volume_slider)
|
||||||
controller.controller_layout.addWidget(controller.mediabar)
|
controller.controller_layout.addWidget(controller.mediabar)
|
||||||
controller.mediabar.setVisible(False)
|
controller.mediabar.setVisible(False)
|
||||||
|
if not controller.is_live:
|
||||||
|
controller.volume_slider.setEnabled(False)
|
||||||
# Signals
|
# Signals
|
||||||
controller.seek_slider.valueChanged.connect(controller.send_to_plugins)
|
controller.seek_slider.valueChanged.connect(controller.send_to_plugins)
|
||||||
controller.volume_slider.valueChanged.connect(controller.send_to_plugins)
|
controller.volume_slider.valueChanged.connect(controller.send_to_plugins)
|
||||||
@ -335,7 +367,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
if self.current_media_players[controller.controller_type] != self.media_players['webkit']:
|
if self.current_media_players[controller.controller_type] != self.media_players['webkit']:
|
||||||
controller.display.set_transparency(False)
|
controller.display.set_transparency(False)
|
||||||
|
|
||||||
def resize(self, display, player):
|
@staticmethod
|
||||||
|
def resize(display, player):
|
||||||
"""
|
"""
|
||||||
After Mainwindow changes or Splitter moved all related media widgets have to be resized
|
After Mainwindow changes or Splitter moved all related media widgets have to be resized
|
||||||
|
|
||||||
@ -353,7 +386,6 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
:param hidden: The player which is doing the playing
|
:param hidden: The player which is doing the playing
|
||||||
:param video_behind_text: Is the video to be played behind text.
|
:param video_behind_text: Is the video to be played behind text.
|
||||||
"""
|
"""
|
||||||
log.debug('video')
|
|
||||||
is_valid = False
|
is_valid = False
|
||||||
controller = self.display_controllers[source]
|
controller = self.display_controllers[source]
|
||||||
# stop running videos
|
# stop running videos
|
||||||
@ -361,6 +393,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller.media_info = MediaInfo()
|
controller.media_info = MediaInfo()
|
||||||
controller.media_info.volume = controller.volume_slider.value()
|
controller.media_info.volume = controller.volume_slider.value()
|
||||||
controller.media_info.is_background = video_behind_text
|
controller.media_info.is_background = video_behind_text
|
||||||
|
# background will always loop video.
|
||||||
|
controller.media_info.can_loop_playback = video_behind_text
|
||||||
controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path())
|
controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path())
|
||||||
display = self._define_display(controller)
|
display = self._define_display(controller)
|
||||||
if controller.is_live:
|
if controller.is_live:
|
||||||
@ -373,6 +407,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller)
|
controller)
|
||||||
else:
|
else:
|
||||||
log.debug('video is not optical and live')
|
log.debug('video is not optical and live')
|
||||||
|
controller.media_info.length = service_item.media_length
|
||||||
is_valid = self._check_file_type(controller, display, service_item)
|
is_valid = self._check_file_type(controller, display, service_item)
|
||||||
display.override['theme'] = ''
|
display.override['theme'] = ''
|
||||||
display.override['video'] = True
|
display.override['video'] = True
|
||||||
@ -392,6 +427,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller)
|
controller)
|
||||||
else:
|
else:
|
||||||
log.debug('video is not optical and preview')
|
log.debug('video is not optical and preview')
|
||||||
|
controller.media_info.length = service_item.media_length
|
||||||
is_valid = self._check_file_type(controller, display, service_item)
|
is_valid = self._check_file_type(controller, display, service_item)
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
# Media could not be loaded correctly
|
# Media could not be loaded correctly
|
||||||
@ -428,26 +464,22 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
|
|
||||||
:param service_item: The ServiceItem containing the details to be played.
|
:param service_item: The ServiceItem containing the details to be played.
|
||||||
"""
|
"""
|
||||||
controller = self.display_controllers[DisplayControllerType.Plugin]
|
media_info = MediaInfo()
|
||||||
log.debug('media_length')
|
media_info.volume = 0
|
||||||
# stop running videos
|
media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path())
|
||||||
self.media_reset(controller)
|
# display = controller.preview_display
|
||||||
controller.media_info = MediaInfo()
|
suffix = '*.%s' % media_info.file_info.suffix().lower()
|
||||||
controller.media_info.volume = 0
|
used_players = get_media_players()[0]
|
||||||
controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path())
|
player = self.media_players[used_players[0]]
|
||||||
display = controller.preview_display
|
if suffix not in player.video_extensions_list and suffix not in player.audio_extensions_list:
|
||||||
if not self._check_file_type(controller, display, service_item):
|
|
||||||
# Media could not be loaded correctly
|
# Media could not be loaded correctly
|
||||||
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported Media File'),
|
||||||
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
translate('MediaPlugin.MediaItem', 'File %s not supported using player %s') %
|
||||||
|
(service_item.get_frame_path(), used_players[0]))
|
||||||
return False
|
return False
|
||||||
if not self.media_play(controller):
|
media_data = MediaInfoWrapper.parse(service_item.get_frame_path())
|
||||||
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
# duration returns in milli seconds
|
||||||
translate('MediaPlugin.MediaItem', 'Unsupported File'))
|
service_item.set_media_length(media_data.tracks[0].duration)
|
||||||
return False
|
|
||||||
service_item.set_media_length(controller.media_info.length)
|
|
||||||
self.media_stop(controller)
|
|
||||||
log.debug('use %s controller' % self.current_media_players[controller.controller_type])
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller):
|
def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller):
|
||||||
@ -458,13 +490,12 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
:param title: The main/title track to play.
|
:param title: The main/title track to play.
|
||||||
:param audio_track: The audio track to play.
|
:param audio_track: The audio track to play.
|
||||||
:param subtitle_track: The subtitle track to play.
|
:param subtitle_track: The subtitle track to play.
|
||||||
:param start: Start position in miliseconds.
|
:param start: Start position in milliseconds.
|
||||||
:param end: End position in miliseconds.
|
:param end: End position in milliseconds.
|
||||||
:param display: The display to play the media.
|
:param display: The display to play the media.
|
||||||
:param controller: The media contraoller.
|
:param controller: The media controller.
|
||||||
:return: True if setup succeded else False.
|
:return: True if setup succeeded else False.
|
||||||
"""
|
"""
|
||||||
log.debug('media_setup_optical')
|
|
||||||
if controller is None:
|
if controller is None:
|
||||||
controller = self.display_controllers[DisplayControllerType.Plugin]
|
controller = self.display_controllers[DisplayControllerType.Plugin]
|
||||||
# stop running videos
|
# stop running videos
|
||||||
@ -476,9 +507,9 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller.media_info.media_type = MediaType.CD
|
controller.media_info.media_type = MediaType.CD
|
||||||
else:
|
else:
|
||||||
controller.media_info.media_type = MediaType.DVD
|
controller.media_info.media_type = MediaType.DVD
|
||||||
controller.media_info.start_time = start / 1000
|
controller.media_info.start_time = start // 1000
|
||||||
controller.media_info.end_time = end / 1000
|
controller.media_info.end_time = end // 1000
|
||||||
controller.media_info.length = (end - start) / 1000
|
controller.media_info.length = (end - start) // 1000
|
||||||
controller.media_info.title_track = title
|
controller.media_info.title_track = title
|
||||||
controller.media_info.audio_track = audio_track
|
controller.media_info.audio_track = audio_track
|
||||||
controller.media_info.subtitle_track = subtitle_track
|
controller.media_info.subtitle_track = subtitle_track
|
||||||
@ -506,13 +537,13 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
controller.media_info.media_type = MediaType.DVD
|
controller.media_info.media_type = MediaType.DVD
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _check_file_type(self, controller, display, service_item):
|
@staticmethod
|
||||||
|
def _get_used_players(service_item):
|
||||||
"""
|
"""
|
||||||
Select the correct media Player type from the prioritized Player list
|
Find the player for a given service item
|
||||||
|
|
||||||
:param controller: First element is the controller which should be used
|
:param service_item: where the information is about the media and required player
|
||||||
:param display: Which display to use
|
:return: player description
|
||||||
:param service_item: The ServiceItem containing the details to be played.
|
|
||||||
"""
|
"""
|
||||||
used_players = get_media_players()[0]
|
used_players = get_media_players()[0]
|
||||||
# If no player, we can't play
|
# If no player, we can't play
|
||||||
@ -525,6 +556,17 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
used_players = default_player
|
used_players = default_player
|
||||||
else:
|
else:
|
||||||
used_players = [service_item.processor.lower()]
|
used_players = [service_item.processor.lower()]
|
||||||
|
return used_players
|
||||||
|
|
||||||
|
def _check_file_type(self, controller, display, service_item):
|
||||||
|
"""
|
||||||
|
Select the correct media Player type from the prioritized Player list
|
||||||
|
|
||||||
|
:param controller: First element is the controller which should be used
|
||||||
|
:param display: Which display to use
|
||||||
|
:param service_item: The ServiceItem containing the details to be played.
|
||||||
|
"""
|
||||||
|
used_players = self._get_used_players(service_item)
|
||||||
if controller.media_info.file_info.isFile():
|
if controller.media_info.file_info.isFile():
|
||||||
suffix = '*.%s' % controller.media_info.file_info.suffix().lower()
|
suffix = '*.%s' % controller.media_info.file_info.suffix().lower()
|
||||||
for title in used_players:
|
for title in used_players:
|
||||||
@ -573,17 +615,15 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
:param msg: First element is the controller which should be used
|
:param msg: First element is the controller which should be used
|
||||||
:param status:
|
:param status:
|
||||||
"""
|
"""
|
||||||
log.debug('media_play_msg')
|
|
||||||
self.media_play(msg[0], status)
|
self.media_play(msg[0], status)
|
||||||
|
|
||||||
def media_play(self, controller, status=True):
|
def media_play(self, controller, first_time=True):
|
||||||
"""
|
"""
|
||||||
Responds to the request to play a loaded video
|
Responds to the request to play a loaded video
|
||||||
|
|
||||||
:param controller: The controller to be played
|
:param controller: The controller to be played
|
||||||
:param status:
|
:param first_time:
|
||||||
"""
|
"""
|
||||||
log.debug('media_play')
|
|
||||||
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)
|
||||||
@ -595,35 +635,60 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
self.media_volume(controller, 0)
|
self.media_volume(controller, 0)
|
||||||
else:
|
else:
|
||||||
self.media_volume(controller, controller.media_info.volume)
|
self.media_volume(controller, controller.media_info.volume)
|
||||||
if status:
|
if first_time:
|
||||||
if not controller.media_info.is_background:
|
if not controller.media_info.is_background:
|
||||||
display.frame.evaluateJavaScript('show_blank("desktop");')
|
display.frame.evaluateJavaScript('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)
|
||||||
# Flash needs to be played and will not AutoPlay
|
controller.mediabar.actions['playbackPlay'].setVisible(False)
|
||||||
if controller.media_info.is_flash:
|
controller.mediabar.actions['playbackPause'].setVisible(True)
|
||||||
controller.mediabar.actions['playbackPlay'].setVisible(True)
|
|
||||||
controller.mediabar.actions['playbackPause'].setVisible(False)
|
|
||||||
else:
|
|
||||||
controller.mediabar.actions['playbackPlay'].setVisible(False)
|
|
||||||
controller.mediabar.actions['playbackPause'].setVisible(True)
|
|
||||||
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
||||||
if controller.is_live:
|
if controller.is_live:
|
||||||
if controller.hide_menu.defaultAction().isChecked() and not controller.media_info.is_background:
|
if controller.hide_menu.defaultAction().isChecked() and not controller.media_info.is_background:
|
||||||
controller.hide_menu.defaultAction().trigger()
|
controller.hide_menu.defaultAction().trigger()
|
||||||
# Start Timer for ui updates
|
# Start Timer for ui updates
|
||||||
if not self.timer.isActive():
|
if not self.live_timer.isActive():
|
||||||
self.timer.start()
|
self.live_timer.start()
|
||||||
|
else:
|
||||||
|
# Start Timer for ui updates
|
||||||
|
if not self.preview_timer.isActive():
|
||||||
|
self.preview_timer.start()
|
||||||
controller.seek_slider.blockSignals(False)
|
controller.seek_slider.blockSignals(False)
|
||||||
controller.volume_slider.blockSignals(False)
|
controller.volume_slider.blockSignals(False)
|
||||||
|
controller.media_info.is_playing = True
|
||||||
|
display = self._define_display(controller)
|
||||||
|
display.setVisible(True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def tick(self, controller):
|
||||||
|
"""
|
||||||
|
Add a tick while the media is playing but only count if not paused
|
||||||
|
|
||||||
|
:param controller: The Controller to be processed
|
||||||
|
"""
|
||||||
|
start_again = False
|
||||||
|
if controller.media_info.is_playing and controller.media_info.length > 0:
|
||||||
|
if controller.media_info.timer > controller.media_info.length:
|
||||||
|
self.media_stop(controller, True)
|
||||||
|
if controller.media_info.can_loop_playback:
|
||||||
|
start_again = True
|
||||||
|
controller.media_info.timer += TICK_TIME
|
||||||
|
seconds = controller.media_info.timer // 1000
|
||||||
|
minutes = seconds // 60
|
||||||
|
seconds %= 60
|
||||||
|
total_seconds = controller.media_info.length // 1000
|
||||||
|
total_minutes = total_seconds // 60
|
||||||
|
total_seconds %= 60
|
||||||
|
controller.position_label.setText(' %02d:%02d / %02d:%02d' %
|
||||||
|
(minutes, seconds, total_minutes, total_seconds))
|
||||||
|
if start_again:
|
||||||
|
self.media_play(controller, True)
|
||||||
|
|
||||||
def media_pause_msg(self, msg):
|
def media_pause_msg(self, msg):
|
||||||
"""
|
"""
|
||||||
Responds to the request to pause a loaded video
|
Responds to the request to pause a loaded video
|
||||||
|
|
||||||
:param msg: First element is the controller which should be used
|
:param msg: First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
log.debug('media_pause_msg')
|
|
||||||
self.media_pause(msg[0])
|
self.media_pause(msg[0])
|
||||||
|
|
||||||
def media_pause(self, controller):
|
def media_pause(self, controller):
|
||||||
@ -632,12 +697,31 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
|
|
||||||
:param controller: The Controller to be paused
|
:param controller: The Controller to be paused
|
||||||
"""
|
"""
|
||||||
log.debug('media_pause')
|
|
||||||
display = self._define_display(controller)
|
display = self._define_display(controller)
|
||||||
self.current_media_players[controller.controller_type].pause(display)
|
if controller.controller_type in self.current_media_players:
|
||||||
controller.mediabar.actions['playbackPlay'].setVisible(True)
|
self.current_media_players[controller.controller_type].pause(display)
|
||||||
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
controller.mediabar.actions['playbackPlay'].setVisible(True)
|
||||||
controller.mediabar.actions['playbackPause'].setVisible(False)
|
controller.mediabar.actions['playbackStop'].setDisabled(False)
|
||||||
|
controller.mediabar.actions['playbackPause'].setVisible(False)
|
||||||
|
controller.media_info.is_playing = False
|
||||||
|
|
||||||
|
def media_loop_msg(self, msg):
|
||||||
|
"""
|
||||||
|
Responds to the request to loop a loaded video
|
||||||
|
|
||||||
|
:param msg: First element is the controller which should be used
|
||||||
|
"""
|
||||||
|
self.media_loop(msg[0])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def media_loop(controller):
|
||||||
|
"""
|
||||||
|
Responds to the request to loop a loaded video
|
||||||
|
|
||||||
|
:param controller: The controller that needs to be stopped
|
||||||
|
"""
|
||||||
|
controller.media_info.can_loop_playback = not controller.media_info.can_loop_playback
|
||||||
|
controller.mediabar.actions['playbackLoop'].setChecked(controller.media_info.can_loop_playback)
|
||||||
|
|
||||||
def media_stop_msg(self, msg):
|
def media_stop_msg(self, msg):
|
||||||
"""
|
"""
|
||||||
@ -645,25 +729,28 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
|
|
||||||
:param msg: First element is the controller which should be used
|
:param msg: First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
log.debug('media_stop_msg')
|
|
||||||
self.media_stop(msg[0])
|
self.media_stop(msg[0])
|
||||||
|
|
||||||
def media_stop(self, controller):
|
def media_stop(self, controller, looping_background=False):
|
||||||
"""
|
"""
|
||||||
Responds to the request to stop a loaded video
|
Responds to the request to stop a loaded video
|
||||||
|
|
||||||
:param controller: The controller that needs to be stopped
|
:param controller: The controller that needs to be stopped
|
||||||
|
:param looping_background: The background is looping so do not blank.
|
||||||
"""
|
"""
|
||||||
log.debug('media_stop')
|
|
||||||
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:
|
||||||
display.frame.evaluateJavaScript('show_blank("black");')
|
if not looping_background:
|
||||||
|
display.frame.evaluateJavaScript('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)
|
||||||
controller.mediabar.actions['playbackPlay'].setVisible(True)
|
controller.mediabar.actions['playbackPlay'].setVisible(True)
|
||||||
controller.mediabar.actions['playbackStop'].setDisabled(True)
|
controller.mediabar.actions['playbackStop'].setDisabled(True)
|
||||||
controller.mediabar.actions['playbackPause'].setVisible(False)
|
controller.mediabar.actions['playbackPause'].setVisible(False)
|
||||||
|
controller.media_info.is_playing = False
|
||||||
|
controller.media_info.timer = 1000
|
||||||
|
controller.media_timer = 0
|
||||||
|
|
||||||
def media_volume_msg(self, msg):
|
def media_volume_msg(self, msg):
|
||||||
"""
|
"""
|
||||||
@ -694,7 +781,6 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
:param msg: First element is the controller which should be used
|
:param msg: First element is the controller which should be used
|
||||||
Second element is a list with the seek value as first element
|
Second element is a list with the seek value as first element
|
||||||
"""
|
"""
|
||||||
log.debug('media_seek')
|
|
||||||
controller = msg[0]
|
controller = msg[0]
|
||||||
seek_value = msg[1][0]
|
seek_value = msg[1][0]
|
||||||
self.media_seek(controller, seek_value)
|
self.media_seek(controller, seek_value)
|
||||||
@ -706,15 +792,15 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
:param controller: The controller to use.
|
:param controller: The controller to use.
|
||||||
:param seek_value: The value to set.
|
:param seek_value: The value to set.
|
||||||
"""
|
"""
|
||||||
log.debug('media_seek')
|
|
||||||
display = self._define_display(controller)
|
display = self._define_display(controller)
|
||||||
self.current_media_players[controller.controller_type].seek(display, seek_value)
|
self.current_media_players[controller.controller_type].seek(display, seek_value)
|
||||||
|
controller.media_info.timer = seek_value
|
||||||
|
|
||||||
def media_reset(self, controller):
|
def media_reset(self, controller):
|
||||||
"""
|
"""
|
||||||
Responds to the request to reset a loaded video
|
Responds to the request to reset a loaded video
|
||||||
|
:param controller: The controller to use.
|
||||||
"""
|
"""
|
||||||
log.debug('media_reset')
|
|
||||||
self.set_controls_visible(controller, False)
|
self.set_controls_visible(controller, False)
|
||||||
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:
|
||||||
@ -735,7 +821,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
return
|
return
|
||||||
display = self._define_display(self.live_controller)
|
display = self._define_display(self.live_controller)
|
||||||
if self.live_controller.controller_type in self.current_media_players and \
|
if self.live_controller.controller_type in self.current_media_players and \
|
||||||
self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing:
|
self.current_media_players[self.live_controller.controller_type].get_live_state() == MediaState.Playing:
|
||||||
self.current_media_players[self.live_controller.controller_type].pause(display)
|
self.current_media_players[self.live_controller.controller_type].pause(display)
|
||||||
self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
|
self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
|
||||||
|
|
||||||
@ -753,7 +839,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
Registry().execute('live_display_hide', hide_mode)
|
Registry().execute('live_display_hide', hide_mode)
|
||||||
display = self._define_display(self.live_controller)
|
display = self._define_display(self.live_controller)
|
||||||
if self.live_controller.controller_type in self.current_media_players and \
|
if self.live_controller.controller_type in self.current_media_players and \
|
||||||
self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing:
|
self.current_media_players[self.live_controller.controller_type].get_live_state() == MediaState.Playing:
|
||||||
self.current_media_players[self.live_controller.controller_type].pause(display)
|
self.current_media_players[self.live_controller.controller_type].pause(display)
|
||||||
self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
|
self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
|
||||||
|
|
||||||
@ -770,22 +856,25 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
|||||||
return
|
return
|
||||||
display = self._define_display(self.live_controller)
|
display = self._define_display(self.live_controller)
|
||||||
if self.live_controller.controller_type in self.current_media_players and \
|
if self.live_controller.controller_type in self.current_media_players and \
|
||||||
self.current_media_players[self.live_controller.controller_type].state != MediaState.Playing:
|
self.current_media_players[self.live_controller.controller_type].get_live_state() != \
|
||||||
|
MediaState.Playing:
|
||||||
if self.current_media_players[self.live_controller.controller_type].play(display):
|
if self.current_media_players[self.live_controller.controller_type].play(display):
|
||||||
self.current_media_players[self.live_controller.controller_type].set_visible(display, True)
|
self.current_media_players[self.live_controller.controller_type].set_visible(display, True)
|
||||||
# Start Timer for ui updates
|
# Start Timer for ui updates
|
||||||
if not self.timer.isActive():
|
if not self.live_timer.isActive():
|
||||||
self.timer.start()
|
self.live_timer.start()
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
Reset all the media controllers when OpenLP shuts down
|
Reset all the media controllers when OpenLP shuts down
|
||||||
"""
|
"""
|
||||||
self.timer.stop()
|
self.live_timer.stop()
|
||||||
|
self.preview_timer.stop()
|
||||||
for controller in self.display_controllers:
|
for controller in self.display_controllers:
|
||||||
self.media_reset(self.display_controllers[controller])
|
self.media_reset(self.display_controllers[controller])
|
||||||
|
|
||||||
def _define_display(self, controller):
|
@staticmethod
|
||||||
|
def _define_display(controller):
|
||||||
"""
|
"""
|
||||||
Extract the correct display for a given controller
|
Extract the correct display for a given controller
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class MediaPlayer(RegistryProperties):
|
|||||||
self.is_active = False
|
self.is_active = False
|
||||||
self.can_background = False
|
self.can_background = False
|
||||||
self.can_folder = False
|
self.can_folder = False
|
||||||
self.state = MediaState.Off
|
self.state = {0: MediaState.Off, 1: MediaState.Off}
|
||||||
self.has_own_widget = False
|
self.has_own_widget = False
|
||||||
self.audio_extensions_list = []
|
self.audio_extensions_list = []
|
||||||
self.video_extensions_list = []
|
self.video_extensions_list = []
|
||||||
@ -55,12 +55,16 @@ class MediaPlayer(RegistryProperties):
|
|||||||
def setup(self, display):
|
def setup(self, display):
|
||||||
"""
|
"""
|
||||||
Create the related widgets for the current display
|
Create the related widgets for the current display
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def load(self, display):
|
def load(self, display):
|
||||||
"""
|
"""
|
||||||
Load a new media file and check if it is valid
|
Load a new media file and check if it is valid
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -68,54 +72,75 @@ class MediaPlayer(RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
If the main display size or position is changed, the media widgets
|
If the main display size or position is changed, the media widgets
|
||||||
should also resized
|
should also resized
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
"""
|
"""
|
||||||
Starts playing of current Media File
|
Starts playing of current Media File
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def pause(self, display):
|
def pause(self, display):
|
||||||
"""
|
"""
|
||||||
Pause of current Media File
|
Pause of current Media File
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def stop(self, display):
|
def stop(self, display):
|
||||||
"""
|
"""
|
||||||
Stop playing of current Media File
|
Stop playing of current Media File
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def volume(self, display, vol):
|
def volume(self, display, volume):
|
||||||
"""
|
"""
|
||||||
Change volume of current Media File
|
Change volume of current Media File
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param volume: The volume to set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def seek(self, display, seek_value):
|
def seek(self, display, seek_value):
|
||||||
"""
|
"""
|
||||||
Change playing position of current Media File
|
Change playing position of current Media File
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param seek_value: The where to seek to.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def reset(self, display):
|
def reset(self, display):
|
||||||
"""
|
"""
|
||||||
Remove the current loaded video
|
Remove the current loaded video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_visible(self, display, status):
|
def set_visible(self, display, status):
|
||||||
"""
|
"""
|
||||||
Show/Hide the media widgets
|
Show/Hide the media widgets
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param status: The status to be set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
Do some ui related stuff (e.g. update the seek slider)
|
Do some ui related stuff (e.g. update the seek slider)
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -142,3 +167,45 @@ class MediaPlayer(RegistryProperties):
|
|||||||
Returns Information about the player
|
Returns Information about the player
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def get_live_state(self):
|
||||||
|
"""
|
||||||
|
Get the state of the live player
|
||||||
|
:return: Live state
|
||||||
|
"""
|
||||||
|
return self.state[0]
|
||||||
|
|
||||||
|
def set_live_state(self, state):
|
||||||
|
"""
|
||||||
|
Set the State of the Live player
|
||||||
|
:param state: State to be set
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.state[0] = state
|
||||||
|
|
||||||
|
def get_preview_state(self):
|
||||||
|
"""
|
||||||
|
Get the state of the preview player
|
||||||
|
:return: Preview State
|
||||||
|
"""
|
||||||
|
return self.state[1]
|
||||||
|
|
||||||
|
def set_preview_state(self, state):
|
||||||
|
"""
|
||||||
|
Set the state of the Preview Player
|
||||||
|
:param state: State to be set
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.state[1] = state
|
||||||
|
|
||||||
|
def set_state(self, state, display):
|
||||||
|
"""
|
||||||
|
Set the State based on the display being processed
|
||||||
|
:param state: State to be set
|
||||||
|
:param display: Identify the Display type
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
if display.controller.is_live:
|
||||||
|
self.set_live_state(state)
|
||||||
|
else:
|
||||||
|
self.set_preview_state(state)
|
||||||
|
@ -133,12 +133,16 @@ class PlayerTab(SettingsTab):
|
|||||||
def on_background_color_changed(self, color):
|
def on_background_color_changed(self, color):
|
||||||
"""
|
"""
|
||||||
Set the background color
|
Set the background color
|
||||||
|
|
||||||
|
:param color: The color to be set.
|
||||||
"""
|
"""
|
||||||
self.background_color = color
|
self.background_color = color
|
||||||
|
|
||||||
def on_player_check_box_changed(self, check_state):
|
def on_player_check_box_changed(self, check_state):
|
||||||
"""
|
"""
|
||||||
Add or remove players depending on their status
|
Add or remove players depending on their status
|
||||||
|
|
||||||
|
:param check_state: The requested status.
|
||||||
"""
|
"""
|
||||||
player = self.sender().player_name
|
player = self.sender().player_name
|
||||||
if check_state == QtCore.Qt.Checked:
|
if check_state == QtCore.Qt.Checked:
|
||||||
|
@ -4,14 +4,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2014 Raoul Snyman #
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
|
||||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
|
||||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
|
||||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
# under the terms of the GNU General Public License as published by the Free #
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
@ -124,7 +117,8 @@ class SystemPlayer(MediaPlayer):
|
|||||||
def load(self, display):
|
def load(self, display):
|
||||||
"""
|
"""
|
||||||
Load a video into the display
|
Load a video into the display
|
||||||
:param display:
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
log.debug('load vid in System Controller')
|
log.debug('load vid in System Controller')
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
@ -141,93 +135,122 @@ class SystemPlayer(MediaPlayer):
|
|||||||
def resize(self, display):
|
def resize(self, display):
|
||||||
"""
|
"""
|
||||||
Resize the display
|
Resize the display
|
||||||
:param display:
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
display.video_widget.resize(display.size())
|
display.video_widget.resize(display.size())
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
"""
|
"""
|
||||||
Play the current media item
|
Play the current media item
|
||||||
:param display:
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
log.info('Play the current item')
|
log.info('Play the current item')
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
start_time = 0
|
start_time = 0
|
||||||
if display.media_player.state() != QtMultimedia.QMediaPlayer.PausedState and \
|
if display.controller.is_live:
|
||||||
controller.media_info.start_time > 0:
|
if self.get_live_state() != QtMultimedia.QMediaPlayer.PausedState and controller.media_info.start_time > 0:
|
||||||
start_time = controller.media_info.start_time
|
start_time = controller.media_info.start_time
|
||||||
|
else:
|
||||||
|
if self.get_preview_state() != QtMultimedia.QMediaPlayer.PausedState and \
|
||||||
|
controller.media_info.start_time > 0:
|
||||||
|
start_time = controller.media_info.start_time
|
||||||
display.media_player.play()
|
display.media_player.play()
|
||||||
if start_time > 0:
|
if start_time > 0:
|
||||||
self.seek(display, controller.media_info.start_time * 1000)
|
self.seek(display, controller.media_info.start_time * 1000)
|
||||||
self.volume(display, controller.media_info.volume)
|
self.volume(display, controller.media_info.volume)
|
||||||
display.media_player.durationChanged.connect(functools.partial(self.set_duration, controller))
|
display.media_player.durationChanged.connect(functools.partial(self.set_duration, controller))
|
||||||
self.state = MediaState.Playing
|
self.set_state(MediaState.Playing, display)
|
||||||
display.video_widget.raise_()
|
display.video_widget.raise_()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self, display):
|
def pause(self, display):
|
||||||
"""
|
"""
|
||||||
Pause the current media item
|
Pause the current media item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
display.media_player.pause()
|
display.media_player.pause()
|
||||||
if display.media_player.state() == QtMultimedia.QMediaPlayer.PausedState:
|
if display.controller.is_live:
|
||||||
self.state = MediaState.Paused
|
if self.get_live_state() == QtMultimedia.QMediaPlayer.PausedState:
|
||||||
|
self.set_state(MediaState.Paused, display)
|
||||||
|
else:
|
||||||
|
if self.get_preview_state() == QtMultimedia.QMediaPlayer.PausedState:
|
||||||
|
self.set_state(MediaState.Paused, display)
|
||||||
|
|
||||||
def stop(self, display):
|
def stop(self, display):
|
||||||
"""
|
"""
|
||||||
Stop the current media item
|
Stop the current media item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
display.media_player.blockSignals(True)
|
|
||||||
display.media_player.durationChanged.disconnect()
|
|
||||||
display.media_player.blockSignals(False)
|
|
||||||
display.media_player.stop()
|
display.media_player.stop()
|
||||||
self.set_visible(display, False)
|
self.set_visible(display, False)
|
||||||
self.state = MediaState.Stopped
|
self.set_state(MediaState.Stopped, display)
|
||||||
|
|
||||||
def volume(self, display, vol):
|
def volume(self, display, volume):
|
||||||
"""
|
"""
|
||||||
Set the volume
|
Set the volume
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:param volume: The volume to be set
|
||||||
"""
|
"""
|
||||||
if display.has_audio:
|
if display.has_audio:
|
||||||
display.media_player.setVolume(vol)
|
display.media_player.setVolume(volume)
|
||||||
|
|
||||||
def seek(self, display, seek_value):
|
def seek(self, display, seek_value):
|
||||||
"""
|
"""
|
||||||
Go to a particular point in the current media item
|
Go to a particular point in the current media item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:param seek_value: The where to seek to
|
||||||
"""
|
"""
|
||||||
display.media_player.setPosition(seek_value)
|
display.media_player.setPosition(seek_value)
|
||||||
|
|
||||||
def reset(self, display):
|
def reset(self, display):
|
||||||
"""
|
"""
|
||||||
Reset the media player
|
Reset the media player
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
display.media_player.stop()
|
display.media_player.stop()
|
||||||
display.media_player.setMedia(QtMultimedia.QMediaContent())
|
display.media_player.setMedia(QtMultimedia.QMediaContent())
|
||||||
self.set_visible(display, False)
|
self.set_visible(display, False)
|
||||||
display.video_widget.setVisible(False)
|
display.video_widget.setVisible(False)
|
||||||
self.state = MediaState.Off
|
self.set_state(MediaState.Off, display)
|
||||||
|
|
||||||
def set_visible(self, display, status):
|
def set_visible(self, display, status):
|
||||||
"""
|
"""
|
||||||
Set the visibility of the widget
|
Set the visibility of the widget
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:param status: The visibility status to be set
|
||||||
"""
|
"""
|
||||||
if self.has_own_widget:
|
if self.has_own_widget:
|
||||||
display.video_widget.setVisible(status)
|
display.video_widget.setVisible(status)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_duration(controller, duration):
|
def set_duration(controller, duration):
|
||||||
controller.media_info.length = int(duration / 1000)
|
"""
|
||||||
controller.seek_slider.setMaximum(controller.media_info.length * 1000)
|
|
||||||
|
:param controller: the controller displaying the media
|
||||||
|
:param duration: how long is the media
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
controller.seek_slider.setMaximum(controller.media_info.length)
|
||||||
|
|
||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
Update the UI
|
Update the UI
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
if display.media_player.state() == QtMultimedia.QMediaPlayer.PausedState and self.state != MediaState.Paused:
|
if display.media_player.state() == QtMultimedia.QMediaPlayer.PausedState and self.state != MediaState.Paused:
|
||||||
self.stop(display)
|
self.stop(display)
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
if controller.media_info.end_time > 0:
|
if controller.media_info.end_time > 0:
|
||||||
if display.media_player.position() > controller.media_info.end_time * 1000:
|
if display.media_player.position() > controller.media_info.end_time:
|
||||||
self.stop(display)
|
self.stop(display)
|
||||||
self.set_visible(display, False)
|
self.set_visible(display, False)
|
||||||
if not controller.seek_slider.isSliderDown():
|
if not controller.seek_slider.isSliderDown():
|
||||||
|
140
openlp/core/ui/media/vendor/mediainfoWrapper.py
vendored
Normal file
140
openlp/core/ui/media/vendor/mediainfoWrapper.py
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
The :mod:`~openlp.core.ui.media.mediainfo` module contains code to run mediainfo on a media file and obtain
|
||||||
|
information related to the rwquested media.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from subprocess import Popen
|
||||||
|
from tempfile import mkstemp
|
||||||
|
|
||||||
|
import six
|
||||||
|
from bs4 import BeautifulSoup, NavigableString
|
||||||
|
|
||||||
|
ENV_DICT = os.environ
|
||||||
|
|
||||||
|
|
||||||
|
class Track(object):
|
||||||
|
|
||||||
|
def __getattribute__(self, name):
|
||||||
|
try:
|
||||||
|
return object.__getattribute__(self, name)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __init__(self, xml_dom_fragment):
|
||||||
|
self.xml_dom_fragment = xml_dom_fragment
|
||||||
|
self.track_type = xml_dom_fragment.attrs['type']
|
||||||
|
for el in self.xml_dom_fragment.children:
|
||||||
|
if not isinstance(el, NavigableString):
|
||||||
|
node_name = el.name.lower().strip().strip('_')
|
||||||
|
if node_name == 'id':
|
||||||
|
node_name = 'track_id'
|
||||||
|
node_value = el.string
|
||||||
|
other_node_name = "other_%s" % node_name
|
||||||
|
if getattr(self, node_name) is None:
|
||||||
|
setattr(self, node_name, node_value)
|
||||||
|
else:
|
||||||
|
if getattr(self, other_node_name) is None:
|
||||||
|
setattr(self, other_node_name, [node_value, ])
|
||||||
|
else:
|
||||||
|
getattr(self, other_node_name).append(node_value)
|
||||||
|
|
||||||
|
for o in [d for d in self.__dict__.keys() if d.startswith('other_')]:
|
||||||
|
try:
|
||||||
|
primary = o.replace('other_', '')
|
||||||
|
setattr(self, primary, int(getattr(self, primary)))
|
||||||
|
except:
|
||||||
|
for v in getattr(self, o):
|
||||||
|
try:
|
||||||
|
current = getattr(self, primary)
|
||||||
|
setattr(self, primary, int(v))
|
||||||
|
getattr(self, o).append(current)
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Track track_id='{0}', track_type='{1}'>".format(self.track_id, self.track_type)
|
||||||
|
|
||||||
|
def to_data(self):
|
||||||
|
data = {}
|
||||||
|
for k, v in six.iteritems(self.__dict__):
|
||||||
|
if k != 'xml_dom_fragment':
|
||||||
|
data[k] = v
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class MediaInfoWrapper(object):
|
||||||
|
|
||||||
|
def __init__(self, xml):
|
||||||
|
self.xml_dom = xml
|
||||||
|
xml_types = (str,) # no unicode type in python3
|
||||||
|
if isinstance(xml, xml_types):
|
||||||
|
self.xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(xml)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_xml_data_into_dom(xml_data):
|
||||||
|
return BeautifulSoup(xml_data, "xml")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse(filename, environment=ENV_DICT):
|
||||||
|
command = ["mediainfo", "-f", "--Output=XML", filename]
|
||||||
|
fileno_out, fname_out = mkstemp(suffix=".xml", prefix="media-")
|
||||||
|
fileno_err, fname_err = mkstemp(suffix=".err", prefix="media-")
|
||||||
|
fp_out = os.fdopen(fileno_out, 'r+b')
|
||||||
|
fp_err = os.fdopen(fileno_err, 'r+b')
|
||||||
|
p = Popen(command, stdout=fp_out, stderr=fp_err, env=environment)
|
||||||
|
p.wait()
|
||||||
|
fp_out.seek(0)
|
||||||
|
|
||||||
|
xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(fp_out.read())
|
||||||
|
fp_out.close()
|
||||||
|
fp_err.close()
|
||||||
|
os.unlink(fname_out)
|
||||||
|
os.unlink(fname_err)
|
||||||
|
return MediaInfoWrapper(xml_dom)
|
||||||
|
|
||||||
|
def _populate_tracks(self):
|
||||||
|
if self.xml_dom is None:
|
||||||
|
return
|
||||||
|
for xml_track in self.xml_dom.Mediainfo.File.find_all("track"):
|
||||||
|
self._tracks.append(Track(xml_track))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tracks(self):
|
||||||
|
if not hasattr(self, "_tracks"):
|
||||||
|
self._tracks = []
|
||||||
|
if len(self._tracks) == 0:
|
||||||
|
self._populate_tracks()
|
||||||
|
return self._tracks
|
||||||
|
|
||||||
|
def to_data(self):
|
||||||
|
data = {'tracks': []}
|
||||||
|
for track in self.tracks:
|
||||||
|
data['tracks'].append(track.to_data())
|
||||||
|
return data
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return json.dumps(self.to_data())
|
@ -144,6 +144,9 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def setup(self, display):
|
def setup(self, display):
|
||||||
"""
|
"""
|
||||||
Set up the media player
|
Set up the media player
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
display.vlc_widget = QtWidgets.QFrame(display)
|
display.vlc_widget = QtWidgets.QFrame(display)
|
||||||
@ -186,6 +189,9 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def load(self, display):
|
def load(self, display):
|
||||||
"""
|
"""
|
||||||
Load a video into VLC
|
Load a video into VLC
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
log.debug('load vid in Vlc Controller')
|
log.debug('load vid in Vlc Controller')
|
||||||
@ -214,18 +220,16 @@ class VlcPlayer(MediaPlayer):
|
|||||||
# parse the metadata of the file
|
# parse the metadata of the file
|
||||||
display.vlc_media.parse()
|
display.vlc_media.parse()
|
||||||
self.volume(display, volume)
|
self.volume(display, volume)
|
||||||
# We need to set media_info.length during load because we want
|
|
||||||
# to avoid start and stop the video twice. Once for real playback
|
|
||||||
# and once to just get media length.
|
|
||||||
#
|
|
||||||
# Media plugin depends on knowing media length before playback.
|
|
||||||
controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def media_state_wait(self, display, media_state):
|
def media_state_wait(self, 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)
|
||||||
|
|
||||||
|
:param media_state: The state of the playing media
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
@ -240,25 +244,40 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def resize(self, display):
|
def resize(self, display):
|
||||||
"""
|
"""
|
||||||
Resize the player
|
Resize the player
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
display.vlc_widget.resize(display.size())
|
display.vlc_widget.resize(display.size())
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
"""
|
"""
|
||||||
Play the current item
|
Play the current item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
start_time = 0
|
start_time = 0
|
||||||
log.debug('vlc play')
|
log.debug('vlc play')
|
||||||
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
|
if display.controller.is_live:
|
||||||
start_time = controller.media_info.start_time
|
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0:
|
||||||
|
start_time = controller.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()
|
threading.Thread(target=display.vlc_media_player.play).start()
|
||||||
if not self.media_state_wait(display, vlc.State.Playing):
|
if not self.media_state_wait(display, vlc.State.Playing):
|
||||||
return False
|
return False
|
||||||
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
|
if display.controller.is_live:
|
||||||
log.debug('vlc play, starttime set')
|
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0:
|
||||||
start_time = controller.media_info.start_time
|
log.debug('vlc play, start time set')
|
||||||
|
start_time = controller.media_info.start_time
|
||||||
|
else:
|
||||||
|
if self.get_preview_state() != MediaState.Paused and controller.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))
|
log.debug('mediatype: ' + str(controller.media_info.media_type))
|
||||||
# Set tracks for the optical device
|
# Set tracks for the optical device
|
||||||
if controller.media_info.media_type == MediaType.DVD:
|
if controller.media_info.media_type == MediaType.DVD:
|
||||||
@ -279,37 +298,45 @@ class VlcPlayer(MediaPlayer):
|
|||||||
log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time))
|
log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time))
|
||||||
start_time = 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
|
controller.media_info.length = controller.media_info.end_time - controller.media_info.start_time
|
||||||
else:
|
|
||||||
controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000)
|
|
||||||
self.volume(display, controller.media_info.volume)
|
self.volume(display, controller.media_info.volume)
|
||||||
if start_time > 0 and display.vlc_media_player.is_seekable():
|
if start_time > 0 and display.vlc_media_player.is_seekable():
|
||||||
display.vlc_media_player.set_time(int(start_time * 1000))
|
display.vlc_media_player.set_time(int(start_time))
|
||||||
controller.seek_slider.setMaximum(controller.media_info.length * 1000)
|
controller.seek_slider.setMaximum(controller.media_info.length)
|
||||||
self.state = MediaState.Playing
|
self.set_state(MediaState.Playing, display)
|
||||||
display.vlc_widget.raise_()
|
display.vlc_widget.raise_()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self, display):
|
def pause(self, display):
|
||||||
"""
|
"""
|
||||||
Pause the current item
|
Pause the current item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
vlc = get_vlc()
|
vlc = get_vlc()
|
||||||
if display.vlc_media.get_state() != vlc.State.Playing:
|
if display.vlc_media.get_state() != vlc.State.Playing:
|
||||||
return
|
return
|
||||||
display.vlc_media_player.pause()
|
display.vlc_media_player.pause()
|
||||||
if self.media_state_wait(display, vlc.State.Paused):
|
if self.media_state_wait(display, vlc.State.Paused):
|
||||||
self.state = MediaState.Paused
|
self.set_state(MediaState.Paused, display)
|
||||||
|
|
||||||
def stop(self, display):
|
def stop(self, display):
|
||||||
"""
|
"""
|
||||||
Stop the current item
|
Stop the current item
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
threading.Thread(target=display.vlc_media_player.stop).start()
|
threading.Thread(target=display.vlc_media_player.stop).start()
|
||||||
self.state = MediaState.Stopped
|
self.set_state(MediaState.Stopped, display)
|
||||||
|
|
||||||
def volume(self, display, vol):
|
def volume(self, display, vol):
|
||||||
"""
|
"""
|
||||||
Set the volume
|
Set the volume
|
||||||
|
|
||||||
|
:param vol: The volume to be sets
|
||||||
|
:param display: The display where the media is
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
if display.has_audio:
|
if display.has_audio:
|
||||||
display.vlc_media_player.audio_set_volume(vol)
|
display.vlc_media_player.audio_set_volume(vol)
|
||||||
@ -317,6 +344,9 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def seek(self, display, seek_value):
|
def seek(self, 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 display: The display where the media is
|
||||||
"""
|
"""
|
||||||
if display.controller.media_info.media_type == MediaType.CD \
|
if display.controller.media_info.media_type == MediaType.CD \
|
||||||
or display.controller.media_info.media_type == MediaType.DVD:
|
or display.controller.media_info.media_type == MediaType.DVD:
|
||||||
@ -327,14 +357,19 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def reset(self, display):
|
def reset(self, display):
|
||||||
"""
|
"""
|
||||||
Reset the player
|
Reset the player
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
"""
|
"""
|
||||||
display.vlc_media_player.stop()
|
display.vlc_media_player.stop()
|
||||||
display.vlc_widget.setVisible(False)
|
display.vlc_widget.setVisible(False)
|
||||||
self.state = MediaState.Off
|
self.set_state(MediaState.Off, display)
|
||||||
|
|
||||||
def set_visible(self, display, status):
|
def set_visible(self, display, status):
|
||||||
"""
|
"""
|
||||||
Set the visibility
|
Set the visibility
|
||||||
|
|
||||||
|
:param display: The display where the media is
|
||||||
|
:param status: The visibility status
|
||||||
"""
|
"""
|
||||||
if self.has_own_widget:
|
if self.has_own_widget:
|
||||||
display.vlc_widget.setVisible(status)
|
display.vlc_widget.setVisible(status)
|
||||||
@ -342,6 +377,8 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
Update the UI
|
Update the UI
|
||||||
|
|
||||||
|
:param 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.
|
||||||
|
@ -99,74 +99,6 @@ VIDEO_HTML = """
|
|||||||
<video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
|
<video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
FLASH_CSS = """
|
|
||||||
#flash {
|
|
||||||
z-index:5;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
FLASH_JS = """
|
|
||||||
function getFlashMovieObject(movieName)
|
|
||||||
{
|
|
||||||
if (window.document[movieName]){
|
|
||||||
return window.document[movieName];
|
|
||||||
}
|
|
||||||
if (document.embeds && document.embeds[movieName]){
|
|
||||||
return document.embeds[movieName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function show_flash(state, path, volume, variable_value){
|
|
||||||
var text = document.getElementById('flash');
|
|
||||||
var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
|
|
||||||
var src = "src = 'file:///" + path + "'";
|
|
||||||
var view_parm = " wmode='opaque'" + " width='100%%'" + " height='100%%'";
|
|
||||||
var swf_parm = " name='OpenLPFlashMovie'" + " autostart='true' loop='false' play='true'" +
|
|
||||||
" hidden='false' swliveconnect='true' allowscriptaccess='always'" + " volume='" + volume + "'";
|
|
||||||
|
|
||||||
switch(state){
|
|
||||||
case 'load':
|
|
||||||
text.innerHTML = "<embed " + src + view_parm + swf_parm + "/>";
|
|
||||||
flashMovie = getFlashMovieObject("OpenLPFlashMovie");
|
|
||||||
flashMovie.Play();
|
|
||||||
break;
|
|
||||||
case 'play':
|
|
||||||
flashMovie.Play();
|
|
||||||
break;
|
|
||||||
case 'pause':
|
|
||||||
flashMovie.StopPlay();
|
|
||||||
break;
|
|
||||||
case 'stop':
|
|
||||||
flashMovie.StopPlay();
|
|
||||||
tempHtml = text.innerHTML;
|
|
||||||
text.innerHTML = '';
|
|
||||||
text.innerHTML = tempHtml;
|
|
||||||
break;
|
|
||||||
case 'close':
|
|
||||||
flashMovie.StopPlay();
|
|
||||||
text.innerHTML = '';
|
|
||||||
break;
|
|
||||||
case 'length':
|
|
||||||
return flashMovie.TotalFrames();
|
|
||||||
case 'current_time':
|
|
||||||
return flashMovie.CurrentFrame();
|
|
||||||
case 'seek':
|
|
||||||
// flashMovie.GotoFrame(variable_value);
|
|
||||||
break;
|
|
||||||
case 'isEnded':
|
|
||||||
//TODO check flash end
|
|
||||||
return false;
|
|
||||||
case 'setVisible':
|
|
||||||
text.style.visibility = variable_value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
FLASH_HTML = """
|
|
||||||
<div id="flash" class="size" style="visibility:hidden"></div>
|
|
||||||
"""
|
|
||||||
|
|
||||||
VIDEO_EXT = ['*.3gp', '*.3gpp', '*.3g2', '*.3gpp2', '*.aac', '*.flv', '*.f4a', '*.f4b', '*.f4p', '*.f4v', '*.mov',
|
VIDEO_EXT = ['*.3gp', '*.3gpp', '*.3g2', '*.3gpp2', '*.aac', '*.flv', '*.f4a', '*.f4b', '*.f4p', '*.f4v', '*.mov',
|
||||||
'*.m4a', '*.m4b', '*.m4p', '*.m4v', '*.mkv', '*.mp4', '*.ogv', '*.webm', '*.mpg', '*.wmv', '*.mpeg',
|
'*.m4a', '*.m4b', '*.m4p', '*.m4v', '*.mkv', '*.mp4', '*.ogv', '*.webm', '*.mpg', '*.wmv', '*.mpeg',
|
||||||
'*.avi', '*.swf']
|
'*.avi', '*.swf']
|
||||||
@ -198,23 +130,25 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
background = QtGui.QColor(Settings().value('players/background color')).name()
|
background = QtGui.QColor(Settings().value('players/background color')).name()
|
||||||
css = VIDEO_CSS % {'bgcolor': background}
|
css = VIDEO_CSS % {'bgcolor': background}
|
||||||
return css + FLASH_CSS
|
return css
|
||||||
|
|
||||||
def get_media_display_javascript(self):
|
def get_media_display_javascript(self):
|
||||||
"""
|
"""
|
||||||
Add javascript functions to htmlbuilder
|
Add javascript functions to htmlbuilder
|
||||||
"""
|
"""
|
||||||
return VIDEO_JS + FLASH_JS
|
return VIDEO_JS
|
||||||
|
|
||||||
def get_media_display_html(self):
|
def get_media_display_html(self):
|
||||||
"""
|
"""
|
||||||
Add html code to htmlbuilder
|
Add html code to htmlbuilder
|
||||||
"""
|
"""
|
||||||
return VIDEO_HTML + FLASH_HTML
|
return VIDEO_HTML
|
||||||
|
|
||||||
def setup(self, display):
|
def setup(self, display):
|
||||||
"""
|
"""
|
||||||
Set up the player
|
Set up the player
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
display.web_view.resize(display.size())
|
display.web_view.resize(display.size())
|
||||||
display.web_view.raise_()
|
display.web_view.raise_()
|
||||||
@ -235,6 +169,8 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
def load(self, display):
|
def load(self, display):
|
||||||
"""
|
"""
|
||||||
Load a video
|
Load a video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
log.debug('load vid in Webkit Controller')
|
log.debug('load vid in Webkit Controller')
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
@ -249,132 +185,120 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
else:
|
else:
|
||||||
loop = 'false'
|
loop = 'false'
|
||||||
display.web_view.setVisible(True)
|
display.web_view.setVisible(True)
|
||||||
if controller.media_info.file_info.suffix() == 'swf':
|
js = 'show_video("load", "%s", %s, %s);' % (path.replace('\\', '\\\\'), str(vol), loop)
|
||||||
controller.media_info.is_flash = True
|
|
||||||
js = 'show_flash("load","%s");' % (path.replace('\\', '\\\\'))
|
|
||||||
else:
|
|
||||||
js = 'show_video("load", "%s", %s, %s);' % (path.replace('\\', '\\\\'), str(vol), loop)
|
|
||||||
display.frame.evaluateJavaScript(js)
|
display.frame.evaluateJavaScript(js)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def resize(self, display):
|
def resize(self, display):
|
||||||
"""
|
"""
|
||||||
Resize the player
|
Resize the player
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
display.web_view.resize(display.size())
|
display.web_view.resize(display.size())
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
"""
|
"""
|
||||||
Play a video
|
Play a video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
display.web_loaded = True
|
display.web_loaded = True
|
||||||
length = 0
|
|
||||||
start_time = 0
|
start_time = 0
|
||||||
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
|
if display.controller.is_live:
|
||||||
start_time = controller.media_info.start_time
|
if self.get_live_state() != MediaState.Paused and controller.media_info.start_time > 0:
|
||||||
self.set_visible(display, True)
|
start_time = controller.media_info.start_time
|
||||||
if controller.media_info.is_flash:
|
|
||||||
display.frame.evaluateJavaScript('show_flash("play");')
|
|
||||||
else:
|
else:
|
||||||
display.frame.evaluateJavaScript('show_video("play");')
|
if self.get_preview_state() != MediaState.Paused and controller.media_info.start_time > 0:
|
||||||
|
start_time = controller.media_info.start_time
|
||||||
|
self.set_visible(display, True)
|
||||||
|
display.frame.evaluateJavaScript('show_video("play");')
|
||||||
if start_time > 0:
|
if start_time > 0:
|
||||||
self.seek(display, controller.media_info.start_time * 1000)
|
self.seek(display, controller.media_info.start_time * 1000)
|
||||||
# TODO add playing check and get the correct media length
|
self.set_state(MediaState.Playing, display)
|
||||||
controller.media_info.length = length
|
|
||||||
self.state = MediaState.Playing
|
|
||||||
display.web_view.raise_()
|
display.web_view.raise_()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self, display):
|
def pause(self, display):
|
||||||
"""
|
"""
|
||||||
Pause a video
|
Pause a video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
display.frame.evaluateJavaScript('show_video("pause");')
|
||||||
if controller.media_info.is_flash:
|
self.set_state(MediaState.Paused, display)
|
||||||
display.frame.evaluateJavaScript('show_flash("pause");')
|
|
||||||
else:
|
|
||||||
display.frame.evaluateJavaScript('show_video("pause");')
|
|
||||||
self.state = MediaState.Paused
|
|
||||||
|
|
||||||
def stop(self, display):
|
def stop(self, display):
|
||||||
"""
|
"""
|
||||||
Stop a video
|
Stop a video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
display.frame.evaluateJavaScript('show_video("stop");')
|
||||||
if controller.media_info.is_flash:
|
self.set_state(MediaState.Stopped, display)
|
||||||
display.frame.evaluateJavaScript('show_flash("stop");')
|
|
||||||
else:
|
|
||||||
display.frame.evaluateJavaScript('show_video("stop");')
|
|
||||||
self.state = MediaState.Stopped
|
|
||||||
|
|
||||||
def volume(self, display, volume):
|
def volume(self, display, volume):
|
||||||
"""
|
"""
|
||||||
Set the volume
|
Set the volume
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param volume: The volume to be set.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
|
||||||
# 1.0 is the highest value
|
# 1.0 is the highest value
|
||||||
if display.has_audio:
|
if display.has_audio:
|
||||||
vol = float(volume) / float(100)
|
vol = float(volume) / float(100)
|
||||||
if not controller.media_info.is_flash:
|
display.frame.evaluateJavaScript('show_video(null, null, %s);' % str(vol))
|
||||||
display.frame.evaluateJavaScript('show_video(null, null, %s);' % str(vol))
|
|
||||||
|
|
||||||
def seek(self, display, seek_value):
|
def seek(self, display, seek_value):
|
||||||
"""
|
"""
|
||||||
Go to a position in the video
|
Go to a position in the video
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param seek_value: The value to be set.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
seek = float(seek_value) / 1000
|
||||||
if controller.media_info.is_flash:
|
display.frame.evaluateJavaScript('show_video("seek", null, null, null, "%f");' % seek)
|
||||||
seek = seek_value
|
|
||||||
display.frame.evaluateJavaScript('show_flash("seek", null, null, "%s");' % seek)
|
|
||||||
else:
|
|
||||||
seek = float(seek_value) / 1000
|
|
||||||
display.frame.evaluateJavaScript('show_video("seek", null, null, null, "%f");' % seek)
|
|
||||||
|
|
||||||
def reset(self, display):
|
def reset(self, display):
|
||||||
"""
|
"""
|
||||||
Reset the player
|
Reset the player
|
||||||
"""
|
|
||||||
controller = display.controller
|
|
||||||
if controller.media_info.is_flash:
|
|
||||||
display.frame.evaluateJavaScript('show_flash("close");')
|
|
||||||
else:
|
|
||||||
display.frame.evaluateJavaScript('show_video("close");')
|
|
||||||
self.state = MediaState.Off
|
|
||||||
|
|
||||||
def set_visible(self, display, status):
|
:param display: The display to be updated.
|
||||||
|
"""
|
||||||
|
display.frame.evaluateJavaScript('show_video("close");')
|
||||||
|
self.set_state(MediaState.Off, display)
|
||||||
|
|
||||||
|
def set_visible(self, display, visibility):
|
||||||
"""
|
"""
|
||||||
Set the visibility
|
Set the visibility
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
|
:param visibility: The visibility to be set.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
if visibility:
|
||||||
if status:
|
|
||||||
is_visible = "visible"
|
is_visible = "visible"
|
||||||
else:
|
else:
|
||||||
is_visible = "hidden"
|
is_visible = "hidden"
|
||||||
if controller.media_info.is_flash:
|
display.frame.evaluateJavaScript('show_video("setVisible", null, null, null, "%s");' % is_visible)
|
||||||
display.frame.evaluateJavaScript('show_flash("setVisible", null, null, "%s");' % is_visible)
|
|
||||||
else:
|
|
||||||
display.frame.evaluateJavaScript('show_video("setVisible", null, null, null, "%s");' % is_visible)
|
|
||||||
|
|
||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
Update the UI
|
Update the UI
|
||||||
|
|
||||||
|
:param display: The display to be updated.
|
||||||
"""
|
"""
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
if controller.media_info.is_flash:
|
if display.frame.evaluateJavaScript('show_video("isEnded");'):
|
||||||
current_time = display.frame.evaluateJavaScript('show_flash("current_time");')
|
self.stop(display)
|
||||||
length = display.frame.evaluateJavaScript('show_flash("length");')
|
current_time = display.frame.evaluateJavaScript('show_video("current_time");')
|
||||||
else:
|
# check if conversion was ok and value is not 'NaN'
|
||||||
if display.frame.evaluateJavaScript('show_video("isEnded");'):
|
if current_time and current_time != float('inf'):
|
||||||
self.stop(display)
|
current_time = int(current_time * 1000)
|
||||||
current_time = display.frame.evaluateJavaScript('show_video("current_time");')
|
length = display.frame.evaluateJavaScript('show_video("length");')
|
||||||
# check if conversion was ok and value is not 'NaN'
|
# check if conversion was ok and value is not 'NaN'
|
||||||
if current_time and current_time != float('inf'):
|
if length and length != float('inf'):
|
||||||
current_time = int(current_time * 1000)
|
length = int(length * 1000)
|
||||||
length = display.frame.evaluateJavaScript('show_video("length");')
|
|
||||||
# check if conversion was ok and value is not 'NaN'
|
|
||||||
if length and length != float('inf'):
|
|
||||||
length = int(length * 1000)
|
|
||||||
if current_time and length:
|
if current_time and length:
|
||||||
controller.media_info.length = length
|
controller.media_info.length = length
|
||||||
controller.seek_slider.setMaximum(length)
|
controller.seek_slider.setMaximum(length)
|
||||||
|
@ -84,7 +84,7 @@ class DisplayController(QtWidgets.QWidget):
|
|||||||
super(DisplayController, self).__init__(parent)
|
super(DisplayController, self).__init__(parent)
|
||||||
self.is_live = False
|
self.is_live = False
|
||||||
self.display = None
|
self.display = None
|
||||||
self.controller_type = DisplayControllerType.Plugin
|
self.controller_type = None
|
||||||
|
|
||||||
def send_to_plugins(self, *args):
|
def send_to_plugins(self, *args):
|
||||||
"""
|
"""
|
||||||
|
@ -147,6 +147,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
|||||||
def update_lines_text(self, lines):
|
def update_lines_text(self, lines):
|
||||||
"""
|
"""
|
||||||
Updates the lines on a page on the wizard
|
Updates the lines on a page on the wizard
|
||||||
|
:param lines: then number of lines to be displayed
|
||||||
"""
|
"""
|
||||||
self.main_line_count_label.setText(
|
self.main_line_count_label.setText(
|
||||||
translate('OpenLP.ThemeForm', '(approximately %d lines per slide)') % int(lines))
|
translate('OpenLP.ThemeForm', '(approximately %d lines per slide)') % int(lines))
|
||||||
@ -186,6 +187,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
|||||||
def on_current_id_changed(self, page_id):
|
def on_current_id_changed(self, page_id):
|
||||||
"""
|
"""
|
||||||
Detects Page changes and updates as appropriate.
|
Detects Page changes and updates as appropriate.
|
||||||
|
:param page_id: current page number
|
||||||
"""
|
"""
|
||||||
enabled = self.page(page_id) == self.area_position_page
|
enabled = self.page(page_id) == self.area_position_page
|
||||||
self.setOption(QtWidgets.QWizard.HaveCustomButton1, enabled)
|
self.setOption(QtWidgets.QWizard.HaveCustomButton1, enabled)
|
||||||
|
@ -111,6 +111,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
|
|||||||
def setupUi(self, image):
|
def setupUi(self, image):
|
||||||
"""
|
"""
|
||||||
Set up the wizard UI.
|
Set up the wizard UI.
|
||||||
|
:param image: path to start up image
|
||||||
"""
|
"""
|
||||||
self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
|
self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
|
||||||
self.setModal(True)
|
self.setModal(True)
|
||||||
@ -210,6 +211,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
|
|||||||
def on_current_id_changed(self, page_id):
|
def on_current_id_changed(self, page_id):
|
||||||
"""
|
"""
|
||||||
Perform necessary functions depending on which wizard page is active.
|
Perform necessary functions depending on which wizard page is active.
|
||||||
|
:param page_id: current page number
|
||||||
"""
|
"""
|
||||||
if self.with_progress_page and self.page(page_id) == self.progress_page:
|
if self.with_progress_page and self.page(page_id) == self.progress_page:
|
||||||
self.pre_wizard()
|
self.pre_wizard()
|
||||||
@ -221,6 +223,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
|
|||||||
def custom_page_changed(self, page_id):
|
def custom_page_changed(self, page_id):
|
||||||
"""
|
"""
|
||||||
Called when changing to a page other than the progress page
|
Called when changing to a page other than the progress page
|
||||||
|
:param page_id: current page number
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
Add custom buttons to the end of the toolbar
|
Add custom buttons to the end of the toolbar
|
||||||
"""
|
"""
|
||||||
self.replace_action = self.toolbar.add_toolbar_action('replace_action',
|
self.replace_action = self.toolbar.add_toolbar_action('replace_action',
|
||||||
icon=':/slides/slide_blank.png',
|
icon=':/slides/slide_theme.png',
|
||||||
triggers=self.on_replace_click)
|
triggers=self.on_replace_click)
|
||||||
self.reset_action = self.toolbar.add_toolbar_action('reset_action',
|
self.reset_action = self.toolbar.add_toolbar_action('reset_action',
|
||||||
icon=':/system/system_close.png',
|
icon=':/system/system_close.png',
|
||||||
|
@ -29,8 +29,8 @@ from openlp.core.common import Registry, RegistryProperties, AppLocation, Settin
|
|||||||
translate
|
translate
|
||||||
from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \
|
from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \
|
||||||
build_icon, check_item_selected
|
build_icon, check_item_selected
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
from openlp.core.lib.ui import create_widget_action, critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
from openlp.core.ui import DisplayControllerType
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds
|
from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds
|
||||||
from openlp.core.common.languagemanager import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.core.ui.media.vlcplayer import get_vlc
|
from openlp.core.ui.media.vlcplayer import get_vlc
|
||||||
@ -78,19 +78,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
self.single_service_item = False
|
self.single_service_item = False
|
||||||
self.has_search = True
|
self.has_search = True
|
||||||
self.media_object = None
|
self.media_object = None
|
||||||
self.display_controller = DisplayController(self.parent())
|
# self.display_controller = DisplayController(self.parent())
|
||||||
self.display_controller.controller_layout = QtWidgets.QVBoxLayout()
|
|
||||||
self.media_controller.register_controller(self.display_controller)
|
|
||||||
self.media_controller.set_controls_visible(self.display_controller, False)
|
|
||||||
self.display_controller.preview_display = Display(self.display_controller)
|
|
||||||
self.display_controller.preview_display.hide()
|
|
||||||
self.display_controller.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300))
|
|
||||||
self.display_controller.preview_display.screen = {'size': self.display_controller.preview_display.geometry()}
|
|
||||||
self.display_controller.preview_display.setup()
|
|
||||||
self.media_controller.setup_display(self.display_controller.preview_display, False)
|
|
||||||
Registry().register_function('video_background_replaced', self.video_background_replaced)
|
Registry().register_function('video_background_replaced', self.video_background_replaced)
|
||||||
Registry().register_function('mediaitem_media_rebuild', self.rebuild_players)
|
Registry().register_function('mediaitem_media_rebuild', self.rebuild_players)
|
||||||
Registry().register_function('config_screen_changed', self.display_setup)
|
|
||||||
# Allow DnD from the desktop
|
# Allow DnD from the desktop
|
||||||
self.list_view.activateDnD()
|
self.list_view.activateDnD()
|
||||||
|
|
||||||
@ -101,12 +91,17 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
||||||
self.replace_action.setText(UiStrings().ReplaceBG)
|
self.replace_action.setText(UiStrings().ReplaceBG)
|
||||||
|
self.replace_action_context.setText(UiStrings().ReplaceBG)
|
||||||
if 'webkit' in get_media_players()[0]:
|
if 'webkit' in get_media_players()[0]:
|
||||||
self.replace_action.setToolTip(UiStrings().ReplaceLiveBG)
|
self.replace_action.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
|
self.replace_action_context.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
else:
|
else:
|
||||||
self.replace_action.setToolTip(UiStrings().ReplaceLiveBGDisabled)
|
self.replace_action.setToolTip(UiStrings().ReplaceLiveBGDisabled)
|
||||||
|
self.replace_action_context.setToolTip(UiStrings().ReplaceLiveBGDisabled)
|
||||||
self.reset_action.setText(UiStrings().ResetBG)
|
self.reset_action.setText(UiStrings().ResetBG)
|
||||||
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
||||||
|
self.reset_action_context.setText(UiStrings().ResetBG)
|
||||||
|
self.reset_action_context.setToolTip(UiStrings().ResetLiveBG)
|
||||||
self.automatic = UiStrings().Automatic
|
self.automatic = UiStrings().Automatic
|
||||||
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||||
|
|
||||||
@ -151,10 +146,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
Adds buttons to the end of the header bar.
|
Adds buttons to the end of the header bar.
|
||||||
"""
|
"""
|
||||||
# Replace backgrounds do not work at present so remove functionality.
|
# Replace backgrounds do not work at present so remove functionality.
|
||||||
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_blank.png',
|
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_theme.png',
|
||||||
triggers=self.on_replace_click)
|
triggers=self.on_replace_click)
|
||||||
if 'webkit' not in get_media_players()[0]:
|
if 'webkit' not in get_media_players()[0]:
|
||||||
self.replace_action.setDisabled(True)
|
self.replace_action.setDisabled(True)
|
||||||
|
self.replace_action_context.setDisabled(True)
|
||||||
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
|
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
|
||||||
visible=False, triggers=self.on_reset_click)
|
visible=False, triggers=self.on_reset_click)
|
||||||
self.media_widget = QtWidgets.QWidget(self)
|
self.media_widget = QtWidgets.QWidget(self)
|
||||||
@ -173,7 +169,17 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
self.page_layout.addWidget(self.media_widget)
|
self.page_layout.addWidget(self.media_widget)
|
||||||
self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed)
|
self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed)
|
||||||
|
|
||||||
def override_player_changed(self, index):
|
def add_custom_context_actions(self):
|
||||||
|
create_widget_action(self.list_view, separator=True)
|
||||||
|
self.replace_action_context = create_widget_action(
|
||||||
|
self.list_view, text=UiStrings().ReplaceBG, icon=':/slides/slide_blank.png',
|
||||||
|
triggers=self.on_replace_click)
|
||||||
|
self.reset_action_context = create_widget_action(
|
||||||
|
self.list_view, text=UiStrings().ReplaceLiveBG, icon=':/system/system_close.png',
|
||||||
|
visible=False, triggers=self.on_reset_click)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def override_player_changed(index):
|
||||||
"""
|
"""
|
||||||
The Player has been overridden
|
The Player has been overridden
|
||||||
|
|
||||||
@ -191,12 +197,14 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
self.media_controller.media_reset(self.live_controller)
|
self.media_controller.media_reset(self.live_controller)
|
||||||
self.reset_action.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
self.reset_action_context.setVisible(False)
|
||||||
|
|
||||||
def video_background_replaced(self):
|
def video_background_replaced(self):
|
||||||
"""
|
"""
|
||||||
Triggered by main display on change of serviceitem.
|
Triggered by main display on change of serviceitem.
|
||||||
"""
|
"""
|
||||||
self.reset_action.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
self.reset_action_context.setVisible(False)
|
||||||
|
|
||||||
def on_replace_click(self):
|
def on_replace_click(self):
|
||||||
"""
|
"""
|
||||||
@ -215,6 +223,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
service_item.add_from_command(path, name, CLAPPERBOARD)
|
service_item.add_from_command(path, name, CLAPPERBOARD)
|
||||||
if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True):
|
if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True):
|
||||||
self.reset_action.setVisible(True)
|
self.reset_action.setVisible(True)
|
||||||
|
self.reset_action_context.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
translate('MediaPlugin.MediaItem',
|
translate('MediaPlugin.MediaItem',
|
||||||
@ -273,16 +282,14 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
service_item.processor = self.display_type_combo_box.currentText()
|
service_item.processor = self.display_type_combo_box.currentText()
|
||||||
service_item.add_from_command(path, name, CLAPPERBOARD)
|
service_item.add_from_command(path, name, CLAPPERBOARD)
|
||||||
# Only get start and end times if going to a service
|
# Only get start and end times if going to a service
|
||||||
if context == ServiceItemContext.Service:
|
if not self.media_controller.media_length(service_item):
|
||||||
# Start media and obtain the length
|
return False
|
||||||
if not self.media_controller.media_length(service_item):
|
|
||||||
return False
|
|
||||||
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
||||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||||
if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked:
|
if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked:
|
||||||
service_item.will_auto_start = True
|
service_item.will_auto_start = True
|
||||||
# force a non-existent theme
|
# force a non-existent theme
|
||||||
service_item.theme = -1
|
service_item.theme = -1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -305,12 +312,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
' '.join(self.media_controller.video_extensions_list),
|
' '.join(self.media_controller.video_extensions_list),
|
||||||
' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles)
|
' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles)
|
||||||
|
|
||||||
def display_setup(self):
|
|
||||||
"""
|
|
||||||
Setup media controller display.
|
|
||||||
"""
|
|
||||||
self.media_controller.setup_display(self.display_controller.preview_display, False)
|
|
||||||
|
|
||||||
def populate_display_types(self):
|
def populate_display_types(self):
|
||||||
"""
|
"""
|
||||||
Load the combobox with the enabled media players, allowing user to select a specific player if settings allow.
|
Load the combobox with the enabled media players, allowing user to select a specific player if settings allow.
|
||||||
@ -385,16 +386,16 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
|
|||||||
if item_name:
|
if item_name:
|
||||||
self.list_view.addItem(item_name)
|
self.list_view.addItem(item_name)
|
||||||
|
|
||||||
def get_list(self, type=MediaType.Audio):
|
def get_list(self, media_type=MediaType.Audio):
|
||||||
"""
|
"""
|
||||||
Get the list of media, optional select media type.
|
Get the list of media, optional select media type.
|
||||||
|
|
||||||
:param type: Type to get, defaults to audio.
|
:param media_type: Type to get, defaults to audio.
|
||||||
:return: The media list
|
:return: The media list
|
||||||
"""
|
"""
|
||||||
media = Settings().value(self.settings_section + '/media files')
|
media = Settings().value(self.settings_section + '/media files')
|
||||||
media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1]))
|
media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1]))
|
||||||
if type == MediaType.Audio:
|
if media_type == MediaType.Audio:
|
||||||
extension = self.media_controller.audio_extensions_list
|
extension = self.media_controller.audio_extensions_list
|
||||||
else:
|
else:
|
||||||
extension = self.media_controller.video_extensions_list
|
extension = self.media_controller.video_extensions_list
|
||||||
|
@ -60,13 +60,6 @@ class MediaPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
Override the inherited initialise() method in order to upgrade the media before trying to load it
|
Override the inherited initialise() method in order to upgrade the media before trying to load it
|
||||||
"""
|
"""
|
||||||
# FIXME: Remove after 2.2 release.
|
|
||||||
# This is needed to load the list of media from the config saved before the settings rewrite.
|
|
||||||
if self.media_item_class is not None:
|
|
||||||
loaded_list = Settings().get_files_from_config(self)
|
|
||||||
# Now save the list to the config using our Settings class.
|
|
||||||
if loaded_list:
|
|
||||||
Settings().setValue('%s/%s files' % (self.settings_section, self.name), loaded_list)
|
|
||||||
super().initialise()
|
super().initialise()
|
||||||
|
|
||||||
def app_startup(self):
|
def app_startup(self):
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 815 B After Width: | Height: | Size: 1.0 KiB |
@ -148,7 +148,7 @@ class TestMainWindow(TestCase, TestMixin):
|
|||||||
|
|
||||||
# THEN: the following registry functions should have been registered
|
# THEN: the following registry functions should have been registered
|
||||||
self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.')
|
self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.')
|
||||||
self.assertEqual(len(self.registry.functions_list), 16, 'The registry should have 16 functions')
|
self.assertEqual(len(self.registry.functions_list), 17, 'The registry should have 17 functions')
|
||||||
self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.')
|
self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.')
|
||||||
self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.')
|
self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.')
|
||||||
self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been '
|
self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been '
|
||||||
|
@ -78,10 +78,11 @@ class TestMediaController(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
Test that we don't try to play media when no players available
|
Test that we don't try to play media when no players available
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
# GIVEN: A mocked UiStrings, get_used_players, controller, display and service_item
|
||||||
with patch('openlp.core.ui.media.mediacontroller.get_media_players') as mocked_get_media_players,\
|
with patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players') as \
|
||||||
|
mocked_get_used_players,\
|
||||||
patch('openlp.core.ui.media.mediacontroller.UiStrings') as mocked_uistrings:
|
patch('openlp.core.ui.media.mediacontroller.UiStrings') as mocked_uistrings:
|
||||||
mocked_get_media_players.return_value = ([], '')
|
mocked_get_used_players.return_value = ([])
|
||||||
mocked_ret_uistrings = MagicMock()
|
mocked_ret_uistrings = MagicMock()
|
||||||
mocked_ret_uistrings.Automatic = 1
|
mocked_ret_uistrings.Automatic = 1
|
||||||
mocked_uistrings.return_value = mocked_ret_uistrings
|
mocked_uistrings.return_value = mocked_ret_uistrings
|
||||||
@ -97,14 +98,14 @@ class TestMediaController(TestCase, TestMixin):
|
|||||||
# THEN: it should return False
|
# THEN: it should return False
|
||||||
self.assertFalse(ret, '_check_file_type should return False when no mediaplayers are available.')
|
self.assertFalse(ret, '_check_file_type should return False when no mediaplayers are available.')
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.mediacontroller.get_media_players')
|
@patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players')
|
||||||
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
||||||
def check_file_type_no_processor_test(self, mocked_uistrings, mocked_get_media_players):
|
def check_file_type_no_processor_test(self, mocked_uistrings, mocked_get_used_players):
|
||||||
"""
|
"""
|
||||||
Test that we don't try to play media when the processor for the service item is None
|
Test that we don't try to play media when the processor for the service item is None
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
||||||
mocked_get_media_players.return_value = ([], '')
|
mocked_get_used_players.return_value = ([], '')
|
||||||
mocked_ret_uistrings = MagicMock()
|
mocked_ret_uistrings = MagicMock()
|
||||||
mocked_ret_uistrings.Automatic = 1
|
mocked_ret_uistrings.Automatic = 1
|
||||||
mocked_uistrings.return_value = mocked_ret_uistrings
|
mocked_uistrings.return_value = mocked_ret_uistrings
|
||||||
@ -120,14 +121,14 @@ class TestMediaController(TestCase, TestMixin):
|
|||||||
# THEN: it should return False
|
# THEN: it should return False
|
||||||
self.assertFalse(ret, '_check_file_type should return False when the processor for service_item is None.')
|
self.assertFalse(ret, '_check_file_type should return False when the processor for service_item is None.')
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.mediacontroller.get_media_players')
|
@patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players')
|
||||||
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
||||||
def check_file_type_automatic_processor_test(self, mocked_uistrings, mocked_get_media_players):
|
def check_file_type_automatic_processor_test(self, mocked_uistrings, mocked_get_used_players):
|
||||||
"""
|
"""
|
||||||
Test that we can play media when players are available and we have a automatic processor from the service item
|
Test that we can play media when players are available and we have a automatic processor from the service item
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
||||||
mocked_get_media_players.return_value = (['vlc', 'webkit'], '')
|
mocked_get_used_players.return_value = (['vlc', 'webkit'])
|
||||||
mocked_ret_uistrings = MagicMock()
|
mocked_ret_uistrings = MagicMock()
|
||||||
mocked_ret_uistrings.Automatic = 1
|
mocked_ret_uistrings.Automatic = 1
|
||||||
mocked_uistrings.return_value = mocked_ret_uistrings
|
mocked_uistrings.return_value = mocked_ret_uistrings
|
||||||
@ -150,21 +151,21 @@ class TestMediaController(TestCase, TestMixin):
|
|||||||
self.assertTrue(ret, '_check_file_type should return True when mediaplayers are available and '
|
self.assertTrue(ret, '_check_file_type should return True when mediaplayers are available and '
|
||||||
'the service item has an automatic processor.')
|
'the service item has an automatic processor.')
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.mediacontroller.get_media_players')
|
@patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players')
|
||||||
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
@patch('openlp.core.ui.media.mediacontroller.UiStrings')
|
||||||
def check_file_type_processor_different_from_available_test(self, mocked_uistrings, mocked_get_media_players):
|
def check_file_type_processor_different_from_available_test(self, mocked_uistrings, mocked_get_used_players):
|
||||||
"""
|
"""
|
||||||
Test that we can play media when players available are different from the processor from the service item
|
Test that we can play media when players available are different from the processor from the service item
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
# GIVEN: A mocked UiStrings, get_media_players, controller, display and service_item
|
||||||
mocked_get_media_players.return_value = (['phonon'], '')
|
mocked_get_used_players.return_value = (['system'])
|
||||||
mocked_ret_uistrings = MagicMock()
|
mocked_ret_uistrings = MagicMock()
|
||||||
mocked_ret_uistrings.Automatic = 'automatic'
|
mocked_ret_uistrings.Automatic = 'automatic'
|
||||||
mocked_uistrings.return_value = mocked_ret_uistrings
|
mocked_uistrings.return_value = mocked_ret_uistrings
|
||||||
media_controller = MediaController()
|
media_controller = MediaController()
|
||||||
mocked_phonon = MagicMock()
|
mocked_phonon = MagicMock()
|
||||||
mocked_phonon.video_extensions_list = ['*.mp4']
|
mocked_phonon.video_extensions_list = ['*.mp4']
|
||||||
media_controller.media_players = {'phonon': mocked_phonon}
|
media_controller.media_players = {'system': mocked_phonon}
|
||||||
mocked_controller = MagicMock()
|
mocked_controller = MagicMock()
|
||||||
mocked_suffix = MagicMock()
|
mocked_suffix = MagicMock()
|
||||||
mocked_suffix.return_value = 'mp4'
|
mocked_suffix.return_value = 'mp4'
|
||||||
|
@ -380,7 +380,6 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
||||||
mocked_vlc_media.parse.assert_called_with()
|
mocked_vlc_media.parse.assert_called_with()
|
||||||
mocked_volume.assert_called_with(mocked_display, 100)
|
mocked_volume.assert_called_with(mocked_display, 100)
|
||||||
self.assertEqual(10, mocked_controller.media_info.length)
|
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
||||||
@ -426,7 +425,6 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
||||||
mocked_vlc_media.parse.assert_called_with()
|
mocked_vlc_media.parse.assert_called_with()
|
||||||
mocked_volume.assert_called_with(mocked_display, 100)
|
mocked_volume.assert_called_with(mocked_display, 100)
|
||||||
self.assertEqual(10, mocked_controller.media_info.length)
|
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
||||||
@ -472,7 +470,6 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
mocked_display.vlc_media_player.set_media.assert_called_with(mocked_vlc_media)
|
||||||
mocked_vlc_media.parse.assert_called_with()
|
mocked_vlc_media.parse.assert_called_with()
|
||||||
mocked_volume.assert_called_with(mocked_display, 100)
|
mocked_volume.assert_called_with(mocked_display, 100)
|
||||||
self.assertEqual(10, mocked_controller.media_info.length)
|
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
@patch('openlp.core.ui.media.vlcplayer.is_win')
|
||||||
@ -628,7 +625,7 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.controller = mocked_controller
|
mocked_display.controller = mocked_controller
|
||||||
mocked_display.vlc_media_player.get_media.return_value = mocked_media
|
mocked_display.vlc_media_player.get_media.return_value = mocked_media
|
||||||
vlc_player = VlcPlayer(None)
|
vlc_player = VlcPlayer(None)
|
||||||
vlc_player.state = MediaState.Paused
|
vlc_player.set_state(MediaState.Paused, mocked_display)
|
||||||
|
|
||||||
# WHEN: play() is called
|
# WHEN: play() is called
|
||||||
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
||||||
@ -638,10 +635,8 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
|
|
||||||
# THEN: A bunch of things should happen to play the media
|
# THEN: A bunch of things should happen to play the media
|
||||||
mocked_thread.start.assert_called_with()
|
mocked_thread.start.assert_called_with()
|
||||||
self.assertEqual(50, mocked_controller.media_info.length)
|
|
||||||
mocked_volume.assert_called_with(mocked_display, 100)
|
mocked_volume.assert_called_with(mocked_display, 100)
|
||||||
mocked_controller.seek_slider.setMaximum.assert_called_with(50000)
|
self.assertEqual(MediaState.Playing, vlc_player.get_live_state())
|
||||||
self.assertEqual(MediaState.Playing, vlc_player.state)
|
|
||||||
mocked_display.vlc_widget.raise_.assert_called_with()
|
mocked_display.vlc_widget.raise_.assert_called_with()
|
||||||
self.assertTrue(result, 'The value returned from play() should be True')
|
self.assertTrue(result, 'The value returned from play() should be True')
|
||||||
|
|
||||||
@ -661,7 +656,7 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display = MagicMock()
|
mocked_display = MagicMock()
|
||||||
mocked_display.controller = mocked_controller
|
mocked_display.controller = mocked_controller
|
||||||
vlc_player = VlcPlayer(None)
|
vlc_player = VlcPlayer(None)
|
||||||
vlc_player.state = MediaState.Paused
|
vlc_player.set_state(MediaState.Paused, mocked_display)
|
||||||
|
|
||||||
# WHEN: play() is called
|
# WHEN: play() is called
|
||||||
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
||||||
@ -695,7 +690,7 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display = MagicMock()
|
mocked_display = MagicMock()
|
||||||
mocked_display.controller = mocked_controller
|
mocked_display.controller = mocked_controller
|
||||||
vlc_player = VlcPlayer(None)
|
vlc_player = VlcPlayer(None)
|
||||||
vlc_player.state = MediaState.Paused
|
vlc_player.set_state(MediaState.Paused, mocked_display)
|
||||||
|
|
||||||
# WHEN: play() is called
|
# WHEN: play() is called
|
||||||
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
with patch.object(vlc_player, 'media_state_wait') as mocked_media_state_wait, \
|
||||||
@ -709,10 +704,8 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.vlc_media_player.play.assert_called_with()
|
mocked_display.vlc_media_player.play.assert_called_with()
|
||||||
mocked_display.vlc_media_player.audio_set_track.assert_called_with(1)
|
mocked_display.vlc_media_player.audio_set_track.assert_called_with(1)
|
||||||
mocked_display.vlc_media_player.video_set_spu.assert_called_with(1)
|
mocked_display.vlc_media_player.video_set_spu.assert_called_with(1)
|
||||||
self.assertEqual(50, mocked_controller.media_info.length)
|
|
||||||
mocked_volume.assert_called_with(mocked_display, 100)
|
mocked_volume.assert_called_with(mocked_display, 100)
|
||||||
mocked_controller.seek_slider.setMaximum.assert_called_with(50000)
|
self.assertEqual(MediaState.Playing, vlc_player.get_live_state())
|
||||||
self.assertEqual(MediaState.Playing, vlc_player.state)
|
|
||||||
mocked_display.vlc_widget.raise_.assert_called_with()
|
mocked_display.vlc_widget.raise_.assert_called_with()
|
||||||
self.assertTrue(result, 'The value returned from play() should be True')
|
self.assertTrue(result, 'The value returned from play() should be True')
|
||||||
|
|
||||||
@ -739,7 +732,7 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
mocked_display.vlc_media.get_state.assert_called_with()
|
mocked_display.vlc_media.get_state.assert_called_with()
|
||||||
mocked_display.vlc_media_player.pause.assert_called_with()
|
mocked_display.vlc_media_player.pause.assert_called_with()
|
||||||
mocked_media_state_wait.assert_called_with(mocked_display, 2)
|
mocked_media_state_wait.assert_called_with(mocked_display, 2)
|
||||||
self.assertEqual(MediaState.Paused, vlc_player.state)
|
self.assertEqual(MediaState.Paused, vlc_player.get_live_state())
|
||||||
|
|
||||||
@patch('openlp.core.ui.media.vlcplayer.get_vlc')
|
@patch('openlp.core.ui.media.vlcplayer.get_vlc')
|
||||||
def pause_not_playing_test(self, mocked_get_vlc):
|
def pause_not_playing_test(self, mocked_get_vlc):
|
||||||
@ -805,7 +798,7 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
# THEN: A thread should have been started to stop VLC
|
# THEN: A thread should have been started to stop VLC
|
||||||
mocked_threading.Thread.assert_called_with(target=mocked_stop)
|
mocked_threading.Thread.assert_called_with(target=mocked_stop)
|
||||||
mocked_thread.start.assert_called_with()
|
mocked_thread.start.assert_called_with()
|
||||||
self.assertEqual(MediaState.Stopped, vlc_player.state)
|
self.assertEqual(MediaState.Stopped, vlc_player.get_live_state())
|
||||||
|
|
||||||
def volume_test(self):
|
def volume_test(self):
|
||||||
"""
|
"""
|
||||||
@ -900,10 +893,10 @@ class TestVLCPlayer(TestCase, TestMixin):
|
|||||||
# WHEN: reset() is called
|
# WHEN: reset() is called
|
||||||
vlc_player.reset(mocked_display)
|
vlc_player.reset(mocked_display)
|
||||||
|
|
||||||
# THEN: The media should be stopped and invsibile
|
# THEN: The media should be stopped and invisible
|
||||||
mocked_display.vlc_media_player.stop.assert_called_with()
|
mocked_display.vlc_media_player.stop.assert_called_with()
|
||||||
mocked_display.vlc_widget.setVisible.assert_called_with(False)
|
mocked_display.vlc_widget.setVisible.assert_called_with(False)
|
||||||
self.assertEqual(MediaState.Off, vlc_player.state)
|
self.assertEqual(MediaState.Off, vlc_player.get_live_state())
|
||||||
|
|
||||||
def set_visible_has_own_widget_test(self):
|
def set_visible_has_own_widget_test(self):
|
||||||
"""
|
"""
|
||||||
|
@ -54,8 +54,6 @@ class MediaPluginTest(TestCase, TestMixin):
|
|||||||
media_plugin.initialise()
|
media_plugin.initialise()
|
||||||
|
|
||||||
# THEN: The settings should be upgraded and the base initialise() method should be called
|
# THEN: The settings should be upgraded and the base initialise() method should be called
|
||||||
mocked_settings.get_files_from_config.assert_called_with(media_plugin)
|
|
||||||
mocked_settings.setValue.assert_called_with('media/media files', True)
|
|
||||||
mocked_initialise.assert_called_with()
|
mocked_initialise.assert_called_with()
|
||||||
|
|
||||||
def test_about_text(self):
|
def test_about_text(self):
|
||||||
|
21
tests/interfaces/openlp_core_ul_media_vendor/__init__.py
Normal file
21
tests/interfaces/openlp_core_ul_media_vendor/__init__.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
@ -0,0 +1,51 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Package to test the openlp.core.ui.media package.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
|
||||||
|
|
||||||
|
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources', 'media'))
|
||||||
|
|
||||||
|
TEST_MEDIA = [['avi_file.avi', 61495], ['mp3_file.mp3', 134426], ['mpg_file.mpg', 9404], ['mp4_file.mp4', 188336]]
|
||||||
|
|
||||||
|
|
||||||
|
class TestMediainfoWrapper(TestCase):
|
||||||
|
|
||||||
|
def media_length_test(self):
|
||||||
|
"""
|
||||||
|
Test the Media Info basic functionality
|
||||||
|
"""
|
||||||
|
for test_data in TEST_MEDIA:
|
||||||
|
# GIVEN: a media file
|
||||||
|
full_path = os.path.normpath(os.path.join(TEST_PATH, test_data[0]))
|
||||||
|
|
||||||
|
# WHEN the media data is retrieved
|
||||||
|
results = MediaInfoWrapper.parse(full_path)
|
||||||
|
|
||||||
|
# THEN you can determine the run time
|
||||||
|
self.assertEqual(results.tracks[0].duration, test_data[1], 'The correct duration is returned for ' +
|
||||||
|
test_data[0])
|
BIN
tests/resources/media/avi_file.avi
Normal file
BIN
tests/resources/media/avi_file.avi
Normal file
Binary file not shown.
BIN
tests/resources/media/mp3_file.mp3
Normal file
BIN
tests/resources/media/mp3_file.mp3
Normal file
Binary file not shown.
BIN
tests/resources/media/mp4_file.mp4
Normal file
BIN
tests/resources/media/mp4_file.mp4
Normal file
Binary file not shown.
BIN
tests/resources/media/mpg_file.mpg
Normal file
BIN
tests/resources/media/mpg_file.mpg
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user