diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c624b58..f6f95ffe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,7 @@ if(BUILD_OUT_OF_TREE)
find_package(LibObs REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
+ find_package(Libcurl REQUIRED)
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
@@ -96,14 +97,16 @@ if(BUILD_OUT_OF_TREE)
"${LIBOBS_INCLUDE_DIRS}"
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
${Qt5Core_INCLUDES}
- ${Qt5Widgets_INCLUDES})
+ ${Qt5Widgets_INCLUDES}
+ ${LIBCURL_INCLUDE_DIRS})
target_link_libraries(advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS}
${LIBOBS_LIB}
${LIBOBS_FRONTEND_API_LIB}
Qt5::Core
- Qt5::Widgets)
+ Qt5::Widgets
+ ${LIBCURL_LIBRARIES})
# Additional commands to install the module in the correct place.
# Find all the translation files so we can copy them to the correct
@@ -224,7 +227,8 @@ else ()
${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api
Qt5::Widgets
- libobs)
+ libobs
+ ${LIBCURL_LIBRARIES})
install_obs_plugin(advanced-scene-switcher data)
endif()
diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui
index 091e18eb..b40f4708 100644
--- a/forms/advanced-scene-switcher.ui
+++ b/forms/advanced-scene-switcher.ui
@@ -2234,6 +2234,13 @@
+ -
+
+
+ Please note that if you choose the remote option the scene switcher will try to access the remote location every x ms as specified on the General tab!
+
+
+
-
diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp
index ad3b7865..9ec2944b 100644
--- a/src/advanced-scene-switcher.cpp
+++ b/src/advanced-scene-switcher.cpp
@@ -291,6 +291,9 @@ void SceneSwitcher::loadUI()
ui->fileType->addItem("local");
ui->fileType->addItem("remote");
+ ui->remoteFileWarningLabel->setText(
+ "Note that the scene switcher will try to access the remote location every " +
+ QString::number(switcher->interval) + "ms");
for (auto &s : switcher->fileSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
diff --git a/src/file-switch.cpp b/src/file-switch.cpp
index d193856c..0f72a719 100644
--- a/src/file-switch.cpp
+++ b/src/file-switch.cpp
@@ -115,48 +115,103 @@ void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
}
}
+static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
+ void *userp)
+{
+ ((std::string *)userp)->append((char *)contents, size * nmemb);
+ return size * nmemb;
+}
+
+std::string getRemoteData(std::string &url)
+{
+ CURL *curl;
+ CURLcode res;
+ std::string readBuffer;
+
+ curl = curl_easy_init();
+ if (curl) {
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
+ res = curl_easy_perform(curl);
+ curl_easy_cleanup(curl);
+ }
+ return readBuffer;
+}
+
+bool compareIgnoringLineEnding(QString &s1, QString &s2)
+{
+ /*
+ Im using QTextStream here so the conversion between different lineendings is done by QT.
+ QT itself uses only the linefeed internally so the input by the user is always using that,
+ but the files selected by the user might use different line endings.
+ If you are reading this and know of a cleaner way to do this, please let me know :)
+ */
+ QTextStream s1stream(&s1);
+ QTextStream s2stream(&s2);
+
+ while (!s1stream.atEnd() && !s2stream.atEnd()) {
+ QString s1s = s1stream.readLine();
+ QString s2s = s2stream.readLine();
+ if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool checkRemoteFileContent(FileSwitch &s)
+{
+ std::string data = getRemoteData(s.file);
+ bool ret = false;
+ if (s.useRegex) {
+ ret = QString::fromStdString(data).contains(
+ QRegularExpression(QString::fromStdString(s.text)));
+ return ret;
+ }
+ QString t = QString::fromStdString(s.text);
+ QString d = QString::fromStdString(data);
+
+ return compareIgnoringLineEnding(t, d);
+}
+
+bool checkLocalFileContent(FileSwitch &s)
+{
+ bool equal = false;
+ QString t = QString::fromStdString(s.text);
+ QFile file(QString::fromStdString(s.file));
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ if (s.useTime) {
+ QDateTime newLastMod = QFileInfo(file).lastModified();
+ if (s.lastMod == newLastMod)
+ return false;
+ s.lastMod = newLastMod;
+ }
+
+ if (s.useRegex) {
+ QTextStream in(&file);
+ QRegExp rx(t);
+ equal = rx.exactMatch(in.readAll());
+ } else {
+ QTextStream in(&file);
+ equal = compareIgnoringLineEnding(in.readAll(), t);
+ }
+ file.close();
+ return equal;
+}
+
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
for (FileSwitch &s : fileSwitches) {
bool equal = false;
- QString t = QString::fromStdString(s.text);
- QFile file(QString::fromStdString(s.file));
- if (!file.open(QIODevice::ReadOnly))
- continue;
-
- if (s.useTime) {
- QDateTime newLastMod = QFileInfo(file).lastModified();
- if (s.lastMod == newLastMod)
- continue;
- s.lastMod = newLastMod;
- }
-
- if (s.useRegex) {
- QTextStream in(&file);
- QRegExp rx(t);
- equal = rx.exactMatch(in.readAll());
+ if (s.remote) {
+ equal = checkRemoteFileContent(s);
} else {
- /*Im using QTextStream here so the conversion between different lineendings is done by QT.
- *QT itself uses only the linefeed internally so the input by the user is always using that,
- *but the files selected by the user might use different line endings.
- *If you are reading this and know of a cleaner way to do this, please let me know :)
- */
- QTextStream in(&file);
- QTextStream text(&t);
- while (!in.atEnd() && !text.atEnd()) {
- QString fileLine = in.readLine();
- QString textLine = text.readLine();
- if (QString::compare(fileLine, textLine,
- Qt::CaseSensitive) != 0) {
- equal = false;
- break;
- } else {
- equal = true;
- }
- }
+ equal = checkLocalFileContent(s);
}
- file.close();
if (equal) {
scene = s.scene;
@@ -181,13 +236,20 @@ void SceneSwitcher::on_browseButton_3_clicked()
ui->filePathLineEdit->setText(path);
}
-void SceneSwitcher::on_fileType_currentIndexChanged(int idx) {
+void SceneSwitcher::on_fileType_currentIndexChanged(int idx)
+{
if (idx == -1)
return;
- if (idx == LOCAL_FILE_IDX)
+ if (idx == LOCAL_FILE_IDX) {
ui->browseButton_3->setDisabled(false);
- if (idx == REMOTE_FILE_IDX)
+ ui->fileContentTimeCheckBox->setDisabled(false);
+ ui->remoteFileWarningLabel->hide();
+ }
+ if (idx == REMOTE_FILE_IDX) {
ui->browseButton_3->setDisabled(true);
+ ui->fileContentTimeCheckBox->setDisabled(true);
+ ui->remoteFileWarningLabel->show();
+ }
}
void SceneSwitcher::on_fileAdd_clicked()
@@ -196,6 +258,7 @@ void SceneSwitcher::on_fileAdd_clicked()
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
+ bool remote = (ui->fileType->currentIndex() == REMOTE_FILE_IDX);
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->isChecked();
@@ -217,8 +280,8 @@ void SceneSwitcher::on_fileAdd_clicked()
std::lock_guard lock(switcher->m);
switcher->fileSwitches.emplace_back(source, transition,
fileName.toUtf8().constData(),
- text.toUtf8().constData(), useRegex,
- useTime);
+ text.toUtf8().constData(), remote,
+ useRegex, useTime);
}
void SceneSwitcher::on_fileRemove_clicked()
@@ -260,6 +323,10 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
ui->fileTransitions->setCurrentText(transitionName.c_str());
ui->fileTextEdit->setPlainText(s.text.c_str());
ui->filePathLineEdit->setText(s.file.c_str());
+ if (s.remote)
+ ui->fileType->setCurrentIndex(REMOTE_FILE_IDX);
+ else
+ ui->fileType->setCurrentIndex(LOCAL_FILE_IDX);
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
}
@@ -283,6 +350,7 @@ void SwitcherData::saveFileSwitches(obs_data_t *obj)
transitionName);
obs_data_set_string(array_obj, "file", s.file.c_str());
obs_data_set_string(array_obj, "text", s.text.c_str());
+ obs_data_set_bool(array_obj, "remote", s.remote);
obs_data_set_bool(array_obj, "useRegex", s.useRegex);
obs_data_set_bool(array_obj, "useTime", s.useTime);
obs_data_array_push_back(fileArray, array_obj);
@@ -316,12 +384,13 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
obs_data_get_string(array_obj, "transition");
const char *file = obs_data_get_string(array_obj, "file");
const char *text = obs_data_get_string(array_obj, "text");
+ bool remote = obs_data_get_bool(array_obj, "remote");
bool useRegex = obs_data_get_bool(array_obj, "useRegex");
bool useTime = obs_data_get_bool(array_obj, "useTime");
switcher->fileSwitches.emplace_back(
GetWeakSourceByName(scene),
- GetWeakTransitionByName(transition), file, text,
+ GetWeakTransitionByName(transition), file, text, remote,
useRegex, useTime);
obs_data_release(array_obj);
diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp
index 45e5d568..6260f17c 100644
--- a/src/headers/switcher-data-structs.hpp
+++ b/src/headers/switcher-data-structs.hpp
@@ -169,18 +169,19 @@ struct FileSwitch {
OBSWeakSource transition;
std::string file;
std::string text;
- bool local = true;
+ bool remote = false;
bool useRegex = false;
bool useTime = false;
QDateTime lastMod;
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
- const char *file_, const char *text_, bool useRegex_,
- bool useTime_)
+ const char *file_, const char *text_, bool remote_,
+ bool useRegex_, bool useTime_)
: scene(scene_),
transition(transition_),
file(file_),
text(text_),
+ remote(remote_),
useRegex(useRegex_),
useTime(useTime_),
lastMod()