mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-13 20:58:34 -05:00
Add Run action/condition temp vars
This commit is contained in:
committed by
WarmUpTill
parent
c8545dea4d
commit
74dc0c871b
@@ -691,7 +691,8 @@ AdvSceneSwitcher.action.streaming.type.username="Set username"
|
||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Run"
|
||||
AdvSceneSwitcher.action.run.entry.wait="{{wait}}Wait for process exit or at most {{timeout}}"
|
||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Wait for process exit or at most {{timeout}}{{waitHelp}}"
|
||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Note that macro properties won't work if you leave this unticked, as the process spawns detached from the rest of logic and there's no control over it."
|
||||
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||
@@ -1619,6 +1620,15 @@ AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of
|
||||
|
||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
||||
|
||||
AdvSceneSwitcher.tempVar.run.process.id="Process ID"
|
||||
AdvSceneSwitcher.tempVar.run.process.id.description="PID of the process assigned by the system."
|
||||
AdvSceneSwitcher.tempVar.run.process.exitCode="Process exit code"
|
||||
AdvSceneSwitcher.tempVar.run.process.exitCode.description="Numeric code with which the process exited. Usually 0 is positive and other values are error codes."
|
||||
AdvSceneSwitcher.tempVar.run.process.stream.output="Process standard output stream"
|
||||
AdvSceneSwitcher.tempVar.run.process.stream.output.description="Full standard output stream, usually numbered 1 and what you see in CLI after running the command."
|
||||
AdvSceneSwitcher.tempVar.run.process.stream.error="Process standard error stream"
|
||||
AdvSceneSwitcher.tempVar.run.process.stream.error.description="Full standard error stream, usually numbered 2."
|
||||
|
||||
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
||||
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "macro-action-run.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDesktopServices>
|
||||
@@ -16,6 +17,8 @@ bool MacroActionRun::PerformAction()
|
||||
{
|
||||
if (_wait) {
|
||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||
SetTempVarValues();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,6 +31,7 @@ bool MacroActionRun::PerformAction()
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(_procConfig.Path())));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,6 +40,45 @@ void MacroActionRun::LogAction() const
|
||||
ablog(LOG_INFO, "run \"%s\"", _procConfig.UnresolvedPath().c_str());
|
||||
}
|
||||
|
||||
void MacroActionRun::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
|
||||
AddTempvar(
|
||||
"process.id",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.run.process.id"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.id.description"));
|
||||
AddTempvar(
|
||||
"process.exitCode",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.exitCode"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.exitCode.description"));
|
||||
AddTempvar(
|
||||
"process.stream.output",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.output"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.output.description"));
|
||||
AddTempvar(
|
||||
"process.stream.error",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.error"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.error.description"));
|
||||
}
|
||||
|
||||
void MacroActionRun::SetTempVarValues()
|
||||
{
|
||||
SetTempVarValue("process.id", _procConfig.GetProcessId());
|
||||
SetTempVarValue("process.exitCode", _procConfig.GetProcessExitCode());
|
||||
SetTempVarValue("process.stream.output",
|
||||
_procConfig.GetProcessOutputStream());
|
||||
SetTempVarValue("process.stream.error",
|
||||
_procConfig.GetProcessErrorStream());
|
||||
}
|
||||
|
||||
bool MacroActionRun::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
@@ -86,8 +129,18 @@ MacroActionRunEdit::MacroActionRunEdit(
|
||||
_procConfig(new ProcessConfigEdit(this)),
|
||||
_waitLayout(new QHBoxLayout()),
|
||||
_wait(new QCheckBox()),
|
||||
_timeout(new DurationSelection(this, true, 0.1))
|
||||
_timeout(new DurationSelection(this, true, 0.1)),
|
||||
_waitHelp(new QLabel())
|
||||
{
|
||||
QString helpIconPath = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
QIcon helpIcon(helpIconPath);
|
||||
_waitHelp->setPixmap(helpIcon.pixmap(QSize(16, 16)));
|
||||
_waitHelp->hide();
|
||||
_waitHelp->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.run.wait.help.tooltip"));
|
||||
|
||||
QWidget::connect(_procConfig,
|
||||
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
||||
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
||||
@@ -98,9 +151,11 @@ MacroActionRunEdit::MacroActionRunEdit(
|
||||
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(TimeoutChanged(const Duration &)));
|
||||
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.wait.entry"),
|
||||
_waitLayout,
|
||||
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
|
||||
{{"{{wait}}", _wait},
|
||||
{"{{timeout}}", _timeout},
|
||||
{"{{waitHelp}}", _waitHelp}});
|
||||
SetLayoutVisible(_waitLayout, false);
|
||||
|
||||
auto layout = new QVBoxLayout;
|
||||
|
||||
@@ -25,6 +25,9 @@ public:
|
||||
Duration _timeout = 1;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
void SetTempVarValues();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -57,6 +60,7 @@ private:
|
||||
QHBoxLayout *_waitLayout;
|
||||
QCheckBox *_wait;
|
||||
DurationSelection *_timeout;
|
||||
QLabel *_waitHelp;
|
||||
|
||||
std::shared_ptr<MacroActionRun> _entryData;
|
||||
bool _loading = true;
|
||||
|
||||
@@ -48,6 +48,7 @@ bool MacroConditionRun::CheckCondition()
|
||||
if (_thread.joinable()) {
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
_threadDone = false;
|
||||
_thread = std::thread(&MacroConditionRun::RunProcess, this);
|
||||
|
||||
@@ -64,7 +65,48 @@ void MacroConditionRun::RunProcess()
|
||||
_error = ProcessConfig::ProcStartError::NONE;
|
||||
_procExitCode = std::get<int>(result);
|
||||
}
|
||||
|
||||
_threadDone = true;
|
||||
SetTempVarValues();
|
||||
}
|
||||
|
||||
void MacroConditionRun::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
|
||||
AddTempvar(
|
||||
"process.id",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.run.process.id"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.id.description"));
|
||||
AddTempvar(
|
||||
"process.exitCode",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.exitCode"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.exitCode.description"));
|
||||
AddTempvar(
|
||||
"process.stream.output",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.output"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.output.description"));
|
||||
AddTempvar(
|
||||
"process.stream.error",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.error"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.run.process.stream.error.description"));
|
||||
}
|
||||
|
||||
void MacroConditionRun::SetTempVarValues()
|
||||
{
|
||||
SetTempVarValue("process.id", _procConfig.GetProcessId());
|
||||
SetTempVarValue("process.exitCode", _procConfig.GetProcessExitCode());
|
||||
SetTempVarValue("process.stream.output",
|
||||
_procConfig.GetProcessOutputStream());
|
||||
SetTempVarValue("process.stream.error",
|
||||
_procConfig.GetProcessErrorStream());
|
||||
}
|
||||
|
||||
bool MacroConditionRun::Save(obs_data_t *obj) const
|
||||
|
||||
@@ -30,6 +30,10 @@ public:
|
||||
|
||||
private:
|
||||
void RunProcess();
|
||||
|
||||
void SetupTempVars();
|
||||
void SetTempVarValues();
|
||||
|
||||
std::thread _thread;
|
||||
std::atomic_bool _threadDone{true};
|
||||
ProcessConfig::ProcStartError _error =
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "name-dialog.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QProcess>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -16,6 +15,7 @@ bool ProcessConfig::Save(obs_data_t *obj) const
|
||||
_args.Save(data, "args", "arg");
|
||||
obs_data_set_obj(obj, "processConfig", data);
|
||||
obs_data_release(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ bool ProcessConfig::Load(obs_data_t *obj)
|
||||
_workingDirectory =
|
||||
obs_data_get_string(obj, "workingDirectory");
|
||||
_args.Load(obj, "args", "arg");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ bool ProcessConfig::Load(obs_data_t *obj)
|
||||
_workingDirectory.Load(data, "workingDirectory");
|
||||
_args.Load(data, "args", "arg");
|
||||
obs_data_release(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,6 +46,7 @@ QStringList ProcessConfig::Args() const
|
||||
for (auto &arg : _args) {
|
||||
result << QString::fromStdString(arg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -61,11 +64,14 @@ void ProcessConfig::ResolveVariables()
|
||||
}
|
||||
|
||||
std::variant<int, ProcessConfig::ProcStartError>
|
||||
ProcessConfig::StartProcessAndWait(int timeout) const
|
||||
ProcessConfig::StartProcessAndWait(int timeout)
|
||||
{
|
||||
ResetFinishedProcessData();
|
||||
|
||||
QProcess process;
|
||||
process.setWorkingDirectory(QString::fromStdString(WorkingDir()));
|
||||
process.start(QString::fromStdString(Path()), Args());
|
||||
SetProcessId(QString::number(process.processId()).toStdString());
|
||||
vblog(LOG_INFO, "run \"%s\" with a timeout of %d ms", Path().c_str(),
|
||||
timeout);
|
||||
|
||||
@@ -75,21 +81,47 @@ ProcessConfig::StartProcessAndWait(int timeout) const
|
||||
Path().c_str());
|
||||
return ProcStartError::FAILED_TO_START;
|
||||
}
|
||||
|
||||
SetFinishedProcessData(process);
|
||||
vblog(LOG_INFO,
|
||||
"timeout while running \"%s\"\nAttempting to kill process!",
|
||||
Path().c_str());
|
||||
process.kill();
|
||||
process.waitForFinished();
|
||||
|
||||
return ProcStartError::TIMEOUT;
|
||||
}
|
||||
|
||||
SetFinishedProcessData(process);
|
||||
|
||||
if (process.exitStatus() == QProcess::NormalExit) {
|
||||
return process.exitCode();
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "process \"%s\" crashed!", Path().c_str());
|
||||
return ProcStartError::CRASH;
|
||||
}
|
||||
|
||||
void ProcessConfig::SetFinishedProcessData(QProcess &process)
|
||||
{
|
||||
static const QRegularExpression regex("(\\r\\n|\\r|\\n)$");
|
||||
_processExitCode = QString::number(process.exitCode()).toStdString();
|
||||
// Qt reads extra newline, at least on Windows, hence the workaround
|
||||
_processOutputStream = QString(process.readAllStandardOutput())
|
||||
.remove(regex)
|
||||
.toStdString();
|
||||
_processErrorStream = QString(process.readAllStandardError())
|
||||
.remove(regex)
|
||||
.toStdString();
|
||||
}
|
||||
|
||||
void ProcessConfig::ResetFinishedProcessData()
|
||||
{
|
||||
_processExitCode = "";
|
||||
_processOutputStream = "";
|
||||
_processErrorStream = "";
|
||||
}
|
||||
|
||||
ProcessConfigEdit::ProcessConfigEdit(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_filePath(new FileSelection()),
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#include <obs-data.h>
|
||||
#include <obs-module-helper.hpp>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QListWidget>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QStringList>
|
||||
#include <QVBoxLayout>
|
||||
#include <variant>
|
||||
@@ -23,6 +24,20 @@ public:
|
||||
std::string WorkingDir() const { return _workingDirectory; }
|
||||
QStringList Args() const; // Resolves variables
|
||||
|
||||
void SetProcessId(std::string processId) { _processId = processId; }
|
||||
std::string GetProcessId() const { return _processId; }
|
||||
void SetFinishedProcessData(QProcess &process);
|
||||
void ResetFinishedProcessData();
|
||||
std::string GetProcessExitCode() const { return _processExitCode; }
|
||||
std::string GetProcessOutputStream() const
|
||||
{
|
||||
return _processOutputStream;
|
||||
}
|
||||
std::string GetProcessErrorStream() const
|
||||
{
|
||||
return _processErrorStream;
|
||||
}
|
||||
|
||||
enum class ProcStartError {
|
||||
NONE,
|
||||
FAILED_TO_START,
|
||||
@@ -30,8 +45,7 @@ public:
|
||||
CRASH,
|
||||
};
|
||||
|
||||
std::variant<int, ProcStartError>
|
||||
StartProcessAndWait(int timeoutInMs) const;
|
||||
std::variant<int, ProcStartError> StartProcessAndWait(int timeoutInMs);
|
||||
bool StartProcessDetached() const;
|
||||
|
||||
void ResolveVariables();
|
||||
@@ -41,6 +55,11 @@ private:
|
||||
StringVariable _workingDirectory = "";
|
||||
StringList _args;
|
||||
|
||||
std::string _processId;
|
||||
std::string _processExitCode;
|
||||
std::string _processOutputStream;
|
||||
std::string _processErrorStream;
|
||||
|
||||
friend class ProcessConfigEdit;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user