Skip to content

Commit

Permalink
Added command-cue(s), able to launch shell commands. ( #3 )
Browse files Browse the repository at this point in the history
 Add: command-cue(s);
 Update: minor UI update.
  • Loading branch information
FrancescoCeruti committed Apr 28, 2016
1 parent 1479e31 commit 94b42a7
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 24 deletions.
22 changes: 11 additions & 11 deletions lisp/cues/cue.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ class Cue(HasProperties):
:ivar next_action: What do after post_wait (see note).
:cvar CueActions: actions supported by the cue (default: CueAction.Start)
A cue should declare CueAction.Default as supported only if CueAction.Stop
is also supported.
A cue should declare CueAction.Default as supported only if CueAction.Start
and CueAction.Stop are both supported.
.. Note::
If 'next_action' is set to CueNextAction.AutoFollow value, then the
Expand Down Expand Up @@ -108,16 +108,16 @@ def __init__(self, id=None):
self._type_ = self.__class__.__name__

self.pre_wait_enter = Signal()
self.pre_wait_exit = Signal()
self.pre_wait_exit = Signal() # True if not interrupted
self.post_wait_enter = Signal()
self.post_wait_exit = Signal()

self.started = Signal()
self.stopped = Signal()
self.paused = Signal()
self.error = Signal()
self.next = Signal()
self.end = Signal()
self.post_wait_exit = Signal() # True if not interrupted

self.started = Signal() # self
self.stopped = Signal() # self
self.paused = Signal() # self
self.error = Signal() # self, error, details
self.next = Signal() # self
self.end = Signal() # self

self.stopped.connect(self._waiting.set)
self.changed('next_action').connect(self.__next_action_changed)
Expand Down
1 change: 0 additions & 1 deletion lisp/modules/action_cues/collection_cue.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ class CollectionCueSettings(SettingsPage):

def __init__(self, **kwargs):
super().__init__(**kwargs)

self.setLayout(QVBoxLayout(self))

self.cuesWidget = QListWidget(self)
Expand Down
133 changes: 133 additions & 0 deletions lisp/modules/action_cues/command_cue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
#
# This file is part of Linux Show Player
#
# Copyright 2012-2016 Francesco Ceruti <[email protected]>
#
# Linux Show Player is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Linux Show Player 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 Linux Show Player. If not, see <http://www.gnu.org/licenses/>.

import subprocess

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QGroupBox, QLineEdit, QCheckBox

from lisp.core.decorators import async
from lisp.core.has_properties import Property
from lisp.cues.cue import Cue, CueState, CueAction
from lisp.ui.settings.cue_settings import CueSettingsRegistry
from lisp.ui.settings.settings_page import SettingsPage


class CommandCue(Cue):
"""Cue able to execute system commands.
Implemented using :class:`subprocess.Popen` with *shell=True*
"""

Name = 'Command Cue'
CueActions = (CueAction.Start, CueAction.Stop, CueAction.Default)

command = Property(default='')
no_output = Property(default=True)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = self.Name

self.__state = CueState.Stop
self.__process = None

@Cue.state.getter
def state(self):
return self.__state

@async
def __start__(self):
if not self.command.strip():
return

if self.__state == CueState.Stop or self.__state == CueState.Error:
self.__state = CueState.Running
self.started.emit(self)

# If no_output is True "suppress" all the outputs
std = subprocess.DEVNULL if self.no_output else None
# Launch the command
self.__process = subprocess.Popen(self.command, shell=True,
stdout=std, stderr=std)
self.__process.wait()

if self.__process.returncode == 0:
self.__state = CueState.Stop
self.end.emit(self)
else:
self.__state = CueState.Error
self.error.emit(self, 'Process exited with an error status',
'Exit code: {}'.format(
self.__process.returncode))

def __stop__(self):
if self.__state == CueState.Running:
self.__process.terminate()
self.__state = CueState.Stop
self.stopped.emit(self)


class CommandCueSettings(SettingsPage):
Name = 'Command Cue'

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setLayout(QVBoxLayout())
self.layout().setAlignment(Qt.AlignTop)

self.group = QGroupBox(self)
self.group.setTitle('Command')
self.group.setLayout(QVBoxLayout(self.group))
self.layout().addWidget(self.group)

self.commandLineEdit = QLineEdit(self.group)
self.commandLineEdit.setPlaceholderText(
'Command to execute as in a shell')
self.group.layout().addWidget(self.commandLineEdit)

self.noOutputCheckBox = QCheckBox(self)
self.noOutputCheckBox.setText('Discard command output')
self.layout().addWidget(self.noOutputCheckBox)

def enable_check(self, enabled):
self.group.setCheckable(enabled)
self.group.setChecked(False)

self.noOutputCheckBox.setTristate(enabled)
if enabled:
self.noOutputCheckBox.setCheckState(Qt.PartiallyChecked)

def load_settings(self, settings):
if 'command' in settings:
self.commandLineEdit.setText(settings['command'])
if 'no_output' in settings:
self.noOutputCheckBox.setChecked(settings['no_output'])

def get_settings(self):
settings = {}

if self.commandLineEdit.text().strip():
settings['command'] = self.commandLineEdit.text()
if self.noOutputCheckBox.checkState() != Qt.PartiallyChecked:
settings['no_output'] = self.noOutputCheckBox.isChecked()

return settings

CueSettingsRegistry().add_item(CommandCueSettings, CommandCue)
5 changes: 2 additions & 3 deletions lisp/modules/action_cues/seek_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ class SeekSettings(SettingsPage):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.setLayout(QVBoxLayout())
self.layout().setAlignment(QtCore.Qt.AlignTop)

self.cue_id = -1
self.setLayout(QVBoxLayout(self))

self.cueDialog = CueListDialog(
cues=Application().cue_model.filter(MediaCue), parent=self)
Expand Down Expand Up @@ -87,8 +88,6 @@ def __init__(self, **kwargs):
self.seekLabel.setAlignment(QtCore.Qt.AlignCenter)
self.seekGroup.layout().addWidget(self.seekLabel)

self.layout().addSpacing(200)

self.retranslateUi()

def retranslateUi(self):
Expand Down
10 changes: 4 additions & 6 deletions lisp/modules/action_cues/stop_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#
# You should have received a copy of the GNU General Public License
# along with Linux Show Player. If not, see <http://www.gnu.org/licenses/>.

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QGroupBox, QHBoxLayout, QCheckBox

from lisp.application import Application
Expand Down Expand Up @@ -51,20 +51,18 @@ class StopAllSettings(SettingsPage):

def __init__(self, **kwargs):
super().__init__(**kwargs)

self.setLayout(QVBoxLayout(self))
self.setLayout(QVBoxLayout())
self.layout().setAlignment(Qt.AlignTop)

self.group = QGroupBox(self)
self.group.setTitle('Mode')
self.group.setLayout(QHBoxLayout(self.group))
self.layout().addWidget(self.group)

self.pauseMode = QCheckBox(self.group)
self.pauseMode.setText('Pause mode')
self.group.layout().addWidget(self.pauseMode)

self.layout().addWidget(self.group)
self.layout().addSpacing(self.height() - 100)

def enable_check(self, enabled):
self.group.setCheckable(enabled)
self.group.setChecked(False)
Expand Down
6 changes: 3 additions & 3 deletions lisp/modules/action_cues/volume_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from time import sleep

from PyQt5 import QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QVBoxLayout, QLabel, QHBoxLayout, QGroupBox, \
QPushButton, QDoubleSpinBox, QGridLayout, QComboBox, QStyledItemDelegate
Expand Down Expand Up @@ -139,9 +140,10 @@ class VolumeSettings(SettingsPage):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.setLayout(QVBoxLayout())
self.layout().setAlignment(Qt.AlignTop)

self.cue_id = -1
self.setLayout(QVBoxLayout(self))

cues = Application().cue_model.filter(MediaCue)
self.cueDialog = CueListDialog(cues=cues, parent=self)
Expand Down Expand Up @@ -193,8 +195,6 @@ def __init__(self, **kwargs):
self.fadeCurveLabel.setAlignment(QtCore.Qt.AlignCenter)
self.fadeGroup.layout().addWidget(self.fadeCurveLabel, 1, 1)

self.layout().addSpacing(50)

self.retranslateUi()

def retranslateUi(self):
Expand Down

0 comments on commit 94b42a7

Please sign in to comment.