diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index 63fa54499..67d3e4d00 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -152,9 +152,6 @@ 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" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 60776611e..390d4a855 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -195,14 +195,17 @@ 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" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index 0ecab8b2e..8e27c6790 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -123,9 +123,6 @@ 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" diff --git a/data/locale/ru-RU.ini b/data/locale/ru-RU.ini index dcb6dd55c..7787408a3 100644 --- a/data/locale/ru-RU.ini +++ b/data/locale/ru-RU.ini @@ -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="точно соответствует" diff --git a/data/locale/tr-TR.ini b/data/locale/tr-TR.ini index 31066cf1a..2d00a017e 100644 --- a/data/locale/tr-TR.ini +++ b/data/locale/tr-TR.ini @@ -113,9 +113,6 @@ 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ı " diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 5c323ce8d..6d92a3d20 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -178,9 +178,6 @@ 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="任何媒体源" diff --git a/src/macro-core/macro-condition-file.cpp b/src/macro-core/macro-condition-file.cpp index 13bf44bdb..9cb285429 100644 --- a/src/macro-core/macro-condition-file.cpp +++ b/src/macro-core/macro-condition-file.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include namespace advss { @@ -41,86 +42,63 @@ static std::string getRemoteData(std::string &url) return readBuffer; } -bool MacroConditionFile::MatchFileContent(QString &filedata) +static bool stringsMatch(const QString &text, const std::string &pattern, + const RegexConfig ®ex) { - if (_onlyMatchIfChanged) { - size_t newHash = strHash(filedata.toUtf8().constData()); - if (newHash == _lastHash) { - return false; - } - _lastHash = newHash; - } - - 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::CheckRemoteFileContent() -{ - std::string path = _file; - 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; + auto qpattern = QString::fromStdString(pattern); + if (regex.Enabled()) { + return regex.Matches(text, qpattern); } - - 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; + auto textCopy = text; + return CompareIgnoringLineEnding(qpattern, textCopy); } -bool MacroConditionFile::CheckChangeContent() +static std::optional getFileContent(MacroConditionFile::FileType type, + const std::string &filePath) { QString filedata; - switch (_fileType) { - case FileType::LOCAL: { - std::string path = _file; + switch (type) { + case MacroConditionFile::FileType::LOCAL: { + std::string path = filePath; QFile file(QString::fromStdString(path)); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; + return {}; } filedata = QTextStream(&file).readAll(); file.close(); } break; - case FileType::REMOTE: { - std::string path = _file; + case MacroConditionFile::FileType::REMOTE: { + std::string path = filePath; std::string data = getRemoteData(path); - QString filedata = QString::fromStdString(data); + filedata = QString::fromStdString(data); } break; default: break; } + return filedata; +} + +bool MacroConditionFile::CheckFileContentMatch() +{ + auto fileData = getFileContent(_fileType, _file); + if (!fileData) { + return false; + } + const bool match = stringsMatch(*fileData, _text, _regex); + SetVariableValue(fileData->toStdString()); + return match; +} - size_t newHash = strHash(filedata.toUtf8().constData()); +bool MacroConditionFile::CheckChangeContent() +{ + auto filedata = getFileContent(_fileType, _file); + if (!filedata) { + return false; + } + 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(_fileType)); + obs_data_set_int(obj, "changeMatchType", + static_cast(_changeMatchType)); obs_data_set_int(obj, "condition", static_cast(_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(obs_data_get_int(obj, "fileType")); + _changeMatchType = static_cast( + obs_data_get_int(obj, "changeMatchType")); _condition = static_cast(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, 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(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, + 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(type)); + } +} + +static void populateChangeMatchTypes(QComboBox *list) +{ + static constexpr std::array< + std::tuple, + 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(type)); + } } MacroConditionFileEdit::MacroConditionFileEdit( QWidget *parent, std::shared_ptr 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 widgetPlaceholders = { + const std::unordered_map 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(_entryData->_fileType)); - _conditions->setCurrentIndex(static_cast(_entryData->_condition)); + _fileTypes->setCurrentIndex( + _fileTypes->findData(static_cast(_entryData->_fileType))); + _conditions->setCurrentIndex(_conditions->findData( + static_cast(_entryData->_condition))); + _changeMatchTypes->setCurrentIndex(_changeMatchTypes->findData( + static_cast(_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(index); + auto type = static_cast( + _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( + _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(index); + _entryData->_condition = static_cast( + _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::CHANGES_MATCH); + _matchText->setVisible( + _entryData->_condition == + MacroConditionFile::ConditionType::MATCH || + _entryData->_condition == + MacroConditionFile::ConditionType::CHANGES_MATCH); + _regex->setVisible( _entryData->_condition == - MacroConditionFile::ConditionType::MATCH); - _checkFileContent->setVisible( - _entryData->_onlyMatchIfChanged && + MacroConditionFile::ConditionType::MATCH || _entryData->_condition == - MacroConditionFile::ConditionType::MATCH); + MacroConditionFile::ConditionType::CHANGES_MATCH); adjustSize(); updateGeometry(); } diff --git a/src/macro-core/macro-condition-file.hpp b/src/macro-core/macro-condition-file.hpp index b4630c449..5b73bbb50 100644 --- a/src/macro-core/macro-condition-file.hpp +++ b/src/macro-core/macro-condition-file.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace advss { @@ -35,27 +36,31 @@ class MacroConditionFile : public MacroCondition { 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 @@ class MacroConditionFileEdit : public QWidget { 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 _entryData; private: diff --git a/src/utils/regex-config.cpp b/src/utils/regex-config.cpp index 35f28636b..bc90eaa23 100644 --- a/src/utils/regex-config.cpp +++ b/src/utils/regex-config.cpp @@ -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; diff --git a/src/utils/regex-config.hpp b/src/utils/regex-config.hpp index e6a0701aa..5c97fc9ae 100644 --- a/src/utils/regex-config.hpp +++ b/src/utils/regex-config.hpp @@ -29,6 +29,9 @@ class RegexConfig { }; 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();