diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui
index c3aebde7..84328e3b 100644
--- a/forms/advanced-scene-switcher.ui
+++ b/forms/advanced-scene-switcher.ui
@@ -2917,13 +2917,23 @@
Time
-
+
-
+
-
+
+
+
+ 100
+ 0
+
+
+
+
-
- At
+ at
@@ -2989,12 +2999,12 @@
true
- true
+ false
-
-
+
-
@@ -3027,6 +3037,91 @@
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 5
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 5
+ 20
+
+
+
+
+ -
+
+
+
+ 22
+ 22
+
+
+
+
+
+
+
+ ../../../forms/images/up.svg../../../forms/images/up.svg
+
+
+ true
+
+
+ upArrowIconSmall
+
+
+
+ -
+
+
+
+ 22
+ 22
+
+
+
+
+
+
+
+ ../../../forms/images/down.svg../../../forms/images/down.svg
+
+
+ true
+
+
+ downArrowIconSmall
+
+
+
-
diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp
index 0f5daf80..205814c0 100644
--- a/src/advanced-scene-switcher.cpp
+++ b/src/advanced-scene-switcher.cpp
@@ -367,6 +367,16 @@ void handleSceneChange(SwitcherData *s)
s->autoStartedRecently = false;
}
+void setLiveTime(SwitcherData *s)
+{
+ s->liveTime = QDateTime::currentDateTime();
+}
+
+void resetLiveTime(SwitcherData *s)
+{
+ s->liveTime = QDateTime();
+}
+
static void OBSEvent(enum obs_frontend_event event, void *switcher)
{
switch (event) {
@@ -376,6 +386,14 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
handleSceneChange((SwitcherData *)switcher);
break;
+ case OBS_FRONTEND_EVENT_RECORDING_STARTED:
+ case OBS_FRONTEND_EVENT_STREAMING_STARTED:
+ setLiveTime((SwitcherData *)switcher);
+ break;
+ case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
+ case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
+ resetLiveTime((SwitcherData *)switcher);
+ break;
default:
break;
}
diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp
index dc333f7b..d76facf8 100644
--- a/src/headers/advanced-scene-switcher.hpp
+++ b/src/headers/advanced-scene-switcher.hpp
@@ -42,7 +42,7 @@ public:
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString &window);
int randomFindByData(const QString &scene);
- int timeFindByData(const QString &timeStr);
+ int timeFindByData(const timeTrigger &trigger, const QTime &time);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
@@ -172,6 +172,8 @@ public slots:
void on_timeSwitches_currentRowChanged(int idx);
void on_timeAdd_clicked();
void on_timeRemove_clicked();
+ void on_timeUp_clicked();
+ void on_timeDown_clicked();
void on_priorityUp_clicked();
void on_priorityDown_clicked();
diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp
index 5bf53612..16a9efc8 100644
--- a/src/headers/switcher-data-structs.hpp
+++ b/src/headers/switcher-data-structs.hpp
@@ -235,16 +235,18 @@ struct MediaSwitch {
struct TimeSwitch {
OBSWeakSource scene;
OBSWeakSource transition;
+ timeTrigger trigger;
QTime time;
bool matched;
bool usePreviousScene;
std::string timeSwitchStr;
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
- QTime time_, bool usePreviousScene_,
- std::string timeSwitchStr_)
+ timeTrigger trigger_, QTime time_,
+ bool usePreviousScene_, std::string timeSwitchStr_)
: scene(scene_),
transition(transition_),
+ trigger(trigger_),
time(time_),
usePreviousScene(usePreviousScene_),
timeSwitchStr(timeSwitchStr_)
@@ -324,6 +326,7 @@ struct SwitcherData {
std::vector mediaSwitches;
std::vector timeSwitches;
+ QDateTime liveTime;
std::vector functionNamesByPriority = std::vector{
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
diff --git a/src/headers/utility.hpp b/src/headers/utility.hpp
index e78758dc..0ca9d980 100644
--- a/src/headers/utility.hpp
+++ b/src/headers/utility.hpp
@@ -2,7 +2,6 @@
#include
#include
#include
-#include "switcher-data-structs.hpp"
static inline bool WeakSourceValid(obs_weak_source_t *ws)
{
@@ -170,12 +169,58 @@ MakeMediaSwitchName(const QString &source, const QString &scene,
return switchName;
}
+typedef enum {
+ ANY_DAY = 0,
+ MONDAY = 1,
+ TUSEDAY = 2,
+ WEDNESDAY = 3,
+ THURSDAY = 4,
+ FRIDAY = 5,
+ SATURDAY = 6,
+ SUNDAY = 7,
+ LIVE = 8
+} timeTrigger;
+
static inline QString MakeTimeSwitchName(const QString &scene,
- const QString &transition, QTime &time)
+ const QString &transition,
+ const timeTrigger &trigger,
+ const QTime &time)
{
- QString switchName = QStringLiteral("At ") + time.toString() +
- QStringLiteral(" switch to ") + scene +
- QStringLiteral(" using ") + transition;
+ QString switchName;
+
+ switch (trigger) {
+ case ANY_DAY:
+ switchName = QStringLiteral("On any weekday");
+ break;
+ case MONDAY:
+ switchName = QStringLiteral("Mondays");
+ break;
+ case TUSEDAY:
+ switchName = QStringLiteral("Tusedays");
+ break;
+ case WEDNESDAY:
+ switchName = QStringLiteral("Wednesdays");
+ break;
+ case THURSDAY:
+ switchName = QStringLiteral("Thursdays");
+ break;
+ case FRIDAY:
+ switchName = QStringLiteral("Fridays");
+ break;
+ case SATURDAY:
+ switchName = QStringLiteral("Saturdays");
+ break;
+ case SUNDAY:
+ switchName = QStringLiteral("Sundays");
+ break;
+ case LIVE:
+ switchName = QStringLiteral(
+ "Relative to starting streaming / recording");
+ break;
+ }
+ switchName += QStringLiteral(" at ") + time.toString() +
+ QStringLiteral(" switch to ") + scene +
+ QStringLiteral(" using ") + transition;
return switchName;
}
diff --git a/src/time-switch.cpp b/src/time-switch.cpp
index dba2fe27..f23198c3 100644
--- a/src/time-switch.cpp
+++ b/src/time-switch.cpp
@@ -1,5 +1,16 @@
#include "headers/advanced-scene-switcher.hpp"
+static std::vector> triggerTable = {
+ {"On any day", timeTrigger::ANY_DAY},
+ {"Mondays", timeTrigger::MONDAY},
+ {"Tuesdays", timeTrigger::TUSEDAY},
+ {"Wednesdays", timeTrigger::WEDNESDAY},
+ {"Thursdays", timeTrigger::THURSDAY},
+ {"Fridays", timeTrigger::FRIDAY},
+ {"Saturdays", timeTrigger::SATURDAY},
+ {"Sundays", timeTrigger::SUNDAY},
+ {"Atfer streaming/recording start", timeTrigger::LIVE}};
+
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
{
if (loading)
@@ -18,6 +29,7 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
QString transitionName =
GetWeakSourceName(s.transition).c_str();
ui->timeScenes->setCurrentText(sceneName);
+ ui->timeTrigger->setCurrentIndex(s.trigger);
ui->timeEdit->setTime(s.time);
ui->timeTransitions->setCurrentText(transitionName);
break;
@@ -25,9 +37,10 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
}
}
-int SceneSwitcher::timeFindByData(const QString &timeStr)
+int SceneSwitcher::timeFindByData(const timeTrigger &trigger, const QTime &time)
{
- QRegExp rx("At " + timeStr + " switch to .*");
+ QRegExp rx(MakeTimeSwitchName(QStringLiteral(".*"),
+ QStringLiteral(".*"), trigger, time));
int count = ui->timeSwitches->count();
for (int i = 0; i < count; i++) {
@@ -53,15 +66,25 @@ void SceneSwitcher::on_timeAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
- QString text = MakeTimeSwitchName(sceneName, transitionName, time);
+ std::string triggerStr = ui->timeTrigger->currentText().toStdString();
+ auto it = std::find_if(
+ triggerTable.begin(), triggerTable.end(),
+ [&triggerStr](
+ const std::pair &element) {
+ return element.first == triggerStr;
+ });
+ timeTrigger trigger = it->second;
+
+ QString text =
+ MakeTimeSwitchName(sceneName, transitionName, trigger, time);
QVariant v = QVariant::fromValue(text);
- int idx = timeFindByData(time.toString());
+ int idx = timeFindByData(trigger, time);
if (idx == -1) {
std::lock_guard lock(switcher->m);
switcher->timeSwitches.emplace_back(
- source, transition, time,
+ source, transition, trigger, time,
(sceneName == QString(PREVIOUS_SCENE_NAME)),
text.toUtf8().constData());
@@ -76,7 +99,7 @@ void SceneSwitcher::on_timeAdd_clicked()
{
std::lock_guard lock(switcher->m);
for (auto &s : switcher->timeSwitches) {
- if (s.time == time) {
+ if (s.trigger == trigger && s.time == time) {
s.scene = source;
s.transition = transition;
s.usePreviousScene =
@@ -88,8 +111,6 @@ void SceneSwitcher::on_timeAdd_clicked()
}
}
}
-
- ui->timeSwitches->sortItems();
}
}
@@ -119,24 +140,83 @@ void SceneSwitcher::on_timeRemove_clicked()
delete item;
}
+void SceneSwitcher::on_timeUp_clicked()
+{
+ int index = ui->timeSwitches->currentRow();
+ if (index != -1 && index != 0) {
+ ui->timeSwitches->insertItem(index - 1,
+ ui->timeSwitches->takeItem(index));
+ ui->timeSwitches->setCurrentRow(index - 1);
+
+ std::lock_guard lock(switcher->m);
+
+ iter_swap(switcher->timeSwitches.begin() + index,
+ switcher->timeSwitches.begin() + index - 1);
+ }
+}
+
+void SceneSwitcher::on_timeDown_clicked()
+{
+ int index = ui->timeSwitches->currentRow();
+ if (index != -1 && index != ui->timeSwitches->count() - 1) {
+ ui->timeSwitches->insertItem(index + 1,
+ ui->timeSwitches->takeItem(index));
+ ui->timeSwitches->setCurrentRow(index + 1);
+
+ std::lock_guard lock(switcher->m);
+
+ iter_swap(switcher->timeSwitches.begin() + index,
+ switcher->timeSwitches.begin() + index + 1);
+ }
+}
+
+bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
+{
+ bool ret = false;
+ QTime validSwitchTimeWindow = time1.addMSecs(interval);
+
+ ret = time1 <= time2 && time2 <= validSwitchTimeWindow;
+ // check for overflow
+ if (!ret && validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
+ ret = time2 >= time1 || time2 <= validSwitchTimeWindow;
+ }
+ return ret;
+}
+
+bool checkLiveTime(TimeSwitch &s, QDateTime &start, int &interval)
+{
+ if (start.isNull())
+ return false;
+
+ QDateTime now = QDateTime::currentDateTime();
+ QTime timePassed = QTime(0, 0).addMSecs(start.msecsTo(now));
+
+ return timesAreInInterval(s.time, timePassed, interval);
+}
+
+bool checkRegularTime(TimeSwitch &s, int &interval)
+{
+ bool match = false;
+ if (s.trigger != ANY_DAY &&
+ s.trigger != QDate::currentDate().dayOfWeek())
+ return false;
+
+ QTime now = QTime::currentTime();
+
+ return timesAreInInterval(s.time, now, interval);
+}
+
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
if (timeSwitches.size() == 0)
return;
- QTime now = QTime::currentTime();
-
for (TimeSwitch &s : timeSwitches) {
-
- QTime validSwitchTimeWindow = s.time.addMSecs(interval);
-
- match = s.time <= now && now <= validSwitchTimeWindow;
- if (!match &&
- validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
- // check for overflow
- match = now >= s.time || now <= validSwitchTimeWindow;
- }
+ if (s.trigger == LIVE)
+ match = checkLiveTime(s, liveTime, interval);
+ else
+ match = checkRegularTime(s, interval);
if (match) {
scene = (s.usePreviousScene) ? previousScene : s.scene;
@@ -172,6 +252,7 @@ void SwitcherData::saveTimeSwitches(obs_data_t *obj)
: sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
+ obs_data_set_int(array_obj, "trigger", s.trigger);
obs_data_set_string(
array_obj, "time",
s.time.toString().toStdString().c_str());
@@ -199,17 +280,19 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
+ timeTrigger trigger =
+ (timeTrigger)obs_data_get_int(array_obj, "trigger");
QTime time = QTime::fromString(
obs_data_get_string(array_obj, "time"));
std::string timeSwitchStr =
- MakeTimeSwitchName(scene, transition, time)
+ MakeTimeSwitchName(scene, transition, trigger, time)
.toUtf8()
.constData();
switcher->timeSwitches.emplace_back(
GetWeakSourceByName(scene),
- GetWeakTransitionByName(transition), time,
+ GetWeakTransitionByName(transition), trigger, time,
(strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
timeSwitchStr);
@@ -223,13 +306,24 @@ void SceneSwitcher::setupTimeTab()
populateSceneSelection(ui->timeScenes, true);
populateTransitionSelection(ui->timeTransitions);
+ for (auto t : triggerTable) {
+ ui->timeTrigger->addItem(t.first.c_str());
+ }
+
+ // assuming the streaming / recording entry is always last
+ ui->timeTrigger->setItemData(
+ (int)triggerTable.size() - 1,
+ "The time relative to the start of streaming / recording will be used",
+ Qt::ToolTipRole);
+
for (auto &s : switcher->timeSwitches) {
std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
- QString listText = MakeTimeSwitchName(
- sceneName.c_str(), transitionName.c_str(), s.time);
+ QString listText = MakeTimeSwitchName(sceneName.c_str(),
+ transitionName.c_str(),
+ s.trigger, s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->timeSwitches);