From 72b2a7a07a0c4cceec04d8f211ada32fcd61e28f Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Sun, 29 Sep 2024 12:40:40 +0200 Subject: [PATCH] Add option to assign screenshot to variable --- data/locale/de-DE.ini | 2 +- data/locale/en-US.ini | 7 +- data/locale/fr-FR.ini | 2 +- data/locale/ja-JP.ini | 2 +- data/locale/pt-BR.ini | 2 +- data/locale/zh-CN.ini | 2 +- lib/variables/variable.hpp | 4 +- plugins/base/macro-action-screenshot.cpp | 100 ++++++++++++++++------- plugins/base/macro-action-screenshot.hpp | 33 ++++---- 9 files changed, 94 insertions(+), 60 deletions(-) diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index bd12cf6c..245a0a71 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -529,7 +529,7 @@ AdvSceneSwitcher.action.screenshot.type.source="Quelle" AdvSceneSwitcher.action.screenshot.type.scene="Szene" AdvSceneSwitcher.action.screenshot.mainOutput="OBS's Haupt-Ausgabe" AdvSceneSwitcher.action.screenshot.blackscreenNote="Quellen oder Szenen, die nicht immer gerendert werden, können dazu führen, dass einige Teile der Screenshots leer bleiben." -AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}Pfad" +AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}{{variables}}Pfad" AdvSceneSwitcher.action.profile="Profil" AdvSceneSwitcher.action.profile.entry="Aktives Profil umschalten auf {{profiles}}" AdvSceneSwitcher.action.sceneCollection="Szenensammlung" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index e8bd2ac4..847f70c5 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -1002,13 +1002,14 @@ AdvSceneSwitcher.action.systray.icon="Icon:" AdvSceneSwitcher.action.systray.iconHint="Leave blank to use the default icon" AdvSceneSwitcher.action.systray.disabled="System tray notifications seem to be disabled in the OBS settings!" AdvSceneSwitcher.action.screenshot="Screenshot" -AdvSceneSwitcher.action.screenshot.save.default="Default" -AdvSceneSwitcher.action.screenshot.save.custom="Custom" +AdvSceneSwitcher.action.screenshot.save.default="Default OBS path" +AdvSceneSwitcher.action.screenshot.save.custom="Custom file path" +AdvSceneSwitcher.action.screenshot.save.variable="Variable (base64 encoded PNG)" AdvSceneSwitcher.action.screenshot.type.source="Source" AdvSceneSwitcher.action.screenshot.type.scene="Scene" AdvSceneSwitcher.action.screenshot.mainOutput="OBS's main output" AdvSceneSwitcher.action.screenshot.blackscreenNote="Sources or scenes, which are not always rendered, may result in some parts of screenshots to remain blank." -AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}and save to{{saveType}}location" +AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}and save to{{saveType}}{{variables}}" AdvSceneSwitcher.action.profile="Profile" AdvSceneSwitcher.action.profile.entry="Switch active profile to{{profiles}}" AdvSceneSwitcher.action.sceneCollection="Scene collection" diff --git a/data/locale/fr-FR.ini b/data/locale/fr-FR.ini index e6b8d2e4..93c8c20b 100644 --- a/data/locale/fr-FR.ini +++ b/data/locale/fr-FR.ini @@ -649,7 +649,7 @@ AdvSceneSwitcher.action.screenshot.type.source="Source" AdvSceneSwitcher.action.screenshot.type.scene="Scène" AdvSceneSwitcher.action.screenshot.mainOutput="Sortie principale d'OBS" AdvSceneSwitcher.action.screenshot.blackscreenNote="Les sources ou les scènes qui ne sont pas toujours rendues peuvent entraîner des parties de captures d'écran vides." -AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}" +AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}{{variables}}" AdvSceneSwitcher.action.profile="Profil" AdvSceneSwitcher.action.profile.entry="Changer le profil actif vers{{profiles}}" AdvSceneSwitcher.action.sceneCollection="Collection de scènes" diff --git a/data/locale/ja-JP.ini b/data/locale/ja-JP.ini index b35f03c6..36ce3269 100644 --- a/data/locale/ja-JP.ini +++ b/data/locale/ja-JP.ini @@ -981,7 +981,7 @@ AdvSceneSwitcher.action.screenshot.save.custom="カスタム" AdvSceneSwitcher.action.screenshot.type.scene="シーン" AdvSceneSwitcher.action.screenshot.mainOutput="OBSの主な出力" AdvSceneSwitcher.action.screenshot.blackscreenNote="常にレンダリングされるわけではないソースやシーンにより、スクリーンショットの一部が空白のままになる場合があります。" -AdvSceneSwitcher.action.screenshot.entry="スクリーンショット{{targetType}}{{sources}}{{scenes}}を作成し、{{saveType}}の場所に保存します" +AdvSceneSwitcher.action.screenshot.entry="スクリーンショット{{targetType}}{{sources}}{{scenes}}を作成し、{{saveType}}{{variables}}の場所に保存します" AdvSceneSwitcher.action.profile="プロファイル" AdvSceneSwitcher.action.profile.entry="アクティブなプロファイルを{{profiles}}に切り替えます" ; AdvSceneSwitcher.action.sceneCollection="Scene collection" diff --git a/data/locale/pt-BR.ini b/data/locale/pt-BR.ini index 5a9a97fb..517cf067 100644 --- a/data/locale/pt-BR.ini +++ b/data/locale/pt-BR.ini @@ -963,7 +963,7 @@ AdvSceneSwitcher.action.screenshot.type.source="Fonte" AdvSceneSwitcher.action.screenshot.type.scene="Cena" AdvSceneSwitcher.action.screenshot.mainOutput="Saída principal do OBS" AdvSceneSwitcher.action.screenshot.blackscreenNote="Fontes ou cenas, que nem sempre são renderizadas, podem resultar em algumas partes das capturas de tela permanecendo em branco." -AdvSceneSwitcher.action.screenshot.entry="Captura de tela{{targetType}}{{sources}}{{scenes}}e salvar em{{saveType}}localização" +AdvSceneSwitcher.action.screenshot.entry="Captura de tela{{targetType}}{{sources}}{{scenes}}e salvar em{{saveType}}{{variables}}localização" AdvSceneSwitcher.action.profile="Perfil" AdvSceneSwitcher.action.profile.entry="Mudar perfil ativo para{{profiles}}" AdvSceneSwitcher.action.sceneCollection="Coleção de cenas" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 923e7c08..48fffbaa 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -590,7 +590,7 @@ AdvSceneSwitcher.action.screenshot.type.source="来源" AdvSceneSwitcher.action.screenshot.type.scene="场景" AdvSceneSwitcher.action.screenshot.mainOutput="OBS 预览画面" AdvSceneSwitcher.action.screenshot.blackscreenNote="源和场景并不总是呈现,可能会导致屏幕截图的某些部分保持空白。" -AdvSceneSwitcher.action.screenshot.entry="截图{{targetType}}{{sources}}{{scenes}}保存在{{saveType}}位置" +AdvSceneSwitcher.action.screenshot.entry="截图{{targetType}}{{sources}}{{scenes}}保存在{{saveType}}{{variables}}位置" AdvSceneSwitcher.action.profile="配置文件" AdvSceneSwitcher.action.profile.entry="将活动配置文件切换到 {{profiles}}" AdvSceneSwitcher.action.sceneCollection="场景集合" diff --git a/lib/variables/variable.hpp b/lib/variables/variable.hpp index 669b7d6e..91613829 100644 --- a/lib/variables/variable.hpp +++ b/lib/variables/variable.hpp @@ -36,7 +36,7 @@ public: EXPORT std::optional IntValue() const; std::string GetPreviousValue() const { return _previousValue; }; std::string GetDefaultValue() const { return _defaultValue; } - void SetValue(const std::string &value); + EXPORT void SetValue(const std::string &value); void SetValue(double value); SaveAction GetSaveAction() const { return _saveAction; } int GetValueChangeCount() const { return _valueChangeCount; } @@ -112,7 +112,7 @@ EXPORT Variable *GetVariableByName(const std::string &name); EXPORT Variable *GetVariableByQString(const QString &name); EXPORT std::weak_ptr GetWeakVariableByName(const std::string &name); EXPORT std::weak_ptr GetWeakVariableByQString(const QString &name); -std::string GetWeakVariableName(std::weak_ptr); +EXPORT std::string GetWeakVariableName(std::weak_ptr); EXPORT QStringList GetVariablesNameList(); void SaveVariables(obs_data_t *obj); diff --git a/plugins/base/macro-action-screenshot.cpp b/plugins/base/macro-action-screenshot.cpp index d86e5c11..a916d73f 100644 --- a/plugins/base/macro-action-screenshot.cpp +++ b/plugins/base/macro-action-screenshot.cpp @@ -3,6 +3,8 @@ #include "selection-helpers.hpp" #include +#include +#include namespace advss { @@ -13,28 +15,49 @@ bool MacroActionScreenshot::_registered = MacroActionFactory::Register( {MacroActionScreenshot::Create, MacroActionScreenshotEdit::Create, "AdvSceneSwitcher.action.screenshot"}); -void MacroActionScreenshot::FrontendScreenshot(OBSWeakSource &source) +void MacroActionScreenshot::FrontendScreenshot(OBSWeakSource &source) const { #if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(26, 0, 0) if (source) { - auto s = obs_weak_source_get_source(source); + auto s = OBSGetStrongRef(source); obs_frontend_take_source_screenshot(s); - obs_source_release(s); } else { obs_frontend_take_screenshot(); } #endif } -void MacroActionScreenshot::CustomScreenshot(OBSWeakSource &source) +void MacroActionScreenshot::CustomScreenshot(OBSWeakSource &source) const { if (!source && _targetType == TargetType::SCENE) { return; } - auto s = obs_weak_source_get_source(source); - _screenshot.~Screenshot(); - new (&_screenshot) Screenshot(s, QRect(), false, 0, true, _path); - obs_source_release(s); + auto s = OBSGetStrongRef(source); + Screenshot screenshot(s, QRect(), true, 3000, true, _path); +} + +void MacroActionScreenshot::VariableScreenshot(OBSWeakSource &source) const +{ + if (!source && _targetType == TargetType::SCENE) { + return; + } + + auto variable = _variable.lock(); + if (!variable) { + return; + } + + auto s = OBSGetStrongRef(source); + Screenshot screenshot(s, QRect(), true, 3000); + + QByteArray byteArray; + QBuffer buffer(&byteArray); + buffer.open(QIODevice::WriteOnly); + if (!screenshot.GetImage().save(&buffer, "PNG")) { + blog(LOG_WARNING, "Failed to save screenshot to variable!"); + } + + variable->SetValue(byteArray.toBase64().toStdString()); } bool MacroActionScreenshot::PerformAction() @@ -52,12 +75,15 @@ bool MacroActionScreenshot::PerformAction() } switch (_saveType) { - case MacroActionScreenshot::SaveType::OBS_DEFAULT: + case MacroActionScreenshot::SaveType::OBS_DEFAULT_PATH: FrontendScreenshot(source); break; - case MacroActionScreenshot::SaveType::CUSTOM: + case MacroActionScreenshot::SaveType::CUSTOM_PATH: CustomScreenshot(source); break; + case MacroActionScreenshot::SaveType::VARIABLE: + VariableScreenshot(source); + break; default: break; } @@ -90,6 +116,8 @@ bool MacroActionScreenshot::Save(obs_data_t *obj) const obs_data_set_int(obj, "saveType", static_cast(_saveType)); obs_data_set_int(obj, "targetType", static_cast(_targetType)); _path.Save(obj, "savePath"); + obs_data_set_string(obj, "variable", + GetWeakVariableName(_variable).c_str()); obs_data_set_int(obj, "version", 1); return true; } @@ -103,6 +131,8 @@ bool MacroActionScreenshot::Load(obs_data_t *obj) _targetType = static_cast(obs_data_get_int(obj, "targetType")); _path.Load(obj, "savePath"); + _variable = + GetWeakVariableByName(obs_data_get_string(obj, "variableName")); // TODO: Remove fallback for older versions if (!obs_data_has_user_value(obj, "version")) { @@ -151,6 +181,8 @@ static void populateSaveTypeSelection(QComboBox *list) "AdvSceneSwitcher.action.screenshot.save.default")); list->addItem(obs_module_text( "AdvSceneSwitcher.action.screenshot.save.custom")); + list->addItem(obs_module_text( + "AdvSceneSwitcher.action.screenshot.save.variable")); } static void populateTargetTypeSelection(QComboBox *list) @@ -170,7 +202,8 @@ MacroActionScreenshotEdit::MacroActionScreenshotEdit( _sources(new SourceSelectionWidget(this, QStringList(), true)), _saveType(new QComboBox()), _targetType(new QComboBox()), - _savePath(new FileSelection(FileSelection::Type::WRITE, this)) + _savePath(new FileSelection(FileSelection::Type::WRITE, this)), + _variables(new VariableSelection(this)) { setToolTip(obs_module_text( "AdvSceneSwitcher.action.screenshot.blackscreenNote")); @@ -192,19 +225,20 @@ MacroActionScreenshotEdit::MacroActionScreenshotEdit( SLOT(TargetTypeChanged(int))); QWidget::connect(_savePath, SIGNAL(PathChanged(const QString &)), this, SLOT(PathChanged(const QString &))); + QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)), + this, SLOT(VariableChanged(const QString &))); - QHBoxLayout *layout = new QHBoxLayout; - std::unordered_map widgetPlaceholders = { - {"{{sources}}", _sources}, - {"{{scenes}}", _scenes}, - {"{{saveType}}", _saveType}, - {"{{targetType}}", _targetType}, - }; + auto layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.action.screenshot.entry"), - layout, widgetPlaceholders); + layout, + {{"{{sources}}", _sources}, + {"{{scenes}}", _scenes}, + {"{{saveType}}", _saveType}, + {"{{targetType}}", _targetType}, + {"{{variables}}", _variables}}); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto mainLayout = new QVBoxLayout; mainLayout->addLayout(layout); mainLayout->addWidget(_savePath); setLayout(mainLayout); @@ -225,6 +259,7 @@ void MacroActionScreenshotEdit::UpdateEntryData() _saveType->setCurrentIndex(static_cast(_entryData->_saveType)); _targetType->setCurrentIndex(static_cast(_entryData->_targetType)); _savePath->SetPath(_entryData->_path); + _variables->SetVariable(_entryData->_variable); SetWidgetVisibility(); } @@ -258,39 +293,42 @@ void MacroActionScreenshotEdit::TargetTypeChanged(int index) void MacroActionScreenshotEdit::PathChanged(const QString &text) { - if (_loading || !_entryData) { - return; - } - - auto lock = LockContext(); + GUARD_LOADING_AND_LOCK(); _entryData->_path = text.toStdString(); } void MacroActionScreenshotEdit::SourceChanged(const SourceSelection &source) { - if (_loading || !_entryData) { - return; - } - - auto lock = LockContext(); + GUARD_LOADING_AND_LOCK(); _entryData->_source = source; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } +void MacroActionScreenshotEdit::VariableChanged(const QString &text) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_variable = GetWeakVariableByQString(text); + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +} + void MacroActionScreenshotEdit::SetWidgetVisibility() { if (!_entryData) { return; } _savePath->setVisible(_entryData->_saveType == - MacroActionScreenshot::SaveType::CUSTOM); + MacroActionScreenshot::SaveType::CUSTOM_PATH); _sources->setVisible(_entryData->_targetType == MacroActionScreenshot::TargetType::SOURCE); _scenes->setVisible(_entryData->_targetType == MacroActionScreenshot::TargetType::SCENE); + _variables->setVisible(_entryData->_saveType == + MacroActionScreenshot::SaveType::VARIABLE); adjustSize(); + updateGeometry(); } } // namespace advss diff --git a/plugins/base/macro-action-screenshot.hpp b/plugins/base/macro-action-screenshot.hpp index fe8e82db..9fee1ce8 100644 --- a/plugins/base/macro-action-screenshot.hpp +++ b/plugins/base/macro-action-screenshot.hpp @@ -4,6 +4,7 @@ #include "scene-selection.hpp" #include "screenshot-helper.hpp" #include "source-selection.hpp" +#include "variable.hpp" #include @@ -22,27 +23,20 @@ public: std::shared_ptr Copy() const; void ResolveVariablesToFixedValues(); - enum class SaveType { - OBS_DEFAULT, - CUSTOM, - }; - SaveType _saveType = SaveType::OBS_DEFAULT; + enum class SaveType { OBS_DEFAULT_PATH, CUSTOM_PATH, VARIABLE }; + SaveType _saveType = SaveType::OBS_DEFAULT_PATH; - enum class TargetType { - SOURCE, - SCENE, - MAIN_OUTPUT, - }; + enum class TargetType { SOURCE, SCENE, MAIN_OUTPUT }; TargetType _targetType = TargetType::SOURCE; SceneSelection _scene; SourceSelection _source; StringVariable _path = obs_module_text("AdvSceneSwitcher.enterPath"); + std::weak_ptr _variable; private: - void FrontendScreenshot(OBSWeakSource &); - void CustomScreenshot(OBSWeakSource &); - - Screenshot _screenshot; + void FrontendScreenshot(OBSWeakSource &) const; + void CustomScreenshot(OBSWeakSource &) const; + void VariableScreenshot(OBSWeakSource &) const; static bool _registered; static const std::string id; @@ -70,20 +64,21 @@ private slots: void SaveTypeChanged(int index); void TargetTypeChanged(int index); void PathChanged(const QString &text); + void VariableChanged(const QString &); signals: void HeaderInfoChanged(const QString &); -protected: +private: + void SetWidgetVisibility(); + SceneSelectionWidget *_scenes; SourceSelectionWidget *_sources; QComboBox *_saveType; QComboBox *_targetType; FileSelection *_savePath; + VariableSelection *_variables; + std::shared_ptr _entryData; - -private: - void SetWidgetVisibility(); - bool _loading = true; };