mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -05:00
485 lines
12 KiB
C++
485 lines
12 KiB
C++
#pragma once
|
|
#include <condition_variable>
|
|
#include <chrono>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <regex>
|
|
#include <mutex>
|
|
#include <fstream>
|
|
#include <QDateTime>
|
|
#include <QThread>
|
|
#include "utility.hpp"
|
|
|
|
#define DEFAULT_INTERVAL 300
|
|
|
|
#define DEFAULT_IDLE_TIME 60
|
|
|
|
#define PREVIOUS_SCENE_NAME "Previous Scene"
|
|
|
|
#define READ_FILE_FUNC 0
|
|
#define ROUND_TRIP_FUNC 1
|
|
#define IDLE_FUNC 2
|
|
#define EXE_FUNC 3
|
|
#define SCREEN_REGION_FUNC 4
|
|
#define WINDOW_TITLE_FUNC 5
|
|
#define MEDIA_FUNC 6
|
|
#define TIME_FUNC 7
|
|
|
|
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
|
|
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
|
|
#define DEFAULT_PRIORITY_2 IDLE_FUNC
|
|
#define DEFAULT_PRIORITY_3 EXE_FUNC
|
|
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
|
|
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
|
|
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
|
|
#define DEFAULT_PRIORITY_7 TIME_FUNC
|
|
|
|
using namespace std;
|
|
|
|
/********************************************************************************
|
|
* Data structs for each scene switching method
|
|
********************************************************************************/
|
|
struct WindowSceneSwitch {
|
|
OBSWeakSource scene;
|
|
string window;
|
|
OBSWeakSource transition;
|
|
bool fullscreen;
|
|
bool focus;
|
|
|
|
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
|
|
OBSWeakSource transition_, bool fullscreen_, bool focus_)
|
|
: scene(scene_),
|
|
window(window_),
|
|
transition(transition_),
|
|
fullscreen(fullscreen_),
|
|
focus(focus_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct ExecutableSceneSwitch {
|
|
OBSWeakSource mScene;
|
|
OBSWeakSource mTransition;
|
|
QString mExe;
|
|
bool mInFocus;
|
|
|
|
inline ExecutableSceneSwitch(OBSWeakSource scene,
|
|
OBSWeakSource transition,
|
|
const QString &exe, bool inFocus)
|
|
: mScene(scene),
|
|
mTransition(transition),
|
|
mExe(exe),
|
|
mInFocus(inFocus)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct ScreenRegionSwitch {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
int minX, minY, maxX, maxY;
|
|
string regionStr;
|
|
|
|
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
|
OBSWeakSource transition_, int minX_,
|
|
int minY_, int maxX_, int maxY_,
|
|
string regionStr_)
|
|
: scene(scene_),
|
|
transition(transition_),
|
|
minX(minX_),
|
|
minY(minY_),
|
|
maxX(maxX_),
|
|
maxY(maxY_),
|
|
regionStr(regionStr_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct SceneRoundTripSwitch {
|
|
OBSWeakSource scene1;
|
|
OBSWeakSource scene2;
|
|
OBSWeakSource transition;
|
|
int delay;
|
|
bool usePreviousScene;
|
|
string sceneRoundTripStr;
|
|
|
|
inline SceneRoundTripSwitch(OBSWeakSource scene1_,
|
|
OBSWeakSource scene2_,
|
|
OBSWeakSource transition_, int delay_,
|
|
bool usePreviousScene_, string str)
|
|
: scene1(scene1_),
|
|
scene2(scene2_),
|
|
transition(transition_),
|
|
delay(delay_),
|
|
usePreviousScene(usePreviousScene_),
|
|
sceneRoundTripStr(str)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct RandomSwitch {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
double delay;
|
|
string randomSwitchStr;
|
|
|
|
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
double delay_, string str)
|
|
: scene(scene_),
|
|
transition(transition_),
|
|
delay(delay_),
|
|
randomSwitchStr(str)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct SceneTransition {
|
|
OBSWeakSource scene1;
|
|
OBSWeakSource scene2;
|
|
OBSWeakSource transition;
|
|
string sceneTransitionStr;
|
|
|
|
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_,
|
|
OBSWeakSource transition_,
|
|
string sceneTransitionStr_)
|
|
: scene1(scene1_),
|
|
scene2(scene2_),
|
|
transition(transition_),
|
|
sceneTransitionStr(sceneTransitionStr_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct DefaultSceneTransition {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
string sceneTransitionStr;
|
|
|
|
inline DefaultSceneTransition(OBSWeakSource scene_,
|
|
OBSWeakSource transition_,
|
|
string sceneTransitionStr_)
|
|
: scene(scene_),
|
|
transition(transition_),
|
|
sceneTransitionStr(sceneTransitionStr_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct FileSwitch {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
string file;
|
|
string text;
|
|
bool useRegex = false;
|
|
bool useTime = false;
|
|
QDateTime lastMod;
|
|
|
|
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
const char *file_, const char *text_, bool useRegex_,
|
|
bool useTime_)
|
|
: scene(scene_),
|
|
transition(transition_),
|
|
file(file_),
|
|
text(text_),
|
|
useRegex(useRegex_),
|
|
useTime(useTime_),
|
|
lastMod()
|
|
{
|
|
}
|
|
};
|
|
|
|
struct FileIOData {
|
|
bool readEnabled = false;
|
|
string readPath;
|
|
bool writeEnabled = false;
|
|
string writePath;
|
|
};
|
|
|
|
struct IdleData {
|
|
bool idleEnable = false;
|
|
int time = DEFAULT_IDLE_TIME;
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
bool usePreviousScene;
|
|
bool alreadySwitched = false;
|
|
};
|
|
|
|
struct MediaSwitch {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource source;
|
|
OBSWeakSource transition;
|
|
obs_media_state state;
|
|
uint64_t time;
|
|
time_restriction restriction;
|
|
bool matched;
|
|
bool usePreviousScene;
|
|
std::string mediaSwitchStr;
|
|
|
|
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
|
OBSWeakSource transition_, obs_media_state state_,
|
|
time_restriction restriction_, uint64_t time_,
|
|
bool usePreviousScene_, std::string mediaSwitchStr_)
|
|
: scene(scene_),
|
|
source(source_),
|
|
transition(transition_),
|
|
state(state_),
|
|
restriction(restriction_),
|
|
time(time_),
|
|
usePreviousScene(usePreviousScene_),
|
|
mediaSwitchStr(mediaSwitchStr_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TimeSwitch {
|
|
OBSWeakSource scene;
|
|
OBSWeakSource transition;
|
|
QTime time;
|
|
bool matched;
|
|
bool usePreviousScene;
|
|
string timeSwitchStr;
|
|
|
|
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
QTime time_, bool usePreviousScene_,
|
|
string timeSwitchStr_)
|
|
: scene(scene_),
|
|
transition(transition_),
|
|
time(time_),
|
|
usePreviousScene(usePreviousScene_),
|
|
timeSwitchStr(timeSwitchStr_)
|
|
{
|
|
}
|
|
};
|
|
|
|
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
|
|
|
/********************************************************************************
|
|
* SwitcherData
|
|
********************************************************************************/
|
|
struct SwitcherData {
|
|
QThread* th = nullptr;
|
|
condition_variable cv;
|
|
mutex m;
|
|
bool transitionActive = false;
|
|
bool waitForTransition = false;
|
|
condition_variable transitionCv;
|
|
bool startAtLaunch = false;
|
|
bool stop = false;
|
|
|
|
int interval = DEFAULT_INTERVAL;
|
|
|
|
obs_source_t *waitScene = NULL; //scene during which wait started
|
|
OBSWeakSource previousScene = NULL;
|
|
OBSWeakSource PreviousScene2 = NULL;
|
|
OBSWeakSource lastRandomScene;
|
|
OBSWeakSource nonMatchingScene;
|
|
NoMatch switchIfNotMatching = NO_SWITCH;
|
|
|
|
vector<WindowSceneSwitch> windowSwitches;
|
|
vector<string> ignoreIdleWindows;
|
|
string lastTitle;
|
|
|
|
vector<ScreenRegionSwitch> screenRegionSwitches;
|
|
|
|
vector<OBSWeakSource> pauseScenesSwitches;
|
|
|
|
vector<string> pauseWindowsSwitches;
|
|
|
|
vector<string> ignoreWindowsSwitches;
|
|
|
|
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
|
|
|
vector<RandomSwitch> randomSwitches;
|
|
|
|
FileIOData fileIO;
|
|
IdleData idleData;
|
|
vector<FileSwitch> fileSwitches;
|
|
|
|
vector<ExecutableSceneSwitch> executableSwitches;
|
|
|
|
bool autoStopEnable = false;
|
|
OBSWeakSource autoStopScene;
|
|
|
|
vector<SceneTransition> sceneTransitions;
|
|
vector<DefaultSceneTransition> defaultSceneTransitions;
|
|
|
|
vector<MediaSwitch> mediaSwitches;
|
|
|
|
vector<TimeSwitch> timeSwitches;
|
|
|
|
vector<int> functionNamesByPriority = vector<int>{
|
|
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
|
|
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
|
|
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
|
|
|
|
struct ThreadPrio {
|
|
std::string name;
|
|
std::string description;
|
|
uint32_t value;
|
|
};
|
|
|
|
std::vector<ThreadPrio> threadPriorities{
|
|
{"Idle",
|
|
"scheduled only when no other threads are running (lowest CPU load)",
|
|
QThread::IdlePriority},
|
|
{"Lowest", "scheduled less often than LowPriority",
|
|
QThread::LowestPriority},
|
|
{"Low", "scheduled less often than NormalPriority",
|
|
QThread::LowPriority},
|
|
{"Normal", "the default priority of the operating system",
|
|
QThread::NormalPriority},
|
|
{"High", "scheduled more often than NormalPriority",
|
|
QThread::HighPriority},
|
|
{"Highest", "scheduled more often than HighPriority",
|
|
QThread::HighestPriority},
|
|
{"Time critical",
|
|
"scheduled as often as possible (highest CPU load)",
|
|
QThread::TimeCriticalPriority},
|
|
};
|
|
|
|
uint32_t threadPriority = QThread::NormalPriority;
|
|
|
|
void Thread();
|
|
void Start();
|
|
void Stop();
|
|
|
|
bool sceneChangedDuringWait();
|
|
bool prioFuncsValid();
|
|
void writeSceneInfoToFile();
|
|
void setDefaultSceneTransitions();
|
|
void autoStopStreamAndRecording();
|
|
bool checkPause();
|
|
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition,
|
|
unique_lock<mutex> &lock);
|
|
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkExeSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkFileContent(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkRandom(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition, int &delay);
|
|
void checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
void checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
|
OBSWeakSource &transition);
|
|
|
|
void Prune()
|
|
{
|
|
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
|
WindowSceneSwitch &s = windowSwitches[i];
|
|
if (!WeakSourceValid(s.scene) ||
|
|
!WeakSourceValid(s.transition))
|
|
windowSwitches.erase(windowSwitches.begin() +
|
|
i--);
|
|
}
|
|
|
|
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
|
switchIfNotMatching = NO_SWITCH;
|
|
nonMatchingScene = nullptr;
|
|
}
|
|
|
|
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
|
RandomSwitch &s = randomSwitches[i];
|
|
if (!WeakSourceValid(s.scene) ||
|
|
!WeakSourceValid(s.transition))
|
|
randomSwitches.erase(randomSwitches.begin() +
|
|
i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
|
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
|
if (!WeakSourceValid(s.scene) ||
|
|
!WeakSourceValid(s.transition))
|
|
screenRegionSwitches.erase(
|
|
screenRegionSwitches.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
|
OBSWeakSource &scene = pauseScenesSwitches[i];
|
|
if (!WeakSourceValid(scene))
|
|
pauseScenesSwitches.erase(
|
|
pauseScenesSwitches.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++) {
|
|
SceneRoundTripSwitch &s = sceneRoundTripSwitches[i];
|
|
if (!WeakSourceValid(s.scene1) ||
|
|
(!s.usePreviousScene &&
|
|
!WeakSourceValid(s.scene2)) ||
|
|
!WeakSourceValid(s.transition))
|
|
sceneRoundTripSwitches.erase(
|
|
sceneRoundTripSwitches.begin() + i--);
|
|
}
|
|
|
|
if (!WeakSourceValid(autoStopScene)) {
|
|
autoStopScene = nullptr;
|
|
autoStopEnable = false;
|
|
}
|
|
|
|
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
|
SceneTransition &s = sceneTransitions[i];
|
|
if (!WeakSourceValid(s.scene1) ||
|
|
!WeakSourceValid(s.scene2) ||
|
|
!WeakSourceValid(s.transition))
|
|
sceneTransitions.erase(
|
|
sceneTransitions.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
|
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
|
if (!WeakSourceValid(s.scene) ||
|
|
!WeakSourceValid(s.transition))
|
|
defaultSceneTransitions.erase(
|
|
defaultSceneTransitions.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
|
ExecutableSceneSwitch &s = executableSwitches[i];
|
|
if (!WeakSourceValid(s.mScene) ||
|
|
!WeakSourceValid(s.mTransition))
|
|
executableSwitches.erase(
|
|
executableSwitches.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
|
FileSwitch &s = fileSwitches[i];
|
|
if (!WeakSourceValid(s.scene) ||
|
|
!WeakSourceValid(s.transition))
|
|
fileSwitches.erase(fileSwitches.begin() + i--);
|
|
}
|
|
|
|
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
|
TimeSwitch &s = timeSwitches[i];
|
|
if ((!s.usePreviousScene &&
|
|
!WeakSourceValid(s.scene)) ||
|
|
!WeakSourceValid(s.transition))
|
|
timeSwitches.erase(timeSwitches.begin() + i--);
|
|
}
|
|
|
|
if (!idleData.usePreviousScene &&
|
|
!WeakSourceValid(idleData.scene) ||
|
|
!WeakSourceValid(idleData.transition)) {
|
|
idleData.idleEnable = false;
|
|
}
|
|
|
|
for (size_t i = 0; i < mediaSwitches.size(); i++) {
|
|
MediaSwitch &s = mediaSwitches[i];
|
|
if ((!s.usePreviousScene &&
|
|
!WeakSourceValid(s.scene)) ||
|
|
!WeakSourceValid(s.source) ||
|
|
!WeakSourceValid(s.transition))
|
|
mediaSwitches.erase(mediaSwitches.begin() +
|
|
i--);
|
|
}
|
|
}
|
|
inline ~SwitcherData() { Stop(); }
|
|
};
|