openlp/openlp/plugins/media/forms/mediaclipselectorform.py

698 lines
32 KiB
Python

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2018 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 #
###############################################################################
import logging
import os
import re
from datetime import datetime
from time import sleep
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_win, is_linux, is_macosx
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import RegistryProperties
from openlp.core.common.path import Path
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media.vlcplayer import get_vlc
from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector
if is_win():
from win32com.client import Dispatch
if is_linux():
import dbus
log = logging.getLogger(__name__)
class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryProperties):
"""
Class to manage the clip selection
"""
log.info('{name} MediaClipSelectorForm loaded'.format(name=__name__))
def __init__(self, media_item, parent, manager):
"""
Constructor
"""
super(MediaClipSelectorForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint |
QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint)
self.vlc_instance = None
self.vlc_media_player = None
self.vlc_media = None
self.timer = None
self.audio_cd_tracks = None
self.audio_cd = False
self.playback_length = 0
self.media_item = media_item
self.setupUi(self)
# setup play/pause icon
self.play_icon = UiIcons().play
self.pause_icon = UiIcons().pause
def reject(self):
"""
Exit Dialog and do not save
"""
log.debug('MediaClipSelectorForm.reject')
# Tear down vlc
if self.vlc_media_player:
self.vlc_media_player.stop()
self.vlc_media_player.release()
self.vlc_media_player = None
if self.vlc_instance:
self.vlc_instance.release()
self.vlc_instance = None
if self.vlc_media:
self.vlc_media.release()
self.vlc_media = None
return QtWidgets.QDialog.reject(self)
def exec(self):
"""
Start dialog
"""
self.reset_ui()
self.setup_vlc()
return QtWidgets.QDialog.exec(self)
def reset_ui(self):
"""
Reset the UI to default values
"""
self.playback_length = 0
self.position_slider.setMinimum(0)
self.disable_all()
self.toggle_disable_load_media(False)
self.subtitle_tracks_combobox.clear()
self.audio_tracks_combobox.clear()
self.titles_combo_box.clear()
time = QtCore.QTime(0, 0, 0)
self.start_position_edit.setTime(time)
self.end_timeedit.setTime(time)
self.position_timeedit.setTime(time)
def setup_vlc(self):
"""
Setup VLC instance and mediaplayer
"""
vlc = get_vlc()
self.vlc_instance = vlc.Instance()
# creating an empty vlc media player
self.vlc_media_player = self.vlc_instance.media_player_new()
# The media player has to be 'connected' to the QFrame.
# (otherwise a video would be displayed in it's own window)
# This is platform specific!
# You have to give the id of the QFrame (or similar object)
# to vlc, different platforms have different functions for this.
win_id = int(self.preview_frame.winId())
if is_win():
self.vlc_media_player.set_hwnd(win_id)
elif is_macosx():
# We have to use 'set_nsobject' since Qt5 on OSX uses Cocoa
# framework and not the old Carbon.
self.vlc_media_player.set_nsobject(win_id)
else:
# for Linux using the X Server
self.vlc_media_player.set_xwindow(win_id)
self.vlc_media = None
# Setup timer every 100 ms to update position
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.update_position)
self.timer.start(100)
self.find_optical_devices()
self.audio_cd = False
self.audio_cd_tracks = None
def detect_audio_cd(self, path):
"""
Detects is the given path is an audio CD
:param path: Path to the device to be tested.
:return: True if it was an audio CD else False.
"""
vlc = get_vlc()
# Detect by trying to play it as a CD
self.vlc_media = self.vlc_instance.media_new_location('cdda://' + path)
self.vlc_media_player.set_media(self.vlc_media)
self.vlc_media_player.play()
# Wait for media to start playing. In this case VLC actually returns an error.
self.media_state_wait(vlc.State.Playing)
self.vlc_media_player.set_pause(1)
# If subitems exists, this is a CD
self.audio_cd_tracks = self.vlc_media.subitems()
if not self.audio_cd_tracks or self.audio_cd_tracks.count() < 1:
return False
# Insert into titles_combo_box
self.titles_combo_box.clear()
for i in range(self.audio_cd_tracks.count()):
item = self.audio_cd_tracks.item_at_index(i)
item_title = item.get_meta(vlc.Meta.Title)
self.titles_combo_box.addItem(item_title, i)
self.vlc_media_player.set_media(self.audio_cd_tracks.item_at_index(0))
self.audio_cd = True
self.titles_combo_box.setDisabled(False)
self.titles_combo_box.setCurrentIndex(0)
self.on_titles_combo_box_currentIndexChanged(0)
return True
@QtCore.pyqtSlot(bool)
def on_load_disc_button_clicked(self, clicked):
"""
Load the media when the load-button has been clicked
:param clicked: Given from signal, not used.
"""
log.debug('on_load_disc_button_clicked')
vlc = get_vlc()
self.disable_all()
self.application.set_busy_cursor()
path = self.media_path_combobox.currentText()
# Check if given path is non-empty and exists before starting VLC
if not path:
log.debug('no given path')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given'))
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return
if not os.path.exists(path):
log.debug('Given path does not exists')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'Given path does not exists'))
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return
# VLC behaves a bit differently on windows and linux when loading, which creates problems when trying to
# detect if we're dealing with a DVD or CD, so we use different loading approaches depending on the OS.
if is_win():
# If the given path is in the format "D:\" or "D:", prefix it with "/" to make VLC happy
pattern = re.compile(r'^\w:\\\\*$')
if pattern.match(path):
path = '/' + path
self.vlc_media = self.vlc_instance.media_new_location('dvd://' + path)
else:
self.vlc_media = self.vlc_instance.media_new_path(path)
if not self.vlc_media:
log.debug('vlc media player is none')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'An error happened during initialization of VLC player'))
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
return
# put the media in the media player
self.vlc_media_player.set_media(self.vlc_media)
self.vlc_media_player.audio_set_mute(True)
# start playback to get vlc to parse the media
if self.vlc_media_player.play() < 0:
log.debug('vlc play returned error')
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'VLC player failed playing the media'))
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
self.vlc_media_player.audio_set_mute(False)
return
self.vlc_media_player.audio_set_mute(True)
if not self.media_state_wait(vlc.State.Playing):
# Tests if this is an audio CD
if not self.detect_audio_cd(path):
critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm',
'VLC player failed playing the media'))
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
self.vlc_media_player.audio_set_mute(False)
return
# pause
self.vlc_media_player.set_time(0)
self.vlc_media_player.set_pause(1)
self.media_state_wait(vlc.State.Paused)
self.toggle_disable_load_media(False)
self.application.set_normal_cursor()
self.vlc_media_player.audio_set_mute(False)
if not self.audio_cd:
# Temporarily disable signals
self.blockSignals(True)
# Get titles, insert in combobox
titles = self.vlc_media_player.video_get_title_description()
self.titles_combo_box.clear()
for title in titles:
self.titles_combo_box.addItem(title[1].decode(), title[0])
# Re-enable signals
self.blockSignals(False)
# Main title is usually title #1
if len(titles) > 1:
self.titles_combo_box.setCurrentIndex(1)
# Enable audio track combobox if anything is in it
if len(titles) > 0:
self.titles_combo_box.setDisabled(False)
log.debug('load_disc_button end - '
'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state()))
@QtCore.pyqtSlot(bool)
def on_play_button_clicked(self, clicked):
"""
Toggle the playback
:param clicked: Given from signal, not used.
"""
vlc = get_vlc()
if self.vlc_media_player.get_state() == vlc.State.Playing:
self.vlc_media_player.pause()
self.play_button.setIcon(self.play_icon)
else:
self.vlc_media_player.play()
self.media_state_wait(vlc.State.Playing)
self.play_button.setIcon(self.pause_icon)
@QtCore.pyqtSlot(bool)
def on_set_start_button_clicked(self, clicked):
"""
Copy the current player position to start_position_edit
:param clicked: Given from signal, not used.
"""
vlc_ms_pos = self.vlc_media_player.get_time()
time = QtCore.QTime(0, 0, 0)
new_pos_time = time.addMSecs(vlc_ms_pos)
self.start_position_edit.setTime(new_pos_time)
# If start time is after end time, update end time.
end_time = self.end_timeedit.time()
if end_time < new_pos_time:
self.end_timeedit.setTime(new_pos_time)
@QtCore.pyqtSlot(bool)
def on_set_end_button_clicked(self, clicked):
"""
Copy the current player position to end_timeedit
:param clicked: Given from signal, not used.
"""
vlc_ms_pos = self.vlc_media_player.get_time()
time = QtCore.QTime(0, 0, 0)
new_pos_time = time.addMSecs(vlc_ms_pos)
self.end_timeedit.setTime(new_pos_time)
# If start time is after end time, update start time.
start_time = self.start_position_edit.time()
if start_time > new_pos_time:
self.start_position_edit.setTime(new_pos_time)
@QtCore.pyqtSlot(QtCore.QTime)
def on_start_timeedit_timeChanged(self, new_time):
"""
Called when start_position_edit is changed manually
:param new_time: The new time
"""
# If start time is after end time, update end time.
end_time = self.end_timeedit.time()
if end_time < new_time:
self.end_timeedit.setTime(new_time)
@QtCore.pyqtSlot(QtCore.QTime)
def on_end_timeedit_timeChanged(self, new_time):
"""
Called when end_timeedit is changed manually
:param new_time: The new time
"""
# If start time is after end time, update start time.
start_time = self.start_position_edit.time()
if start_time > new_time:
self.start_position_edit.setTime(new_time)
@QtCore.pyqtSlot(bool)
def on_jump_end_button_clicked(self, clicked):
"""
Set the player position to the position stored in end_timeedit
:param clicked: Given from signal, not used.
"""
end_time = self.end_timeedit.time()
end_time_ms = end_time.hour() * 60 * 60 * 1000 + \
end_time.minute() * 60 * 1000 + \
end_time.second() * 1000 + \
end_time.msec()
self.vlc_media_player.set_time(end_time_ms)
@QtCore.pyqtSlot(bool)
def on_jump_start_button_clicked(self, clicked):
"""
Set the player position to the position stored in start_position_edit
:param clicked: Given from signal, not used.
"""
start_time = self.start_position_edit.time()
start_time_ms = start_time.hour() * 60 * 60 * 1000 + \
start_time.minute() * 60 * 1000 + \
start_time.second() * 1000 + \
start_time.msec()
self.vlc_media_player.set_time(start_time_ms)
@QtCore.pyqtSlot(int)
def on_titles_combo_box_currentIndexChanged(self, index):
"""
When a new title is chosen, it is loaded by VLC and info about audio and subtitle tracks is reloaded
:param index: The index of the newly chosen title track.
"""
log.debug('in on_titles_combo_box_changed, index: {index:d}'.format(index=index))
vlc = get_vlc()
if not self.vlc_media_player:
log.error('vlc_media_player was None')
return
self.application.set_busy_cursor()
if self.audio_cd:
self.vlc_media = self.audio_cd_tracks.item_at_index(index)
self.vlc_media_player.set_media(self.vlc_media)
self.vlc_media_player.set_time(0)
self.vlc_media_player.play()
if not self.media_state_wait(vlc.State.Playing):
log.error('Could not start playing audio cd, needed to get track info')
self.application.set_normal_cursor()
return
self.vlc_media_player.audio_set_mute(True)
# pause
self.vlc_media_player.set_time(0)
self.vlc_media_player.set_pause(1)
self.vlc_media_player.audio_set_mute(False)
self.application.set_normal_cursor()
self.toggle_disable_player(False)
else:
self.vlc_media_player.set_title(index)
self.vlc_media_player.set_time(0)
self.vlc_media_player.play()
if not self.media_state_wait(vlc.State.Playing):
log.error('Could not start playing dvd, needed to get track info')
self.application.set_normal_cursor()
return
self.vlc_media_player.audio_set_mute(True)
# Get audio tracks
audio_tracks = self.vlc_media_player.audio_get_track_description()
log.debug('number of audio tracks: {tracks:d}'.format(tracks=len(audio_tracks)))
# Clear the audio track combobox, insert new tracks
self.audio_tracks_combobox.clear()
for audio_track in audio_tracks:
self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0])
# Enable audio track combobox if anything is in it
if len(audio_tracks) > 0:
self.audio_tracks_combobox.setDisabled(False)
# First track is "deactivated", so set to next if it exists
if len(audio_tracks) > 1:
self.audio_tracks_combobox.setCurrentIndex(1)
# Get subtitle tracks, insert in combobox
subtitles_tracks = self.vlc_media_player.video_get_spu_description()
self.subtitle_tracks_combobox.clear()
for subtitle_track in subtitles_tracks:
self.subtitle_tracks_combobox.addItem(subtitle_track[1].decode(), subtitle_track[0])
# Enable subtitle track combobox is anything in it
if len(subtitles_tracks) > 0:
self.subtitle_tracks_combobox.setDisabled(False)
self.vlc_media_player.audio_set_mute(False)
self.vlc_media_player.set_pause(1)
# If a title or audio track is available the player is enabled
if self.titles_combo_box.count() > 0 or len(audio_tracks) > 0:
self.toggle_disable_player(False)
# Set media length info
self.playback_length = self.vlc_media_player.get_length()
log.debug('playback_length: {length:d} ms'.format(length=self.playback_length))
# if length is 0, wait a bit, maybe vlc will change its mind...
loop_count = 0
while self.playback_length == 0 and loop_count < 20:
sleep(0.1)
self.playback_length = self.vlc_media_player.get_length()
loop_count += 1
log.debug('in loop, playback_length: {length:d} ms'.format(length=self.playback_length))
self.position_slider.setMaximum(self.playback_length)
# setup start and end time
rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0)
time = QtCore.QTime(0, 0, 0)
playback_length_time = time.addMSecs(rounded_vlc_ms_length)
self.start_position_edit.setMaximumTime(playback_length_time)
self.end_timeedit.setMaximumTime(playback_length_time)
self.end_timeedit.setTime(playback_length_time)
# Pause once again, just to make sure
loop_count = 0
while self.vlc_media_player.get_state() == vlc.State.Playing and loop_count < 20:
sleep(0.1)
self.vlc_media_player.set_pause(1)
loop_count += 1
log.debug('titles_combo_box end - '
'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state()))
self.application.set_normal_cursor()
@QtCore.pyqtSlot(int)
def on_audio_tracks_combobox_currentIndexChanged(self, index):
"""
When a new audio track is chosen update audio track bing played by VLC
:param index: The index of the newly chosen audio track.
"""
if not self.vlc_media_player:
return
audio_track = self.audio_tracks_combobox.itemData(index)
log.debug('in on_audio_tracks_combobox_currentIndexChanged, '
'index: {index:d} audio_track: {tracks}'.format(index=index, tracks=audio_track))
if audio_track and int(audio_track) > 0:
self.vlc_media_player.audio_set_track(int(audio_track))
@QtCore.pyqtSlot(int)
def on_subtitle_tracks_combobox_currentIndexChanged(self, index):
"""
When a new subtitle track is chosen update subtitle track bing played by VLC
:param index: The index of the newly chosen subtitle.
"""
if not self.vlc_media_player:
return
subtitle_track = self.subtitle_tracks_combobox.itemData(index)
if subtitle_track:
self.vlc_media_player.video_set_spu(int(subtitle_track))
def on_position_slider_sliderMoved(self, position):
"""
Set player position according to new slider position.
:param position: Position to seek to.
"""
self.vlc_media_player.set_time(position)
def update_position(self):
"""
Update slider position and displayed time according to VLC player position.
"""
if self.vlc_media_player:
vlc_ms_pos = self.vlc_media_player.get_time()
rounded_vlc_ms_pos = int(round(vlc_ms_pos / 100.0) * 100.0)
time = QtCore.QTime(0, 0, 0)
new_pos_time = time.addMSecs(rounded_vlc_ms_pos)
self.position_timeedit.setTime(new_pos_time)
self.position_slider.setSliderPosition(vlc_ms_pos)
def disable_all(self):
"""
Disable all elements in the dialog
"""
self.toggle_disable_load_media(True)
self.titles_combo_box.setDisabled(True)
self.audio_tracks_combobox.setDisabled(True)
self.subtitle_tracks_combobox.setDisabled(True)
self.toggle_disable_player(True)
def toggle_disable_load_media(self, action):
"""
Enable/disable load media combobox and button.
:param action: If True elements are disabled, if False they are enabled.
"""
self.media_path_combobox.setDisabled(action)
self.load_disc_button.setDisabled(action)
def toggle_disable_player(self, action):
"""
Enable/disable player elements.
:param action: If True elements are disabled, if False they are enabled.
"""
self.play_button.setDisabled(action)
self.position_slider.setDisabled(action)
self.position_timeedit.setDisabled(action)
self.start_position_edit.setDisabled(action)
self.set_start_button.setDisabled(action)
self.jump_start_button.setDisabled(action)
self.end_timeedit.setDisabled(action)
self.set_end_button.setDisabled(action)
self.jump_end_button.setDisabled(action)
self.save_button.setDisabled(action)
def accept(self):
"""
Saves the current media and trackinfo as a clip to the mediamanager
"""
log.debug('in MediaClipSelectorForm.accept')
start_time = self.start_position_edit.time()
start_time_ms = start_time.hour() * 60 * 60 * 1000 + \
start_time.minute() * 60 * 1000 + \
start_time.second() * 1000 + \
start_time.msec()
end_time = self.end_timeedit.time()
end_time_ms = end_time.hour() * 60 * 60 * 1000 + \
end_time.minute() * 60 * 1000 + \
end_time.second() * 1000 + \
end_time.msec()
title = self.titles_combo_box.itemData(self.titles_combo_box.currentIndex())
path = self.media_path_combobox.currentText()
optical = ''
if self.audio_cd:
# Check for load problems
if start_time_ms is None or end_time_ms is None or title is None:
critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'CD not loaded correctly'),
translate('MediaPlugin.MediaClipSelectorForm',
'The CD was not loaded correctly, please re-load and try again.'))
return
optical = 'optical:{title:d}:-1:-1:{start:d}:{end:d}:'.format(title=title,
start=start_time_ms,
end=end_time_ms)
else:
audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex())
subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex())
# Check for load problems
if start_time_ms is None or end_time_ms is None or title is None or audio_track is None\
or subtitle_track is None:
critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'DVD not loaded correctly'),
translate('MediaPlugin.MediaClipSelectorForm',
'The DVD was not loaded correctly, please re-load and try again.'))
return
optical = 'optical:{title:d}:{audio:d}:{sub:d}:{start:d}:{end:d}:'.format(title=title,
audio=audio_track,
sub=subtitle_track,
start=start_time_ms,
end=end_time_ms)
# Ask for an alternative name for the mediaclip
while True:
new_optical_name, ok = QtWidgets.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm',
'Set name of mediaclip'),
translate('MediaPlugin.MediaClipSelectorForm',
'Name of mediaclip:'),
QtWidgets.QLineEdit.Normal)
# User pressed cancel, don't save the clip
if not ok:
return
# User pressed ok, but the input text is blank
if not new_optical_name:
critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm',
'Enter a valid name or cancel'),
translate('MediaPlugin.MediaClipSelectorForm',
'Enter a valid name or cancel'))
# The entered new name contains a colon, which we don't allow because colons is used to seperate clip info
elif new_optical_name.find(':') >= 0:
critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'Invalid character'),
translate('MediaPlugin.MediaClipSelectorForm',
'The name of the mediaclip must not contain the character ":"'))
# New name entered and we use it
else:
break
# Append the new name to the optical string and the path
optical += new_optical_name + ':' + path
self.media_item.add_optical_clip(Path(optical))
def media_state_wait(self, media_state):
"""
Wait for the video to change its state
Wait no longer than 15 seconds. (loading an optical disc takes some time)
:param media_state: VLC media state to wait for.
:return: True if state was reached within 15 seconds, False if not or error occurred.
"""
vlc = get_vlc()
start = datetime.now()
while media_state != self.vlc_media_player.get_state():
if self.vlc_media_player.get_state() == vlc.State.Error:
return False
if (datetime.now() - start).seconds > 15:
return False
return True
def find_optical_devices(self):
"""
Attempt to autodetect optical devices on the computer, and add them to the media-dropdown
:return:
"""
# Clear list first
self.media_path_combobox.clear()
if is_win():
# use win api to find optical drives
fso = Dispatch('scripting.filesystemobject')
for drive in fso.Drives:
log.debug('Drive {drive} has type {types:d}'.format(drive=drive.DriveLetter, types=drive.DriveType))
# if type is 4, it is a cd-rom drive
if drive.DriveType == 4:
self.media_path_combobox.addItem('{drive}:\\'.format(drive=drive.DriveLetter))
elif is_linux():
# Get disc devices from dbus and find the ones that are optical
bus = dbus.SystemBus()
try:
udev_manager_obj = bus.get_object('org.freedesktop.UDisks', '/org/freedesktop/UDisks')
udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.UDisks')
for dev in udev_manager.EnumerateDevices():
device_obj = bus.get_object("org.freedesktop.UDisks", dev)
device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
if device_props.Get('org.freedesktop.UDisks.Device', 'DeviceIsDrive'):
drive_props = device_props.Get('org.freedesktop.UDisks.Device', 'DriveMediaCompatibility')
if any('optical' in prop for prop in drive_props):
self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device',
'DeviceFile'))
return
except dbus.exceptions.DBusException:
log.debug('could not use udisks, will try udisks2')
udev_manager_obj = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2')
udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.DBus.ObjectManager')
for k, v in udev_manager.GetManagedObjects().items():
drive_info = v.get('org.freedesktop.UDisks2.Drive', {})
drive_props = drive_info.get('MediaCompatibility')
if drive_props and any('optical' in prop for prop in drive_props):
for device in udev_manager.GetManagedObjects().values():
if dbus.String('org.freedesktop.UDisks2.Block') in device:
if device[dbus.String('org.freedesktop.UDisks2.Block')][dbus.String('Drive')] == k:
block_file = ''
for c in device[dbus.String('org.freedesktop.UDisks2.Block')][
dbus.String('PreferredDevice')]:
if chr(c) != '\x00':
block_file += chr(c)
self.media_path_combobox.addItem(block_file)
elif is_macosx():
# Look for DVD folders in devices to find optical devices
volumes = os.listdir('/Volumes')
for volume in volumes:
if volume.startswith('.'):
continue
dirs = os.listdir('/Volumes/' + volume)
# Detect DVD
if 'VIDEO_TS' in dirs:
self.media_path_combobox.addItem('/Volumes/' + volume)
# Detect audio cd
files = [f for f in dirs if os.path.isfile(f)]
for file in files:
if file.endswith('aiff'):
self.media_path_combobox.addItem('/Volumes/' + volume)
break