mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 17:16:00 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70bbc7cdac | ||
|
|
d892298995 | ||
|
|
0fe31432be | ||
|
|
aaa0113ccb | ||
|
|
b908954b46 | ||
|
|
b0eede8a85 |
5
.github/workflows/build-project.yaml
vendored
5
.github/workflows/build-project.yaml
vendored
@@ -210,6 +210,11 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-ccache-x86_64-
|
${{ runner.os }}-ccache-x86_64-
|
||||||
|
|
||||||
|
- name: Set up CMake 🏗️
|
||||||
|
uses: jwlawson/actions-setup-cmake@v1.13
|
||||||
|
with:
|
||||||
|
cmake-version: '3.24.x'
|
||||||
|
|
||||||
- name: Set up Homebrew 🍺
|
- name: Set up Homebrew 🍺
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
|
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -28,3 +28,6 @@
|
|||||||
[submodule "deps/libusb"]
|
[submodule "deps/libusb"]
|
||||||
path = deps/libusb
|
path = deps/libusb
|
||||||
url = https://github.com/libusb/libusb.git
|
url = https://github.com/libusb/libusb.git
|
||||||
|
[submodule "deps/date"]
|
||||||
|
path = deps/date
|
||||||
|
url = https://github.com/HowardHinnant/date.git
|
||||||
|
|||||||
1
deps/date
vendored
Submodule
1
deps/date
vendored
Submodule
Submodule deps/date added at 5bdb7e6f31
@@ -550,6 +550,11 @@ static void initProc2()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ignoreXerror(Display *d, XErrorEvent *e)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformInit()
|
void PlatformInit()
|
||||||
{
|
{
|
||||||
auto display = disp();
|
auto display = disp();
|
||||||
@@ -560,6 +565,7 @@ void PlatformInit()
|
|||||||
initXss();
|
initXss();
|
||||||
initProcps();
|
initProcps();
|
||||||
initProc2();
|
initProc2();
|
||||||
|
XSetErrorHandler(ignoreXerror);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanupHelper(QLibrary *lib)
|
static void cleanupHelper(QLibrary *lib)
|
||||||
@@ -576,6 +582,7 @@ void PlatformCleanup()
|
|||||||
cleanupHelper(libprocps);
|
cleanupHelper(libprocps);
|
||||||
cleanupHelper(libproc2);
|
cleanupHelper(libproc2);
|
||||||
cleanupDisplay();
|
cleanupDisplay();
|
||||||
|
XSetErrorHandler(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
#include "section.hpp"
|
#include "section.hpp"
|
||||||
#include "switch-button.hpp"
|
#include "switch-button.hpp"
|
||||||
|
|
||||||
#include <QGraphicsOpacityEffect>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static inline void populateActionSelection(QComboBox *list)
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
@@ -119,17 +117,6 @@ void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
|||||||
_entryData = data;
|
_entryData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionEdit::SetDisableEffect(bool value)
|
|
||||||
{
|
|
||||||
if (value) {
|
|
||||||
auto effect = new QGraphicsOpacityEffect(this);
|
|
||||||
effect->setOpacity(0.5);
|
|
||||||
_section->setGraphicsEffect(effect);
|
|
||||||
} else {
|
|
||||||
_section->setGraphicsEffect(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionEdit::ActionEnableChanged(bool value)
|
void MacroActionEdit::ActionEnableChanged(bool value)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
@@ -147,13 +134,9 @@ void MacroActionEdit::UpdateActionState()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEnableAppearance((*_entryData)->Enabled());
|
const bool enabled = (*_entryData)->Enabled();
|
||||||
}
|
SetEnableAppearance(enabled);
|
||||||
|
_enable->setChecked(enabled);
|
||||||
void MacroActionEdit::SetEnableAppearance(bool value)
|
|
||||||
{
|
|
||||||
_enable->setChecked(value);
|
|
||||||
SetDisableEffect(!value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<MacroSegment> Data() const;
|
std::shared_ptr<MacroSegment> Data() const;
|
||||||
void SetDisableEffect(bool);
|
|
||||||
void SetEnableAppearance(bool);
|
|
||||||
|
|
||||||
FilterComboBox *_actionSelection;
|
FilterComboBox *_actionSelection;
|
||||||
SwitchButton *_enable;
|
SwitchButton *_enable;
|
||||||
|
|||||||
@@ -11,15 +11,12 @@ bool MacroAction::Save(obs_data_t *obj) const
|
|||||||
{
|
{
|
||||||
MacroSegment::Save(obj);
|
MacroSegment::Save(obj);
|
||||||
obs_data_set_string(obj, "id", GetId().c_str());
|
obs_data_set_string(obj, "id", GetId().c_str());
|
||||||
obs_data_set_bool(obj, "enabled", _enabled);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroAction::Load(obs_data_t *obj)
|
bool MacroAction::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroSegment::Load(obj);
|
MacroSegment::Load(obj);
|
||||||
obs_data_set_default_bool(obj, "enabled", true);
|
|
||||||
_enabled = obs_data_get_bool(obj, "enabled");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,16 +25,6 @@ void MacroAction::LogAction() const
|
|||||||
ablog(LOG_INFO, "performed action %s", GetId().c_str());
|
ablog(LOG_INFO, "performed action %s", GetId().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroAction::SetEnabled(bool value)
|
|
||||||
{
|
|
||||||
_enabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroAction::Enabled() const
|
|
||||||
{
|
|
||||||
return _enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroAction::ResolveVariablesToFixedValues() {}
|
void MacroAction::ResolveVariablesToFixedValues() {}
|
||||||
|
|
||||||
std::string_view MacroAction::GetDefaultID()
|
std::string_view MacroAction::GetDefaultID()
|
||||||
|
|||||||
@@ -19,13 +19,9 @@ public:
|
|||||||
// Used to resolve variables before actions are added to action queues
|
// Used to resolve variables before actions are added to action queues
|
||||||
virtual void ResolveVariablesToFixedValues();
|
virtual void ResolveVariablesToFixedValues();
|
||||||
|
|
||||||
void SetEnabled(bool);
|
|
||||||
bool Enabled() const;
|
|
||||||
|
|
||||||
static std::string_view GetDefaultID();
|
static std::string_view GetDefaultID();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _enabled = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EXPORT MacroRefAction : virtual public MacroAction {
|
class EXPORT MacroRefAction : virtual public MacroAction {
|
||||||
|
|||||||
@@ -152,6 +152,8 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
|||||||
const auto logic = static_cast<Logic::Type>(
|
const auto logic = static_cast<Logic::Type>(
|
||||||
_logicSelection->itemData(idx).toInt());
|
_logicSelection->itemData(idx).toInt());
|
||||||
(*_entryData)->SetLogicType(logic);
|
(*_entryData)->SetLogicType(logic);
|
||||||
|
|
||||||
|
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionEdit::IsRootNode()
|
bool MacroConditionEdit::IsRootNode()
|
||||||
@@ -164,6 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
|
|||||||
const auto logic = (*_entryData)->GetLogicType();
|
const auto logic = (*_entryData)->GetLogicType();
|
||||||
_logicSelection->setCurrentIndex(
|
_logicSelection->setCurrentIndex(
|
||||||
_logicSelection->findData(static_cast<int>(logic)));
|
_logicSelection->findData(static_cast<int>(logic)));
|
||||||
|
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::SetRootNode(bool root)
|
void MacroConditionEdit::SetRootNode(bool root)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
|
#include <QGraphicsOpacityEffect>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
@@ -24,24 +25,24 @@ bool MacroSegment::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_bool(data, "collapsed", _collapsed);
|
obs_data_set_bool(data, "collapsed", _collapsed);
|
||||||
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
||||||
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
||||||
|
obs_data_set_bool(data, "enabled", _enabled);
|
||||||
|
obs_data_set_int(data, "version", 1);
|
||||||
obs_data_set_obj(obj, "segmentSettings", data);
|
obs_data_set_obj(obj, "segmentSettings", data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroSegment::Load(obs_data_t *obj)
|
bool MacroSegment::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
|
OBSDataAutoRelease data = obs_data_get_obj(obj, "segmentSettings");
|
||||||
|
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||||
|
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||||
|
_customLabel = obs_data_get_string(data, "customLabel");
|
||||||
|
obs_data_set_default_bool(data, "enabled", true);
|
||||||
|
_enabled = obs_data_get_bool(data, "enabled");
|
||||||
|
|
||||||
// TODO: remove this fallback at some point
|
// TODO: remove this fallback at some point
|
||||||
if (obs_data_has_user_value(obj, "segmentSettings")) {
|
if (!obs_data_has_user_value(data, "version")) {
|
||||||
OBSDataAutoRelease data =
|
_enabled = obs_data_get_bool(obj, "enabled");
|
||||||
obs_data_get_obj(obj, "segmentSettings");
|
|
||||||
_collapsed = obs_data_get_bool(data, "collapsed");
|
|
||||||
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
|
||||||
_customLabel = obs_data_get_string(data, "customLabel");
|
|
||||||
} else {
|
|
||||||
_collapsed = obs_data_get_bool(obj, "collapsed");
|
|
||||||
_useCustomLabel = false;
|
|
||||||
_customLabel = obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.segment.defaultCustomLabel");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearAvailableTempvars();
|
ClearAvailableTempvars();
|
||||||
@@ -73,6 +74,16 @@ bool MacroSegment::GetHighlightAndReset()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroSegment::SetEnabled(bool value)
|
||||||
|
{
|
||||||
|
_enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroSegment::Enabled() const
|
||||||
|
{
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
std::string MacroSegment::GetVariableValue() const
|
std::string MacroSegment::GetVariableValue() const
|
||||||
{
|
{
|
||||||
if (_supportsVariableValue) {
|
if (_supportsVariableValue) {
|
||||||
@@ -320,6 +331,22 @@ void MacroSegmentEdit::Collapsed(bool collapsed)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroSegmentEdit::SetDisableEffect(bool value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
auto effect = new QGraphicsOpacityEffect(this);
|
||||||
|
effect->setOpacity(0.5);
|
||||||
|
_section->setGraphicsEffect(effect);
|
||||||
|
} else {
|
||||||
|
_section->setGraphicsEffect(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSegmentEdit::SetEnableAppearance(bool value)
|
||||||
|
{
|
||||||
|
SetDisableEffect(!value);
|
||||||
|
}
|
||||||
|
|
||||||
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
||||||
{
|
{
|
||||||
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public:
|
|||||||
virtual std::string GetId() const = 0;
|
virtual std::string GetId() const = 0;
|
||||||
void EnableHighlight();
|
void EnableHighlight();
|
||||||
bool GetHighlightAndReset();
|
bool GetHighlightAndReset();
|
||||||
|
void SetEnabled(bool);
|
||||||
|
bool Enabled() const;
|
||||||
virtual std::string GetVariableValue() const;
|
virtual std::string GetVariableValue() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -75,6 +77,7 @@ private:
|
|||||||
// UI helper
|
// UI helper
|
||||||
bool _highlight = false;
|
bool _highlight = false;
|
||||||
bool _collapsed = false;
|
bool _collapsed = false;
|
||||||
|
bool _enabled = true;
|
||||||
|
|
||||||
// Custom header labels
|
// Custom header labels
|
||||||
bool _useCustomLabel = false;
|
bool _useCustomLabel = false;
|
||||||
@@ -118,6 +121,9 @@ signals:
|
|||||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void SetDisableEffect(bool);
|
||||||
|
void SetEnableAppearance(bool);
|
||||||
|
|
||||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||||
|
|
||||||
Section *_section;
|
Section *_section;
|
||||||
|
|||||||
@@ -94,11 +94,15 @@ bool MacroConditionScene::CheckCondition()
|
|||||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||||
SetTempVarValue("current",
|
SetTempVarValue("current",
|
||||||
GetWeakSourceName(GetCurrentScene()));
|
GetWeakSourceName(GetCurrentScene()));
|
||||||
|
SetTempVarValue("previous",
|
||||||
|
GetWeakSourceName(GetPreviousScene()));
|
||||||
return sceneChanged;
|
return sceneChanged;
|
||||||
case Type::NOT_CHANGED:
|
case Type::NOT_CHANGED:
|
||||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||||
SetTempVarValue("current",
|
SetTempVarValue("current",
|
||||||
GetWeakSourceName(GetCurrentScene()));
|
GetWeakSourceName(GetCurrentScene()));
|
||||||
|
SetTempVarValue("previous",
|
||||||
|
GetWeakSourceName(GetPreviousScene()));
|
||||||
return !sceneChanged;
|
return !sceneChanged;
|
||||||
case Type::CURRENT_PATTERN: {
|
case Type::CURRENT_PATTERN: {
|
||||||
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
||||||
@@ -212,8 +216,6 @@ void MacroConditionScene::SetupTempVars()
|
|||||||
MacroCondition::SetupTempVars();
|
MacroCondition::SetupTempVars();
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case Type::CURRENT:
|
case Type::CURRENT:
|
||||||
case Type::CHANGED:
|
|
||||||
case Type::NOT_CHANGED:
|
|
||||||
case Type::CURRENT_PATTERN:
|
case Type::CURRENT_PATTERN:
|
||||||
AddTempvar("current",
|
AddTempvar("current",
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
@@ -231,6 +233,15 @@ void MacroConditionScene::SetupTempVars()
|
|||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.tempVar.scene.preview"));
|
"AdvSceneSwitcher.tempVar.scene.preview"));
|
||||||
break;
|
break;
|
||||||
|
case Type::CHANGED:
|
||||||
|
case Type::NOT_CHANGED:
|
||||||
|
AddTempvar("current",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.scene.current"));
|
||||||
|
AddTempvar("previous",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.scene.previous"));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,31 @@ if(NOT ZLIB_FOUND)
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(DATE_LIB_DIR "${ADVSS_SOURCE_DIR}/deps/date")
|
||||||
|
if(EXISTS "${DATE_LIB_DIR}/CMakeLists.txt")
|
||||||
|
set(BUILD_TZ_LIB ON)
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
if(CURL_FOUND AND TARGET CURL::libcurl)
|
||||||
|
get_target_property(CURL_INCLUDE_DIR CURL::libcurl
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
add_subdirectory("${DATE_LIB_DIR}" "${DATE_LIB_DIR}/build"
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
target_include_directories(date-tz PRIVATE "${CURL_INCLUDE_DIR}")
|
||||||
|
set(VERIFY_TWITCH_TIMESTAMPS ON)
|
||||||
|
else()
|
||||||
|
message(WARNING "CURL not found - not verifying Twitch timestamps")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_subdirectory("${DATE_LIB_DIR}" "${DATE_LIB_DIR}/build" EXCLUDE_FROM_ALL)
|
||||||
|
target_compile_options(date-tz PUBLIC -Wno-error=conversion
|
||||||
|
-Wno-error=shadow)
|
||||||
|
set(VERIFY_TWITCH_TIMESTAMPS ON)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "date lib not found in \"${DATE_LIB_DIR}\"!\n"
|
||||||
|
"Twitch timestamps will not be checked!")
|
||||||
|
endif()
|
||||||
|
|
||||||
# --- End of section ---
|
# --- End of section ---
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} MODULE)
|
add_library(${PROJECT_NAME} MODULE)
|
||||||
@@ -76,6 +101,14 @@ set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
|
|||||||
target_include_directories(${PROJECT_NAME} PRIVATE "${CPP_HTTPLIB_DIR}/"
|
target_include_directories(${PROJECT_NAME} PRIVATE "${CPP_HTTPLIB_DIR}/"
|
||||||
"${OPENSSL_INCLUDE_DIR}")
|
"${OPENSSL_INCLUDE_DIR}")
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSSL_LIBRARIES} ZLIB::ZLIB)
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSSL_LIBRARIES} ZLIB::ZLIB)
|
||||||
|
if(DEFINED VERIFY_TWITCH_TIMESTAMPS)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE VERIFY_TIMESTAMPS=1)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE date::date-tz)
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE CURL::libcurl)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
install_advss_plugin(${PROJECT_NAME})
|
install_advss_plugin(${PROJECT_NAME})
|
||||||
if(OS_WINDOWS)
|
if(OS_WINDOWS)
|
||||||
# Couldn't really find a better way to install runtime dependencies for
|
# Couldn't really find a better way to install runtime dependencies for
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
|
|
||||||
|
#ifdef VERIFY_TIMESTAMPS
|
||||||
|
#include "date/tz.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
using websocketpp::lib::placeholders::_1;
|
using websocketpp::lib::placeholders::_1;
|
||||||
@@ -237,15 +241,43 @@ void EventSub::OnOpen(connection_hdl)
|
|||||||
|
|
||||||
static bool isValidTimestamp(const std::string ×tamp)
|
static bool isValidTimestamp(const std::string ×tamp)
|
||||||
{
|
{
|
||||||
std::tm tm = {};
|
#ifdef VERIFY_TIMESTAMPS
|
||||||
std::istringstream ss(timestamp);
|
// Example input: 2023-07-19T14:56:51.634234626Z
|
||||||
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S.%fZ");
|
try {
|
||||||
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
// Discard the nanosecond part
|
||||||
tp += std::chrono::hours(1); // UTC
|
static constexpr size_t dotPos = 19;
|
||||||
std::chrono::system_clock::time_point currentTime =
|
std::string trimmed = timestamp.substr(0, dotPos);
|
||||||
std::chrono::system_clock::now();
|
auto tzStart = timestamp.find_first_of("Z+-", dotPos);
|
||||||
auto diff = currentTime - tp;
|
trimmed = timestamp.substr(0, dotPos);
|
||||||
return diff <= std::chrono::minutes(10);
|
if (tzStart != std::string::npos) {
|
||||||
|
trimmed += timestamp.substr(tzStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream in(trimmed);
|
||||||
|
date::sys_time<std::chrono::seconds> parsedTime;
|
||||||
|
in >> date::parse("%FT%TZ", parsedTime);
|
||||||
|
if (in.fail()) {
|
||||||
|
blog(LOG_WARNING, "failed to parse timestamp %s",
|
||||||
|
timestamp.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = date::zoned_time{date::current_zone(),
|
||||||
|
std::chrono::system_clock::now()}
|
||||||
|
.get_sys_time();
|
||||||
|
|
||||||
|
auto duration = now - parsedTime;
|
||||||
|
// Clocks might be off by a bit, so allow negative values also
|
||||||
|
return duration <= std::chrono::minutes(10) &&
|
||||||
|
duration >= std::chrono::minutes(-1);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __func__, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Just assume timestamps are always valid
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventSub::IsValidMessageID(const std::string &id)
|
bool EventSub::IsValidMessageID(const std::string &id)
|
||||||
@@ -288,7 +320,8 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
|||||||
obs_data_get_string(metadata, "message_timestamp");
|
obs_data_get_string(metadata, "message_timestamp");
|
||||||
if (!isValidTimestamp(timestamp)) {
|
if (!isValidTimestamp(timestamp)) {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"Discarding Twitch EventSub with invalid timestamp");
|
"Discarding Twitch EventSub with invalid timestamp %s",
|
||||||
|
timestamp.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string id = obs_data_get_string(metadata, "message_id");
|
std::string id = obs_data_get_string(metadata, "message_id");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "points-reward-selection.hpp"
|
#include "points-reward-selection.hpp"
|
||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
|
#include <log-helper.hpp>
|
||||||
#include <obs-module-helper.hpp>
|
#include <obs-module-helper.hpp>
|
||||||
#include <ui-helpers.hpp>
|
#include <ui-helpers.hpp>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user