diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index b44bd10b..63fa5449 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -221,7 +221,6 @@ AdvSceneSwitcher.condition.record="Aufnahme" AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft" AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert" AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt" -AdvSceneSwitcher.condition.record.entry="{{recordState}}" AdvSceneSwitcher.condition.process="Prozess" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert" AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index b0eff907..3324c4bc 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -298,7 +298,8 @@ AdvSceneSwitcher.condition.record="Recording" AdvSceneSwitcher.condition.record.state.start="Recording running" AdvSceneSwitcher.condition.record.state.pause="Recording paused" AdvSceneSwitcher.condition.record.state.stop="Recording stopped" -AdvSceneSwitcher.condition.record.entry="{{recordState}}" +AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than" +AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}" AdvSceneSwitcher.condition.process="Process" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}is running{{focused}}and is focused" AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}" @@ -1491,6 +1492,9 @@ AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of AdvSceneSwitcher.tempVar.process.name="Process name" +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." + AdvSceneSwitcher.selectScene="--select scene--" AdvSceneSwitcher.selectPreviousScene="Previous Scene" AdvSceneSwitcher.selectCurrentScene="Current Scene" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index d2a650b3..0ecab8b2 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -182,7 +182,6 @@ AdvSceneSwitcher.condition.record="Grabación" AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución" AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa" AdvSceneSwitcher.condition.record.state.stop="Grabación detenida" -AdvSceneSwitcher.condition.record.entry="{{recordState}}" AdvSceneSwitcher.condition.process="Proceso" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado" AdvSceneSwitcher.condition.idle="Inactivo" diff --git a/data/locale/tr-TR.ini b/data/locale/tr-TR.ini index eff85b84..31066cf1 100644 --- a/data/locale/tr-TR.ini +++ b/data/locale/tr-TR.ini @@ -159,7 +159,6 @@ AdvSceneSwitcher.condition.record="Kayıt" AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor" AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı" AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu" -AdvSceneSwitcher.condition.record.entry="{{recordState}}" AdvSceneSwitcher.condition.process="İşlem" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı" AdvSceneSwitcher.condition.idle="Boşta" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 696089e6..5c323ce8 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -267,7 +267,6 @@ AdvSceneSwitcher.condition.record="录制" AdvSceneSwitcher.condition.record.state.start="录制运行中" AdvSceneSwitcher.condition.record.state.pause="录制暂停" AdvSceneSwitcher.condition.record.state.stop="录制停止" -AdvSceneSwitcher.condition.record.entry="{{recordState}}" AdvSceneSwitcher.condition.process="进程" AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}是正在运行{{focused}}并且是获得焦点" AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}" diff --git a/src/macro-core/macro-condition-recording.cpp b/src/macro-core/macro-condition-recording.cpp index 6b86d823..3e47b3a6 100644 --- a/src/macro-core/macro-condition-recording.cpp +++ b/src/macro-core/macro-condition-recording.cpp @@ -1,6 +1,8 @@ #include "macro-condition-recording.hpp" #include "utility.hpp" +#include + namespace advss { const std::string MacroConditionRecord::id = "recording"; @@ -10,45 +12,81 @@ bool MacroConditionRecord::_registered = MacroConditionFactory::Register( {MacroConditionRecord::Create, MacroConditionRecordEdit::Create, "AdvSceneSwitcher.condition.record"}); -const static std::map recordStates = { - {RecordState::STOP, "AdvSceneSwitcher.condition.record.state.stop"}, - {RecordState::PAUSE, "AdvSceneSwitcher.condition.record.state.pause"}, - {RecordState::START, "AdvSceneSwitcher.condition.record.state.start"}, +const static std::map + recordStates = { + {MacroConditionRecord::Condition::STOP, + "AdvSceneSwitcher.condition.record.state.stop"}, + {MacroConditionRecord::Condition::PAUSE, + "AdvSceneSwitcher.condition.record.state.pause"}, + {MacroConditionRecord::Condition::START, + "AdvSceneSwitcher.condition.record.state.start"}, + {MacroConditionRecord::Condition::DURATION, + "AdvSceneSwitcher.condition.record.state.duration"}, }; +static bool SetupRecordingTimer(); +static bool recordingTimerIsSetup = SetupRecordingTimer(); +static int currentRecordingDurationInSeconds = 0; + bool MacroConditionRecord::CheckCondition() { - bool stateMatch = false; - switch (_recordState) { - case RecordState::STOP: - stateMatch = !obs_frontend_recording_active(); - break; - case RecordState::PAUSE: - stateMatch = obs_frontend_recording_paused(); - break; - case RecordState::START: - stateMatch = obs_frontend_recording_active(); - break; + switch (_condition) { + case Condition::STOP: + return !obs_frontend_recording_active(); + case Condition::PAUSE: + return obs_frontend_recording_paused(); + case Condition::START: + return obs_frontend_recording_active(); + case Condition::DURATION: + SetTempVarValue( + "durationSeconds", + std::to_string(currentRecordingDurationInSeconds)); + return currentRecordingDurationInSeconds > _duration.Seconds(); default: break; } - return stateMatch; + return false; } bool MacroConditionRecord::Save(obs_data_t *obj) const { MacroCondition::Save(obj); - obs_data_set_int(obj, "state", static_cast(_recordState)); + obs_data_set_int(obj, "state", static_cast(_condition)); + _duration.Save(obj); return true; } bool MacroConditionRecord::Load(obs_data_t *obj) { MacroCondition::Load(obj); - _recordState = static_cast(obs_data_get_int(obj, "state")); + _condition = static_cast(obs_data_get_int(obj, "state")); + _duration.Load(obj); return true; } +void MacroConditionRecord::SetCondition(Condition condition) +{ + _condition = condition; + SetupTempVars(); +} + +void MacroConditionRecord::SetupTempVars() +{ + MacroCondition::SetupTempVars(); + switch (_condition) { + case Condition::DURATION: + AddTempvar( + "durationSeconds", + obs_module_text( + "AdvSceneSwitcher.tempVar.recording.durationSeconds"), + obs_module_text( + "AdvSceneSwitcher.tempVar.recording.durationSeconds.description")); + break; + default: + break; + } +} + static inline void populateStateSelection(QComboBox *list) { for (auto entry : recordStates) { @@ -58,38 +96,39 @@ static inline void populateStateSelection(QComboBox *list) MacroConditionRecordEdit::MacroConditionRecordEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), + _condition(new QComboBox(this)), + _duration(new DurationSelection(this)) { - _recordState = new QComboBox(); + populateStateSelection(_condition); - QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this, - SLOT(StateChanged(int))); - - populateStateSelection(_recordState); - - QHBoxLayout *mainLayout = new QHBoxLayout; - - std::unordered_map widgetPlaceholders = { - {"{{recordState}}", _recordState}, - }; + QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this, + SLOT(ConditionChanged(int))); + QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)), + this, SLOT(DurationChanged(const Duration &))); + auto layout = new QHBoxLayout; PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"), - mainLayout, widgetPlaceholders); - setLayout(mainLayout); + layout, + {{"{{condition}}", _condition}, + {"{{duration}}", _duration}}); + setLayout(layout); _entryData = entryData; UpdateEntryData(); _loading = false; } -void MacroConditionRecordEdit::StateChanged(int value) +void MacroConditionRecordEdit::ConditionChanged(int value) { if (_loading || !_entryData) { return; } auto lock = LockContext(); - _entryData->_recordState = static_cast(value); + _entryData->SetCondition( + static_cast(value)); + SetWidgetVisibility(); } void MacroConditionRecordEdit::UpdateEntryData() @@ -98,8 +137,65 @@ void MacroConditionRecordEdit::UpdateEntryData() return; } - _recordState->setCurrentIndex( - static_cast(_entryData->_recordState)); + _condition->setCurrentIndex( + static_cast(_entryData->GetCondition())); + _duration->SetDuration(_entryData->_duration); + SetWidgetVisibility(); +} + +void MacroConditionRecordEdit::DurationChanged(const Duration &duration) +{ + if (_loading || !_entryData) { + return; + } + + auto lock = LockContext(); + _entryData->_duration = duration; +} + +void MacroConditionRecordEdit::SetWidgetVisibility() +{ + _duration->setVisible(_entryData->GetCondition() == + MacroConditionRecord::Condition::DURATION); +} + +bool SetupRecordingTimer() +{ + static std::atomic_bool recordingStopped = {true}; + static std::atomic_bool recordingPaused = {false}; + static auto handleRecordingEvents = [](enum obs_frontend_event event, + void *) { + switch (event) { + case OBS_FRONTEND_EVENT_RECORDING_STOPPED: + recordingStopped = true; + break; + case OBS_FRONTEND_EVENT_RECORDING_STARTED: + recordingStopped = false; + break; + case OBS_FRONTEND_EVENT_RECORDING_PAUSED: + recordingPaused = true; + break; + case OBS_FRONTEND_EVENT_RECORDING_UNPAUSED: + recordingPaused = false; + break; + }; + }; + obs_frontend_add_event_callback(handleRecordingEvents, nullptr); + std::thread thread([]() { + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (recordingStopped) { + currentRecordingDurationInSeconds = 0; + continue; + } + if (recordingPaused) { + continue; + } + ++currentRecordingDurationInSeconds; + } + }); + thread.detach(); + return true; } } // namespace advss diff --git a/src/macro-core/macro-condition-recording.hpp b/src/macro-core/macro-condition-recording.hpp index 2833e0f0..5ccc36f6 100644 --- a/src/macro-core/macro-condition-recording.hpp +++ b/src/macro-core/macro-condition-recording.hpp @@ -6,12 +6,6 @@ namespace advss { -enum class RecordState { - STOP, - PAUSE, - START, -}; - class MacroConditionRecord : public MacroCondition { public: MacroConditionRecord(Macro *m) : MacroCondition(m) {} @@ -24,9 +18,21 @@ public: return std::make_shared(m); } - RecordState _recordState = RecordState::STOP; + enum class Condition { + STOP, + PAUSE, + START, + DURATION, + }; + + void SetCondition(Condition); + Condition GetCondition() const { return _condition; } + Duration _duration; private: + void SetupTempVars(); + + Condition _condition = Condition::STOP; static bool _registered; static const std::string id; }; @@ -48,13 +54,15 @@ public: } private slots: - void StateChanged(int value); - -protected: - QComboBox *_recordState; - std::shared_ptr _entryData; + void ConditionChanged(int value); + void DurationChanged(const Duration &); private: + void SetWidgetVisibility(); + + QComboBox *_condition; + DurationSelection *_duration; + std::shared_ptr _entryData; bool _loading = true; };