mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -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: |
|
||||
${{ 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 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -28,3 +28,6 @@
|
||||
[submodule "deps/libusb"]
|
||||
path = deps/libusb
|
||||
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
|
||||
}
|
||||
|
||||
int ignoreXerror(Display *d, XErrorEvent *e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
auto display = disp();
|
||||
@@ -560,6 +565,7 @@ void PlatformInit()
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
XSetErrorHandler(ignoreXerror);
|
||||
}
|
||||
|
||||
static void cleanupHelper(QLibrary *lib)
|
||||
@@ -576,6 +582,7 @@ void PlatformCleanup()
|
||||
cleanupHelper(libprocps);
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
XSetErrorHandler(NULL);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
@@ -119,17 +117,6 @@ void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *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)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -147,13 +134,9 @@ void MacroActionEdit::UpdateActionState()
|
||||
return;
|
||||
}
|
||||
|
||||
SetEnableAppearance((*_entryData)->Enabled());
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
{
|
||||
_enable->setChecked(value);
|
||||
SetDisableEffect(!value);
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
SetEnableAppearance(enabled);
|
||||
_enable->setChecked(enabled);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
|
||||
@@ -27,8 +27,6 @@ private slots:
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
FilterComboBox *_actionSelection;
|
||||
SwitchButton *_enable;
|
||||
|
||||
@@ -11,15 +11,12 @@ bool MacroAction::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroSegment::Save(obj);
|
||||
obs_data_set_string(obj, "id", GetId().c_str());
|
||||
obs_data_set_bool(obj, "enabled", _enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroAction::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroSegment::Load(obj);
|
||||
obs_data_set_default_bool(obj, "enabled", true);
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,16 +25,6 @@ void MacroAction::LogAction() const
|
||||
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() {}
|
||||
|
||||
std::string_view MacroAction::GetDefaultID()
|
||||
|
||||
@@ -19,13 +19,9 @@ public:
|
||||
// Used to resolve variables before actions are added to action queues
|
||||
virtual void ResolveVariablesToFixedValues();
|
||||
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
|
||||
static std::string_view GetDefaultID();
|
||||
|
||||
private:
|
||||
bool _enabled = true;
|
||||
};
|
||||
|
||||
class EXPORT MacroRefAction : virtual public MacroAction {
|
||||
|
||||
@@ -152,6 +152,8 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
const auto logic = static_cast<Logic::Type>(
|
||||
_logicSelection->itemData(idx).toInt());
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode()
|
||||
@@ -164,6 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
|
||||
const auto logic = (*_entryData)->GetLogicType();
|
||||
_logicSelection->setCurrentIndex(
|
||||
_logicSelection->findData(static_cast<int>(logic)));
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetRootNode(bool root)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#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, "useCustomLabel", _useCustomLabel);
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
if (obs_data_has_user_value(obj, "segmentSettings")) {
|
||||
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");
|
||||
} else {
|
||||
_collapsed = obs_data_get_bool(obj, "collapsed");
|
||||
_useCustomLabel = false;
|
||||
_customLabel = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.segment.defaultCustomLabel");
|
||||
if (!obs_data_has_user_value(data, "version")) {
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
}
|
||||
|
||||
ClearAvailableTempvars();
|
||||
@@ -73,6 +74,16 @@ bool MacroSegment::GetHighlightAndReset()
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroSegment::SetEnabled(bool value)
|
||||
{
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
bool MacroSegment::Enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
std::string MacroSegment::GetVariableValue() const
|
||||
{
|
||||
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()
|
||||
{
|
||||
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
||||
|
||||
@@ -39,6 +39,8 @@ public:
|
||||
virtual std::string GetId() const = 0;
|
||||
void EnableHighlight();
|
||||
bool GetHighlightAndReset();
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
virtual std::string GetVariableValue() const;
|
||||
|
||||
protected:
|
||||
@@ -75,6 +77,7 @@ private:
|
||||
// UI helper
|
||||
bool _highlight = false;
|
||||
bool _collapsed = false;
|
||||
bool _enabled = true;
|
||||
|
||||
// Custom header labels
|
||||
bool _useCustomLabel = false;
|
||||
@@ -118,6 +121,9 @@ signals:
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
||||
protected:
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
|
||||
Section *_section;
|
||||
|
||||
@@ -94,11 +94,15 @@ bool MacroConditionScene::CheckCondition()
|
||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("current",
|
||||
GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("previous",
|
||||
GetWeakSourceName(GetPreviousScene()));
|
||||
return sceneChanged;
|
||||
case Type::NOT_CHANGED:
|
||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("current",
|
||||
GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("previous",
|
||||
GetWeakSourceName(GetPreviousScene()));
|
||||
return !sceneChanged;
|
||||
case Type::CURRENT_PATTERN: {
|
||||
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
||||
@@ -212,8 +216,6 @@ void MacroConditionScene::SetupTempVars()
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_type) {
|
||||
case Type::CURRENT:
|
||||
case Type::CHANGED:
|
||||
case Type::NOT_CHANGED:
|
||||
case Type::CURRENT_PATTERN:
|
||||
AddTempvar("current",
|
||||
obs_module_text(
|
||||
@@ -231,6 +233,15 @@ void MacroConditionScene::SetupTempVars()
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.scene.preview"));
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,31 @@ if(NOT ZLIB_FOUND)
|
||||
return()
|
||||
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 ---
|
||||
|
||||
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}/"
|
||||
"${OPENSSL_INCLUDE_DIR}")
|
||||
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})
|
||||
if(OS_WINDOWS)
|
||||
# Couldn't really find a better way to install runtime dependencies for
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#include <log-helper.hpp>
|
||||
|
||||
#ifdef VERIFY_TIMESTAMPS
|
||||
#include "date/tz.h"
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
@@ -237,15 +241,43 @@ void EventSub::OnOpen(connection_hdl)
|
||||
|
||||
static bool isValidTimestamp(const std::string ×tamp)
|
||||
{
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(timestamp);
|
||||
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S.%fZ");
|
||||
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
tp += std::chrono::hours(1); // UTC
|
||||
std::chrono::system_clock::time_point currentTime =
|
||||
std::chrono::system_clock::now();
|
||||
auto diff = currentTime - tp;
|
||||
return diff <= std::chrono::minutes(10);
|
||||
#ifdef VERIFY_TIMESTAMPS
|
||||
// Example input: 2023-07-19T14:56:51.634234626Z
|
||||
try {
|
||||
// Discard the nanosecond part
|
||||
static constexpr size_t dotPos = 19;
|
||||
std::string trimmed = timestamp.substr(0, dotPos);
|
||||
auto tzStart = timestamp.find_first_of("Z+-", dotPos);
|
||||
trimmed = timestamp.substr(0, dotPos);
|
||||
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)
|
||||
@@ -288,7 +320,8 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
||||
obs_data_get_string(metadata, "message_timestamp");
|
||||
if (!isValidTimestamp(timestamp)) {
|
||||
blog(LOG_WARNING,
|
||||
"Discarding Twitch EventSub with invalid timestamp");
|
||||
"Discarding Twitch EventSub with invalid timestamp %s",
|
||||
timestamp.c_str());
|
||||
return;
|
||||
}
|
||||
std::string id = obs_data_get_string(metadata, "message_id");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "points-reward-selection.hpp"
|
||||
#include "twitch-helpers.hpp"
|
||||
|
||||
#include <log-helper.hpp>
|
||||
#include <obs-module-helper.hpp>
|
||||
#include <ui-helpers.hpp>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user