Compare commits

..

3 Commits

Author SHA1 Message Date
WarmUpTill
7ada858046 Add option to match changed content 2023-12-16 19:42:02 +01:00
WarmUpTill
51d121bda2 Add Matches() helper function 2023-12-13 18:31:53 +01:00
WarmUpTill
a7cf5769dd Remove deprecated functionality of "File" condition 2023-12-13 15:23:16 +01:00
108 changed files with 1172 additions and 1648 deletions

View File

@@ -97,8 +97,6 @@ target_sources(
src/macro-core/macro-action-clipboard.hpp
src/macro-core/macro-action-edit.cpp
src/macro-core/macro-action-edit.hpp
src/macro-core/macro-action-factory.cpp
src/macro-core/macro-action-factory.hpp
src/macro-core/macro-action-file.cpp
src/macro-core/macro-action-file.hpp
src/macro-core/macro-action-filter.cpp
@@ -175,8 +173,6 @@ target_sources(
src/macro-core/macro-condition-display.hpp
src/macro-core/macro-condition-edit.cpp
src/macro-core/macro-condition-edit.hpp
src/macro-core/macro-condition-factory.cpp
src/macro-core/macro-condition-factory.hpp
src/macro-core/macro-condition-file.cpp
src/macro-core/macro-condition-file.hpp
src/macro-core/macro-condition-filter.cpp
@@ -237,8 +233,6 @@ target_sources(
src/macro-core/macro-condition.hpp
src/macro-core/macro-dock.cpp
src/macro-core/macro-dock.hpp
src/macro-core/macro-helpers.cpp
src/macro-core/macro-helpers.hpp
src/macro-core/macro-properties.cpp
src/macro-core/macro-properties.hpp
src/macro-core/macro-ref.cpp
@@ -297,8 +291,8 @@ target_sources(
src/utils/obs-module-helper.hpp
src/utils/osc-helpers.cpp
src/utils/osc-helpers.hpp
src/utils/plugin-state-helpers.cpp
src/utils/plugin-state-helpers.hpp
src/utils/plugin-state-helper.cpp
src/utils/plugin-state-helper.hpp
src/utils/priority-helper.cpp
src/utils/priority-helper.hpp
src/utils/process-config.cpp
@@ -329,8 +323,8 @@ target_sources(
src/utils/striped-frame.hpp
src/utils/switch-button.cpp
src/utils/switch-button.hpp
src/utils/sync-helpers.cpp
src/utils/sync-helpers.hpp
src/utils/sync-helper.cpp
src/utils/sync-helper.hpp
src/utils/temp-variable.cpp
src/utils/temp-variable.hpp
src/utils/transition-selection.cpp

View File

@@ -152,13 +152,11 @@ AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
AdvSceneSwitcher.condition.file.local="Lokale Datei"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medien"
AdvSceneSwitcher.condition.media.source="Quelle"
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
AdvSceneSwitcher.condition.media.matchOnChange="Nur bei Änderung übereinstimmen (Hinweis: Diese Option wird in einer zukünftigen Version entfernt werden - bitte stattdessen Dauer-Modifikatoren verwenden)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Video"
@@ -573,6 +571,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
; Transition Tab

View File

@@ -195,18 +195,22 @@ AdvSceneSwitcher.condition.window.entry.text="{{checkText}}Window contains text{
AdvSceneSwitcher.condition.window.entry.text.note="This option might not work on every text being displayed in a window.\nIf that is the case, you can consider using the Video conditions OCR check instead."
AdvSceneSwitcher.condition.window.entry.currentFocus="Current focus window:{{focusWindow}}"
AdvSceneSwitcher.condition.file="File"
AdvSceneSwitcher.condition.file.type.match="matches"
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
AdvSceneSwitcher.condition.file.type.dateChange="modification date changed"
AdvSceneSwitcher.condition.file.type.match="Matches"
AdvSceneSwitcher.condition.file.type.contentChange="Content changed"
AdvSceneSwitcher.condition.file.type.dateChange="Modification date changed"
AdvSceneSwitcher.condition.file.type.changesMatch="Changed lines match"
AdvSceneSwitcher.condition.file.remote="Remote file"
AdvSceneSwitcher.condition.file.local="Local file"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.changeMatchType.any="Any lines"
AdvSceneSwitcher.condition.file.changeMatchType.added="Added lines"
AdvSceneSwitcher.condition.file.changeMatchType.removed="Removed lines"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{changeMatchType}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Media"
AdvSceneSwitcher.condition.media.source="Source"
AdvSceneSwitcher.condition.media.anyOnScene="Any media source on"
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use duration modifiers instead)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Unfortunately not all media source types behave the same (e.g. Media Source vs. VLC Video Source \"Stopped\" state).\nSo please experiment what works for your setup!"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}state is{{states}}and{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Video"
@@ -609,7 +613,6 @@ 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.sceneVisibility="Scene item visibility"
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
@@ -820,7 +823,6 @@ AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
@@ -832,7 +834,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{sceneItemIndex}}"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
@@ -1294,9 +1296,9 @@ AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived="Shoutout time"
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
AdvSceneSwitcher.tempVar.twitch.id.reward="Reward id"
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User id redeeming the reward"
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming the reward"
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User name redeeming the reward"
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User id redeeming reward"
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming reward"
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User login redeeming reward"
AdvSceneSwitcher.tempVar.twitch.user_input.reward="User input for reward"
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information"
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed, at the time it was redeemed."

View File

@@ -123,12 +123,10 @@ AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Ventana"
AdvSceneSwitcher.condition.file="Archivo"
AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medios"
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"
AdvSceneSwitcher.condition.media.matchOnChange="Solo coincidir con el cambio (Nota: esta opción se eliminará en una versión futura; use modificadores de duración en su lugar)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Desafortunadamente, no todos los tipos de fuentes de medios se comportan de la misma manera (p. ej., fuente de medios frente a estado \"Detenido\" de fuente de video VLC).\n¡Así que experimente lo que funciona para su configuración!"
AdvSceneSwitcher.condition.media.entry="El estado de{{sourceTypes}}{{mediaSources}}{{scenes}}es{{states}}y{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Video"

View File

@@ -197,6 +197,7 @@ AdvSceneSwitcher.condition.media="Média"
AdvSceneSwitcher.condition.media.source="Source"
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
AdvSceneSwitcher.condition.media.allOnScene="Toutes les sources média sur la scène"
AdvSceneSwitcher.condition.media.matchOnChange="Ne correspondre qu'au changement (Remarque : Cette option sera supprimée dans une version future - veuillez plutôt utiliser les modificateurs de durée)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Malheureusement, toutes les sources média ne se comportent pas de la même manière (par exemple, l'état \"Arrêté\" de la source Media par rapport à la source Vidéo VLC).\nPar conséquent, veuillez expérimenter ce qui fonctionne le mieux pour votre configuration !"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}l'état est{{states}}et{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Vidéo"
@@ -739,6 +740,7 @@ AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Définir le titre du
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Définir la catégorie du flux"
AdvSceneSwitcher.action.twitch.type.commercial.start="Démarrer une publicité d'une durée de"
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Impossible de sélectionner une catégorie sans avoir d'abord sélectionné un compte Twitch !"
AdvSceneSwitcher.action.twitch.entry.line1="Sur{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"

View File

@@ -87,8 +87,6 @@ AdvSceneSwitcher.condition.scene.type.current="Текущий"
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
AdvSceneSwitcher.condition.window="Окно"
AdvSceneSwitcher.condition.file="Файл"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Медиа"
AdvSceneSwitcher.condition.video="Видео"
AdvSceneSwitcher.condition.video.condition.match="точно соответствует"

View File

@@ -113,12 +113,10 @@ AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Pencere"
AdvSceneSwitcher.condition.file="Dosya"
AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medya"
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "
AdvSceneSwitcher.condition.media.matchOnChange="Yalnızca değişiklikle eşleştirin (Not: Bu seçenek gelecekteki bir sürümde kaldırılacaktır - lütfen bunun yerine zaman kısıtlamalarını kullanın)"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}durumu{{states}}ve{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Video"
AdvSceneSwitcher.condition.video.condition.match="Tam olarak eşleşir"

View File

@@ -178,13 +178,11 @@ AdvSceneSwitcher.condition.file.type.contentChange="内容已更改"
AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改"
AdvSceneSwitcher.condition.file.remote="远程文件"
AdvSceneSwitcher.condition.file.local="本地文件"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="媒体"
AdvSceneSwitcher.condition.media.source="源"
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是并非所有媒体源类型的行为都相同例如媒体源与VLC视频源“停止”状态。\n所以请尝试适合您的设置"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="视频"
@@ -649,6 +647,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"

View File

@@ -119,7 +119,7 @@
<string notr="true">ms</string>
</property>
<property name="minimum">
<number>10</number>
<number>50</number>
</property>
<property name="maximum">
<number>20000</number>

View File

@@ -1,6 +1,5 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "macro-helpers.hpp"
#include "status-control.hpp"
#include "scene-switch-helpers.hpp"
#include "curl-helper.hpp"
@@ -11,7 +10,6 @@
#include <QMainWindow>
#include <QAction>
#include <QFileDialog>
#include <QTextStream>
#include <QDirIterator>
#include <regex>
#include <filesystem>
@@ -137,7 +135,7 @@ bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
/******************************************************************************
* Saving and loading
******************************************************************************/
static void AskForBackup(const QString &json);
static void AskForBackup(obs_data_t *obj);
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{
@@ -158,25 +156,16 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->Stop();
switcher->m.lock();
OBSDataAutoRelease obj =
obs_data_t *obj =
obs_data_get_obj(save_data, "advanced-scene-switcher");
if (!obj) {
obj = obs_data_create();
}
if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
auto json = obs_data_get_json(obj);
static QString jsonQString = json ? json : "";
std::thread t([]() {
obs_queue_task(
OBS_TASK_UI,
[](void *) {
AskForBackup(jsonQString);
},
nullptr, false);
});
t.detach();
AskForBackup(obj);
}
switcher->LoadSettings(obj);
obs_data_release(obj);
switcher->m.unlock();
if (!switcher->stop) {
@@ -185,12 +174,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
}
}
static void AskForBackup(const QString &json)
static void AskForBackup(obs_data_t *obj)
{
const bool backupWasConfirmed = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
bool backupSettings = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true);
if (!backupWasConfirmed) {
if (!backupSettings) {
return;
}
@@ -209,8 +198,8 @@ static void AskForBackup(const QString &json)
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
auto out = QTextStream(&file);
out << json;
obs_data_save_json(obj, file.fileName().toUtf8().constData());
}
/******************************************************************************
@@ -237,6 +226,7 @@ void SwitcherData::Thread()
// if a longer transition is used than the configured check interval
bool setPrevSceneAfterLinger = false;
bool macroMatch = false;
macroSceneSwitched = false;
endTime = std::chrono::high_resolution_clock::now();
auto runTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -347,6 +337,12 @@ void SwitcherData::SetPreconditions()
// Process name
GetForegroundProcessName(currentForegroundProcess);
// Cursor
std::pair<int, int> cursorPos = GetCursorPos();
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
cursorPos.second != switcher->lastCursorPos.second;
lastCursorPos = GetCursorPos();
// Macro
InvalidateMacroTempVarValues();
}
@@ -428,7 +424,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
static void ResetMacros()
{
for (auto &m : GetMacros()) {
for (auto &m : switcher->macros) {
m->ResetRunCount();
m->ResetTimers();
}
@@ -471,9 +467,9 @@ void SwitcherData::Stop()
if (th && th->isRunning()) {
stop = true;
cv.notify_all();
SetMacroAbortWait(true);
GetMacroWaitCV().notify_all();
GetMacroTransitionCV().notify_all();
abortMacroWait = true;
macroWaitCv.notify_all();
macroTransitionCv.notify_all();
// Not waiting if a dialog was closed is a workaround to avoid
// deadlocks when a variable input dialog is opened while Stop()
@@ -546,6 +542,9 @@ extern "C" void FreeSceneSwitcher()
static void handleSceneChange()
{
switcher->lastSceneChangeTime =
std::chrono::high_resolution_clock::now();
// Stop waiting if scene was changed
if (switcher->SceneChangedDuringWait()) {
switcher->cv.notify_one();
@@ -612,9 +611,28 @@ static void handlePeviewSceneChange()
}
}
static void handleTransitionEnd()
static void setReplayBufferSaved()
{
GetMacroTransitionCV().notify_all();
switcher->replayBufferSaved = true;
}
static void setTranstionEnd()
{
switcher->lastTransitionEndTime =
std::chrono::high_resolution_clock::now();
switcher->macroTransitionCv.notify_all();
}
static void setStreamStarting()
{
switcher->lastStreamStartingTime =
std::chrono::high_resolution_clock::now();
}
static void setStreamStopping()
{
switcher->lastStreamStoppingTime =
std::chrono::high_resolution_clock::now();
}
static void handleShutdown()
@@ -623,10 +641,10 @@ static void handleShutdown()
return;
}
switcher->obsIsShuttingDown = true;
if (ShutdownCheckIsNecessary()) {
if (switcher->shutdownConditionCount) {
switcher->Stop();
CheckMacros();
RunMacros();
switcher->CheckMacros();
switcher->RunMacros();
// Unfortunately this will not work as OBS will now allow saving
// the scene collection data at this point, So any OBS specific
@@ -683,8 +701,19 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
resetLiveTime();
break;
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(26, 0, 0)
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
setReplayBufferSaved();
break;
#endif
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
handleTransitionEnd();
setTranstionEnd();
break;
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
setStreamStarting();
break;
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
setStreamStopping();
break;
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 2, 0)
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:

View File

@@ -3,7 +3,6 @@
#include "status-control.hpp"
#include "file-selection.hpp"
#include "filter-combo-box.hpp"
#include "variable.hpp"
#include "utility.hpp"
#include "version.h"
@@ -513,7 +512,6 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
}
LoadMacros(obj);
LoadGlobalMacroProperties(obj);
loadWindowTitleSwitches(obj);
loadScreenRegionSwitches(obj);
loadPauseSwitches(obj);
@@ -550,7 +548,6 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
saveSceneGroups(obj);
SaveMacros(obj);
SaveGlobalMacroProperties(obj);
SaveVariables(obj);
saveWindowTitleSwitches(obj);
saveScreenRegionSwitches(obj);

View File

@@ -160,9 +160,7 @@ enum class HotkeyType {
Key_NumpadMultiply,
Key_NumpadDivide,
Key_NumpadDecimal,
Key_NumpadEnter,
Key_Tilde,
Key_NumpadEnter
};
} // namespace advss

View File

@@ -12,11 +12,6 @@ namespace advss {
static QMetaObject::Connection addPulse;
SceneGroupEditWidget *typeEdit = nullptr;
std::deque<SceneGroup> &GetSceneGroups()
{
return switcher->sceneGroups;
}
void SceneGroup::advanceIdx()
{
currentIdx++;

View File

@@ -1,5 +1,5 @@
#pragma once
#include <deque>
#include <vector>
#include <QDialog>
#include <QLabel>
@@ -87,6 +87,5 @@ private:
SceneGroup *GetSceneGroupByName(const char *name);
SceneGroup *GetSceneGroupByQString(const QString &name);
std::deque<SceneGroup> &GetSceneGroups();
} // namespace advss

View File

@@ -177,17 +177,17 @@ static std::string getRemoteData(std::string &url)
{
std::string readBuffer;
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
// Set timeout to at least one second
int timeout = switcher->interval / 1000;
if (timeout == 0) {
timeout = 1;
}
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
CurlHelper::Perform();
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
switcher->curl.Perform();
return readBuffer;
}
@@ -422,7 +422,7 @@ void AdvSceneSwitcher::SetupFileTab()
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
ui->remoteFileWarningLabel->hide();
if (CurlHelper::Initialized()) {
if (switcher->curl.Initialized()) {
ui->libcurlWarning->setVisible(false);
}

View File

@@ -555,9 +555,6 @@ static std::unordered_map<HotkeyType, long> keyTable = {
{HotkeyType::Key_8, XK_8},
{HotkeyType::Key_9, XK_9},
// Other
{HotkeyType::Key_Tilde, XK_asciitilde},
{HotkeyType::Key_F1, XK_F1},
{HotkeyType::Key_F2, XK_F2},
{HotkeyType::Key_F3, XK_F3},

View File

@@ -1,5 +1,5 @@
#include "macro-action-audio.hpp"
#include "macro.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -36,16 +36,6 @@ const static std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
"AdvSceneSwitcher.action.audio.fade.type.rate"},
};
namespace {
struct FadeInfo {
std::atomic_bool active = {false};
std::atomic_int id = {0};
};
}
static FadeInfo masterAudioFade;
static std::unordered_map<std::string, FadeInfo> audioFades;
constexpr auto fadeInterval = std::chrono::milliseconds(100);
constexpr float minFade = 0.000001f;
@@ -68,9 +58,10 @@ auto set_master_volume = obs_set_master_volume;
void MacroActionAudio::SetFadeActive(bool value)
{
if (_action == Action::SOURCE_VOLUME) {
audioFades[_audioSource.ToString()].active = value;
switcher->activeAudioFades[_audioSource.ToString()].active =
value;
} else {
masterAudioFade.active = value;
switcher->masterAudioFade.active = value;
}
}
@@ -78,13 +69,14 @@ bool MacroActionAudio::FadeActive()
{
bool active = true;
if (_action == Action::SOURCE_VOLUME) {
auto it = audioFades.find(_audioSource.ToString());
if (it == audioFades.end()) {
auto it = switcher->activeAudioFades.find(
_audioSource.ToString());
if (it == switcher->activeAudioFades.end()) {
return false;
}
active = it->second.active;
} else {
active = masterAudioFade.active;
active = switcher->masterAudioFade.active;
}
return active;
@@ -94,13 +86,14 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr()
{
if (_action == Action::SOURCE_VOLUME) {
auto it = audioFades.find(_audioSource.ToString());
if (it == audioFades.end()) {
auto it = switcher->activeAudioFades.find(
_audioSource.ToString());
if (it == switcher->activeAudioFades.end()) {
return nullptr;
}
return &it->second.id;
}
return &masterAudioFade.id;
return &switcher->masterAudioFade.id;
}
void MacroActionAudio::SetVolume(float vol)

View File

@@ -1,5 +1,6 @@
#include "macro-action-clipboard.hpp"
#include "curl-helper.hpp"
#include "switcher-data.hpp"
#include <QApplication>
#include <QClipboard>
@@ -33,17 +34,17 @@ static std::optional<QImage> getImageFromUrl(const char *url)
{
QByteArray response;
CurlHelper::SetOpt(CURLOPT_URL, url);
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, 30000);
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, writeCallback);
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
auto code = CurlHelper::Perform();
switcher->curl.SetOpt(CURLOPT_URL, url);
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, 30000);
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, writeCallback);
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &response);
auto code = switcher->curl.Perform();
if (code != CURLE_OK) {
blog(LOG_WARNING,
"Retrieving image failed in %s with error: %s", __func__,
CurlHelper::GetError(code));
switcher->curl.GetError(code));
return {};
}

View File

@@ -1,8 +1,6 @@
#include "macro-action-edit.hpp"
#include "macro-helpers.hpp"
#include "macro.hpp"
#include "macro-properties.hpp"
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "macro-action-edit.hpp"
#include "macro-action-scene-switch.hpp"
#include "section.hpp"
#include "switch-button.hpp"
@@ -12,9 +10,61 @@
namespace advss {
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
{
static std::map<std::string, MacroActionInfo> _methods;
return _methods;
}
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
{
if (auto it = GetMap().find(id); it == GetMap().end()) {
GetMap()[id] = info;
return true;
}
return false;
}
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
Macro *m)
{
if (auto it = GetMap().find(id); it != GetMap().end())
return it->second._createFunc(m);
return nullptr;
}
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
QWidget *parent,
std::shared_ptr<MacroAction> action)
{
if (auto it = GetMap().find(id); it != GetMap().end())
return it->second._createWidgetFunc(parent, action);
return nullptr;
}
std::string MacroActionFactory::GetActionName(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._name;
}
return "unknown action";
}
std::string MacroActionFactory::GetIdByName(const QString &name)
{
for (auto it : GetMap()) {
if (name == obs_module_text(it.second._name.c_str())) {
return it.first;
}
}
return "";
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[_, action] : MacroActionFactory::GetActionTypes()) {
for (auto &[_, action] : MacroActionFactory::GetActionTypes()) {
QString entry(obs_module_text(action._name.c_str()));
if (list->findText(entry) == -1) {
list->addItem(entry);
@@ -30,8 +80,7 @@ static inline void populateActionSelection(QComboBox *list)
MacroActionEdit::MacroActionEdit(QWidget *parent,
std::shared_ptr<MacroAction> *entryData,
const std::string &id)
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
parent),
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
_actionSelection(new FilterComboBox()),
_enable(new SwitchButton()),
_entryData(entryData)
@@ -85,7 +134,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
auto idx = _entryData->get()->GetIndex();
auto macro = _entryData->get()->GetMacro();
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->reset();
*_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx);
@@ -136,7 +185,7 @@ void MacroActionEdit::ActionEnableChanged(bool value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
(*_entryData)->SetEnabled(value);
SetDisableEffect(!value);
}
@@ -180,7 +229,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
id = temp.GetId();
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
macro->Actions().emplace(
macro->Actions().begin() + idx,
MacroActionFactory::Create(id, macro.get()));
@@ -231,11 +280,11 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
ui->actionsList->Remove(idx);
macro->Actions().erase(macro->Actions().begin() + idx);
SetMacroAbortWait(true);
GetMacroWaitCV().notify_all();
switcher->abortMacroWait = true;
switcher->macroWaitCv.notify_all();
macro->UpdateActionIndices();
SetActionData(*macro);
}
@@ -376,7 +425,7 @@ void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
std::swap(pos1, pos2);
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
m->UpdateActionIndices();
auto widget1 = static_cast<MacroActionEdit *>(
@@ -436,7 +485,7 @@ void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
return;
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto action = macro->ElseActions().at(from);
macro->ElseActions().erase(macro->ElseActions().begin() + from);
macro->ElseActions().insert(macro->ElseActions().begin() + to,
@@ -469,7 +518,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
id = temp.GetId();
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
macro->ElseActions().emplace(
macro->ElseActions().begin() + idx,
MacroActionFactory::Create(id, macro.get()));
@@ -501,11 +550,11 @@ void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
ui->elseActionsList->Remove(idx);
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
SetMacroAbortWait(true);
GetMacroWaitCV().notify_all();
switcher->abortMacroWait = true;
switcher->macroWaitCv.notify_all();
macro->UpdateElseActionIndices();
SetActionData(*macro);
}
@@ -523,7 +572,7 @@ void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
std::swap(pos1, pos2);
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(m->ElseActions().begin() + pos1,
m->ElseActions().begin() + pos2);
m->UpdateElseActionIndices();
@@ -586,7 +635,7 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
return;
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto action = macro->Actions().at(from);
macro->Actions().erase(macro->Actions().begin() + from);
macro->Actions().insert(macro->Actions().begin() + to, action);

View File

@@ -1,6 +1,5 @@
#pragma once
#include "macro-action.hpp"
#include "macro-action-factory.hpp"
#include "filter-combo-box.hpp"
#include <memory>
@@ -9,6 +8,32 @@ namespace advss {
class SwitchButton;
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
std::shared_ptr<MacroAction>);
TCreateMethod _createFunc = nullptr;
TCreateWidgetMethod _createWidgetFunc = nullptr;
std::string _name;
};
class MacroActionFactory {
public:
MacroActionFactory() = delete;
static bool Register(const std::string &id, MacroActionInfo);
static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroAction> action);
static auto GetActionTypes() { return GetMap(); }
static std::string GetActionName(const std::string &id);
static std::string GetIdByName(const QString &name);
private:
static std::map<std::string, MacroActionInfo> &GetMap();
};
class MacroActionEdit : public MacroSegmentEdit {
Q_OBJECT

View File

@@ -1,57 +0,0 @@
#include "macro-action-factory.hpp"
namespace advss {
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
{
static std::map<std::string, MacroActionInfo> _methods;
return _methods;
}
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
{
if (auto it = GetMap().find(id); it == GetMap().end()) {
GetMap()[id] = info;
return true;
}
return false;
}
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
Macro *m)
{
if (auto it = GetMap().find(id); it != GetMap().end())
return it->second._create(m);
return nullptr;
}
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
QWidget *parent,
std::shared_ptr<MacroAction> action)
{
if (auto it = GetMap().find(id); it != GetMap().end())
return it->second._createWidget(parent, action);
return nullptr;
}
std::string MacroActionFactory::GetActionName(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._name;
}
return "unknown action";
}
std::string MacroActionFactory::GetIdByName(const QString &name)
{
for (auto it : GetMap()) {
if (name == obs_module_text(it.second._name.c_str())) {
return it.first;
}
}
return "";
}
} // namespace advss

View File

@@ -1,34 +0,0 @@
#pragma once
#include "macro-action.hpp"
#include <memory>
namespace advss {
struct MacroActionInfo {
using CreateAction = std::shared_ptr<MacroAction> (*)(Macro *m);
using CreateActionWidget = QWidget *(*)(QWidget *parent,
std::shared_ptr<MacroAction>);
CreateAction _create = nullptr;
CreateActionWidget _createWidget = nullptr;
std::string _name;
};
class MacroActionFactory {
public:
MacroActionFactory() = delete;
static bool Register(const std::string &id, MacroActionInfo);
static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroAction> action);
static auto GetActionTypes() { return GetMap(); }
static std::string GetActionName(const std::string &id);
static std::string GetIdByName(const QString &name);
private:
static std::map<std::string, MacroActionInfo> &GetMap();
};
} // namespace advss

View File

@@ -14,14 +14,14 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
"AdvSceneSwitcher.action.hotkey"});
static const std::map<MacroActionHotkey::Action, std::string> actionTypes = {
const static std::map<MacroActionHotkey::Action, std::string> actionTypes = {
{MacroActionHotkey::Action::OBS_HOTKEY,
"AdvSceneSwitcher.action.hotkey.type.obs"},
{MacroActionHotkey::Action::CUSTOM,
"AdvSceneSwitcher.action.hotkey.type.custom"},
};
static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
{OBS_HOTKEY_REGISTERER_FRONTEND,
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
{OBS_HOTKEY_REGISTERER_SOURCE,
@@ -34,7 +34,7 @@ static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
};
static const std::unordered_map<HotkeyType, long> keyTable = {
static std::unordered_map<HotkeyType, long> keyTable = {
// Chars
{HotkeyType::Key_A, OBS_KEY_A},
{HotkeyType::Key_B, OBS_KEY_B},
@@ -75,9 +75,6 @@ static const std::unordered_map<HotkeyType, long> keyTable = {
{HotkeyType::Key_8, OBS_KEY_8},
{HotkeyType::Key_9, OBS_KEY_9},
// Other
{HotkeyType::Key_Tilde, OBS_KEY_ASCIITILDE},
{HotkeyType::Key_F1, OBS_KEY_F1},
{HotkeyType::Key_F2, OBS_KEY_F2},
{HotkeyType::Key_F3, OBS_KEY_F3},
@@ -528,7 +525,6 @@ static inline void populateKeySelection(QComboBox *list)
list->addItem("NumpadDivide");
list->addItem("NumpadDecimal");
list->addItem("NumpadEnter");
list->addItem("Tilde");
}
static void populateActionSelection(QComboBox *list)

View File

@@ -1,4 +1,5 @@
#include "macro-action-http.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include "curl-helper.hpp"
@@ -35,44 +36,44 @@ void MacroActionHttp::SetupHeaders()
}
struct curl_slist *headers = nullptr;
for (auto &header : _headers) {
headers = CurlHelper::SlistAppend(headers, header.c_str());
headers = switcher->curl.SlistAppend(headers, header.c_str());
}
if (!_headers.empty()) {
CurlHelper::SetOpt(CURLOPT_HTTPHEADER, headers);
switcher->curl.SetOpt(CURLOPT_HTTPHEADER, headers);
}
}
void MacroActionHttp::Get()
{
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
SetupHeaders();
std::string response;
if (IsReferencedInVars()) {
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
} else {
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
}
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
CurlHelper::Perform();
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &response);
switcher->curl.Perform();
SetVariableValue(response);
}
void MacroActionHttp::Post()
{
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
CurlHelper::SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
switcher->curl.SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
SetupHeaders();
CurlHelper::Perform();
switcher->curl.Perform();
}
bool MacroActionHttp::PerformAction()
{
if (!CurlHelper::Initialized()) {
if (!switcher->curl.Initialized()) {
blog(LOG_WARNING,
"cannot perform http action (curl not found)");
return true;

View File

@@ -1,5 +1,5 @@
#include "macro-action-plugin-state.hpp"
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include "utility.hpp"
#include <thread>

View File

@@ -14,14 +14,9 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
bool MacroActionRun::PerformAction()
{
if (_wait) {
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
return true;
}
bool procStarted = _procConfig.StartProcessDetached();
// Fall back to using default application to open given file
bool procStarted = QProcess::startDetached(
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
QString::fromStdString(_procConfig.WorkingDir()));
if (!procStarted && _procConfig.Args().empty()) {
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
_procConfig.Path().c_str());
@@ -40,9 +35,6 @@ bool MacroActionRun::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_procConfig.Save(obj);
_timeout.Save(obj);
obs_data_set_bool(obj, "wait", _wait);
obs_data_set_int(obj, "version", 1);
return true;
}
@@ -50,12 +42,6 @@ bool MacroActionRun::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_procConfig.Load(obj);
// TODO: Remove this fallback in a future version
if (!obs_data_has_user_value(obj, "version")) {
return true;
}
_timeout.Load(obj);
_wait = obs_data_get_bool(obj, "wait");
return true;
}
@@ -66,30 +52,14 @@ std::string MacroActionRun::GetShortDesc() const
MacroActionRunEdit::MacroActionRunEdit(
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
: QWidget(parent),
_procConfig(new ProcessConfigEdit(this)),
_waitLayout(new QHBoxLayout()),
_wait(new QCheckBox()),
_timeout(new DurationSelection(this, true, 0.1))
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
{
QWidget::connect(_procConfig,
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
SLOT(ProcessConfigChanged(const ProcessConfig &)));
QWidget::connect(_procConfig, SIGNAL(AdvancedSettingsEnabled()), this,
SLOT(ProcessConfigAdvancedSettingsShown()));
QWidget::connect(_wait, SIGNAL(stateChanged(int)), this,
SLOT(WaitChanged(int)));
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(TimeoutChanged(const Duration &)));
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
_waitLayout,
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
SetLayoutVisible(_waitLayout, false);
auto layout = new QVBoxLayout;
auto *layout = new QVBoxLayout;
layout->addWidget(_procConfig);
layout->addLayout(_waitLayout);
setLayout(layout);
_entryData = entryData;
@@ -103,31 +73,6 @@ void MacroActionRunEdit::UpdateEntryData()
return;
}
_procConfig->SetProcessConfig(_entryData->_procConfig);
_wait->setChecked(_entryData->_wait);
_timeout->SetDuration(_entryData->_timeout);
}
void MacroActionRunEdit::ProcessConfigAdvancedSettingsShown()
{
SetLayoutVisible(_waitLayout, true);
}
void MacroActionRunEdit::WaitChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_wait = value;
}
void MacroActionRunEdit::TimeoutChanged(const Duration &timeout)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_timeout = timeout;
}
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)

View File

@@ -1,9 +1,6 @@
#pragma once
#include "macro-action-edit.hpp"
#include "process-config.hpp"
#include "duration-control.hpp"
#include <QCheckBox>
namespace advss {
@@ -22,8 +19,6 @@ public:
}
ProcessConfig _procConfig;
bool _wait = false;
Duration _timeout = 1;
private:
static bool _registered;
@@ -47,19 +42,14 @@ public:
private slots:
void ProcessConfigChanged(const ProcessConfig &);
void ProcessConfigAdvancedSettingsShown();
void WaitChanged(int);
void TimeoutChanged(const Duration &);
signals:
void HeaderInfoChanged(const QString &);
protected:
std::shared_ptr<MacroActionRun> _entryData;
private:
ProcessConfigEdit *_procConfig;
QHBoxLayout *_waitLayout;
QCheckBox *_wait;
DurationSelection *_timeout;
std::shared_ptr<MacroActionRun> _entryData;
bool _loading = true;
};

View File

@@ -1,5 +1,5 @@
#include "macro-action-scene-collection.hpp"
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include "utility.hpp"
namespace advss {

View File

@@ -1,7 +1,5 @@
#include "macro-action-scene-switch.hpp"
#include "macro-helpers.hpp"
#include "plugin-state-helpers.hpp"
#include "macro.hpp"
#include "switcher-data.hpp"
#include "scene-switch-helpers.hpp"
#include "utility.hpp"
@@ -9,7 +7,7 @@ namespace advss {
using namespace std::chrono_literals;
const std::string MacroActionSwitchScene::id = GetSceneSwitchActionId().data();
const std::string MacroActionSwitchScene::id = "scene_switch";
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
MacroActionSwitchScene::id,
@@ -35,9 +33,9 @@ static void waitForTransitionChange(OBSWeakSource &transition,
}
bool stillTransitioning = true;
while (stillTransitioning && !MacroWaitShouldAbort() &&
while (stillTransitioning && !switcher->abortMacroWait &&
!macro->GetStop()) {
GetMacroTransitionCV().wait_for(*lock, time);
switcher->macroTransitionCv.wait_for(*lock, time);
float t = obs_transition_get_time(source);
stillTransitioning = t < 1.0f && t > 0.0f;
}
@@ -51,8 +49,8 @@ static void waitForTransitionChangeFixedDuration(
auto time = std::chrono::high_resolution_clock::now() +
std::chrono::milliseconds(duration);
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
if (GetMacroTransitionCV().wait_until(*lock, time) ==
while (!switcher->abortMacroWait && !macro->GetStop()) {
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
std::cv_status::timeout) {
break;
}
@@ -93,16 +91,11 @@ static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
return transition;
}
static int getExpectedTransitionDuration(OBSWeakSource &scene,
OBSWeakSource &transiton_,
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
double duration)
{
OBSWeakSource transition = transiton_;
// If we are not modifying the transition override, we will have to
// check, if a transition override is set by the user and use its
// duration instead
if (!ShouldModifyTransitionOverrides()) {
OBSWeakSource transition = t;
if (!switcher->transitionOverrideOverride) {
auto overrideTransition = getOverrideTransition(scene);
if (overrideTransition) {
transition = overrideTransition;
@@ -111,7 +104,6 @@ static int getExpectedTransitionDuration(OBSWeakSource &scene,
}
}
}
if (isUsingFixedLengthTransition(transition)) {
return -1; // no API is available to access the fixed duration
}
@@ -126,9 +118,9 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
{
const int expectedTransitionDuration = getExpectedTransitionDuration(
scene, transition, _duration.Seconds());
SetMacroAbortWait(false);
switcher->abortMacroWait = false;
std::unique_lock<std::mutex> lock(*GetMutex());
std::unique_lock<std::mutex> lock(switcher->m);
if (expectedTransitionDuration < 0) {
waitForTransitionChange(transition, &lock, GetMacro());
} else {
@@ -136,7 +128,7 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
&lock, GetMacro());
}
return !MacroWaitShouldAbort();
return !switcher->abortMacroWait;
}
bool MacroActionSwitchScene::PerformAction()
@@ -153,7 +145,8 @@ bool MacroActionSwitchScene::PerformAction()
auto transition = _transition.GetTransition();
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
obs_frontend_preview_program_mode_active());
if (_blockUntilTransitionDone && scene && scene != GetCurrentScene()) {
if (_blockUntilTransitionDone && scene &&
scene != switcher->currentScene) {
return WaitForTransition(scene, transition);
}
return true;

View File

@@ -1,5 +1,6 @@
#include "macro-action-variable.hpp"
#include "macro-condition-edit.hpp"
#include "switcher-data.hpp"
#include "advanced-scene-switcher.hpp"
#include "macro.hpp"
#include "math-helpers.hpp"
@@ -50,8 +51,6 @@ const static std::map<MacroActionVariable::Type, std::string> actionTypes = {
"AdvSceneSwitcher.action.variable.type.extractJson"},
{MacroActionVariable::Type::SET_TO_TEMPVAR,
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
{MacroActionVariable::Type::SCENE_ITEM_NAME,
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
};
static void apppend(Variable &var, const std::string &value)
@@ -135,49 +134,6 @@ void MacroActionVariable::HandleMathExpression(Variable *var)
var->SetValue(std::get<double>(result));
}
struct GetSceneItemNameHelper {
int curIdx = 0;
int targetIdx = 0;
std::string name = "";
};
static bool getSceneItemAtIdx(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
auto data = reinterpret_cast<GetSceneItemNameHelper *>(ptr);
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, getSceneItemAtIdx, ptr);
}
if (data->curIdx == data->targetIdx) {
data->name =
obs_source_get_name(obs_sceneitem_get_source(item));
data->curIdx--;
return false;
}
data->curIdx--;
return true;
}
void MacroActionVariable::SetToSceneItemName(Variable *var)
{
auto weakSource = _scene.GetScene();
if (!weakSource) {
var->SetValue("");
return;
}
auto index = _sceneItemIndex.GetValue();
if (index < 1) {
var->SetValue("");
return;
}
auto sceneItemCount = GetSceneItemCount(weakSource);
OBSSourceAutoRelease source = obs_weak_source_get_source(weakSource);
auto scene = obs_scene_from_source(source);
GetSceneItemNameHelper data{sceneItemCount, index};
obs_scene_enum_items(scene, getSceneItemAtIdx, &data);
var->SetValue(data.name);
}
struct AskForInputParams {
QString prompt;
QString placeholder;
@@ -312,9 +268,6 @@ bool MacroActionVariable::PerformAction()
var->SetValue(*value);
return true;
}
case Type::SCENE_ITEM_NAME:
SetToSceneItemName(var.get());
return true;
}
return true;
@@ -346,7 +299,6 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
_envVariableName.Save(obj, "environmentVariableName");
_scene.Save(obj);
_tempVar.Save(obj);
_sceneItemIndex.Save(obj, "sceneItemIndex");
return true;
}
@@ -376,7 +328,6 @@ bool MacroActionVariable::Load(obs_data_t *obj)
_envVariableName.Load(obj, "environmentVariableName");
_scene.Load(obj);
_tempVar.Load(obj, GetMacro());
_sceneItemIndex.Load(obj, "sceneItemIndex");
return true;
}
@@ -506,8 +457,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_envVariable(new VariableLineEdit(this)),
_scenes(new SceneSelectionWidget(this, true, false, true, true,
true)),
_tempVars(new TempVariableSelection(this)),
_sceneItemIndex(new VariableSpinBox())
_tempVars(new TempVariableSelection(this))
{
_numValue->setMinimum(-9999999999);
_numValue->setMaximum(9999999999);
@@ -525,7 +475,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_regexMatchIdx->setSuffix(".");
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
QSizePolicy::Preferred);
_sceneItemIndex->setMinimum(1);
populateTypeSelection(_actions);
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
@@ -574,10 +523,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
QWidget::connect(_tempVars,
SIGNAL(SelectionChanged(const TempVariableRef &)),
this, SLOT(SelectionChanged(const TempVariableRef &)));
QWidget::connect(
_sceneItemIndex,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{variables}}", _variables},
@@ -599,7 +544,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
{"{{envVariableName}}", _envVariable},
{"{{scenes}}", _scenes},
{"{{tempVars}}", _tempVars},
{"{{sceneItemIndex}}", _sceneItemIndex},
};
auto entryLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
@@ -694,7 +638,6 @@ void MacroActionVariableEdit::UpdateEntryData()
_envVariable->setText(_entryData->_envVariableName);
_scenes->SetScene(_entryData->_scene);
_tempVars->SetVariable(_entryData->_tempVar);
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
SetWidgetVisibility();
}
@@ -1039,17 +982,6 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
_entryData->_tempVar = var;
}
void MacroActionVariableEdit::SceneItemIndexChanged(
const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_sceneItemIndex = value;
}
void MacroActionVariableEdit::SetWidgetVisibility()
{
if (!_entryData) {
@@ -1126,15 +1058,10 @@ void MacroActionVariableEdit::SetWidgetVisibility()
}
_envVariable->setVisible(_entryData->_type ==
MacroActionVariable::Type::ENV_VARIABLE);
_scenes->setVisible(
_entryData->_type ==
MacroActionVariable::Type::SCENE_ITEM_COUNT ||
_entryData->_type ==
MacroActionVariable::Type::SCENE_ITEM_NAME);
_scenes->setVisible(_entryData->_type ==
MacroActionVariable::Type::SCENE_ITEM_COUNT);
_tempVars->setVisible(_entryData->_type ==
MacroActionVariable::Type::SET_TO_TEMPVAR);
_sceneItemIndex->setVisible(_entryData->_type ==
MacroActionVariable::Type::SCENE_ITEM_NAME);
adjustSize();
updateGeometry();
}

View File

@@ -6,7 +6,6 @@
#include "scene-selection.hpp"
#include "variable-line-edit.hpp"
#include "variable-text-edit.hpp"
#include "variable-spinbox.hpp"
namespace advss {
@@ -45,7 +44,6 @@ public:
STRING_LENGTH,
EXTRACT_JSON,
SET_TO_TEMPVAR,
SCENE_ITEM_NAME,
};
Type _type = Type::SET_FIXED_VALUE;
@@ -77,7 +75,6 @@ public:
#endif
SceneSelection _scene;
TempVariableRef _tempVar;
IntVariable _sceneItemIndex = 1;
private:
void DecrementCurrentSegmentVariableRef();
@@ -85,7 +82,6 @@ private:
void HandleRegexSubString(Variable *);
void HandleFindAndReplace(Variable *);
void HandleMathExpression(Variable *);
void SetToSceneItemName(Variable *);
std::weak_ptr<MacroSegment> _macroSegment;
int _segmentIdxLoadValue = -1;
@@ -133,7 +129,6 @@ private slots:
void EnvVariableChanged();
void SceneChanged(const SceneSelection &);
void SelectionChanged(const TempVariableRef &var);
void SceneItemIndexChanged(const NumberVariable<int> &);
signals:
void HeaderInfoChanged(const QString &);
@@ -172,7 +167,6 @@ private:
VariableLineEdit *_envVariable;
SceneSelectionWidget *_scenes;
TempVariableSelection *_tempVars;
VariableSpinBox *_sceneItemIndex;
std::shared_ptr<MacroActionVariable> _entryData;
QTimer _timer;

View File

@@ -1,7 +1,5 @@
#include "macro-action-wait.hpp"
#include "macro-helpers.hpp"
#include "macro.hpp"
#include "sync-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <random>
@@ -26,8 +24,8 @@ static std::default_random_engine re(rd());
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
std::chrono::high_resolution_clock::time_point &time)
{
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
if (GetMacroWaitCV().wait_until(*lock, time) ==
while (!switcher->abortMacroWait && !macro->GetStop()) {
if (switcher->macroWaitCv.wait_until(*lock, time) ==
std::cv_status::timeout) {
break;
}
@@ -55,11 +53,11 @@ bool MacroActionWait::PerformAction()
auto time = std::chrono::high_resolution_clock::now() +
std::chrono::milliseconds((int)(sleepDuration * 1000));
SetMacroAbortWait(false);
std::unique_lock<std::mutex> lock(*GetMutex());
switcher->abortMacroWait = false;
std::unique_lock<std::mutex> lock(switcher->m);
waitHelper(&lock, GetMacro(), time);
return !MacroWaitShouldAbort();
return !switcher->abortMacroWait;
}
bool MacroActionWait::Save(obs_data_t *obj) const

View File

@@ -62,17 +62,17 @@ MacroConditionAudio::~MacroConditionAudio()
bool MacroConditionAudio::CheckOutputCondition()
{
bool ret = false;
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
auto s = obs_weak_source_get_source(_audioSource.GetSource());
// peak will have a value from -60 db to 0 db so we need to scale it
double curVolume = ((double)_peak + 60) * 1.7;
switch (_outputCondition) {
case OutputCondition::ABOVE:
// peak will have a value from -60 db to 0 db
ret = curVolume > _volume;
break;
case OutputCondition::BELOW:
// peak will have a value from -60 db to 0 db
ret = curVolume < _volume;
break;
default:
@@ -84,21 +84,21 @@ bool MacroConditionAudio::CheckOutputCondition()
// Reset for next check
_peak = -std::numeric_limits<float>::infinity();
obs_source_release(s);
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
ResetVolmeter();
}
return ret && source;
return ret;
}
bool MacroConditionAudio::CheckVolumeCondition()
{
bool ret = false;
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
auto s = obs_weak_source_get_source(_audioSource.GetSource());
float curVolume = obs_source_get_volume(source);
bool muted = obs_source_muted(source);
float curVolume = obs_source_get_volume(s);
bool muted = obs_source_muted(s);
switch (_volumeCondition) {
case VolumeCondition::ABOVE:
@@ -126,9 +126,10 @@ bool MacroConditionAudio::CheckVolumeCondition()
}
SetTempVarValue("configured_volume", std::to_string(curVolume));
SetTempVarValue("muted", (source && muted) ? "true" : "false");
SetTempVarValue("muted", muted ? "true" : "false");
return ret && source;
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckSyncOffset()
@@ -138,9 +139,8 @@ bool MacroConditionAudio::CheckSyncOffset()
}
bool ret = false;
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
auto curOffset = obs_source_get_sync_offset(source) / nsPerMs;
auto s = obs_weak_source_get_source(_audioSource.GetSource());
auto curOffset = obs_source_get_sync_offset(s) / nsPerMs;
if (_outputCondition == OutputCondition::ABOVE) {
ret = curOffset > _syncOffset;
} else {
@@ -148,7 +148,8 @@ bool MacroConditionAudio::CheckSyncOffset()
}
SetVariableValue(std::to_string(curOffset));
SetTempVarValue("sync_offset", std::to_string(curOffset));
return ret && source;
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckMonitor()
@@ -158,13 +159,13 @@ bool MacroConditionAudio::CheckMonitor()
}
bool ret = false;
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
ret = obs_source_get_monitoring_type(source) == _monitorType;
auto s = obs_weak_source_get_source(_audioSource.GetSource());
ret = obs_source_get_monitoring_type(s) == _monitorType;
SetVariableValue("");
SetTempVarValue("monitor",
std::to_string(obs_source_get_monitoring_type(source)));
return ret && source;
std::to_string(obs_source_get_monitoring_type(s)));
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckBalance()
@@ -174,9 +175,8 @@ bool MacroConditionAudio::CheckBalance()
}
bool ret = false;
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
auto curBalance = obs_source_get_balance_value(source);
auto s = obs_weak_source_get_source(_audioSource.GetSource());
auto curBalance = obs_source_get_balance_value(s);
if (_outputCondition == OutputCondition::ABOVE) {
ret = curBalance > _balance;
} else {
@@ -184,7 +184,8 @@ bool MacroConditionAudio::CheckBalance()
}
SetVariableValue(std::to_string(curBalance));
SetTempVarValue("balance", std::to_string(curBalance));
return ret && source;
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckCondition()
@@ -238,12 +239,13 @@ obs_volmeter_t *AddVolmeterToSource(MacroConditionAudio *entry,
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, MacroConditionAudio::SetVolumeLevel,
entry);
OBSSourceAutoRelease audioSource = obs_weak_source_get_source(source);
if (!obs_volmeter_attach_source(volmeter, audioSource)) {
const char *name = obs_source_get_name(audioSource);
obs_source_t *as = obs_weak_source_get_source(source);
if (!obs_volmeter_attach_source(volmeter, as)) {
const char *name = obs_source_get_name(as);
blog(LOG_WARNING, "failed to attach volmeter to source %s",
name);
}
obs_source_release(as);
return volmeter;
}
@@ -453,9 +455,10 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
void MacroConditionAudioEdit::UpdateVolmeterSource()
{
delete _volMeter;
OBSSourceAutoRelease soruce = obs_weak_source_get_source(
obs_source_t *soruce = obs_weak_source_get_source(
_entryData->_audioSource.GetSource());
_volMeter = new VolControl(soruce.Get());
_volMeter = new VolControl(soruce);
obs_source_release(soruce);
QLayout *layout = this->layout();
layout->addWidget(_volMeter);

View File

@@ -1,4 +1,5 @@
#include "macro-condition-cursor.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
@@ -60,15 +61,13 @@ bool MacroConditionCursor::CheckCondition()
std::to_string(cursorPos.second));
break;
case Condition::MOVING:
ret = cursorPos.first != _lastCursorPosition.first ||
cursorPos.second != _lastCursorPosition.second;
ret = switcher->cursorPosChanged;
break;
case Condition::CLICK:
ret = CheckClick();
break;
}
_lastCheckTime = std::chrono::high_resolution_clock::now();
_lastCursorPosition = cursorPos;
if (GetVariableValue().empty()) {
SetVariableValue(ret ? "true" : "false");

View File

@@ -41,7 +41,6 @@ public:
private:
bool CheckClick();
std::chrono::high_resolution_clock::time_point _lastCheckTime{};
std::pair<int, int> _lastCursorPosition;
static bool _registered;
static const std::string id;

View File

@@ -638,24 +638,10 @@ void MacroConditionDateEdit::AdvancedSettingsToggleClicked()
{
auto lock = LockContext();
_entryData->_dayOfWeekCheck = !_entryData->_dayOfWeekCheck;
_entryData->_condition = MacroConditionDate::Condition::AT;
}
switch (_entryData->_condition) {
case MacroConditionDate::Condition::BETWEEN:
case MacroConditionDate::Condition::PATTERN:
_condition->setCurrentIndex(0);
_weekCondition->setCurrentIndex(0);
break;
case MacroConditionDate::Condition::AT:
case MacroConditionDate::Condition::AFTER:
case MacroConditionDate::Condition::BEFORE:
_weekCondition->setCurrentIndex(
static_cast<int>(_entryData->_condition));
_condition->setCurrentIndex(
static_cast<int>(_entryData->_condition));
break;
}
_condition->setCurrentIndex(0);
_weekCondition->setCurrentIndex(0);
SetWidgetStatus();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));

View File

@@ -1,24 +1,84 @@
#include "macro-condition-edit.hpp"
#include "macro.hpp"
#include "macro-properties.hpp"
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "macro-condition-edit.hpp"
#include "macro-condition-scene.hpp"
#include "section.hpp"
#include "utility.hpp"
namespace advss {
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
{
static std::map<std::string, MacroConditionInfo> _methods;
return _methods;
}
bool MacroConditionFactory::Register(const std::string &id,
MacroConditionInfo info)
{
if (auto it = GetMap().find(id); it == GetMap().end()) {
GetMap()[id] = info;
return true;
}
return false;
}
std::shared_ptr<MacroCondition>
MacroConditionFactory::Create(const std::string &id, Macro *m)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._createFunc(m);
}
return nullptr;
}
QWidget *
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._createWidgetFunc(parent, cond);
}
return nullptr;
}
std::string MacroConditionFactory::GetConditionName(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._name;
}
return "unknown condition";
}
std::string MacroConditionFactory::GetIdByName(const QString &name)
{
for (auto it : GetMap()) {
if (name == obs_module_text(it.second._name.c_str())) {
return it.first;
}
}
return "";
}
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._useDurationModifier;
}
return false;
}
static inline void populateLogicSelection(QComboBox *list, bool root = false)
{
if (root) {
for (const auto &entry : MacroCondition::logicTypes) {
for (auto entry : MacroCondition::logicTypes) {
if (static_cast<int>(entry.first) < logic_root_offset) {
list->addItem(obs_module_text(
entry.second._name.c_str()));
}
}
} else {
for (const auto &entry : MacroCondition::logicTypes) {
for (auto entry : MacroCondition::logicTypes) {
if (static_cast<int>(entry.first) >=
logic_root_offset) {
list->addItem(obs_module_text(
@@ -30,7 +90,7 @@ static inline void populateLogicSelection(QComboBox *list, bool root = false)
static inline void populateConditionSelection(QComboBox *list)
{
for (const auto &[_, condition] :
for (auto &[_, condition] :
MacroConditionFactory::GetConditionTypes()) {
QString entry(obs_module_text(condition._name.c_str()));
if (list->findText(entry) == -1) {
@@ -119,7 +179,7 @@ void DurationModifierEdit::Collapse(bool collapse)
MacroConditionEdit::MacroConditionEdit(
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
const std::string &id, bool root)
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
: MacroSegmentEdit(switcher->macroProperties._highlightConditions,
parent),
_logicSelection(new QComboBox()),
_conditionSelection(new FilterComboBox()),

View File

@@ -1,12 +1,38 @@
#pragma once
#include "macro-condition.hpp"
#include "macro-condition-factory.hpp"
#include "filter-combo-box.hpp"
#include <memory>
namespace advss {
struct MacroConditionInfo {
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
using TCreateWidgetMethod =
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
TCreateMethod _createFunc = nullptr;
TCreateWidgetMethod _createWidgetFunc = nullptr;
std::string _name;
bool _useDurationModifier = true;
};
class MacroConditionFactory {
public:
MacroConditionFactory() = delete;
static bool Register(const std::string &, MacroConditionInfo);
static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition>);
static auto GetConditionTypes() { return GetMap(); }
static std::string GetConditionName(const std::string &);
static std::string GetIdByName(const QString &name);
static bool UsesDurationModifier(const std::string &id);
private:
static std::map<std::string, MacroConditionInfo> &GetMap();
};
class DurationModifierEdit : public QWidget {
Q_OBJECT
public:

View File

@@ -1,66 +0,0 @@
#include "macro-condition-factory.hpp"
namespace advss {
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
{
static std::map<std::string, MacroConditionInfo> _methods;
return _methods;
}
bool MacroConditionFactory::Register(const std::string &id,
MacroConditionInfo info)
{
if (auto it = GetMap().find(id); it == GetMap().end()) {
GetMap()[id] = info;
return true;
}
return false;
}
std::shared_ptr<MacroCondition>
MacroConditionFactory::Create(const std::string &id, Macro *m)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._create(m);
}
return nullptr;
}
QWidget *
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._createWidget(parent, cond);
}
return nullptr;
}
std::string MacroConditionFactory::GetConditionName(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._name;
}
return "unknown condition";
}
std::string MacroConditionFactory::GetIdByName(const QString &name)
{
for (auto it : GetMap()) {
if (name == obs_module_text(it.second._name.c_str())) {
return it.first;
}
}
return "";
}
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
{
if (auto it = GetMap().find(id); it != GetMap().end()) {
return it->second._useDurationModifier;
}
return false;
}
} // namespace advss

View File

@@ -1,35 +0,0 @@
#pragma once
#include "macro-condition.hpp"
#include <memory>
namespace advss {
struct MacroConditionInfo {
using CreateCondition = std::shared_ptr<MacroCondition> (*)(Macro *m);
using CreateConditionWidget =
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
CreateCondition _create = nullptr;
CreateConditionWidget _createWidget = nullptr;
std::string _name;
bool _useDurationModifier = true;
};
class MacroConditionFactory {
public:
MacroConditionFactory() = delete;
static bool Register(const std::string &, MacroConditionInfo);
static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition>);
static auto GetConditionTypes() { return GetMap(); }
static std::string GetConditionName(const std::string &);
static std::string GetIdByName(const QString &name);
static bool UsesDurationModifier(const std::string &id);
private:
static std::map<std::string, MacroConditionInfo> &GetMap();
};
} // namespace advss

View File

@@ -1,11 +1,12 @@
#include "macro-condition-file.hpp"
#include "utility.hpp"
#include "switcher-data.hpp"
#include "curl-helper.hpp"
#include "plugin-state-helpers.hpp"
#include <QTextStream>
#include <QFileDialog>
#include <regex>
#include <array>
#include <tuple>
namespace advss {
@@ -28,99 +29,76 @@ static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
static std::string getRemoteData(std::string &url)
{
std::string readBuffer;
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
// Set timeout to at least one second
int timeout = GetIntervalValue() / 1000;
int timeout = switcher->interval / 1000;
if (timeout == 0) {
timeout = 1;
}
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
CurlHelper::Perform();
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
switcher->curl.Perform();
return readBuffer;
}
bool MacroConditionFile::MatchFileContent(QString &filedata)
static bool stringsMatch(const QString &text, const std::string &pattern,
const RegexConfig &regex)
{
if (_onlyMatchIfChanged) {
size_t newHash = strHash(filedata.toUtf8().constData());
if (newHash == _lastHash) {
return false;
}
_lastHash = newHash;
auto qpattern = QString::fromStdString(pattern);
if (regex.Enabled()) {
return regex.Matches(text, qpattern);
}
if (_regex.Enabled()) {
auto expr = _regex.GetRegularExpression(_text);
if (!expr.isValid()) {
return false;
}
auto match = expr.match(filedata);
return match.hasMatch();
}
QString text = QString::fromStdString(_text);
return CompareIgnoringLineEnding(text, filedata);
auto textCopy = text;
return CompareIgnoringLineEnding(qpattern, textCopy);
}
bool MacroConditionFile::CheckRemoteFileContent()
static std::optional<QString> getFileContent(MacroConditionFile::FileType type,
const std::string &filePath)
{
std::string path = _file;
std::string data = getRemoteData(path);
SetVariableValue(data);
QString qdata = QString::fromStdString(data);
return MatchFileContent(qdata);
QString filedata;
switch (type) {
case MacroConditionFile::FileType::LOCAL: {
std::string path = filePath;
QFile file(QString::fromStdString(path));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return {};
}
filedata = QTextStream(&file).readAll();
file.close();
} break;
case MacroConditionFile::FileType::REMOTE: {
std::string path = filePath;
std::string data = getRemoteData(path);
filedata = QString::fromStdString(data);
} break;
default:
break;
}
return filedata;
}
bool MacroConditionFile::CheckLocalFileContent()
bool MacroConditionFile::CheckFileContentMatch()
{
QFile file(QString::fromStdString(_file));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
auto fileData = getFileContent(_fileType, _file);
if (!fileData) {
return false;
}
if (_useTime) {
QDateTime newLastMod = QFileInfo(file).lastModified();
if (_lastMod == newLastMod) {
return false;
}
_lastMod = newLastMod;
}
QString filedata = QTextStream(&file).readAll();
SetVariableValue(filedata.toStdString());
bool match = MatchFileContent(filedata);
file.close();
const bool match = stringsMatch(*fileData, _text, _regex);
SetVariableValue(fileData->toStdString());
return match;
}
bool MacroConditionFile::CheckChangeContent()
{
QString filedata;
switch (_fileType) {
case FileType::LOCAL: {
std::string path = _file;
QFile file(QString::fromStdString(path));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return false;
}
filedata = QTextStream(&file).readAll();
file.close();
} break;
case FileType::REMOTE: {
std::string path = _file;
std::string data = getRemoteData(path);
QString filedata = QString::fromStdString(data);
} break;
default:
break;
auto filedata = getFileContent(_fileType, _file);
if (!filedata) {
return false;
}
size_t newHash = strHash(filedata.toUtf8().constData());
size_t newHash = strHash(filedata->toUtf8().constData());
const bool contentChanged = newHash != _lastHash;
_lastHash = newHash;
SetVariableValue(contentChanged ? "true" : "false");
return contentChanged;
}
@@ -135,35 +113,94 @@ bool MacroConditionFile::CheckChangeDate()
SetVariableValue(newLastMod.toString().toStdString());
const bool dateChanged = _lastMod != newLastMod;
_lastMod = newLastMod;
SetVariableValue(dateChanged ? "true" : "false");
return dateChanged;
}
static QStringList splitLines(const QString &string)
{
static auto regex = QRegularExpression("\n|\r\n|\r");
return string.split(regex);
}
bool MacroConditionFile::CheckChangedMatch()
{
static bool setupDone = false;
if (!setupDone) {
auto content = getFileContent(_fileType, _file);
if (!content) {
return false;
}
_previousContent = splitLines(*content);
setupDone = true;
return false;
}
auto currentFileContent = getFileContent(_fileType, _file);
if (!currentFileContent) {
return false;
}
auto currentContent = splitLines(*currentFileContent);
auto newContent = currentContent;
QStringList addedLines;
QStringList removedLines;
for (const auto &line : newContent) {
if (auto it = std::find(_previousContent.begin(),
_previousContent.end(),
line) == _previousContent.end()) {
addedLines.push_back(line);
}
}
for (const auto &line : _previousContent) {
if (std::find(newContent.begin(), newContent.end(), line) ==
newContent.end()) {
removedLines.push_back(line);
}
}
_previousContent = currentContent;
if (_changeMatchType == ChangeMatchType::ADDED ||
_changeMatchType == ChangeMatchType::ANY) {
for (const auto &line : addedLines) {
if (stringsMatch(line, _text, _regex)) {
return true;
}
}
}
if (_changeMatchType == ChangeMatchType::REMOVED ||
_changeMatchType == ChangeMatchType::ANY) {
for (const auto &line : removedLines) {
if (stringsMatch(line, _text, _regex)) {
return true;
}
}
}
return false;
}
bool MacroConditionFile::CheckCondition()
{
bool ret = false;
switch (_condition) {
case MacroConditionFile::ConditionType::MATCH:
if (_fileType == FileType::REMOTE) {
ret = CheckRemoteFileContent();
break;
}
ret = CheckLocalFileContent();
break;
return CheckFileContentMatch();
case MacroConditionFile::ConditionType::CONTENT_CHANGE:
ret = CheckChangeContent();
break;
return CheckChangeContent();
case MacroConditionFile::ConditionType::DATE_CHANGE:
ret = CheckChangeDate();
break;
return CheckChangeDate();
case MacroConditionFile::ConditionType::CHANGES_MATCH:
return CheckChangedMatch();
default:
break;
}
if (GetVariableValue().empty()) {
SetVariableValue(ret ? "true" : "false");
}
return ret;
return false;
}
bool MacroConditionFile::Save(obs_data_t *obj) const
@@ -173,9 +210,9 @@ bool MacroConditionFile::Save(obs_data_t *obj) const
_file.Save(obj, "file");
_text.Save(obj, "text");
obs_data_set_int(obj, "fileType", static_cast<int>(_fileType));
obs_data_set_int(obj, "changeMatchType",
static_cast<int>(_changeMatchType));
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_bool(obj, "useTime", _useTime);
obs_data_set_bool(obj, "onlyMatchIfChanged", _onlyMatchIfChanged);
return true;
}
@@ -191,10 +228,10 @@ bool MacroConditionFile::Load(obs_data_t *obj)
_file.Load(obj, "file");
_text.Load(obj, "text");
_fileType = static_cast<FileType>(obs_data_get_int(obj, "fileType"));
_changeMatchType = static_cast<ChangeMatchType>(
obs_data_get_int(obj, "changeMatchType"));
_condition =
static_cast<ConditionType>(obs_data_get_int(obj, "condition"));
_useTime = obs_data_get_bool(obj, "useTime");
_onlyMatchIfChanged = obs_data_get_bool(obj, "onlyMatchIfChanged");
return true;
}
@@ -205,39 +242,79 @@ std::string MacroConditionFile::GetShortDesc() const
static void populateFileTypes(QComboBox *list)
{
list->addItem(obs_module_text("AdvSceneSwitcher.condition.file.local"));
list->addItem(
obs_module_text("AdvSceneSwitcher.condition.file.remote"));
static constexpr std::array<
std::tuple<MacroConditionFile::FileType, std::string_view>, 2>
fileTypes = {{{MacroConditionFile::FileType::LOCAL,
"AdvSceneSwitcher.condition.file.local"},
{MacroConditionFile::FileType::REMOTE,
"AdvSceneSwitcher.condition.file.remote"}}};
for (const auto &[type, name] : fileTypes) {
list->addItem(obs_module_text(name.data()),
static_cast<int>(type));
}
}
static void populateConditions(QComboBox *list)
{
list->addItem(
obs_module_text("AdvSceneSwitcher.condition.file.type.match"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.condition.file.type.contentChange"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.condition.file.type.dateChange"));
static constexpr std::array<
std::tuple<MacroConditionFile::ConditionType, std::string_view>,
4>
conditionTypes = {{
{MacroConditionFile::ConditionType::MATCH,
"AdvSceneSwitcher.condition.file.type.match"},
{MacroConditionFile::ConditionType::CONTENT_CHANGE,
"AdvSceneSwitcher.condition.file.type.contentChange"},
{MacroConditionFile::ConditionType::DATE_CHANGE,
"AdvSceneSwitcher.condition.file.type.dateChange"},
{MacroConditionFile::ConditionType::CHANGES_MATCH,
"AdvSceneSwitcher.condition.file.type.changesMatch"},
}};
for (const auto &[type, name] : conditionTypes) {
list->addItem(obs_module_text(name.data()),
static_cast<int>(type));
}
}
static void populateChangeMatchTypes(QComboBox *list)
{
static constexpr std::array<
std::tuple<MacroConditionFile::ChangeMatchType, std::string_view>,
3>
matchTypes = {{
{MacroConditionFile::ChangeMatchType::ANY,
"AdvSceneSwitcher.condition.file.changeMatchType.any"},
{MacroConditionFile::ChangeMatchType::ADDED,
"AdvSceneSwitcher.condition.file.changeMatchType.added"},
{MacroConditionFile::ChangeMatchType::REMOVED,
"AdvSceneSwitcher.condition.file.changeMatchType.removed"},
}};
for (const auto &[type, name] : matchTypes) {
list->addItem(obs_module_text(name.data()),
static_cast<int>(type));
}
}
MacroConditionFileEdit::MacroConditionFileEdit(
QWidget *parent, std::shared_ptr<MacroConditionFile> entryData)
: QWidget(parent),
_fileTypes(new QComboBox()),
_changeMatchTypes(new QComboBox()),
_conditions(new QComboBox()),
_filePath(new FileSelection()),
_matchText(new VariableTextEdit(this)),
_regex(new RegexConfigWidget(parent)),
_checkModificationDate(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.fileTab.checkfileContentTime"))),
_checkFileContent(new QCheckBox(
obs_module_text("AdvSceneSwitcher.fileTab.checkfileContent")))
_regex(new RegexConfigWidget(parent))
{
populateFileTypes(_fileTypes);
populateConditions(_conditions);
populateChangeMatchTypes(_changeMatchTypes);
QWidget::connect(_fileTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(FileTypeChanged(int)));
QWidget::connect(_changeMatchTypes, SIGNAL(currentIndexChanged(int)),
this, SLOT(ChangeMatchTypeChanged(int)));
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this,
@@ -246,41 +323,30 @@ MacroConditionFileEdit::MacroConditionFileEdit(
SLOT(MatchTextChanged()));
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
SLOT(RegexChanged(RegexConfig)));
QWidget::connect(_checkModificationDate, SIGNAL(stateChanged(int)),
this, SLOT(CheckModificationDateChanged(int)));
QWidget::connect(_checkFileContent, SIGNAL(stateChanged(int)), this,
SLOT(OnlyMatchIfChangedChanged(int)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fileType}}", _fileTypes},
{"{{changeMatchType}}", _changeMatchTypes},
{"{{conditions}}", _conditions},
{"{{filePath}}", _filePath},
{"{{matchText}}", _matchText},
{"{{useRegex}}", _regex},
{"{{checkModificationDate}}", _checkModificationDate},
{"{{checkFileContent}}", _checkFileContent},
};
QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
QHBoxLayout *line3Layout = new QHBoxLayout;
auto line1Layout = new QHBoxLayout;
line1Layout->setContentsMargins(0, 0, 0, 0);
line2Layout->setContentsMargins(0, 0, 0, 0);
line3Layout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.file.entry.line1"),
line1Layout, widgetPlaceholders);
auto line2Layout = new QHBoxLayout;
line2Layout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.file.entry.line2"),
line2Layout, widgetPlaceholders, false);
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.file.entry.line3"),
line3Layout, widgetPlaceholders);
auto mainLayout = new QVBoxLayout;
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
mainLayout->addLayout(line3Layout);
setLayout(mainLayout);
_entryData = entryData;
@@ -294,21 +360,15 @@ void MacroConditionFileEdit::UpdateEntryData()
return;
}
_fileTypes->setCurrentIndex(static_cast<int>(_entryData->_fileType));
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
_fileTypes->setCurrentIndex(
_fileTypes->findData(static_cast<int>(_entryData->_fileType)));
_conditions->setCurrentIndex(_conditions->findData(
static_cast<int>(_entryData->_condition)));
_changeMatchTypes->setCurrentIndex(_changeMatchTypes->findData(
static_cast<int>(_entryData->_changeMatchType)));
_filePath->SetPath(_entryData->_file);
_matchText->setPlainText(_entryData->_text);
_regex->SetRegexConfig(_entryData->_regex);
_checkModificationDate->setChecked(_entryData->_useTime);
_checkFileContent->setChecked(_entryData->_onlyMatchIfChanged);
// TODO: Remove in future version
if (!_entryData->_useTime) {
_checkModificationDate->hide();
}
if (!_entryData->_onlyMatchIfChanged) {
_checkFileContent->hide();
}
SetWidgetVisibility();
}
@@ -319,19 +379,25 @@ void MacroConditionFileEdit::FileTypeChanged(int index)
return;
}
MacroConditionFile::FileType type =
static_cast<MacroConditionFile::FileType>(index);
auto type = static_cast<MacroConditionFile::FileType>(
_fileTypes->itemData(index).toInt());
_filePath->Button()->setEnabled(type ==
MacroConditionFile::FileType::LOCAL);
auto lock = LockContext();
_entryData->_fileType = type;
}
if (type == MacroConditionFile::FileType::LOCAL) {
_filePath->Button()->setDisabled(false);
_checkModificationDate->setDisabled(false);
} else {
_filePath->Button()->setDisabled(true);
_checkModificationDate->setDisabled(true);
void MacroConditionFileEdit::ChangeMatchTypeChanged(int index)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_fileType = type;
_entryData->_changeMatchType =
static_cast<MacroConditionFile::ChangeMatchType>(
_changeMatchTypes->itemData(index).toInt());
SetWidgetVisibility();
}
void MacroConditionFileEdit::ConditionChanged(int index)
@@ -341,8 +407,8 @@ void MacroConditionFileEdit::ConditionChanged(int index)
}
auto lock = LockContext();
_entryData->_condition =
static_cast<MacroConditionFile::ConditionType>(index);
_entryData->_condition = static_cast<MacroConditionFile::ConditionType>(
_conditions->itemData(index).toInt());
SetWidgetVisibility();
}
@@ -383,44 +449,25 @@ void MacroConditionFileEdit::RegexChanged(RegexConfig conf)
updateGeometry();
}
void MacroConditionFileEdit::CheckModificationDateChanged(int state)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_useTime = state;
}
void MacroConditionFileEdit::OnlyMatchIfChangedChanged(int state)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_onlyMatchIfChanged = state;
}
void MacroConditionFileEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_matchText->setVisible(_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
_regex->setVisible(_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
_checkModificationDate->setVisible(
_entryData->_useTime &&
_changeMatchTypes->setVisible(
_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
_checkFileContent->setVisible(
_entryData->_onlyMatchIfChanged &&
MacroConditionFile::ConditionType::CHANGES_MATCH);
_matchText->setVisible(
_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
MacroConditionFile::ConditionType::MATCH ||
_entryData->_condition ==
MacroConditionFile::ConditionType::CHANGES_MATCH);
_regex->setVisible(
_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH ||
_entryData->_condition ==
MacroConditionFile::ConditionType::CHANGES_MATCH);
adjustSize();
updateGeometry();
}

View File

@@ -10,6 +10,7 @@
#include <QLineEdit>
#include <QPushButton>
#include <QCheckBox>
#include <QStringList>
namespace advss {
@@ -35,27 +36,31 @@ public:
MATCH,
CONTENT_CHANGE,
DATE_CHANGE,
CHANGES_MATCH,
};
enum class ChangeMatchType {
ANY,
ADDED,
REMOVED,
};
StringVariable _file = obs_module_text("AdvSceneSwitcher.enterPath");
StringVariable _text = obs_module_text("AdvSceneSwitcher.enterText");
FileType _fileType = FileType::LOCAL;
ChangeMatchType _changeMatchType = ChangeMatchType::ANY;
ConditionType _condition = ConditionType::MATCH;
RegexConfig _regex;
// TODO: Remove in future version
bool _useTime = false;
bool _onlyMatchIfChanged = false;
private:
bool MatchFileContent(QString &filedata);
bool CheckRemoteFileContent();
bool CheckLocalFileContent();
bool CheckFileContentMatch();
bool CheckChangeContent();
bool CheckChangeDate();
bool CheckChangedMatch();
QDateTime _lastMod;
size_t _lastHash = 0;
QStringList _previousContent;
static bool _registered;
static const std::string id;
};
@@ -78,23 +83,21 @@ public:
private slots:
void FileTypeChanged(int index);
void ChangeMatchTypeChanged(int index);
void ConditionChanged(int index);
void PathChanged(const QString &text);
void MatchTextChanged();
void RegexChanged(RegexConfig);
void CheckModificationDateChanged(int state);
void OnlyMatchIfChangedChanged(int state);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_fileTypes;
QComboBox *_changeMatchTypes;
QComboBox *_conditions;
FileSelection *_filePath;
VariableTextEdit *_matchText;
RegexConfigWidget *_regex;
QCheckBox *_checkModificationDate;
QCheckBox *_checkFileContent;
std::shared_ptr<MacroConditionFile> _entryData;
private:

View File

@@ -1,7 +1,5 @@
#include "macro-condition-media.hpp"
#include "macro.hpp"
#include "plugin-state-helpers.hpp"
#include "scene-switch-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -150,20 +148,26 @@ bool MacroConditionMedia::CheckMediaMatch()
if (!_source.GetSource()) {
return false;
}
bool match = false;
bool matched = CheckState() && CheckTime();
if (matched && !(_onlyMatchOnChagne && _alreadyMatched)) {
match = true;
}
_alreadyMatched = matched;
// reset for next check
_stopped = false;
_ended = false;
_next = false;
return matched;
return match;
}
void MacroConditionMedia::HandleSceneChange()
{
UpdateMediaSourcesOfSceneList();
_lastConfigureScene = GetCurrentScene();
_lastConfigureScene = switcher->currentScene;
}
bool MacroConditionMedia::CheckCondition()
@@ -190,7 +194,7 @@ bool MacroConditionMedia::CheckCondition()
break;
}
if (_lastConfigureScene != GetCurrentScene()) {
if (_lastConfigureScene != switcher->currentScene) {
HandleSceneChange();
}
@@ -206,6 +210,7 @@ bool MacroConditionMedia::Save(obs_data_t *obj) const
obs_data_set_int(obj, "state", static_cast<int>(_state));
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
_time.Save(obj);
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchOnChagne);
obs_data_set_int(obj, "version", 0);
return true;
}
@@ -263,6 +268,7 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
_restriction = static_cast<MacroConditionMedia::Time>(
obs_data_get_int(obj, "restriction"));
_time.Load(obj);
_onlyMatchOnChagne = obs_data_get_bool(obj, "matchOnChagne");
if (_sourceType == Type::SOURCE) {
obs_source_t *mediasource =
@@ -402,7 +408,9 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_states(new QComboBox()),
_timeRestrictions(new QComboBox()),
_time(new DurationSelection())
_time(new DurationSelection()),
_onChange(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.media.matchOnChange")))
{
_states->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.media.inconsistencyInfo"));
@@ -424,12 +432,14 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
this, SLOT(TimeRestrictionChanged(int)));
QWidget::connect(_time, SIGNAL(DurationChanged(const Duration &)), this,
SLOT(TimeChanged(const Duration &)));
QWidget::connect(_onChange, SIGNAL(stateChanged(int)), this,
SLOT(OnChangeChanged(int)));
populateSourceTypes(_sourceTypes);
populateMediaStates(_states);
populateMediaTimes(_timeRestrictions);
auto layout = new QHBoxLayout;
QHBoxLayout *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{sourceTypes}}", _sourceTypes},
{"{{mediaSources}}", _sources},
@@ -439,8 +449,11 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
{"{{time}}", _time},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.media.entry"),
layout, widgetPlaceholders);
setLayout(layout);
entryLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(_onChange);
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
@@ -559,12 +572,28 @@ void MacroConditionMediaEdit::TimeChanged(const Duration &dur)
}
}
void MacroConditionMediaEdit::OnChangeChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_onlyMatchOnChagne = value;
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
_entryData->UpdateMediaSourcesOfSceneList();
}
}
void MacroConditionMediaEdit::SetWidgetVisibility()
{
_sources->setVisible(_entryData->_sourceType ==
MacroConditionMedia::Type::SOURCE);
_scenes->setVisible(_entryData->_sourceType !=
MacroConditionMedia::Type::SOURCE);
if (!_onChange->isChecked()) {
_onChange->hide();
}
}
static int getIdxFromMediaState(MacroConditionMedia::State state)
@@ -596,6 +625,7 @@ void MacroConditionMediaEdit::UpdateEntryData()
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
_time->setDisabled(true);
}
_onChange->setChecked(_entryData->_onlyMatchOnChagne);
SetWidgetVisibility();
}

View File

@@ -72,6 +72,7 @@ public:
OBSWeakSource _rawSource = nullptr;
std::vector<MacroConditionMedia> _sourceGroup;
Duration _time;
bool _onlyMatchOnChagne = false;
private:
bool CheckTime();
@@ -83,7 +84,9 @@ private:
bool _stopped = false;
bool _ended = false;
bool _next = false;
// TODO: Remove _alreadyMatched as it does not make much sense when
// time restrictions for macro conditions are available.
bool _alreadyMatched = false;
// Workaround to enable use of "ended" to specify end of VLC playlist
bool _previousStateEnded = false;
// Used to keep track of scene changes
@@ -116,6 +119,7 @@ private slots:
void StateChanged(int index);
void TimeRestrictionChanged(int index);
void TimeChanged(const Duration &seconds);
void OnChangeChanged(int);
signals:
void HeaderInfoChanged(const QString &);
@@ -126,6 +130,7 @@ protected:
QComboBox *_states;
QComboBox *_timeRestrictions;
DurationSelection *_time;
QCheckBox *_onChange;
std::shared_ptr<MacroConditionMedia> _entryData;
private:

View File

@@ -1,6 +1,5 @@
#include "macro-condition-plugin-state.hpp"
#include "macro-helpers.hpp"
#include "plugin-state-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -34,7 +33,7 @@ const static std::map<MacroConditionPluginState::Condition, std::string>
MacroConditionPluginState::~MacroConditionPluginState()
{
if (_condition == Condition::OBS_SHUTDOWN) {
GetShutdownConditionCount()--;
switcher->shutdownConditionCount--;
}
}
@@ -42,15 +41,15 @@ bool MacroConditionPluginState::CheckCondition()
{
switch (_condition) {
case Condition::PLUGIN_SCENE_CHANGE:
return MacroSwitchedScene();
return switcher->macroSceneSwitched;
case Condition::PLUGIN_RUNNING:
return true;
case Condition::OBS_SHUTDOWN:
return OBSIsShuttingDown();
return switcher->obsIsShuttingDown;
case Condition::PLUGIN_START:
return IsFirstInterval();
return switcher->firstInterval;
case Condition::PLUGIN_RESTART:
return IsFirstIntervalAfterStop();
return switcher->firstIntervalAfterStop;
case Condition::SCENE_COLLECTION_CHANGE:
if (_firstCheckAfterSceneCollectionChange) {
_firstCheckAfterSceneCollectionChange = false;
@@ -84,33 +83,25 @@ bool MacroConditionPluginState::Load(obs_data_t *obj)
obs_data_get_int(obj, "condition"));
switch (oldValue) {
case PluginStateCondition::SCENE_SWITCHED:
SetCondition(Condition::PLUGIN_SCENE_CHANGE);
_condition = Condition::PLUGIN_SCENE_CHANGE;
break;
case PluginStateCondition::RUNNING:
SetCondition(Condition::PLUGIN_RUNNING);
_condition = Condition::PLUGIN_RUNNING;
break;
case PluginStateCondition::SHUTDOWN:
SetCondition(Condition::OBS_SHUTDOWN);
_condition = Condition::OBS_SHUTDOWN;
break;
}
} else {
SetCondition(static_cast<Condition>(
obs_data_get_int(obj, "condition")));
_condition = static_cast<Condition>(
obs_data_get_int(obj, "condition"));
}
if (_condition == Condition::OBS_SHUTDOWN) {
switcher->shutdownConditionCount++;
}
return true;
}
void MacroConditionPluginState::SetCondition(Condition newValue)
{
if (_condition == Condition::OBS_SHUTDOWN) {
GetShutdownConditionCount()--;
}
if (newValue == Condition::OBS_SHUTDOWN) {
GetShutdownConditionCount()++;
}
_condition = newValue;
}
static inline void populateConditionSelection(QComboBox *list)
{
for (const auto &[action, name] : pluginStateConditionTypes) {
@@ -157,9 +148,17 @@ void MacroConditionPluginStateEdit::ConditionChanged(int idx)
}
auto lock = LockContext();
_entryData->SetCondition(
if (_entryData->_condition ==
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
switcher->shutdownConditionCount--;
}
_entryData->_condition =
static_cast<MacroConditionPluginState::Condition>(
_condition->itemData(idx).toInt()));
_condition->itemData(idx).toInt());
if (_entryData->_condition ==
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
switcher->shutdownConditionCount++;
}
SetWidgetVisibility();
}
@@ -169,15 +168,15 @@ void MacroConditionPluginStateEdit::UpdateEntryData()
return;
}
_condition->setCurrentIndex(_condition->findData(
static_cast<int>(_entryData->GetCondition())));
_condition->setCurrentIndex(
_condition->findData(static_cast<int>(_entryData->_condition)));
SetWidgetVisibility();
}
void MacroConditionPluginStateEdit::SetWidgetVisibility()
{
_shutdownLimitation->setVisible(
_entryData->GetCondition() ==
_entryData->_condition ==
MacroConditionPluginState::Condition::OBS_SHUTDOWN);
adjustSize();
updateGeometry();

View File

@@ -26,11 +26,10 @@ public:
SCENE_COLLECTION_CHANGE,
PLUGIN_SCENE_CHANGE,
};
void SetCondition(Condition);
Condition GetCondition() const { return _condition; }
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
private:
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
bool _firstCheckAfterSceneCollectionChange = true;
const static uint32_t _version;

View File

@@ -1,4 +1,5 @@
#include "macro-condition-process.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
@@ -171,9 +172,8 @@ void MacroConditionProcessEdit::FocusChanged(int state)
void MacroConditionProcessEdit::UpdateFocusProcess()
{
std::string name;
GetForegroundProcessName(name);
_focusProcess->setText(QString::fromStdString(name));
_focusProcess->setText(
QString::fromStdString(switcher->currentForegroundProcess));
}
void MacroConditionProcessEdit::SetWidgetVisibility()

View File

@@ -178,8 +178,6 @@ bool SetupRecordingTimer()
case OBS_FRONTEND_EVENT_RECORDING_UNPAUSED:
recordingPaused = false;
break;
default:
break;
};
};
obs_frontend_add_event_callback(handleRecordingEvents, nullptr);

View File

@@ -1,4 +1,5 @@
#include "macro-condition-replay-buffer.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -10,63 +11,35 @@ bool MacroConditionReplayBuffer::_registered = MacroConditionFactory::Register(
MacroConditionReplayBufferEdit::Create,
"AdvSceneSwitcher.condition.replay"});
const static std::map<MacroConditionReplayBuffer::Condition, std::string>
conditions = {
{MacroConditionReplayBuffer::Condition::STOP,
"AdvSceneSwitcher.condition.replay.state.stopped"},
{MacroConditionReplayBuffer::Condition::START,
"AdvSceneSwitcher.condition.replay.state.started"},
{MacroConditionReplayBuffer::Condition::SAVE,
"AdvSceneSwitcher.condition.replay.state.saved"},
const static std::map<ReplayBufferState, std::string> ReplayBufferStates = {
{ReplayBufferState::STOP,
"AdvSceneSwitcher.condition.replay.state.stopped"},
{ReplayBufferState::START,
"AdvSceneSwitcher.condition.replay.state.started"},
{ReplayBufferState::SAVE,
"AdvSceneSwitcher.condition.replay.state.saved"},
};
static bool replayBufferSaved = false;
static std::chrono::high_resolution_clock::time_point replayBufferSaveTime{};
static bool setupReplayBufferEventHandler();
static bool replayBufferEventHandlerIsSetup = setupReplayBufferEventHandler();
static bool setupReplayBufferEventHandler()
{
static auto handleReplayBufferEvent = [](enum obs_frontend_event event,
void *) {
switch (event) {
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
replayBufferSaveTime =
std::chrono::high_resolution_clock::now();
break;
default:
break;
};
};
obs_frontend_add_event_callback(handleReplayBufferEvent, nullptr);
return true;
}
bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
{
bool timersAreInitialized =
_saveTime.time_since_epoch().count() != 0 &&
replayBufferSaveTime.time_since_epoch().count() != 0;
bool newSaveOccurred = timersAreInitialized &&
_saveTime != replayBufferSaveTime;
_saveTime = replayBufferSaveTime;
return newSaveOccurred;
}
bool MacroConditionReplayBuffer::CheckCondition()
{
bool stateMatch = false;
switch (_state) {
case Condition::STOP:
return !obs_frontend_replay_buffer_active();
case Condition::START:
return obs_frontend_replay_buffer_active();
case Condition::SAVE:
return ReplayBufferWasSaved();
case ReplayBufferState::STOP:
stateMatch = !obs_frontend_replay_buffer_active();
break;
case ReplayBufferState::START:
stateMatch = obs_frontend_replay_buffer_active();
break;
case ReplayBufferState::SAVE:
if (switcher->replayBufferSaved) {
stateMatch = true;
switcher->replayBufferSaved = false;
}
break;
default:
break;
}
return false;
return stateMatch;
}
bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
@@ -79,30 +52,37 @@ bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_state = static_cast<Condition>(obs_data_get_int(obj, "state"));
_state = static_cast<ReplayBufferState>(obs_data_get_int(obj, "state"));
return true;
}
static inline void populateStateSelection(QComboBox *list)
{
for (const auto &entry : conditions) {
for (auto entry : ReplayBufferStates) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
MacroConditionReplayBufferEdit::MacroConditionReplayBufferEdit(
QWidget *parent, std::shared_ptr<MacroConditionReplayBuffer> entryData)
: QWidget(parent), _state(new QComboBox())
: QWidget(parent)
{
_state = new QComboBox();
QWidget::connect(_state, SIGNAL(currentIndexChanged(int)), this,
SLOT(StateChanged(int)));
populateStateSelection(_state);
auto layout = new QHBoxLayout;
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{state}}", _state},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.replay.entry"),
layout, {{"{{state}}", _state}});
setLayout(layout);
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
@@ -116,8 +96,7 @@ void MacroConditionReplayBufferEdit::StateChanged(int value)
}
auto lock = LockContext();
_entryData->_state =
static_cast<MacroConditionReplayBuffer::Condition>(value);
_entryData->_state = static_cast<ReplayBufferState>(value);
}
void MacroConditionReplayBufferEdit::UpdateEntryData()

View File

@@ -6,6 +6,12 @@
namespace advss {
enum class ReplayBufferState {
STOP,
START,
SAVE,
};
class MacroConditionReplayBuffer : public MacroCondition {
public:
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
@@ -18,18 +24,9 @@ public:
return std::make_shared<MacroConditionReplayBuffer>(m);
}
enum class Condition {
STOP,
START,
SAVE,
};
Condition _state = Condition::STOP;
ReplayBufferState _state = ReplayBufferState::STOP;
private:
bool ReplayBufferWasSaved();
std::chrono::high_resolution_clock::time_point _saveTime = {};
static bool _registered;
static const std::string id;
};

View File

@@ -2,6 +2,7 @@
#include "utility.hpp"
#include <QProcess>
#include <QDesktopServices>
namespace advss {
@@ -27,18 +28,17 @@ bool MacroConditionRun::CheckCondition()
bool ret = false;
switch (_error) {
case ProcessConfig::ProcStartError::FAILED_TO_START:
switch (_procStatus) {
case MacroConditionRun::Status::FAILED_TO_START:
SetVariableValue("Failed to start process");
ret = false;
break;
case ProcessConfig::ProcStartError::TIMEOUT:
case MacroConditionRun::Status::TIMEOUT:
SetVariableValue("Timeout while running process");
ret = false;
break;
case ProcessConfig::ProcStartError::CRASH:
SetVariableValue("Timeout while running process");
break;
case ProcessConfig::ProcStartError::NONE:
ret = _checkExitCode ? _exitCodeToCheck == _procExitCode : true;
case MacroConditionRun::Status::OK:
ret = _checkExitCode ? _exitCode == _procExitCode : true;
SetVariableValue(std::to_string(_procExitCode));
break;
default:
@@ -56,14 +56,42 @@ bool MacroConditionRun::CheckCondition()
void MacroConditionRun::RunProcess()
{
auto result = _procConfig.StartProcessAndWait(_timeout.Milliseconds());
QProcess process;
process.setWorkingDirectory(
QString::fromStdString(_procConfig.WorkingDir()));
process.start(QString::fromStdString(_procConfig.Path()),
_procConfig.Args());
int timeout = _timeout.Milliseconds();
if (std::holds_alternative<ProcessConfig::ProcStartError>(result)) {
_error = std::get<ProcessConfig::ProcStartError>(result);
} else {
_error = ProcessConfig::ProcStartError::NONE;
_procExitCode = std::get<int>(result);
vblog(LOG_INFO, "run \"%s\" with a timeout of %d ms",
_procConfig.Path().c_str(), timeout);
bool procFinishedInTime = process.waitForFinished(timeout);
if (!procFinishedInTime) {
if (process.error() == QProcess::FailedToStart) {
vblog(LOG_INFO, "failed to start \"%s\"!",
_procConfig.Path().c_str());
_procStatus = Status::FAILED_TO_START;
} else {
vblog(LOG_INFO,
"timeout while running \"%s\"\nAttempting to kill process!",
_procConfig.Path().c_str());
process.kill();
process.waitForFinished();
_procStatus = Status::TIMEOUT;
}
}
bool validExitCode = process.exitStatus() == QProcess::NormalExit;
if ((_checkExitCode && !validExitCode) || !procFinishedInTime) {
_threadDone = true;
return;
}
_procExitCode = process.exitCode();
_procStatus = Status::OK;
_threadDone = true;
}
@@ -72,7 +100,7 @@ bool MacroConditionRun::Save(obs_data_t *obj) const
MacroCondition::Save(obj);
_procConfig.Save(obj);
obs_data_set_bool(obj, "checkExitCode", _checkExitCode);
obs_data_set_int(obj, "exitCode", _exitCodeToCheck);
obs_data_set_int(obj, "exitCode", _exitCode);
_timeout.Save(obj, "timeout");
return true;
}
@@ -82,7 +110,7 @@ bool MacroConditionRun::Load(obs_data_t *obj)
MacroCondition::Load(obj);
_procConfig.Load(obj);
_checkExitCode = obs_data_get_bool(obj, "checkExitCode");
_exitCodeToCheck = obs_data_get_int(obj, "exitCode");
_exitCode = obs_data_get_int(obj, "exitCode");
_timeout.Load(obj, "timeout");
return true;
}
@@ -146,7 +174,7 @@ void MacroConditionRunEdit::UpdateEntryData()
_procConfig->SetProcessConfig(_entryData->_procConfig);
_timeout->SetDuration(_entryData->_timeout);
_checkExitCode->setChecked(_entryData->_checkExitCode);
_exitCode->setValue(_entryData->_exitCodeToCheck);
_exitCode->setValue(_entryData->_exitCode);
}
void MacroConditionRunEdit::TimeoutChanged(const Duration &dur)
@@ -176,7 +204,7 @@ void MacroConditionRunEdit::ExitCodeChanged(int exitCode)
}
auto lock = LockContext();
_entryData->_exitCodeToCheck = exitCode;
_entryData->_exitCode = exitCode;
}
void MacroConditionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)

View File

@@ -25,15 +25,22 @@ public:
ProcessConfig _procConfig;
bool _checkExitCode = true;
int _exitCodeToCheck = 0;
int _exitCode = 0;
Duration _timeout = Duration(0.1);
private:
enum class Status {
NONE,
FAILED_TO_START,
TIMEOUT,
OK,
};
void RunProcess();
std::thread _thread;
std::atomic_bool _threadDone{true};
ProcessConfig::ProcStartError _error =
ProcessConfig::ProcStartError::NONE;
Status _procStatus = Status::NONE;
int _procExitCode = 0;
static bool _registered;

View File

@@ -1,5 +1,5 @@
#include "macro-condition-scene.hpp"
#include "scene-switch-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -53,22 +53,23 @@ static OBSWeakSource getCurrentSceneHelper(bool useTransitionTargetScene)
obs_source_release(current);
return weak;
}
return GetCurrentScene();
return switcher->currentScene;
}
static OBSWeakSource getPreviousSceneHelper(bool useTransitionTargetScene)
{
if (AnySceneTransitionStarted() && useTransitionTargetScene) {
return GetCurrentScene();
if (switcher->AnySceneTransitionStarted() && useTransitionTargetScene) {
return switcher->currentScene;
}
return GetPreviousScene();
return switcher->previousScene;
}
bool MacroConditionScene::CheckCondition()
{
bool sceneChanged = _lastSceneChangeTime != GetLastSceneChangeTime();
bool sceneChanged = _lastSceneChangeTime !=
switcher->lastSceneChangeTime;
if (sceneChanged) {
_lastSceneChangeTime = GetLastSceneChangeTime();
_lastSceneChangeTime = switcher->lastSceneChangeTime;
}
switch (_type) {
@@ -94,14 +95,14 @@ bool MacroConditionScene::CheckCondition()
return scene == _scene.GetScene(false);
}
case Type::CHANGED:
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
SetVariableValue(GetWeakSourceName(switcher->currentScene));
SetTempVarValue("current",
GetWeakSourceName(GetCurrentScene()));
GetWeakSourceName(switcher->currentScene));
return sceneChanged;
case Type::NOT_CHANGED:
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
SetVariableValue(GetWeakSourceName(switcher->currentScene));
SetTempVarValue("current",
GetWeakSourceName(GetCurrentScene()));
GetWeakSourceName(switcher->currentScene));
return !sceneChanged;
case Type::CURRENT_PATTERN: {
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
@@ -188,8 +189,8 @@ bool MacroConditionScene::Load(obs_data_t *obj)
break;
default:
blog(LOG_WARNING,
"failed to convert scene condition type (%d)",
oldType);
"failed to convert scene condition type (%d) for macro %s",
oldType, GetMacro()->Name().c_str());
_type = Type::CURRENT;
break;
}

View File

@@ -1,4 +1,5 @@
#include "macro-condition-streaming.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -24,32 +25,6 @@ const static std::map<MacroConditionStream::Condition, std::string>
"AdvSceneSwitcher.condition.stream.state.keyFrameInterval"},
};
static bool setupStreamingEventHandler();
static bool steamingEventHandlerIsSetup = setupStreamingEventHandler();
static std::chrono::high_resolution_clock::time_point streamStartTime{};
static std::chrono::high_resolution_clock::time_point streamStopTime{};
bool setupStreamingEventHandler()
{
static auto handleStreamingEvents = [](enum obs_frontend_event event,
void *) {
switch (event) {
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
streamStartTime =
std::chrono::high_resolution_clock::now();
break;
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
streamStopTime =
std::chrono::high_resolution_clock::now();
break;
default:
break;
};
};
obs_frontend_add_event_callback(handleStreamingEvents, nullptr);
return true;
}
int MacroConditionStream::GetKeyFrameInterval()
{
const auto configPath = GetPathInProfileDir("streamEncoder.json");
@@ -67,8 +42,10 @@ bool MacroConditionStream::CheckCondition()
{
bool match = false;
bool streamStarting = streamStartTime != _lastStreamStartingTime;
bool streamStopping = streamStopTime != _lastStreamStoppingTime;
bool streamStarting = switcher->lastStreamStartingTime !=
_lastStreamStartingTime;
bool streamStopping = switcher->lastStreamStoppingTime !=
_lastStreamStoppingTime;
switch (_condition) {
case Condition::STOP:
@@ -91,10 +68,10 @@ bool MacroConditionStream::CheckCondition()
}
if (streamStarting) {
_lastStreamStartingTime = streamStartTime;
_lastStreamStartingTime = switcher->lastStreamStartingTime;
}
if (streamStopping) {
_lastStreamStoppingTime = streamStopTime;
_lastStreamStoppingTime = switcher->lastStreamStoppingTime;
}
return match;
}

View File

@@ -1,5 +1,5 @@
#include "macro-condition-transition.hpp"
#include "scene-switch-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -50,8 +50,8 @@ static bool isTargetScene(OBSWeakSource &target)
bool MacroConditionTransition::CheckCondition()
{
bool anyTransitionEnded = _lastTransitionEndTime !=
GetLastTransitionEndTime();
bool anyTransitionStarted = AnySceneTransitionStarted();
switcher->lastTransitionEndTime;
bool anyTransitionStarted = switcher->AnySceneTransitionStarted();
bool transitionStarted = false;
bool transitionEnded = false;
@@ -82,7 +82,7 @@ bool MacroConditionTransition::CheckCondition()
break;
case TransitionCondition::TRANSITION_SOURCE:
ret = anyTransitionStarted &&
_scene.GetScene() == GetCurrentScene();
_scene.GetScene() == switcher->currentScene;
break;
case TransitionCondition::TRANSITION_TARGET: {
auto scene = _scene.GetScene();
@@ -101,7 +101,7 @@ bool MacroConditionTransition::CheckCondition()
_ended = false;
}
if (anyTransitionEnded) {
_lastTransitionEndTime = GetLastTransitionEndTime();
_lastTransitionEndTime = switcher->lastTransitionEndTime;
}
return ret;

View File

@@ -1,4 +1,5 @@
#include "macro-condition-websocket.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <regex>

View File

@@ -1,5 +1,5 @@
#include "macro-condition-window.hpp"
#include "plugin-state-helpers.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
@@ -43,8 +43,7 @@ static bool windowContainsText(const std::string &window,
bool MacroConditionWindow::WindowMatchesRequirements(
const std::string &window) const
{
const bool focusCheckOK =
(!_focus || window == ForegroundWindowTitle());
const bool focusCheckOK = (!_focus || window == switcher->currentTitle);
if (!focusCheckOK) {
return false;
}
@@ -105,13 +104,13 @@ void MacroConditionWindow::SetVariableValueBasedOnMatch(
auto text = GetTextInWindow(matchWindow);
SetVariableValue(text.value_or(""));
} else {
SetVariableValue(ForegroundWindowTitle());
SetVariableValue(switcher->currentTitle);
}
}
static bool foregroundWindowChanged()
{
return ForegroundWindowTitle() != PreviousForegroundWindowTitle();
return switcher->currentTitle != switcher->lastTitle;
}
bool MacroConditionWindow::CheckCondition()
@@ -433,7 +432,7 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state)
void MacroConditionWindowEdit::UpdateFocusWindow()
{
_focusWindow->setText(QString::fromStdString(ForegroundWindowTitle()));
_focusWindow->setText(QString::fromStdString(switcher->currentTitle));
}
void MacroConditionWindowEdit::SetWidgetVisibility()

View File

@@ -1,59 +0,0 @@
#include "macro-helpers.hpp"
#include "plugin-state-helpers.hpp"
namespace advss {
static std::atomic_bool abortMacroWait = {false};
static std::atomic_bool macroSceneSwitched = {false};
static std::atomic_int shutdownConditionCount = {0};
std::condition_variable &GetMacroWaitCV()
{
static std::condition_variable cv;
return cv;
}
std::condition_variable &GetMacroTransitionCV()
{
static std::condition_variable cv;
return cv;
}
std::atomic_bool &MacroWaitShouldAbort()
{
return abortMacroWait;
}
void SetMacroAbortWait(bool value)
{
abortMacroWait = value;
}
bool ShutdownCheckIsNecessary()
{
return shutdownConditionCount > 0;
}
std::atomic_int &GetShutdownConditionCount()
{
return shutdownConditionCount;
}
void SetMacroSwitchedScene(bool value)
{
static bool setupDone = false;
if (!setupDone) {
// Will always be called with switcher lock already held
AddIntervalResetStep([]() { macroSceneSwitched = false; },
false);
setupDone = true;
}
macroSceneSwitched = value;
}
bool MacroSwitchedScene()
{
return macroSceneSwitched;
}
} // namespace advss

View File

@@ -1,21 +0,0 @@
#pragma once
#include <atomic>
#include <condition_variable>
#include <string_view>
namespace advss {
constexpr std::string_view GetSceneSwitchActionId()
{
return "scene_switch";
}
std::condition_variable &GetMacroWaitCV();
std::condition_variable &GetMacroTransitionCV();
std::atomic_bool &MacroWaitShouldAbort();
void SetMacroAbortWait(bool);
bool ShutdownCheckIsNecessary();
std::atomic_int &GetShutdownConditionCount();
void SetMacroSwitchedScene(bool value);
bool MacroSwitchedScene();
} // namespace advss

View File

@@ -9,8 +9,6 @@
namespace advss {
static MacroProperties macroProperties;
void MacroProperties::Save(obs_data_t *obj) const
{
auto data = obs_data_create();
@@ -327,19 +325,4 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
return true;
}
MacroProperties &GetGlobalMacroProperties()
{
return macroProperties;
}
void SaveGlobalMacroProperties(obs_data_t *obj)
{
macroProperties.Save(obj);
}
void LoadGlobalMacroProperties(obs_data_t *obj)
{
macroProperties.Load(obj);
}
} // namespace advss

View File

@@ -68,8 +68,4 @@ private:
int _conditionsFalseTextRow = -1;
};
MacroProperties &GetGlobalMacroProperties();
void SaveGlobalMacroProperties(obs_data_t *obj);
void LoadGlobalMacroProperties(obs_data_t *obj);
} // namespace advss

View File

@@ -44,28 +44,8 @@ MacroSegmentList::~MacroSegmentList()
}
}
static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
{
if (!scrollbar) {
return false;
}
if (!scrollbar->isVisible()) {
return false;
}
const auto geo = scrollbar->geometry();
const auto globalGeo = QRect(scrollbar->mapToGlobal(geo.topLeft()),
scrollbar->mapToGlobal(geo.bottomRight()));
return globalGeo.contains(pos);
}
int MacroSegmentList::GetDragIndex(const QPoint &pos)
{
// Don't drag widget when interacting with the scrollbars
if (posIsInScrollbar(horizontalScrollBar(), mapTo(this, pos)) ||
posIsInScrollbar(verticalScrollBar(), mapTo(this, pos))) {
return -1;
}
for (int idx = 0; idx < _contentLayout->count(); ++idx) {
auto item = _contentLayout->itemAt(idx);
if (!item) {
@@ -181,7 +161,7 @@ void MacroSegmentList::mousePressEvent(QMouseEvent *event)
#else
_dragPosition = GetDragIndex(event->globalPosition().toPoint());
#endif
emit SelectionChanged(_dragPosition);
emit SelectionChagned(_dragPosition);
} else {
_dragPosition = -1;
}

View File

@@ -28,7 +28,7 @@ public:
QVBoxLayout *ContentLayout() { return _contentLayout; }
signals:
void SelectionChanged(int idx);
void SelectionChagned(int idx);
void Reorder(int source, int target);
protected:

View File

@@ -4,7 +4,7 @@
// so it makes sense to include them here:
#include "log-helper.hpp"
#include "obs-module-helper.hpp"
#include "sync-helpers.hpp"
#include "sync-helper.hpp"
#include "temp-variable.hpp"
#include <QWidget>

View File

@@ -1,6 +1,6 @@
#include "macro-selection.hpp"
#include "macro.hpp"
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <QStandardItemModel>
@@ -12,7 +12,7 @@ MacroSelection::MacroSelection(QWidget *parent)
: FilterComboBox(parent,
obs_module_text("AdvSceneSwitcher.selectMacro"))
{
for (const auto &m : GetMacros()) {
for (const auto &m : switcher->macros) {
if (m->IsGroup()) {
continue;
}

View File

@@ -63,7 +63,7 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
}
res = std::make_shared<Macro>(
name, GetGlobalMacroProperties()._newMacroRegisterHotkeys);
name, switcher->macroProperties._newMacroRegisterHotkeys);
return true;
}
@@ -197,8 +197,8 @@ static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> &macros,
subitems.reserve(group->GroupSize());
// Find all subitems
auto allMacros = GetMacros();
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
for (auto it = switcher->macros.begin(); it < switcher->macros.end();
it++) {
if ((*it)->Name() == group->Name()) {
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
subitems.emplace_back(*std::next(it, i));
@@ -243,7 +243,7 @@ void AdvSceneSwitcher::ExportMacros()
obs_data_array_push_back(macroArray, obj);
}
obs_data_set_array(data, "macros", macroArray);
SaveVariables(data);
switcher->SaveVariables(data);
obs_data_set_string(data, "version", g_GIT_TAG);
auto json = obs_data_get_json(data);
QString exportString(json);
@@ -382,7 +382,7 @@ static void importVariables(obs_data_t *obj)
if (variableWithNameExists(var->Name())) {
continue;
}
GetVariables().emplace_back(var);
switcher->variables.emplace_back(var);
}
}
@@ -429,7 +429,7 @@ void AdvSceneSwitcher::ImportMacros()
}
importedMacros.emplace_back(macro);
GetMacros().emplace_back(macro);
switcher->macros.emplace_back(macro);
if (groupSize > 0 && !macro->IsGroup()) {
Macro::PrepareMoveToGroup(group, macro);
groupSize--;
@@ -449,8 +449,8 @@ void AdvSceneSwitcher::ImportMacros()
macro->PostLoad();
}
ui->macros->Reset(GetMacros(),
GetGlobalMacroProperties()._highlightExecuted);
ui->macros->Reset(switcher->macros,
switcher->macroProperties._highlightExecuted);
}
void AdvSceneSwitcher::on_macroName_editingFinished()
@@ -729,8 +729,8 @@ void AdvSceneSwitcher::MacroSelectionChanged()
void AdvSceneSwitcher::HighlightOnChange()
{
if (!GetGlobalMacroProperties()._highlightActions &&
!GetGlobalMacroProperties()._highlightExecuted) {
if (!switcher->macroProperties._highlightActions &&
!switcher->macroProperties._highlightExecuted) {
return;
}
@@ -747,13 +747,13 @@ void AdvSceneSwitcher::HighlightOnChange()
void AdvSceneSwitcher::on_macroProperties_clicked()
{
MacroProperties prop = GetGlobalMacroProperties();
MacroProperties prop = switcher->macroProperties;
bool accepted = MacroPropertiesDialog::AskForSettings(
this, prop, GetSelectedMacro().get());
if (!accepted) {
return;
}
GetGlobalMacroProperties() = prop;
switcher->macroProperties = prop;
emit HighlightMacrosChanged(prop._highlightExecuted);
emit HighlightActionsChanged(prop._highlightActions);
emit HighlightConditionsChanged(prop._highlightConditions);
@@ -789,11 +789,11 @@ void AdvSceneSwitcher::SetupMacroTab()
{
ui->macroElseActions->installEventFilter(this);
if (GetMacros().size() == 0 && !switcher->disableHints) {
if (switcher->macros.size() == 0 && !switcher->disableHints) {
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
}
ui->macros->Reset(GetMacros(),
GetGlobalMacroProperties()._highlightExecuted);
ui->macros->Reset(switcher->macros,
switcher->macroProperties._highlightExecuted);
connect(ui->macros, SIGNAL(MacroSelectionAboutToChange()), this,
SLOT(MacroSelectionAboutToChange()));
connect(ui->macros, SIGNAL(MacroSelectionChanged()), this,
@@ -802,21 +802,21 @@ void AdvSceneSwitcher::SetupMacroTab()
ui->conditionsList->SetHelpMsg(
obs_module_text("AdvSceneSwitcher.macroTab.editConditionHelp"));
connect(ui->conditionsList, &MacroSegmentList::SelectionChanged, this,
connect(ui->conditionsList, &MacroSegmentList::SelectionChagned, this,
&AdvSceneSwitcher::MacroConditionSelectionChanged);
connect(ui->conditionsList, &MacroSegmentList::Reorder, this,
&AdvSceneSwitcher::MacroConditionReorder);
ui->actionsList->SetHelpMsg(
obs_module_text("AdvSceneSwitcher.macroTab.editActionHelp"));
connect(ui->actionsList, &MacroSegmentList::SelectionChanged, this,
connect(ui->actionsList, &MacroSegmentList::SelectionChagned, this,
&AdvSceneSwitcher::MacroActionSelectionChanged);
connect(ui->actionsList, &MacroSegmentList::Reorder, this,
&AdvSceneSwitcher::MacroActionReorder);
ui->elseActionsList->SetHelpMsg(obs_module_text(
"AdvSceneSwitcher.macroTab.editElseActionHelp"));
connect(ui->elseActionsList, &MacroSegmentList::SelectionChanged, this,
connect(ui->elseActionsList, &MacroSegmentList::SelectionChagned, this,
&AdvSceneSwitcher::MacroElseActionSelectionChanged);
connect(ui->elseActionsList, &MacroSegmentList::Reorder, this,
&AdvSceneSwitcher::MacroElseActionReorder);

View File

@@ -1,7 +1,7 @@
#include "macro-tree.hpp"
#include "macro.hpp"
#include "sync-helpers.hpp"
#include "utility.hpp"
#include "switcher-data.hpp"
#include <obs.h>
#include <string>
@@ -395,7 +395,7 @@ CountItemsVisibleInModel(const std::deque<std::shared_ptr<Macro>> &macros)
void MacroTreeModel::Add(std::shared_ptr<Macro> item)
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto idx = CountItemsVisibleInModel(_macros);
beginInsertRows(QModelIndex(), idx, idx);
_macros.emplace_back(item);
@@ -408,7 +408,7 @@ void MacroTreeModel::Add(std::shared_ptr<Macro> item)
void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto uiStartIdx = GetItemModelIndex(item);
if (uiStartIdx == -1) {
return;
@@ -643,7 +643,7 @@ void MacroTreeModel::GroupSelectedItems(QModelIndexList &indices)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
QString name = GetNewGroupName();
std::vector<std::shared_ptr<Macro>> itemsToGroup;
itemsToGroup.reserve(indices.size());
@@ -691,7 +691,7 @@ void MacroTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
for (int i = indices.count() - 1; i >= 0; i--) {
std::shared_ptr<Macro> item = _macros[ModelIndexToMacroIndex(
indices[i].row(), _macros)];
@@ -1055,7 +1055,7 @@ void MacroTree::dropEvent(QDropEvent *event)
}
// Move items in backend
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
int to = row;
try {
to = ModelIndexToMacroIndex(row, items);
@@ -1181,7 +1181,7 @@ void MacroTree::Remove(std::shared_ptr<Macro> item) const
void MacroTree::Up(std::shared_ptr<Macro> item) const
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto above = GetModel()->Neighbor(item, true);
if (!above) {
return;
@@ -1207,7 +1207,7 @@ void MacroTree::Up(std::shared_ptr<Macro> item) const
void MacroTree::Down(std::shared_ptr<Macro> item) const
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
auto below = GetModel()->Neighbor(item, false);
if (!below) {
return;

View File

@@ -1,24 +1,20 @@
#include "macro.hpp"
#include "macro-action-factory.hpp"
#include "macro-condition-factory.hpp"
#include "macro-action-edit.hpp"
#include "macro-condition-edit.hpp"
#include "macro-dock.hpp"
#include "macro-helpers.hpp"
#include "plugin-state-helpers.hpp"
#include "macro-action-scene-switch.hpp"
#include "switcher-data.hpp"
#include "hotkey.hpp"
#include "sync-helpers.hpp"
#include "utility.hpp"
#include <limits>
#undef max
#include <chrono>
#include <unordered_map>
#include <QAction>
#include <QMainWindow>
namespace advss {
static constexpr int perfLogThreshold = 300;
static std::deque<std::shared_ptr<Macro>> macros;
constexpr int perfLogThreshold = 300;
Macro::Macro(const std::string &name, const bool addHotkey)
{
@@ -37,7 +33,7 @@ Macro::~Macro()
// Keep the dock widgets in case of shutdown so they can be restored by
// OBS on startup
if (!OBSIsShuttingDown()) {
if (!switcher->obsIsShuttingDown) {
RemoveDock();
}
}
@@ -57,8 +53,9 @@ Macro::CreateGroup(const std::string &name,
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
{
auto it = std::find(macros.begin(), macros.end(), group);
if (it == macros.end()) {
auto it = std::find(switcher->macros.begin(), switcher->macros.end(),
group);
if (it == switcher->macros.end()) {
return;
}
@@ -68,12 +65,12 @@ void Macro::RemoveGroup(std::shared_ptr<Macro> group)
(*m)->SetParent(nullptr);
}
macros.erase(it);
switcher->macros.erase(it);
}
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
{
for (const auto &m : macros) {
for (auto &m : switcher->macros) {
if (m.get() == group) {
PrepareMoveToGroup(m, item);
return;
@@ -354,7 +351,7 @@ void Macro::AddHelperThread(std::thread &&newThread)
void Macro::Stop()
{
_stop = true;
GetMacroWaitCV().notify_all();
switcher->macroWaitCv.notify_all();
for (auto &t : _helperThreads) {
if (t.joinable()) {
t.join();
@@ -746,13 +743,15 @@ bool Macro::PostLoad()
bool Macro::SwitchesScene() const
{
MacroActionSwitchScene temp(nullptr);
auto sceneSwitchId = temp.GetId();
for (const auto &a : _actions) {
if (a->GetId() == GetSceneSwitchActionId()) {
if (a->GetId() == sceneSwitchId) {
return true;
}
}
for (const auto &a : _elseActions) {
if (a->GetId() == GetSceneSwitchActionId()) {
if (a->GetId() == sceneSwitchId) {
return true;
}
}
@@ -948,7 +947,7 @@ void Macro::EnableDock(bool value)
// geometry set here.
// The function calls here are only intended to attempt to restore the
// dock status when switching scene collections.
if (InitialLoadIsComplete()) {
if (switcher->startupLoadDone) {
_dock->setVisible(_dockIsVisible);
if (window->dockWidgetArea(_dock) != _dockArea) {
window->addDockWidget(_dockArea, _dock);
@@ -1164,10 +1163,12 @@ void Macro::SetHotkeysDesc() const
_name, _togglePauseHotkey);
}
void SaveMacros(obs_data_t *obj)
void SwitcherData::SaveMacros(obs_data_t *obj)
{
switcher->macroProperties.Save(obj);
obs_data_array_t *macroArray = obs_data_array_create();
for (const auto &m : macros) {
for (auto &m : macros) {
obs_data_t *array_obj = obs_data_create();
m->Save(array_obj);
@@ -1179,9 +1180,10 @@ void SaveMacros(obs_data_t *obj)
obs_data_array_release(macroArray);
}
void LoadMacros(obs_data_t *obj)
void SwitcherData::LoadMacros(obs_data_t *obj)
{
Hotkey::ClearAllHotkeys();
switcher->macroProperties.Load(obj);
macros.clear();
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
@@ -1198,7 +1200,7 @@ void LoadMacros(obs_data_t *obj)
int groupCount = 0;
std::shared_ptr<Macro> group;
std::vector<std::shared_ptr<Macro>> invalidGroups;
for (const auto &m : macros) {
for (auto &m : macros) {
if (groupCount && m->IsGroup()) {
blog(LOG_ERROR,
"nested group detected - will delete \"%s\"",
@@ -1233,28 +1235,23 @@ void LoadMacros(obs_data_t *obj)
}
}
std::deque<std::shared_ptr<Macro>> &GetMacros()
bool SwitcherData::CheckMacros()
{
return macros;
}
bool CheckMacros()
{
bool matchFound = false;
for (const auto &m : macros) {
bool ret = false;
for (auto &m : macros) {
if (m->CeckMatch() || m->ElseActions().size() > 0) {
matchFound = true;
ret = true;
// This has to be performed here for now as actions are
// not performed immediately after checking conditions.
if (m->SwitchesScene()) {
SetMacroSwitchedScene(true);
switcher->macroSceneSwitched = true;
}
}
}
return matchFound;
return ret;
}
bool RunMacros()
bool SwitcherData::RunMacros()
{
// Create copy of macro list as elements might be removed, inserted, or
// reordered while macros are currently being executed.
@@ -1272,16 +1269,15 @@ bool RunMacros()
// the constructor of AdvSceneSwitcher() to complete.
// The constructor of AdvSceneSwitcher() cannot continue however as it
// cannot lock the main switcher mutex.
auto lock = GetLoopLock();
if (lock) {
lock->unlock();
if (GetLock()) {
GetLock()->unlock();
}
for (auto &m : runPhaseMacros) {
if (!m || !m->ShouldRunActions()) {
continue;
}
if (IsFirstInterval() && m->SkipExecOnStart()) {
if (firstInterval && m->SkipExecOnStart()) {
blog(LOG_INFO,
"skip execution of macro \"%s\" at startup",
m->Name().c_str());
@@ -1292,15 +1288,15 @@ bool RunMacros()
blog(LOG_WARNING, "abort macro: %s", m->Name().c_str());
}
}
if (lock) {
lock->lock();
if (GetLock()) {
GetLock()->lock();
}
return true;
}
Macro *GetMacroByName(const char *name)
{
for (const auto &m : macros) {
for (auto &m : switcher->macros) {
if (m->Name() == name) {
return m.get();
}
@@ -1316,7 +1312,7 @@ Macro *GetMacroByQString(const QString &name)
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
{
for (const auto &m : macros) {
for (auto &m : switcher->macros) {
if (m->Name() == name) {
return m;
}
@@ -1327,7 +1323,7 @@ std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
void InvalidateMacroTempVarValues()
{
for (const auto &m : macros) {
for (auto &m : switcher->macros) {
m->InvalidateTempVarValues();
}
}

View File

@@ -202,11 +202,6 @@ private:
QAction *_dockAction = nullptr;
};
void LoadMacros(obs_data_t *obj);
void SaveMacros(obs_data_t *obj);
std::deque<std::shared_ptr<Macro>> &GetMacros();
bool CheckMacros();
bool RunMacros();
Macro *GetMacroByName(const char *name);
Macro *GetMacroByQString(const QString &name);
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);

View File

@@ -3,8 +3,8 @@
#include <utility.hpp>
#include <log-helper.hpp>
#include <obs-module-helper.hpp>
#include <plugin-state-helpers.hpp>
#include <sync-helpers.hpp>
#include <plugin-state-helper.hpp>
#include <sync-helper.hpp>
namespace advss {

View File

@@ -3,7 +3,7 @@
#include "twitch-helpers.hpp"
#include <log-helper.hpp>
#include <plugin-state-helpers.hpp>
#include <plugin-state-helper.hpp>
namespace advss {

View File

@@ -3,7 +3,7 @@
#include "twitch-helpers.hpp"
#include <log-helper.hpp>
#include <plugin-state-helpers.hpp>
#include <plugin-state-helper.hpp>
namespace advss {

View File

@@ -1,7 +1,7 @@
#include "token.hpp"
#include "twitch-helpers.hpp"
#include <plugin-state-helpers.hpp>
#include <plugin-state-helper.hpp>
#include <log-helper.hpp>
#include <obs-module-helper.hpp>
#include <utility.hpp>

View File

@@ -1,7 +1,7 @@
#include "macro-condition-video.hpp"
#include <macro-condition-edit.hpp>
#include <plugin-state-helpers.hpp>
#include <switcher-data.hpp>
#include <utility.hpp>
#include <QFileDialog>
@@ -222,8 +222,8 @@ void MacroConditionVideo::GetScreenshot(bool blocking)
_areaParameters.area.width,
_areaParameters.area.height);
}
new (&_screenshotData) ScreenshotHelper(source, screenshotArea,
blocking, GetIntervalValue());
new (&_screenshotData) ScreenshotHelper(
source, screenshotArea, blocking, GetSwitcher()->interval);
obs_source_release(source);
_getNextScreenshot = false;
}
@@ -1110,9 +1110,9 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
"AdvSceneSwitcher.condition.video.patternMatchMode.tip"));
populatePatternMatchModeSelection(_patternMatchMode);
_throttleCount->setMinimum(1 * GetIntervalValue());
_throttleCount->setMaximum(10 * GetIntervalValue());
_throttleCount->setSingleStep(GetIntervalValue());
_throttleCount->setMinimum(1 * GetSwitcher()->interval);
_throttleCount->setMaximum(10 * GetSwitcher()->interval);
_throttleCount->setSingleStep(GetSwitcher()->interval);
_brightness->setSizePolicy(QSizePolicy::MinimumExpanding,
QSizePolicy::Preferred);
@@ -1507,7 +1507,7 @@ void MacroConditionVideoEdit::ThrottleCountChanged(int value)
}
auto lock = LockContext();
_entryData->_throttleCount = value / GetIntervalValue();
_entryData->_throttleCount = value / GetSwitcher()->interval;
}
void MacroConditionVideoEdit::ShowMatchClicked()
@@ -1629,7 +1629,7 @@ void MacroConditionVideoEdit::UpdateEntryData()
_entryData->_patternMatchParameters.matchMode));
_throttleEnable->setChecked(_entryData->_throttleEnabled);
_throttleCount->setValue(_entryData->_throttleCount *
GetIntervalValue());
GetSwitcher()->interval);
UpdatePreviewTooltip();
SetupPreviewDialogParams();
SetWidgetVisibility();

View File

@@ -383,9 +383,6 @@ static std::map<HotkeyType, CGKeyCode> keyTable = {
{HotkeyType::Key_8, kVK_ANSI_8},
{HotkeyType::Key_9, kVK_ANSI_9},
// Other
// Not sure which key to use for tilde
{HotkeyType::Key_F1, kVK_F1},
{HotkeyType::Key_F2, kVK_F2},
{HotkeyType::Key_F3, kVK_F3},

View File

@@ -1,5 +1,5 @@
#include "status-control.hpp"
#include "plugin-state-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <obs-module.h>
@@ -51,10 +51,10 @@ StatusControl::StatusControl(QWidget *parent, bool noLayout)
setLayout(layout);
}
if (PluginIsRunning()) {
SetStarted();
} else {
if (switcher->stop) {
SetStopped();
} else {
SetStarted();
}
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdateStatus()));
_timer.start(1000);
@@ -62,18 +62,22 @@ StatusControl::StatusControl(QWidget *parent, bool noLayout)
void StatusControl::ButtonClicked()
{
if (PluginIsRunning()) {
StopPlugin();
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
} else {
StartPlugin();
switcher->Start();
SetStarted();
}
}
void StatusControl::UpdateStatus()
{
if (PluginIsRunning()) {
if (!switcher) {
return;
}
if (switcher->th && switcher->th->isRunning()) {
if (!_setToStopped) {
return;
}
@@ -100,7 +104,7 @@ void StatusControl::SetStopped()
_button->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
_status->setText(obs_module_text("AdvSceneSwitcher.status.inactive"));
if (HighlightUIElementsEnabled()) {
if (!switcher->disableHints) {
_pulse = PulseWidget(_status, QColor(Qt::red),
QColor(0, 0, 0, 0));
}

View File

@@ -14,11 +14,6 @@ std::mutex *GetSwitcherMutex()
return switcher ? &switcher->m : nullptr;
}
std::unique_lock<std::mutex> *GetSwitcherLoopLock()
{
return switcher ? switcher->mainLoopLock : nullptr;
}
bool VerboseLoggingEnabled()
{
return switcher ? switcher->verbose : false;
@@ -173,13 +168,8 @@ void SwitcherData::SaveVersion(obs_data_t *obj,
obs_data_set_string(obj, "version", currentVersion.c_str());
}
void SwitcherData::AddIntervalResetStep(std::function<void()> function,
bool tryLock)
void SwitcherData::AddIntervalResetStep(std::function<void()> function)
{
if (!tryLock) {
resetIntervalSteps.emplace_back(function);
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
resetIntervalSteps.emplace_back(function);
}

View File

@@ -18,9 +18,10 @@
#include "macro-properties.hpp"
#include "duration-control.hpp"
#include "curl-helper.hpp"
#include "priority-helper.hpp"
#include "log-helper.hpp"
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include <condition_variable>
#include <vector>
@@ -28,6 +29,7 @@
#include <mutex>
#include <QDateTime>
#include <QThread>
#include <curl/curl.h>
#include <unordered_map>
namespace advss {
@@ -45,7 +47,6 @@ class SwitcherData;
extern SwitcherData *switcher;
SwitcherData *GetSwitcher();
std::mutex *GetSwitcherMutex();
std::unique_lock<std::mutex> *GetSwitcherLoopLock();
bool VerboseLoggingEnabled();
class SwitcherData {
@@ -53,6 +54,7 @@ public:
void Thread();
void Start();
void Stop();
std::unique_lock<std::mutex> *GetLock() { return mainLoopLock; }
const char *Translate(const char *);
obs_module_t *GetModule();
@@ -66,22 +68,28 @@ public:
void AddSaveStep(std::function<void(obs_data_t *)>);
void AddLoadStep(std::function<void(obs_data_t *)>);
void AddPostLoadStep(std::function<void()>);
void AddIntervalResetStep(std::function<void()>, bool lock = true);
void AddIntervalResetStep(std::function<void()>);
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
int &linger, bool &setPreviousSceneAsMatch,
bool &macroMatch);
bool CheckMacros();
bool RunMacros();
void CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, int &sleep);
/* --- Start of saving / loading section --- */
void SaveSettings(obs_data_t *obj);
void SaveMacros(obs_data_t *obj);
void SaveVariables(obs_data_t *obj);
void SaveGeneralSettings(obs_data_t *obj);
void SaveHotkeys(obs_data_t *obj);
void SaveUISettings(obs_data_t *obj);
void SaveVersion(obs_data_t *obj, const std::string &currentVersion);
void LoadSettings(obs_data_t *obj);
void LoadMacros(obs_data_t *obj);
void LoadVariables(obs_data_t *obj);
void LoadGeneralSettings(obs_data_t *obj);
void LoadHotkeys(obs_data_t *obj);
void LoadUISettings(obs_data_t *obj);
@@ -102,6 +110,9 @@ public:
std::unique_lock<std::mutex> *mainLoopLock = nullptr;
bool stop = false;
std::condition_variable cv;
std::condition_variable macroWaitCv;
std::atomic_bool abortMacroWait = {false};
std::condition_variable macroTransitionCv;
std::vector<std::function<void(obs_data_t *)>> saveSteps;
std::vector<std::function<void(obs_data_t *)>> loadSteps;
@@ -111,14 +122,21 @@ public:
bool firstBoot = true;
bool transitionActive = false;
bool sceneColletionStop = false;
bool replayBufferSaved = false;
bool obsIsShuttingDown = false;
bool firstInterval = true;
bool firstIntervalAfterStop = true;
int shutdownConditionCount = 0;
bool startupLoadDone = false;
obs_source_t *waitScene = nullptr;
OBSWeakSource currentScene = nullptr;
OBSWeakSource previousScene = nullptr;
std::chrono::high_resolution_clock::time_point lastSceneChangeTime{};
std::chrono::high_resolution_clock::time_point lastTransitionEndTime{};
std::chrono::high_resolution_clock::time_point lastStreamStartingTime{};
std::chrono::high_resolution_clock::time_point lastStreamStoppingTime{};
std::chrono::high_resolution_clock::time_point lastMatchTime;
/* --- Start of General tab section --- */
@@ -143,9 +161,25 @@ public:
/* --- End of General tab section --- */
struct AudioFadeInfo {
std::atomic_bool active = {false};
std::atomic_int id = {0};
};
AudioFadeInfo masterAudioFade;
std::unordered_map<std::string, AudioFadeInfo> activeAudioFades;
MacroProperties macroProperties;
std::deque<std::shared_ptr<Macro>> macros;
bool macroSceneSwitched = false;
Curlhelper curl;
std::deque<std::shared_ptr<Item>> variables;
std::string lastTitle;
std::string currentTitle;
std::string currentForegroundProcess;
std::pair<int, int> lastCursorPos = {0, 0};
bool cursorPosChanged = false;
std::vector<int> functionNamesByPriority =
GetDefaultFunctionPriorityList();

View File

@@ -1,7 +1,7 @@
#include "connection-manager.hpp"
#include "utility.hpp"
#include "obs-module-helper.hpp"
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include "name-dialog.hpp"
#include <algorithm>

View File

@@ -15,7 +15,7 @@ constexpr auto curl_library_name = "libcurl.4.dylib";
constexpr auto curl_library_name = "libcurl.so.4";
#endif
CurlHelper::CurlHelper()
Curlhelper::Curlhelper()
{
if (LoadLib()) {
_curl = _init();
@@ -23,7 +23,7 @@ CurlHelper::CurlHelper()
}
}
CurlHelper::~CurlHelper()
Curlhelper::~Curlhelper()
{
if (_lib) {
if (_cleanup) {
@@ -34,46 +34,32 @@ CurlHelper::~CurlHelper()
}
}
CurlHelper &CurlHelper::GetInstance()
curl_slist *Curlhelper::SlistAppend(curl_slist *list, const char *string)
{
static CurlHelper curl;
return curl;
}
bool CurlHelper::Initialized()
{
return GetInstance()._initialized;
}
curl_slist *CurlHelper::SlistAppend(curl_slist *list, const char *string)
{
auto &curl = GetInstance();
if (!curl._initialized) {
if (!_initialized) {
return nullptr;
}
return curl._slistAppend(list, string);
return _slistAppend(list, string);
}
CURLcode CurlHelper::Perform()
CURLcode Curlhelper::Perform()
{
auto &curl = GetInstance();
if (!curl._initialized) {
if (!_initialized) {
return CURLE_FAILED_INIT;
}
return curl._perform(curl._curl);
return _perform(_curl);
}
char *CurlHelper::GetError(CURLcode code)
char *Curlhelper::GetError(CURLcode code)
{
auto &curl = GetInstance();
if (!curl._initialized) {
if (!_initialized) {
return (char *)"CURL initialization failed";
}
return curl._error(code);
return _error(code);
}
bool CurlHelper::LoadLib()
bool Curlhelper::LoadLib()
{
_lib = new QLibrary(curl_library_name, nullptr);
if (Resolve()) {
@@ -117,7 +103,7 @@ bool CurlHelper::LoadLib()
return false;
}
bool CurlHelper::Resolve()
bool Curlhelper::Resolve()
{
_init = (initFunction)_lib->resolve("curl_easy_init");
_setopt = (setOptFunction)_lib->resolve("curl_easy_setopt");

View File

@@ -1,35 +1,31 @@
#pragma once
#include <curl/curl.h>
#include <QLibrary>
#include <atomic>
namespace advss {
class CurlHelper {
typedef CURL *(*initFunction)(void);
typedef CURLcode (*setOptFunction)(CURL *, CURLoption, ...);
typedef struct curl_slist *(*slistAppendFunction)(struct curl_slist *list,
const char *string);
typedef CURLcode (*performFunction)(CURL *);
typedef void (*cleanupFunction)(CURL *);
typedef char *(*errorFunction)(CURLcode);
class Curlhelper {
public:
static bool Initialized();
template<typename... Args> static CURLcode SetOpt(CURLoption, Args...);
static struct curl_slist *SlistAppend(struct curl_slist *list,
const char *string);
static CURLcode Perform();
static char *GetError(CURLcode code);
Curlhelper();
~Curlhelper();
bool Initialized() { return _initialized; }
template<typename... Args> CURLcode SetOpt(CURLoption, Args...);
struct curl_slist *SlistAppend(struct curl_slist *list,
const char *string);
CURLcode Perform();
char *GetError(CURLcode code);
private:
CurlHelper();
CurlHelper(const CurlHelper &) = delete;
CurlHelper &operator=(const CurlHelper &) = delete;
~CurlHelper();
typedef CURL *(*initFunction)(void);
typedef CURLcode (*setOptFunction)(CURL *, CURLoption, ...);
typedef struct curl_slist *(*slistAppendFunction)(
struct curl_slist *list, const char *string);
typedef CURLcode (*performFunction)(CURL *);
typedef void (*cleanupFunction)(CURL *);
typedef char *(*errorFunction)(CURLcode);
static CurlHelper &GetInstance();
bool LoadLib();
bool Resolve();
@@ -41,17 +37,16 @@ private:
errorFunction _error = nullptr;
CURL *_curl = nullptr;
QLibrary *_lib;
std::atomic_bool _initialized = {false};
bool _initialized = false;
};
template<typename... Args>
inline CURLcode CurlHelper::SetOpt(CURLoption option, Args... args)
inline CURLcode Curlhelper::SetOpt(CURLoption option, Args... args)
{
auto &curl = GetInstance();
if (!curl._initialized) {
if (!_initialized) {
return CURLE_FAILED_INIT;
}
return curl._setopt(curl._curl, option, args...);
return _setopt(_curl, option, args...);
}
} // namespace advss

View File

@@ -54,7 +54,7 @@ FilterComboBox::FilterComboBox(QWidget *parent, const QString &placehodler)
connect(c, QOverload<const QModelIndex &>::of(&QCompleter::highlighted),
this, &FilterComboBox::CompleterHighlightChanged);
connect(lineEdit(), &QLineEdit::textChanged, this,
&FilterComboBox::TextChanged);
&FilterComboBox::TextChagned);
}
void FilterComboBox::SetFilterBehaviourEnabled(bool value)
@@ -108,7 +108,7 @@ void FilterComboBox::CompleterHighlightChanged(const QModelIndex &index)
emit currentTextChanged(text);
}
void FilterComboBox::TextChanged(const QString &text)
void FilterComboBox::TextChagned(const QString &text)
{
auto c = completer();
const bool completerActive = c->completionCount() > 0;

View File

@@ -19,7 +19,7 @@ protected:
private slots:
void CompleterHighlightChanged(const QModelIndex &);
void TextChanged(const QString &);
void TextChagned(const QString &);
private:
int _lastCompleterHighlightRow = -1;

View File

@@ -1,7 +1,7 @@
#include "macro-segment-selection.hpp"
#include "advanced-scene-switcher.hpp"
#include "obs-module-helper.hpp"
#include "plugin-state-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -108,7 +108,7 @@ void MacroSegmentSelection::IndexChanged(const IntVariable &value)
void MacroSegmentSelection::MarkSelectedSegment()
{
if (!HighlightUIElementsEnabled()) {
if (!GetSwitcher() || GetSwitcher()->disableHints) {
return;
}

View File

@@ -1,4 +1,4 @@
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include "switcher-data.hpp"
namespace advss {
@@ -23,9 +23,9 @@ void AddPostLoadStep(std::function<void()> step)
GetSwitcher()->AddPostLoadStep(step);
}
void AddIntervalResetStep(std::function<void()> step, bool lock)
void AddIntervalResetStep(std::function<void()> step)
{
GetSwitcher()->AddIntervalResetStep(step, lock);
GetSwitcher()->AddIntervalResetStep(step);
}
void StopPlugin()
@@ -38,40 +38,19 @@ void StartPlugin()
GetSwitcher()->Start();
}
bool PluginIsRunning()
{
return GetSwitcher() && GetSwitcher()->th &&
GetSwitcher()->th->isRunning();
}
int GetIntervalValue()
{
return GetSwitcher()->interval;
}
void SetPluginNoMatchBehavior(NoMatchBehavior behavior)
{
GetSwitcher()->switchIfNotMatching = behavior;
}
NoMatchBehavior GetPluginNoMatchBehavior()
{
return GetSwitcher()->switchIfNotMatching;
}
void SetNoMatchScene(const OBSWeakSource &scene)
{
GetSwitcher()->nonMatchingScene = scene;
}
std::string ForegroundWindowTitle()
NoMatchBehavior GetPluginNoMatchBehavior()
{
return GetSwitcher()->currentTitle;
}
std::string PreviousForegroundWindowTitle()
{
return GetSwitcher()->lastTitle;
return GetSwitcher()->switchIfNotMatching;
}
bool SettingsWindowIsOpened()
@@ -79,29 +58,4 @@ bool SettingsWindowIsOpened()
return GetSwitcher()->settingsWindowOpened;
}
bool HighlightUIElementsEnabled()
{
return GetSwitcher() && !GetSwitcher()->disableHints;
}
bool OBSIsShuttingDown()
{
return GetSwitcher()->obsIsShuttingDown;
}
bool InitialLoadIsComplete()
{
return GetSwitcher()->startupLoadDone;
}
bool IsFirstInterval()
{
return GetSwitcher()->firstInterval;
}
bool IsFirstIntervalAfterStop()
{
return GetSwitcher()->firstIntervalAfterStop;
}
} // namespace advss

View File

@@ -1,7 +1,6 @@
#pragma once
#include <functional>
#include <obs.hpp>
#include <string>
namespace advss {
@@ -10,27 +9,16 @@ void LoadPluginSettings(obs_data_t *);
void AddSaveStep(std::function<void(obs_data_t *)>);
void AddLoadStep(std::function<void(obs_data_t *)>);
void AddPostLoadStep(std::function<void()>);
void AddIntervalResetStep(std::function<void()>, bool lock = true);
void AddIntervalResetStep(std::function<void()>);
void StopPlugin();
void StartPlugin();
bool PluginIsRunning();
int GetIntervalValue();
enum class NoMatchBehavior { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 };
void SetPluginNoMatchBehavior(NoMatchBehavior);
NoMatchBehavior GetPluginNoMatchBehavior();
void SetNoMatchScene(const OBSWeakSource &);
std::string ForegroundWindowTitle();
std::string PreviousForegroundWindowTitle();
bool SettingsWindowIsOpened();
bool HighlightUIElementsEnabled();
bool OBSIsShuttingDown();
bool InitialLoadIsComplete();
bool IsFirstInterval();
bool IsFirstIntervalAfterStop();
} // namespace advss

View File

@@ -1,5 +1,4 @@
#include "process-config.hpp"
#include "log-helper.hpp"
#include "name-dialog.hpp"
#include "utility.hpp"
@@ -38,7 +37,7 @@ bool ProcessConfig::Load(obs_data_t *obj)
return true;
}
QStringList ProcessConfig::Args() const
QStringList ProcessConfig::Args()
{
QStringList result;
for (auto &arg : _args) {
@@ -47,42 +46,6 @@ QStringList ProcessConfig::Args() const
return result;
}
bool ProcessConfig::StartProcessDetached() const
{
return QProcess::startDetached(QString::fromStdString(Path()), Args(),
QString::fromStdString(WorkingDir()));
}
std::variant<int, ProcessConfig::ProcStartError>
ProcessConfig::StartProcessAndWait(int timeout) const
{
QProcess process;
process.setWorkingDirectory(QString::fromStdString(WorkingDir()));
process.start(QString::fromStdString(Path()), Args());
vblog(LOG_INFO, "run \"%s\" with a timeout of %d ms", Path().c_str(),
timeout);
if (!process.waitForFinished(timeout)) {
if (process.error() == QProcess::FailedToStart) {
vblog(LOG_INFO, "failed to start \"%s\"!",
Path().c_str());
return ProcStartError::FAILED_TO_START;
}
vblog(LOG_INFO,
"timeout while running \"%s\"\nAttempting to kill process!",
Path().c_str());
process.kill();
process.waitForFinished();
return ProcStartError::TIMEOUT;
}
if (process.exitStatus() == QProcess::NormalExit) {
return process.exitCode();
}
vblog(LOG_INFO, "process \"%s\" crashed!", Path().c_str());
return ProcStartError::CRASH;
}
ProcessConfigEdit::ProcessConfigEdit(QWidget *parent)
: QWidget(parent),
_filePath(new FileSelection()),
@@ -128,7 +91,7 @@ ProcessConfigEdit::ProcessConfigEdit(QWidget *parent)
_advancedSettingsLayout->addWidget(_argList);
_advancedSettingsLayout->addLayout(workingDirectoryLayout);
auto mainLayout = new QVBoxLayout;
auto *mainLayout = new QVBoxLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addLayout(entryLayout);
mainLayout->addLayout(_advancedSettingsLayout);
@@ -180,9 +143,6 @@ void ProcessConfigEdit::ShowAdvancedSettings(bool showAdvancedSettings)
_showAdvancedSettings->setVisible(!showAdvancedSettings);
adjustSize();
updateGeometry();
if (showAdvancedSettings) {
emit AdvancedSettingsEnabled();
}
}
} // namespace advss

View File

@@ -3,13 +3,12 @@
#include "string-list.hpp"
#include <obs-data.h>
#include <obs-module-helper.hpp>
#include <obs-module.h>
#include <QPushButton>
#include <QListWidget>
#include <QStringList>
#include <QVBoxLayout>
#include <variant>
namespace advss {
@@ -18,21 +17,10 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string Path() const { return _path; }
std::string Path() { return _path; }
std::string UnresolvedPath() const { return _path.UnresolvedValue(); }
std::string WorkingDir() const { return _workingDirectory; }
QStringList Args() const; // Resolves variables
enum class ProcStartError {
NONE,
FAILED_TO_START,
TIMEOUT,
CRASH,
};
std::variant<int, ProcStartError>
StartProcessAndWait(int timeoutInMs) const;
bool StartProcessDetached() const;
std::string WorkingDir() { return _workingDirectory; }
QStringList Args(); // Resolves variables
private:
StringVariable _path = obs_module_text("AdvSceneSwitcher.enterPath");
@@ -56,7 +44,6 @@ private slots:
void ArgsChanged(const StringList &);
signals:
void ConfigChanged(const ProcessConfig &);
void AdvancedSettingsEnabled();
private:
void ShowAdvancedSettings(bool);

View File

@@ -51,6 +51,23 @@ RegexConfig::GetRegularExpression(const std::string &expr) const
return GetRegularExpression(QString::fromStdString(expr));
}
bool RegexConfig::Matches(const QString &text, const QString &expression) const
{
auto regex = GetRegularExpression(expression);
if (!regex.isValid()) {
return false;
}
auto match = regex.match(text);
return match.hasMatch();
}
bool RegexConfig::Matches(const std::string &text,
const std::string &expression) const
{
return Matches(QString::fromStdString(text),
QString::fromStdString(expression));
}
RegexConfig RegexConfig::PartialMatchRegexConfig()
{
RegexConfig conf;

View File

@@ -29,6 +29,9 @@ public:
};
QRegularExpression GetRegularExpression(const QString &) const;
QRegularExpression GetRegularExpression(const std::string &) const;
bool Matches(const QString &text, const QString &expression) const;
bool Matches(const std::string &text,
const std::string &expression) const;
static RegexConfig PartialMatchRegexConfig();

View File

@@ -1,7 +1,6 @@
#include "resizing-text-edit.hpp"
#include <obs-module-helper.hpp>
#include <QScrollBar>
#include <obs-module.h>
#include <utility.hpp>
namespace advss {
@@ -15,12 +14,10 @@ ResizingPlainTextEdit::ResizingPlainTextEdit(QWidget *parent,
_minLines(minLines),
_paddingLines(paddingLines)
{
setWordWrapMode(QTextOption::NoWrap);
QWidget::connect(this, SIGNAL(textChanged()), this,
SLOT(ResizeTexteditArea()));
QWidget::connect(this, SIGNAL(textChanged()), this,
SLOT(PreventExceedingMaxLength()));
verticalScrollBar()->installEventFilter(this);
}
int ResizingPlainTextEdit::maxLength()
@@ -33,35 +30,19 @@ void ResizingPlainTextEdit::setMaxLength(int maxLength)
_maxLength = maxLength;
}
bool ResizingPlainTextEdit::eventFilter(QObject *obj, QEvent *event)
{
if (obj == horizontalScrollBar()) {
if (event->type() == QEvent::Show) {
AddHeightForScrollBar(true);
} else if (event->type() == QEvent::Hide) {
AddHeightForScrollBar(false);
}
}
return QPlainTextEdit::eventFilter(obj, event);
}
void ResizingPlainTextEdit::ResizeTexteditArea()
{
QFontMetrics f(font());
int rowHeight = f.lineSpacing();
int numLines = document()->blockCount();
int height = 0;
if (numLines + _paddingLines < _minLines) {
height = _minLines * rowHeight;
setFixedHeight(_minLines * rowHeight);
} else if (numLines + _paddingLines < _scrollAt) {
height = (numLines + _paddingLines) * rowHeight;
setFixedHeight((numLines + _paddingLines) * rowHeight);
} else {
height = _scrollAt * rowHeight;
setFixedHeight(_scrollAt * rowHeight);
}
setFixedHeight(height + _hScrollBarAddedHeight);
adjustSize();
updateGeometry();
}
@@ -81,21 +62,4 @@ void ResizingPlainTextEdit::PreventExceedingMaxLength()
}
}
void ResizingPlainTextEdit::AddHeightForScrollBar(bool addHeight)
{
if (!addHeight) {
setFixedHeight(height() - _hScrollBarAddedHeight);
_hScrollBarAddedHeight = 0;
return;
}
// Check if we have already added space for the scroll bar
if (_hScrollBarAddedHeight > 0) {
return;
}
_hScrollBarAddedHeight = verticalScrollBar()->height();
setFixedHeight(height() + _hScrollBarAddedHeight);
}
} // namespace advss

View File

@@ -13,21 +13,15 @@ public:
int maxLength();
void setMaxLength(int maxLength);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private slots:
void ResizeTexteditArea();
void PreventExceedingMaxLength();
private:
void AddHeightForScrollBar(bool addHeight);
const int _scrollAt;
const int _minLines;
const int _paddingLines;
int _maxLength = -1;
int _hScrollBarAddedHeight = 0;
};
} // namespace advss

View File

@@ -1,7 +1,5 @@
#include "scene-selection.hpp"
#include "obs-module-helper.hpp"
#include "scene-group.hpp"
#include "scene-switch-helpers.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
@@ -110,9 +108,9 @@ OBSWeakSource SceneSelection::GetScene(bool advance) const
}
return _group->getCurrentScene();
case Type::PREVIOUS:
return GetPreviousScene();
return switcher->previousScene;
case Type::CURRENT:
return GetCurrentScene();
return switcher->currentScene;
case Type::PREVIEW: {
auto s = obs_frontend_get_current_preview_scene();
auto scene = obs_source_get_weak_source(s);
@@ -239,7 +237,7 @@ static QStringList getScenesList()
static QStringList getSceneGroupsList()
{
QStringList list;
for (const auto &sg : GetSceneGroups()) {
for (const auto &sg : switcher->sceneGroups) {
list << QString::fromStdString(sg.name);
}
list.sort();

View File

@@ -1,36 +1,10 @@
#include "scene-switch-helpers.hpp"
#include "log-helper.hpp"
#include "obs-frontend-api.h"
#include "switcher-data.hpp"
#include "obs-frontend-api.h"
#include "utility.hpp"
namespace advss {
static std::chrono::high_resolution_clock::time_point lastSceneChangeTime{};
static std::chrono::high_resolution_clock::time_point lastTransitionEndTime{};
static bool setupEventHandler();
static bool eventHandlerIsSetup = setupEventHandler();
static bool setupEventHandler()
{
static auto handleEvents = [](enum obs_frontend_event event, void *) {
switch (event) {
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
lastSceneChangeTime =
std::chrono::high_resolution_clock::now();
break;
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
lastTransitionEndTime =
std::chrono::high_resolution_clock::now();
break;
default:
break;
};
};
obs_frontend_add_event_callback(handleEvents, nullptr);
return true;
}
static std::pair<obs_weak_source_t *, int>
getNextTransition(obs_weak_source_t *scene1, obs_weak_source_t *scene2)
{
@@ -61,9 +35,10 @@ void SetNextTransition(const SceneSwitchInfo &sceneSwitch,
// 3. Current transition settings
// Transition Tab
OBSWeakSourceAutoRelease currentScene =
obs_weak_source_t *currentScene =
obs_source_get_weak_source(currentSource);
auto tinfo = getNextTransition(currentScene, sceneSwitch.scene);
obs_weak_source_release(currentScene);
OBSWeakSource nextTransition = tinfo.first;
int nextTransitionDuration = tinfo.second;
@@ -78,23 +53,23 @@ void SetNextTransition(const SceneSwitchInfo &sceneSwitch,
// Current transition settings
if (!nextTransition) {
OBSSourceAutoRelease currentTransition =
obs_frontend_get_current_transition();
nextTransition = obs_source_get_weak_source(currentTransition);
auto ct = obs_frontend_get_current_transition();
nextTransition = obs_source_get_weak_source(ct);
obs_weak_source_release(nextTransition);
obs_source_release(ct);
}
if (!nextTransitionDuration) {
nextTransitionDuration = obs_frontend_get_transition_duration();
}
if (ShouldModifyActiveTransition()) {
if (switcher->adjustActiveTransitionType) {
obs_frontend_set_transition_duration(nextTransitionDuration);
OBSSourceAutoRelease transition =
obs_weak_source_get_source(nextTransition);
obs_frontend_set_current_transition(transition);
auto t = obs_weak_source_get_source(nextTransition);
obs_frontend_set_current_transition(t);
obs_source_release(t);
}
if (ShouldModifyTransitionOverrides()) {
if (switcher->transitionOverrideOverride) {
OverwriteTransitionOverride({sceneSwitch.scene, nextTransition,
nextTransitionDuration},
td);
@@ -103,8 +78,8 @@ void SetNextTransition(const SceneSwitchInfo &sceneSwitch,
void OverwriteTransitionOverride(const SceneSwitchInfo &ssi, TransitionData &td)
{
OBSSourceAutoRelease scene = obs_weak_source_get_source(ssi.scene);
OBSDataAutoRelease data = obs_source_get_private_settings(scene);
obs_source_t *scene = obs_weak_source_get_source(ssi.scene);
obs_data_t *data = obs_source_get_private_settings(scene);
td.name = obs_data_get_string(data, "transition");
td.duration = obs_data_get_int(data, "transition_duration");
@@ -113,13 +88,19 @@ void OverwriteTransitionOverride(const SceneSwitchInfo &ssi, TransitionData &td)
obs_data_set_string(data, "transition", name.c_str());
obs_data_set_int(data, "transition_duration", ssi.duration);
obs_data_release(data);
obs_source_release(scene);
}
void RestoreTransitionOverride(obs_source_t *scene, const TransitionData &td)
{
OBSDataAutoRelease data = obs_source_get_private_settings(scene);
obs_data_t *data = obs_source_get_private_settings(scene);
obs_data_set_string(data, "transition", td.name.c_str());
obs_data_set_int(data, "transition_duration", td.duration);
obs_data_release(data);
}
void SwitchScene(const SceneSwitchInfo &sceneSwitch, bool force)
@@ -129,67 +110,36 @@ void SwitchScene(const SceneSwitchInfo &sceneSwitch, bool force)
return;
}
OBSSourceAutoRelease source =
obs_weak_source_get_source(sceneSwitch.scene);
OBSSourceAutoRelease currentSource = obs_frontend_get_current_scene();
obs_source_t *source = obs_weak_source_get_source(sceneSwitch.scene);
obs_source_t *currentSource = obs_frontend_get_current_scene();
if (source && (source != currentSource || force)) {
TransitionData currentTransitionData;
SetNextTransition(sceneSwitch, currentSource,
currentTransitionData);
obs_frontend_set_current_scene(source);
if (ShouldModifyTransitionOverrides()) {
if (switcher->transitionOverrideOverride) {
RestoreTransitionOverride(source,
currentTransitionData);
}
vblog(LOG_INFO, "switched scene");
if (switcher->verbose) {
blog(LOG_INFO, "switched scene");
}
if (switcher->networkConfig.ShouldSendSceneChange()) {
switcher->server.sendMessage(sceneSwitch);
}
}
obs_source_release(currentSource);
obs_source_release(source);
}
void SwitchPreviewScene(const OBSWeakSource &ws)
{
OBSSourceAutoRelease source = obs_weak_source_get_source(ws);
auto source = obs_weak_source_get_source(ws);
obs_frontend_set_current_preview_scene(source);
}
std::chrono::high_resolution_clock::time_point GetLastTransitionEndTime()
{
return lastTransitionEndTime;
}
std::chrono::high_resolution_clock::time_point GetLastSceneChangeTime()
{
return lastSceneChangeTime;
}
OBSWeakSource GetCurrentScene()
{
return switcher->currentScene;
}
OBSWeakSource GetPreviousScene()
{
return switcher->previousScene;
}
bool AnySceneTransitionStarted()
{
return switcher->AnySceneTransitionStarted();
}
bool ShouldModifyTransitionOverrides()
{
return switcher->transitionOverrideOverride;
}
bool ShouldModifyActiveTransition()
{
return switcher->adjustActiveTransitionType;
obs_source_release(source);
}
} // namespace advss

View File

@@ -1,6 +1,5 @@
#pragma once
#include <obs.hpp>
#include <chrono>
#include <string>
namespace advss {
@@ -16,24 +15,12 @@ struct TransitionData {
int duration = 0;
};
void SwitchScene(const SceneSwitchInfo &, bool force = false);
void SwitchPreviewScene(const OBSWeakSource &scene);
std::chrono::high_resolution_clock::time_point GetLastTransitionEndTime();
std::chrono::high_resolution_clock::time_point GetLastSceneChangeTime();
OBSWeakSource GetCurrentScene();
OBSWeakSource GetPreviousScene();
bool ShouldModifyTransitionOverrides();
bool ShouldModifyActiveTransition();
void OverwriteTransitionOverride(const SceneSwitchInfo &, TransitionData &);
void RestoreTransitionOverride(obs_source_t *scene, const TransitionData &);
bool AnySceneTransitionStarted();
// TODO: Remove at some point
void SetNextTransition(const SceneSwitchInfo &, obs_source_t *currentSource,
TransitionData &);
void SetNextTransition(const SceneSwitchInfo &ssi, obs_source_t *currentSource,
TransitionData &td);
void OverwriteTransitionOverride(const SceneSwitchInfo &ssi,
TransitionData &td);
void RestoreTransitionOverride(obs_source_t *scene, const TransitionData &td);
void SwitchScene(const SceneSwitchInfo &ssi, bool force = false);
void SwitchPreviewScene(const OBSWeakSource &ws);
} // namespace advss

View File

@@ -125,7 +125,6 @@ bool Section::eventFilter(QObject *obj, QEvent *event)
// filter will cause a segfault for some reason
SetupAnimations();
}
setMinimumWidth(_content->sizeHint().width());
}
return QObject::eventFilter(obj, event);
}

11
src/utils/sync-helper.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "sync-helper.hpp"
namespace advss {
std::mutex *GetSwitcherMutex();
std::lock_guard<std::mutex> LockContext()
{
return std::lock_guard<std::mutex>(*GetSwitcherMutex());
}
} // namespace advss

View File

@@ -3,8 +3,6 @@
namespace advss {
[[nodiscard]] std::mutex *GetMutex();
[[nodiscard]] std::lock_guard<std::mutex> LockContext();
[[nodiscard]] std::unique_lock<std::mutex> *GetLoopLock();
} // namespace advss

View File

@@ -1,23 +0,0 @@
#include "sync-helpers.hpp"
namespace advss {
std::mutex *GetSwitcherMutex();
std::unique_lock<std::mutex> *GetSwitcherLoopLock();
std::mutex *GetMutex()
{
return GetSwitcherMutex();
}
std::lock_guard<std::mutex> LockContext()
{
return std::lock_guard<std::mutex>(*GetSwitcherMutex());
}
std::unique_lock<std::mutex> *GetLoopLock()
{
return GetSwitcherLoopLock();
}
} // namespace advss

View File

@@ -2,7 +2,7 @@
#include "advanced-scene-switcher.hpp"
#include "macro.hpp"
#include "macro-segment.hpp"
#include "plugin-state-helpers.hpp"
#include "plugin-state-helper.hpp"
#include "utility.hpp"
#include <QVariant>

Some files were not shown because too many files have changed in this diff Show More