Compare commits

..

3 Commits

Author SHA1 Message Date
WarmUpTill
267855fded Cleanup
* Use OBSSourceAutoRelease
* Do not return true if source selection is invalid
2023-12-17 10:40:29 +01:00
WarmUpTill
4bdebb7feb Fix crash when asking for settings backup
This dialog cannot be modal since other plugins might attempt to display
content which might result in a deadlock.
2023-12-16 19:02:38 +01:00
Michael Kirsch
ab5f69d2ef Decrease the minimal interval time to 10ms 2023-12-13 19:29:14 +01:00
13 changed files with 249 additions and 301 deletions

View File

@@ -152,6 +152,9 @@ AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert" AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
AdvSceneSwitcher.condition.file.remote="Entfernte Datei" AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
AdvSceneSwitcher.condition.file.local="Lokale 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="Medien"
AdvSceneSwitcher.condition.media.source="Quelle" AdvSceneSwitcher.condition.media.source="Quelle"
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in" AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"

View File

@@ -195,17 +195,14 @@ 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.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.window.entry.currentFocus="Current focus window:{{focusWindow}}"
AdvSceneSwitcher.condition.file="File" AdvSceneSwitcher.condition.file="File"
AdvSceneSwitcher.condition.file.type.match="Matches" AdvSceneSwitcher.condition.file.type.match="matches"
AdvSceneSwitcher.condition.file.type.contentChange="Content changed" AdvSceneSwitcher.condition.file.type.contentChange="content changed"
AdvSceneSwitcher.condition.file.type.dateChange="Modification date 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.remote="Remote file"
AdvSceneSwitcher.condition.file.local="Local file" AdvSceneSwitcher.condition.file.local="Local file"
AdvSceneSwitcher.condition.file.changeMatchType.any="Any lines" AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
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.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
AdvSceneSwitcher.condition.media="Media" AdvSceneSwitcher.condition.media="Media"
AdvSceneSwitcher.condition.media.source="Source" AdvSceneSwitcher.condition.media.source="Source"
AdvSceneSwitcher.condition.media.anyOnScene="Any media source on" AdvSceneSwitcher.condition.media.anyOnScene="Any media source on"

View File

@@ -123,6 +123,9 @@ AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}" AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Ventana" AdvSceneSwitcher.condition.window="Ventana"
AdvSceneSwitcher.condition.file="Archivo" 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="Medios"
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada" AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas" AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"

View File

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

View File

@@ -113,6 +113,9 @@ AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}" AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Pencere" AdvSceneSwitcher.condition.window="Pencere"
AdvSceneSwitcher.condition.file="Dosya" 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="Medya"
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı" AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları " AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "

View File

@@ -178,6 +178,9 @@ AdvSceneSwitcher.condition.file.type.contentChange="内容已更改"
AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改" AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改"
AdvSceneSwitcher.condition.file.remote="远程文件" AdvSceneSwitcher.condition.file.remote="远程文件"
AdvSceneSwitcher.condition.file.local="本地文件" 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="媒体"
AdvSceneSwitcher.condition.media.source="源" AdvSceneSwitcher.condition.media.source="源"
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源" AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"

View File

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

View File

@@ -10,6 +10,7 @@
#include <QMainWindow> #include <QMainWindow>
#include <QAction> #include <QAction>
#include <QFileDialog> #include <QFileDialog>
#include <QTextStream>
#include <QDirIterator> #include <QDirIterator>
#include <regex> #include <regex>
#include <filesystem> #include <filesystem>
@@ -135,7 +136,7 @@ bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
/****************************************************************************** /******************************************************************************
* Saving and loading * Saving and loading
******************************************************************************/ ******************************************************************************/
static void AskForBackup(obs_data_t *obj); static void AskForBackup(const QString &json);
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{ {
@@ -156,16 +157,25 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->Stop(); switcher->Stop();
switcher->m.lock(); switcher->m.lock();
obs_data_t *obj = OBSDataAutoRelease obj =
obs_data_get_obj(save_data, "advanced-scene-switcher"); obs_data_get_obj(save_data, "advanced-scene-switcher");
if (!obj) { if (!obj) {
obj = obs_data_create(); obj = obs_data_create();
} }
if (switcher->VersionChanged(obj, g_GIT_SHA1)) { if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
AskForBackup(obj); 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();
} }
switcher->LoadSettings(obj); switcher->LoadSettings(obj);
obs_data_release(obj);
switcher->m.unlock(); switcher->m.unlock();
if (!switcher->stop) { if (!switcher->stop) {
@@ -174,12 +184,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
} }
} }
static void AskForBackup(obs_data_t *obj) static void AskForBackup(const QString &json)
{ {
bool backupSettings = DisplayMessage( const bool backupWasConfirmed = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true); obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
if (!backupSettings) { if (!backupWasConfirmed) {
return; return;
} }
@@ -198,8 +208,8 @@ static void AskForBackup(obs_data_t *obj)
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return; return;
} }
auto out = QTextStream(&file);
obs_data_save_json(obj, file.fileName().toUtf8().constData()); out << json;
} }
/****************************************************************************** /******************************************************************************

View File

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

View File

@@ -5,8 +5,7 @@
#include <QTextStream> #include <QTextStream>
#include <QFileDialog> #include <QFileDialog>
#include <array> #include <regex>
#include <tuple>
namespace advss { namespace advss {
@@ -42,63 +41,86 @@ static std::string getRemoteData(std::string &url)
return readBuffer; return readBuffer;
} }
static bool stringsMatch(const QString &text, const std::string &pattern, bool MacroConditionFile::MatchFileContent(QString &filedata)
const RegexConfig &regex)
{ {
auto qpattern = QString::fromStdString(pattern); if (_onlyMatchIfChanged) {
if (regex.Enabled()) { size_t newHash = strHash(filedata.toUtf8().constData());
return regex.Matches(text, qpattern); if (newHash == _lastHash) {
} return false;
auto textCopy = text;
return CompareIgnoringLineEnding(qpattern, textCopy);
}
static std::optional<QString> getFileContent(MacroConditionFile::FileType type,
const std::string &filePath)
{
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(); _lastHash = newHash;
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;
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);
} }
bool MacroConditionFile::CheckFileContentMatch() bool MacroConditionFile::CheckRemoteFileContent()
{ {
auto fileData = getFileContent(_fileType, _file); std::string path = _file;
if (!fileData) { std::string data = getRemoteData(path);
SetVariableValue(data);
QString qdata = QString::fromStdString(data);
return MatchFileContent(qdata);
}
bool MacroConditionFile::CheckLocalFileContent()
{
QFile file(QString::fromStdString(_file));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return false; return false;
} }
const bool match = stringsMatch(*fileData, _text, _regex);
SetVariableValue(fileData->toStdString()); 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();
return match; return match;
} }
bool MacroConditionFile::CheckChangeContent() bool MacroConditionFile::CheckChangeContent()
{ {
auto filedata = getFileContent(_fileType, _file); QString filedata;
if (!filedata) { switch (_fileType) {
return false; 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;
} }
size_t newHash = strHash(filedata->toUtf8().constData());
size_t newHash = strHash(filedata.toUtf8().constData());
const bool contentChanged = newHash != _lastHash; const bool contentChanged = newHash != _lastHash;
_lastHash = newHash; _lastHash = newHash;
SetVariableValue(contentChanged ? "true" : "false");
return contentChanged; return contentChanged;
} }
@@ -113,94 +135,35 @@ bool MacroConditionFile::CheckChangeDate()
SetVariableValue(newLastMod.toString().toStdString()); SetVariableValue(newLastMod.toString().toStdString());
const bool dateChanged = _lastMod != newLastMod; const bool dateChanged = _lastMod != newLastMod;
_lastMod = newLastMod; _lastMod = newLastMod;
SetVariableValue(dateChanged ? "true" : "false");
return dateChanged; 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 MacroConditionFile::CheckCondition()
{ {
bool ret = false;
switch (_condition) { switch (_condition) {
case MacroConditionFile::ConditionType::MATCH: case MacroConditionFile::ConditionType::MATCH:
return CheckFileContentMatch(); if (_fileType == FileType::REMOTE) {
ret = CheckRemoteFileContent();
break;
}
ret = CheckLocalFileContent();
break;
case MacroConditionFile::ConditionType::CONTENT_CHANGE: case MacroConditionFile::ConditionType::CONTENT_CHANGE:
return CheckChangeContent(); ret = CheckChangeContent();
break;
case MacroConditionFile::ConditionType::DATE_CHANGE: case MacroConditionFile::ConditionType::DATE_CHANGE:
return CheckChangeDate(); ret = CheckChangeDate();
case MacroConditionFile::ConditionType::CHANGES_MATCH: break;
return CheckChangedMatch();
default: default:
break; break;
} }
return false; if (GetVariableValue().empty()) {
SetVariableValue(ret ? "true" : "false");
}
return ret;
} }
bool MacroConditionFile::Save(obs_data_t *obj) const bool MacroConditionFile::Save(obs_data_t *obj) const
@@ -210,9 +173,9 @@ bool MacroConditionFile::Save(obs_data_t *obj) const
_file.Save(obj, "file"); _file.Save(obj, "file");
_text.Save(obj, "text"); _text.Save(obj, "text");
obs_data_set_int(obj, "fileType", static_cast<int>(_fileType)); 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_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_bool(obj, "useTime", _useTime);
obs_data_set_bool(obj, "onlyMatchIfChanged", _onlyMatchIfChanged);
return true; return true;
} }
@@ -228,10 +191,10 @@ bool MacroConditionFile::Load(obs_data_t *obj)
_file.Load(obj, "file"); _file.Load(obj, "file");
_text.Load(obj, "text"); _text.Load(obj, "text");
_fileType = static_cast<FileType>(obs_data_get_int(obj, "fileType")); _fileType = static_cast<FileType>(obs_data_get_int(obj, "fileType"));
_changeMatchType = static_cast<ChangeMatchType>(
obs_data_get_int(obj, "changeMatchType"));
_condition = _condition =
static_cast<ConditionType>(obs_data_get_int(obj, "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; return true;
} }
@@ -242,79 +205,39 @@ std::string MacroConditionFile::GetShortDesc() const
static void populateFileTypes(QComboBox *list) static void populateFileTypes(QComboBox *list)
{ {
static constexpr std::array< list->addItem(obs_module_text("AdvSceneSwitcher.condition.file.local"));
std::tuple<MacroConditionFile::FileType, std::string_view>, 2> list->addItem(
fileTypes = {{{MacroConditionFile::FileType::LOCAL, obs_module_text("AdvSceneSwitcher.condition.file.remote"));
"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) static void populateConditions(QComboBox *list)
{ {
static constexpr std::array< list->addItem(
std::tuple<MacroConditionFile::ConditionType, std::string_view>, obs_module_text("AdvSceneSwitcher.condition.file.type.match"));
4> list->addItem(obs_module_text(
conditionTypes = {{ "AdvSceneSwitcher.condition.file.type.contentChange"));
{MacroConditionFile::ConditionType::MATCH, list->addItem(obs_module_text(
"AdvSceneSwitcher.condition.file.type.match"}, "AdvSceneSwitcher.condition.file.type.dateChange"));
{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( MacroConditionFileEdit::MacroConditionFileEdit(
QWidget *parent, std::shared_ptr<MacroConditionFile> entryData) QWidget *parent, std::shared_ptr<MacroConditionFile> entryData)
: QWidget(parent), : QWidget(parent),
_fileTypes(new QComboBox()), _fileTypes(new QComboBox()),
_changeMatchTypes(new QComboBox()),
_conditions(new QComboBox()), _conditions(new QComboBox()),
_filePath(new FileSelection()), _filePath(new FileSelection()),
_matchText(new VariableTextEdit(this)), _matchText(new VariableTextEdit(this)),
_regex(new RegexConfigWidget(parent)) _regex(new RegexConfigWidget(parent)),
_checkModificationDate(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.fileTab.checkfileContentTime"))),
_checkFileContent(new QCheckBox(
obs_module_text("AdvSceneSwitcher.fileTab.checkfileContent")))
{ {
populateFileTypes(_fileTypes); populateFileTypes(_fileTypes);
populateConditions(_conditions); populateConditions(_conditions);
populateChangeMatchTypes(_changeMatchTypes);
QWidget::connect(_fileTypes, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_fileTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(FileTypeChanged(int))); SLOT(FileTypeChanged(int)));
QWidget::connect(_changeMatchTypes, SIGNAL(currentIndexChanged(int)),
this, SLOT(ChangeMatchTypeChanged(int)));
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int))); SLOT(ConditionChanged(int)));
QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this, QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this,
@@ -323,30 +246,41 @@ MacroConditionFileEdit::MacroConditionFileEdit(
SLOT(MatchTextChanged())); SLOT(MatchTextChanged()));
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this, QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
SLOT(RegexChanged(RegexConfig))); SLOT(RegexChanged(RegexConfig)));
QWidget::connect(_checkModificationDate, SIGNAL(stateChanged(int)),
this, SLOT(CheckModificationDateChanged(int)));
QWidget::connect(_checkFileContent, SIGNAL(stateChanged(int)), this,
SLOT(OnlyMatchIfChangedChanged(int)));
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = { std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fileType}}", _fileTypes}, {"{{fileType}}", _fileTypes},
{"{{changeMatchType}}", _changeMatchTypes},
{"{{conditions}}", _conditions}, {"{{conditions}}", _conditions},
{"{{filePath}}", _filePath}, {"{{filePath}}", _filePath},
{"{{matchText}}", _matchText}, {"{{matchText}}", _matchText},
{"{{useRegex}}", _regex}, {"{{useRegex}}", _regex},
{"{{checkModificationDate}}", _checkModificationDate},
{"{{checkFileContent}}", _checkFileContent},
}; };
auto line1Layout = new QHBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
QHBoxLayout *line3Layout = new QHBoxLayout;
line1Layout->setContentsMargins(0, 0, 0, 0); line1Layout->setContentsMargins(0, 0, 0, 0);
line2Layout->setContentsMargins(0, 0, 0, 0);
line3Layout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets( PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.file.entry.line1"), obs_module_text("AdvSceneSwitcher.condition.file.entry.line1"),
line1Layout, widgetPlaceholders); line1Layout, widgetPlaceholders);
auto line2Layout = new QHBoxLayout;
line2Layout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets( PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.file.entry.line2"), obs_module_text("AdvSceneSwitcher.condition.file.entry.line2"),
line2Layout, widgetPlaceholders, false); line2Layout, widgetPlaceholders, false);
PlaceWidgets(
auto mainLayout = new QVBoxLayout; obs_module_text("AdvSceneSwitcher.condition.file.entry.line3"),
line3Layout, widgetPlaceholders);
mainLayout->addLayout(line1Layout); mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout); mainLayout->addLayout(line2Layout);
mainLayout->addLayout(line3Layout);
setLayout(mainLayout); setLayout(mainLayout);
_entryData = entryData; _entryData = entryData;
@@ -360,15 +294,21 @@ void MacroConditionFileEdit::UpdateEntryData()
return; return;
} }
_fileTypes->setCurrentIndex( _fileTypes->setCurrentIndex(static_cast<int>(_entryData->_fileType));
_fileTypes->findData(static_cast<int>(_entryData->_fileType))); _conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
_conditions->setCurrentIndex(_conditions->findData(
static_cast<int>(_entryData->_condition)));
_changeMatchTypes->setCurrentIndex(_changeMatchTypes->findData(
static_cast<int>(_entryData->_changeMatchType)));
_filePath->SetPath(_entryData->_file); _filePath->SetPath(_entryData->_file);
_matchText->setPlainText(_entryData->_text); _matchText->setPlainText(_entryData->_text);
_regex->SetRegexConfig(_entryData->_regex); _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(); SetWidgetVisibility();
} }
@@ -379,25 +319,19 @@ void MacroConditionFileEdit::FileTypeChanged(int index)
return; return;
} }
auto type = static_cast<MacroConditionFile::FileType>( MacroConditionFile::FileType type =
_fileTypes->itemData(index).toInt()); static_cast<MacroConditionFile::FileType>(index);
_filePath->Button()->setEnabled(type ==
MacroConditionFile::FileType::LOCAL);
auto lock = LockContext();
_entryData->_fileType = type;
}
void MacroConditionFileEdit::ChangeMatchTypeChanged(int index) if (type == MacroConditionFile::FileType::LOCAL) {
{ _filePath->Button()->setDisabled(false);
if (_loading || !_entryData) { _checkModificationDate->setDisabled(false);
return; } else {
_filePath->Button()->setDisabled(true);
_checkModificationDate->setDisabled(true);
} }
auto lock = LockContext(); auto lock = LockContext();
_entryData->_changeMatchType = _entryData->_fileType = type;
static_cast<MacroConditionFile::ChangeMatchType>(
_changeMatchTypes->itemData(index).toInt());
SetWidgetVisibility();
} }
void MacroConditionFileEdit::ConditionChanged(int index) void MacroConditionFileEdit::ConditionChanged(int index)
@@ -407,8 +341,8 @@ void MacroConditionFileEdit::ConditionChanged(int index)
} }
auto lock = LockContext(); auto lock = LockContext();
_entryData->_condition = static_cast<MacroConditionFile::ConditionType>( _entryData->_condition =
_conditions->itemData(index).toInt()); static_cast<MacroConditionFile::ConditionType>(index);
SetWidgetVisibility(); SetWidgetVisibility();
} }
@@ -449,25 +383,44 @@ void MacroConditionFileEdit::RegexChanged(RegexConfig conf)
updateGeometry(); 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() void MacroConditionFileEdit::SetWidgetVisibility()
{ {
if (!_entryData) { if (!_entryData) {
return; return;
} }
_changeMatchTypes->setVisible( _matchText->setVisible(_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
_regex->setVisible(_entryData->_condition ==
MacroConditionFile::ConditionType::MATCH);
_checkModificationDate->setVisible(
_entryData->_useTime &&
_entryData->_condition == _entryData->_condition ==
MacroConditionFile::ConditionType::CHANGES_MATCH); MacroConditionFile::ConditionType::MATCH);
_matchText->setVisible( _checkFileContent->setVisible(
_entryData->_onlyMatchIfChanged &&
_entryData->_condition == _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(); adjustSize();
updateGeometry(); updateGeometry();
} }

View File

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

View File

@@ -51,23 +51,6 @@ RegexConfig::GetRegularExpression(const std::string &expr) const
return GetRegularExpression(QString::fromStdString(expr)); 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 RegexConfig::PartialMatchRegexConfig()
{ {
RegexConfig conf; RegexConfig conf;

View File

@@ -29,9 +29,6 @@ public:
}; };
QRegularExpression GetRegularExpression(const QString &) const; QRegularExpression GetRegularExpression(const QString &) const;
QRegularExpression GetRegularExpression(const std::string &) 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(); static RegexConfig PartialMatchRegexConfig();